diff options
Diffstat (limited to 'contrib/gcc/cp/method.c')
| -rw-r--r-- | contrib/gcc/cp/method.c | 2878 |
1 files changed, 1499 insertions, 1379 deletions
diff --git a/contrib/gcc/cp/method.c b/contrib/gcc/cp/method.c index a0e152751402..29b31c426468 100644 --- a/contrib/gcc/cp/method.c +++ b/contrib/gcc/cp/method.c @@ -1,9 +1,9 @@ /* Handle the hair of processing (but not expanding) inline functions. Also manage function and variable name overloading. - Copyright (C) 1987, 89, 92, 93, 94, 1995 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 @@ -21,28 +21,33 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef __GNUC__ +#define __inline +#endif + #ifndef PARM_CAN_BE_ARRAY_TYPE #define PARM_CAN_BE_ARRAY_TYPE 1 #endif /* Handle method declarations. */ -#include <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" #include "hard-reg-set.h" #include "flags.h" +#include "toplev.h" /* TREE_LIST of the current inline functions that need to be processed. */ struct pending_inline *pending_inlines; +int static_labelno; + #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free @@ -50,6 +55,38 @@ struct pending_inline *pending_inlines; 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((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 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)); +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)); +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) \ @@ -62,10 +99,6 @@ static char *scratch_firstobj; # 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 () { @@ -91,10 +124,12 @@ do_inline_function_hair (type, friend_list) 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) @@ -112,11 +147,6 @@ do_inline_function_hair (type, friend_list) 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); } @@ -135,157 +165,142 @@ do_inline_function_hair (type, friend_list) 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); } } -/* 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; - - 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); - cp_error ("call to non-const %s `%#D' with const object", - name_kind, cp->function); - return; - } - - ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function)); - tta = parmtypes; - - while (i-- > 0) - { - ttf = TREE_CHAIN (ttf); - tta = TREE_CHAIN (tta); - } +/* Here is where overload code starts. */ - 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 (); +/* type tables for K and B type compression */ +static tree *btypelist = NULL; +static tree *ktypelist = NULL; +static int maxbsize = 0; +static int maxksize = 0; - tmp_firstobj = (char *)alloca (obstack_object_size (&scratch_obstack)); - bcopy (obstack_base (&scratch_obstack), tmp_firstobj, - obstack_object_size (&scratch_obstack)); - error (tmp_firstobj); -} - -/* Here is where overload code starts. */ +/* number of each type seen */ +static int maxbtype = 0; +static int maxktype = 0; -/* Array of types seen so far in top-level call to `build_overload_name'. +/* Array of types seen so far in top-level call to `build_mangled_name'. Allocated and deallocated by caller. */ -static tree *typevec; - -/* Number of types interned by `build_overload_name' so far. */ -static int maxtype; +static tree *typevec = NULL; +static int typevec_size; -/* Number of occurrences of last type seen. */ -static int nrepeats; +/* Number of types interned by `build_mangled_name' so far. */ +static int maxtype = 0; /* Nonzero if we should not try folding parameter types. */ static int nofold; -#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) + { + nofold = 0; + maxbtype = 0; + maxktype = 0; + maxbsize = 50; + maxksize = 50; + btypelist = (tree *)xmalloc (sizeof (tree) * maxbsize); + ktypelist = (tree *)xmalloc (sizeof (tree) * maxksize); + } +} + +static __inline void +end_squangling () +{ + if (flag_do_squangling) + { + if (ktypelist) + free (ktypelist); + if (btypelist) + free (btypelist); + maxbsize = 0; + maxksize = 0; + maxbtype = 0; + maxktype = 0; + ktypelist = NULL; + btypelist = NULL; + } +} /* Code to concatenate an asciified integer to a string. */ -static -#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 -flush_repeats (type) +static __inline void +flush_repeats (nrepeats, type) + int nrepeats; tree type; { int tindex = 0; @@ -302,86 +317,327 @@ flush_repeats (type) } else OB_PUTC ('T'); - nrepeats = 0; icat (tindex); if (tindex > 9) OB_PUTC ('_'); } -static int numeric_output_need_bar; -static void build_overload_identifier (); +/* Returns nonzero iff this is a type to which we will want to make + back-references (using the `B' code). */ + +int +is_back_referenceable_type (type) + tree type; +{ + if (btypelist == NULL) + /* We're not generating any back-references. */ + return 0; + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case REAL_TYPE: + case VOID_TYPE: + case BOOLEAN_TYPE: + /* These types have single-character manglings, so there's no + point in generating back-references. */ + return 0; + + case TEMPLATE_TYPE_PARM: + /* It would be a bit complex to demangle signatures correctly if + we generated back-references to these, and the manglings of + type parameters are short. */ + return 0; + + default: + return 1; + } +} + +/* Issue the squangling code indicating NREPEATS repetitions of TYPE, + which was the last parameter type output. */ + +static void +issue_nrepeats (nrepeats, type) + int nrepeats; + tree type; +{ + if (nrepeats == 1 && !is_back_referenceable_type (type)) + /* For types whose manglings are short, don't bother using the + repetition code if there's only one repetition, since the + repetition code will be about as long as the ordinary mangling. */ + build_mangled_name_for_type (type); + else + { + OB_PUTC ('n'); + icat (nrepeats); + if (nrepeats > 9) + OB_PUTC ('_'); + } +} + +/* Check to see if a tree node has been entered into the Kcode typelist */ +/* if not, add it. 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 (ktypelist, sizeof (tree) * maxksize); + } + ktypelist[maxktype++] = localnode; + } + return -1; +} + + +static __inline int +issue_ktype (decl) + tree decl; +{ + int kindex; + kindex = check_ktype (decl, FALSE); + if (kindex != -1) + { + OB_PUTC ('K'); + icat (kindex); + if (kindex > 9) + OB_PUTC ('_'); + return TRUE; + } + return FALSE; +} + +/* Build a representation for DECL, which may be an entity not at + global scope. If so, a marker indicating that the name is + qualified has already been output, but the qualifying context has + not. */ static void build_overload_nested_name (decl) tree decl; { - if (DECL_CONTEXT (decl)) + tree context; + + if (ktypelist && issue_ktype (decl)) + return; + + if (decl == global_namespace) + return; + + context = CP_DECL_CONTEXT (decl); + + /* try to issue a K type, and if we can't continue the normal path */ + if (!(ktypelist && issue_ktype (context))) + { + /* For a template type parameter, we want to output an 'Xn' + rather than 'T' or some such. */ + if (TREE_CODE (context) == TEMPLATE_TYPE_PARM + || TREE_CODE (context) == TEMPLATE_TEMPLATE_PARM) + build_mangled_name_for_type (context); + else { - tree context = DECL_CONTEXT (decl); if (TREE_CODE_CLASS (TREE_CODE (context)) == 't') - context = TYPE_MAIN_DECL (context); + context = TYPE_NAME (context); build_overload_nested_name (context); } + } 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 */ - { - tree name = DECL_NAME (decl); - build_overload_identifier (name); - } + build_overload_identifier (decl); } -/* Encoding for an INTEGER_CST value. */ +/* Output the decimal representation of I. If I > 9, the decimal + representation is preceeded and followed by an underscore. */ + static void -build_overload_int (value) +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; { - my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243); - if (TYPE_PRECISION (value) == 2 * HOST_BITS_PER_WIDE_INT) + OB_PUTC2 ('Q', '2'); + numeric_output_need_bar = 0; + build_mangled_name_for_type (TREE_OPERAND (value, 0)); + build_overload_identifier (TREE_OPERAND (value, 1)); +} + +/* Encoding for an INTEGER_CST value. */ + +static void +build_overload_int (value, in_template) + tree value; + int in_template; +{ + if (in_template && TREE_CODE (value) != INTEGER_CST) { - if (tree_int_cst_lt (value, integer_zero_node)) + if (TREE_CODE (value) == SCOPE_REF) + { + build_overload_scope_ref (value); + return; + } + + OB_PUTC ('E'); + numeric_output_need_bar = 0; + + if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (value)))) + { + int i; + int operands = tree_code_length[(int) TREE_CODE (value)]; + tree id; + char* name; + + id = ansi_opname [(int) TREE_CODE (value)]; + my_friendly_assert (id != NULL_TREE, 0); + name = IDENTIFIER_POINTER (id); + if (name[0] != '_' || name[1] != '_') + /* On some erroneous inputs, we can get here with VALUE a + LOOKUP_EXPR. In that case, the NAME will be the + identifier for "<invalid operator>". We must survive + this routine in order to issue a sensible error + message, so we fall through to the case below. */ + goto bad_value; + + for (i = 0; i < operands; ++i) + { + tree operand; + enum tree_code tc; + + /* We just outputted either the `E' or the name of the + operator. */ + numeric_output_need_bar = 0; + + if (i != 0) + /* Skip the leading underscores. */ + OB_PUTCP (name + 2); + + operand = TREE_OPERAND (value, i); + tc = TREE_CODE (operand); + + if (TREE_CODE_CLASS (tc) == 't') + /* We can get here with sizeof, e.g.: + + template <class T> void f(A<sizeof(T)>); */ + build_mangled_name_for_type (operand); + else if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc))) + build_overload_int (operand, in_template); + else + build_overload_value (TREE_TYPE (operand), + operand, + in_template); + } + } + else { - OB_PUTC ('m'); - value = build_int_2 (~ TREE_INT_CST_LOW (value), - - TREE_INT_CST_HIGH (value)); + /* We don't ever want this output, but it's + inconvenient not to be able to build the string. + This should cause assembler errors we'll notice. */ + + static int n; + bad_value: + sprintf (digit_buffer, " *%d", n++); + OB_PUTCP (digit_buffer); } + + OB_PUTC ('W'); + numeric_output_need_bar = 0; + return; + } + + my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243); + if (TYPE_PRECISION (TREE_TYPE (value)) == 2 * HOST_BITS_PER_WIDE_INT) + { if (TREE_INT_CST_HIGH (value) != (TREE_INT_CST_LOW (value) >> (HOST_BITS_PER_WIDE_INT - 1))) { /* need to print a DImode value in decimal */ - 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) { @@ -389,6 +645,12 @@ build_overload_value (type, value) 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) { @@ -411,65 +673,82 @@ build_overload_value (type, value) 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 (value) == CONSTRUCTOR) { - /* This is dangerous code, crack built up pointer to members. */ + /* 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)); @@ -479,9 +758,9 @@ build_overload_value (type, value) 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) { @@ -496,8 +775,7 @@ build_overload_value (type, value) 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; } } @@ -507,23 +785,31 @@ build_overload_value (type, value) } 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) { 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 if (TREE_CODE (value) == SCOPE_REF) + build_overload_scope_ref (value); else my_friendly_abort (71); break; /* not really needed */ @@ -535,46 +821,120 @@ build_overload_value (type, value) } } + +/* Add encodings for the declaration of template template parameters. + PARMLIST must be a TREE_VEC */ + +static void +build_template_template_parm_names (parmlist) + tree parmlist; +{ + int i, nparms; + + my_friendly_assert (TREE_CODE (parmlist) == TREE_VEC, 246.5); + nparms = TREE_VEC_LENGTH (parmlist); + icat (nparms); + for (i = 0; i < nparms; i++) + { + tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i)); + if (TREE_CODE (parm) == TYPE_DECL) + { + /* This parameter is a type. */ + OB_PUTC ('Z'); + } + else if (TREE_CODE (parm) == TEMPLATE_DECL) + { + /* This parameter is a template. */ + OB_PUTC ('z'); + build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm)); + } + else + /* It's a PARM_DECL. */ + build_mangled_name_for_type (TREE_TYPE (parm)); + } +} + + +/* Add encodings for the vector of template parameters in PARMLIST, + given the vector of arguments to be substituted in ARGLIST. */ + +static void +build_template_parm_names (parmlist, arglist) + tree parmlist; + tree arglist; +{ + int i, nparms; + + 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_for_type (arg); + } + else if (TREE_CODE (parm) == TEMPLATE_DECL) + { + /* This parameter is a template. */ + if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) + /* Output parameter declaration, argument index and level */ + build_mangled_name_for_type (arg); + else + { + /* A TEMPLATE_DECL node, output the parameter declaration + and template name */ + + OB_PUTC ('z'); + build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm)); + icat (IDENTIFIER_LENGTH (DECL_NAME (arg))); + OB_PUTID (DECL_NAME (arg)); + } + } + else + { + parm = tsubst (parm, arglist, NULL_TREE); + /* It's a PARM_DECL. */ + build_mangled_name_for_type (TREE_TYPE (parm)); + build_overload_value (parm, arg, uses_template_parms (arglist)); + } + } + } + +/* Output the representation for NAME, which is either a TYPE_DECL or + an IDENTIFIER. */ + static void build_overload_identifier (name) tree name; { - if (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_CODE (DECL_CONTEXT (CLASSTYPE_TI_TEMPLATE + (TREE_TYPE (name)))) + == FUNCTION_DECL))) + { + /* NAME is the TYPE_DECL for a template specialization. */ tree template, parmlist, arglist, tname; - int i, nparms; - template = IDENTIFIER_TEMPLATE (name); - arglist = TREE_VALUE (template); + template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name)); + arglist = innermost_args (TREE_VALUE (template), 0); 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 { + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); if (numeric_output_need_bar) { OB_PUTC ('_'); @@ -585,6 +945,81 @@ build_overload_identifier (name) } } +/* Given DECL, either a class TYPE, TYPE_DECL or FUNCTION_DECL, produce + the mangling for it. Used by build_mangled_name and build_static_name. */ + +static void +build_qualified_name (decl) + tree decl; +{ + tree context; + int i = 1; + + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't') + decl = TYPE_NAME (decl); + + /* If DECL_ASSEMBLER_NAME has been set properly, use it. */ + if (TREE_CODE (decl) == TYPE_DECL + && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling) + { + tree id = DECL_ASSEMBLER_NAME (decl); + OB_PUTID (id); + if (ISDIGIT (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1])) + numeric_output_need_bar = 1; + return; + } + + context = decl; + /* if we can't find a Ktype, do it the hard way */ + if (check_ktype (context, FALSE) == -1) + { + /* count type and namespace scopes */ + while (DECL_CONTEXT (context) && DECL_CONTEXT (context) != global_namespace) + { + 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); + } + } + + if (i > 1) + { + OB_PUTC ('Q'); + build_underscore_int (i); + numeric_output_need_bar = 0; + } + build_overload_nested_name (decl); +} + +/* Output the mangled representation for TYPE. If EXTRA_GCODE is + non-zero, mangled names for structure/union types are intentionally + mangled differently from the method described in the ARM. */ + +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); + type = canonical_type_variant (type); + process_modifiers (type); + process_overload_item (type, extra_Gcode); +} + +/* Like build_mangled_name_for_type_with_Gcode, but never outputs the + `G'. */ + +void +build_mangled_name_for_type (type) + tree type; +{ + build_mangled_name_for_type_with_Gcode (type, 0); +} + /* Given a list of parameters in PARMTYPES, create an unambiguous overload string. Should distinguish any type that C (or C++) can distinguish. I.e., pointers to functions are treated correctly. @@ -602,375 +1037,495 @@ build_overload_name (parmtypes, begin, end) tree parmtypes; int begin, end; { - int just_one; - tree parmtype; + char *ret; + start_squangling (); + ret = build_mangled_name (parmtypes, begin, end); + end_squangling (); + return ret ; +} - if (begin) OB_INIT (); - numeric_output_need_bar = 0; +/* Output the mangled representation for PARMTYPES. If PARMTYPES is a + TREE_LIST, then it is a list of parameter types. Otherwise, + PARMTYPES must be a single type. */ - if ((just_one = (TREE_CODE (parmtypes) != TREE_LIST))) - { - parmtype = parmtypes; - goto only_one; - } +static char * +build_mangled_name (parmtypes, begin, end) + tree parmtypes; + int begin, end; +{ + if (begin) + OB_INIT (); - while (parmtypes) + if (TREE_CODE (parmtypes) != TREE_LIST) + /* There is only one type. */ + build_mangled_name_for_type (parmtypes); + else { - parmtype = TREE_VALUE (parmtypes); - - only_one: + /* There are several types in a parameter list. */ + int nrepeats = 0; + int old_style_repeats = !flag_do_squangling && !nofold && typevec; + tree last_type = NULL_TREE; - if (! nofold && ! just_one) + for (; parmtypes && parmtypes != void_list_node; + parmtypes = TREE_CHAIN (parmtypes)) { - /* Every argument gets counted. */ - typevec[maxtype++] = parmtype; + tree parmtype = canonical_type_variant (TREE_VALUE (parmtypes)); - if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2]) + if (old_style_repeats) { - nrepeats++; - goto next; + /* Every argument gets counted. */ + my_friendly_assert (maxtype < typevec_size, 387); + typevec[maxtype++] = parmtype; } - if (nrepeats) - flush_repeats (typevec[maxtype-2]); + if (parmtype == last_type) + { + if (flag_do_squangling + || (old_style_repeats && TREE_USED (parmtype) + && !TYPE_FOR_JAVA (parmtype))) + { + /* The next type is the same as this one. Keep + track of the repetition, and output the repeat + count later. */ + nrepeats++; + continue; + } + } + else if (nrepeats != 0) + { + /* Indicate how many times the previous parameter was + repeated. */ + if (old_style_repeats) + flush_repeats (nrepeats, last_type); + else + issue_nrepeats (nrepeats, last_type); + nrepeats = 0; + } + + last_type = parmtype; - if (TREE_USED (parmtype)) + if (old_style_repeats) { - flush_repeats (parmtype); - goto next; + if (nrepeats) + { + flush_repeats (nrepeats, last_type); + nrepeats = 0; + } + + 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 (nrepeats, parmtype); +#endif + nrepeats = 0; + 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)) + && ! TYPE_FOR_JAVA (parmtype)) + TREE_USED (parmtype) = 1; } - /* 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; + /* Output the PARMTYPE. */ + build_mangled_name_for_type_with_Gcode (parmtype, 1); } - if (TYPE_PTRMEMFUNC_P (parmtype)) - parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype); + /* Output the repeat count for the last parameter, if + necessary. */ + if (nrepeats != 0) + { + if (old_style_repeats) + flush_repeats (nrepeats, last_type); + else + issue_nrepeats (nrepeats, last_type); + nrepeats = 0; + } - if (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 (!parmtypes) + /* The parameter list ends in an ellipsis. */ + OB_PUTC ('e'); + } - switch (TREE_CODE (parmtype)) - { - case OFFSET_TYPE: - OB_PUTC ('O'); - build_overload_name (TYPE_OFFSET_BASETYPE (parmtype), 0, 0); + if (end) + OB_FINISH (); + return (char *)obstack_base (&scratch_obstack); +} + +/* handles emitting modifiers such as Constant, read-only, and volatile */ +void +process_modifiers (parmtype) + tree parmtype; +{ + if (TREE_READONLY (parmtype)) + OB_PUTC ('C'); + if (TREE_CODE (parmtype) == INTEGER_TYPE + && (TYPE_MAIN_VARIANT (parmtype) + == unsigned_type (TYPE_MAIN_VARIANT (parmtype))) + && ! TYPE_FOR_JAVA (parmtype)) + OB_PUTC ('U'); + if (TYPE_VOLATILE (parmtype)) + OB_PUTC ('V'); +} + +/* Check to see if TYPE has been entered into the Bcode typelist. If + so, return 1 and emit a backreference to TYPE. Otherwise, add TYPE + to the list of back-referenceable types and return 0. */ + +int +check_btype (type) + tree type; +{ + int x; + + if (btypelist == NULL) + return 0; + + if (!is_back_referenceable_type (type)) + return 0; + + /* We assume that our caller has put out any necessary + qualifiers. */ + type = TYPE_MAIN_VARIANT (type); + + for (x = 0; x < maxbtype; x++) + if (type == btypelist[x]) + { + OB_PUTC ('B'); + icat (x); + if (x > 9) OB_PUTC ('_'); - build_overload_name (TREE_TYPE (parmtype), 0, 0); - break; + return 1 ; + } + + if (maxbsize <= maxbtype) + { + /* Enlarge the table. */ + maxbsize = maxbsize * 3 / 2; + btypelist = (tree *)xrealloc (btypelist, sizeof (tree) * maxbsize); + } + + /* Register the TYPE. */ + btypelist[maxbtype++] = type; - case REFERENCE_TYPE: - OB_PUTC ('R'); - goto more; + return 0; +} - case ARRAY_TYPE: +/* handle emitting the correct code for various node types */ +static void +process_overload_item (parmtype, extra_Gcode) + tree parmtype; + int extra_Gcode; +{ + numeric_output_need_bar = 0; + + /* These tree types are considered modifiers for B code squangling , */ + /* and therefore should not get entries in the Btypelist */ + /* they are, however, repeatable types */ + + switch (TREE_CODE (parmtype)) + { + case REFERENCE_TYPE: + OB_PUTC ('R'); + goto more; + + case ARRAY_TYPE: #if PARM_CAN_BE_ARRAY_TYPE - { - tree length; + { + tree length; - OB_PUTC ('A'); - if (TYPE_DOMAIN (parmtype) == NULL_TREE) - error ("pointer or reference to array of unknown bound in parm type"); - else + OB_PUTC ('A'); + if (TYPE_DOMAIN (parmtype) == NULL_TREE) + error("pointer/reference to array of unknown bound in parm type"); + else + { + tree length = array_type_nelts (parmtype); + if (TREE_CODE (length) != INTEGER_CST || flag_do_squangling) { - length = array_type_nelts (parmtype); - if (TREE_CODE (length) == INTEGER_CST) - icat (TREE_INT_CST_LOW (length) + 1); + length = fold (build (PLUS_EXPR, TREE_TYPE (length), + length, integer_one_node)); + STRIP_NOPS (length); } - OB_PUTC ('_'); - goto more; + build_overload_value (sizetype, length, 1); } + if (numeric_output_need_bar && ! flag_do_squangling) + 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_for_type (TREE_TYPE (parmtype)); + 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; + } + + if (flag_do_squangling && check_btype (parmtype)) + /* If PARMTYPE is already in the list of back-referenceable types, + then check_btype will output the appropriate reference, and + there's nothing more to do. */ + return; - /* Separate args from return type. */ - OB_PUTC ('_'); - build_overload_name (TREE_TYPE (parmtype), 0, 0); - nofold = old_nofold; - break; + switch (TREE_CODE (parmtype)) + { + case OFFSET_TYPE: + OB_PUTC ('O'); + build_mangled_name_for_type (TYPE_OFFSET_BASETYPE (parmtype)); + OB_PUTC ('_'); + build_mangled_name_for_type (TREE_TYPE (parmtype)); + break; + + case FUNCTION_TYPE: + case METHOD_TYPE: + { + tree parms = TYPE_ARG_TYPES (parmtype); + + /* Rather than implementing a reentrant TYPEVEC, we turn off + repeat codes here, unless we're squangling. Squangling + doesn't make use of the TYPEVEC, so there's no reentrancy + problem. */ + int old_nofold = nofold; + if (!flag_do_squangling) + nofold = 1; + + if (TREE_CODE (parmtype) == METHOD_TYPE) + { + /* Mark this as a method. */ + OB_PUTC ('M'); + /* Output the class of which this method is a member. */ + build_mangled_name_for_type (TYPE_METHOD_BASETYPE (parmtype)); + /* Output any qualifiers for the `this' parameter. */ + process_modifiers (TREE_TYPE (TREE_VALUE (parms))); } - 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'); + /* Output the parameter types. */ + OB_PUTC ('F'); + if (parms == NULL_TREE) + OB_PUTC ('e'); + else if (parms == void_list_node) + OB_PUTC ('v'); + else + build_mangled_name (parms, 0, 0); + + /* Output the return type. */ + OB_PUTC ('_'); + build_mangled_name_for_type (TREE_TYPE (parmtype)); + + nofold = old_nofold; + break; + } + + case INTEGER_TYPE: + parmtype = TYPE_MAIN_VARIANT (parmtype); + 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'); #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 if (parmtype == java_boolean_type_node) + OB_PUTC ('b'); + 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 + || 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; - /* 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 (name); - break; - } + case COMPLEX_TYPE: + OB_PUTC ('J'); + build_mangled_name_for_type (TREE_TYPE (parmtype)); + break; - case UNKNOWN_TYPE: - /* This will take some work. */ - OB_PUTC ('?'); - break; - - case TEMPLATE_TYPE_PARM: - case TEMPLATE_CONST_PARM: - case UNINSTANTIATED_P_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); + + 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; - /* To get here, parms must end with `...'. */ - OB_PUTC ('e'); + 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); } -tree -build_static_name (basetype, name) - tree basetype, 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); -} - -/* 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 +/* Produce the mangling for a variable named NAME in CONTEXT, which can + be either a class TYPE or a FUNCTION_DECL. */ tree -cplus_exception_name (type) - tree type; +build_static_name (context, name) + tree context, name; { OB_INIT (); - OB_PUTS (EXCEPTION_NAME_PREFIX); - return get_identifier (build_overload_name (type, 0, 1)); + 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)); } -/* 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) +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); @@ -978,50 +1533,107 @@ build_decl_overload (dname, parms, for_method) and figure out its name without any extra encoding. */ OB_PUTC2 ('_', '_'); - if (for_method) - { -#if 0 - /* We can get away without doing this. */ - OB_PUTC ('M'); -#endif - { - tree this_type = TREE_VALUE (parms); + numeric_output_need_bar = 0; - if (TREE_CODE (this_type) == RECORD_TYPE) /* a signature pointer */ - parms = temp_tree_cons (NULL_TREE, SIGNATURE_TYPE (this_type), - TREE_CHAIN (parms)); - else - parms = temp_tree_cons (NULL_TREE, TREE_TYPE (this_type), - TREE_CHAIN (parms)); - } + if (tparms) + { + OB_PUTC ('H'); + build_template_parm_names (tparms, targs); + OB_PUTC ('_'); } - else + else if (!for_method && current_namespace == global_namespace) + /* XXX this works only if we call this in the same namespace + as the declaration. Unfortunately, we don't have the _DECL, + only its name */ OB_PUTC ('F'); + if (!for_method && current_namespace != global_namespace) + /* qualify with namespace */ + build_qualified_name (current_namespace); + if (parms == NULL_TREE) - OB_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; + typevec_size = list_length (parms); + if (!for_method && current_namespace != global_namespace) + /* the namespace of a global function needs one slot */ + typevec_size++; + typevec = (tree *)alloca (typevec_size * sizeof (tree)); + } nofold = 0; + if (for_method) { - build_overload_name (TREE_VALUE (parms), 0, 0); + tree this_type = TREE_VALUE (parms); + + if (TREE_CODE (this_type) == RECORD_TYPE) /* a signature pointer */ + this_type = SIGNATURE_TYPE (this_type); + else + this_type = TREE_TYPE (this_type); - typevec[maxtype++] = TREE_VALUE (parms); - TREE_USED (TREE_VALUE (parms)) = 1; + build_mangled_name_for_type (this_type); + + if (!flag_do_squangling) + { + my_friendly_assert (maxtype < typevec_size, 387); + typevec[maxtype++] = this_type; + TREE_USED (this_type) = 1; + + /* By setting up PARMS in this way, the loop below will + automatically clear TREE_USED on THIS_TYPE. */ + parms = temp_tree_cons (NULL_TREE, this_type, + TREE_CHAIN (parms)); + } 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) + { + my_friendly_assert (maxtype < typevec_size, 387); + 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 temp = TREE_VALUE (t); + TREE_USED (temp) = 0; + /* clear out the type variant in case we used it */ + temp = canonical_type_variant (temp); + TREE_USED (temp) = 0; + t = TREE_CHAIN (t); + } + } + } + + if (ret_type != NULL_TREE && for_method != 2) + { + /* Add the return type. */ + OB_PUTC ('_'); + build_mangled_name_for_type (ret_type); } + + OB_FINISH (); + end_squangling (); { tree n = get_identifier (obstack_base (&scratch_obstack)); if (IDENTIFIER_OPNAME_P (dname)) @@ -1030,7 +1642,59 @@ build_decl_overload (dname, parms, for_method) } } +/* 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 (decl, parms, ret_type, tparms, targs, + for_method) + tree decl; + tree parms; + tree ret_type; + tree tparms; + tree targs; + int for_method; +{ + tree res, saved_ctx; + + /* If the template is in a namespace, we need to put that into the + mangled name. Unfortunately, build_decl_overload_real does not + get the decl to mangle, so it relies on the current + namespace. Therefore, we set that here temporarily. */ + + my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd', 980702); + saved_ctx = current_namespace; + current_namespace = CP_DECL_CONTEXT (decl); + + res = build_decl_overload_real (DECL_NAME (decl), parms, ret_type, + tparms, targs, for_method); + + current_namespace = saved_ctx; + return res; +} + + /* Build an overload name for the type expression TYPE. */ + tree build_typename_overload (type) tree type; @@ -1040,111 +1704,53 @@ build_typename_overload (type) 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; } -#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); + start_squangling (); + build_mangled_name (type, 0, 1); + end_squangling (); 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; +tree +get_id_2 (name, name2) + char *name; + tree name2; { -#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 + OB_INIT (); + OB_PUTCP (name); + OB_PUTID (name2); + OB_FINISH (); + return get_identifier (obstack_base (&scratch_obstack)); } -#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; +/* Returns a DECL_ASSEMBLER_NAME for the destructor of type TYPE. */ + +tree +build_destructor_name (type) + tree type; { - /* @@ */ - return (TREE_OVERLOADED (name) - && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0) - && ! IDENTIFIER_LOCAL_VALUE (name)); + return build_overload_with_type (get_identifier (DESTRUCTOR_DECL_PREFIX), + type); } -#endif /* Given a tree_code CODE, and some arguments (at least one), attempt to use an overloaded operator on the arguments. @@ -1175,296 +1781,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3) 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 (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, - (struct candidate *)0); - - 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, - (struct candidate *)0); - - rval = build_method_call - (build_indirect_ref (build1 (NOP_EXPR, TREE_TYPE (xarg1), - 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 (0, 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, - (struct candidate *)0); - } - - return rval; + return build_new_op (code, flags, xarg1, xarg2, arg3); } /* This function takes an identifier, ID, and attempts to figure out what @@ -1478,7 +1795,6 @@ build_opfncall (code, flags, xarg1, xarg2, arg3) 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. @@ -1488,13 +1804,12 @@ build_opfncall (code, flags, xarg1, xarg2, arg3) compiler faster). */ tree -hack_identifier (value, name, yychar) +hack_identifier (value, name) tree value, name; - int yychar; { tree type; - if (TREE_CODE (value) == ERROR_MARK) + if (value == error_mark_node) { if (current_class_name) { @@ -1507,6 +1822,9 @@ hack_identifier (value, name, yychar) fndecl = TREE_VALUE (fields); my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 251); + /* I could not trigger this code. MvL */ + my_friendly_abort (980325); +#ifdef DEAD if (DECL_CHAIN (fndecl) == NULL_TREE) { warning ("methods cannot be converted to function pointers"); @@ -1518,6 +1836,7 @@ hack_identifier (value, name, yychar) IDENTIFIER_POINTER (name)); return error_mark_node; } +#endif } } if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name)) @@ -1530,23 +1849,27 @@ hack_identifier (value, name, yychar) 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; + 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 (TREE_CODE (value) == FUNCTION_DECL + && DECL_FUNCTION_MEMBER_P (value)) + /* This is a placeholder; don't mark it used. */ + return value; + else if (really_overloaded_fn (value)) { +#if 0 tree t = get_first_fn (value); for (; t; t = DECL_CHAIN (t)) { @@ -1556,21 +1879,46 @@ hack_identifier (value, name, yychar) assemble_external (t); TREE_USED (t) = 1; } +#endif } + else if (TREE_CODE (value) == OVERLOAD) + /* not really overloaded function */ + mark_used (OVL_FUNCTION (value)); else if (TREE_CODE (value) == TREE_LIST) { + /* Ambiguous reference to base members, possibly other cases?. */ tree t = value; while (t && TREE_CODE (t) == TREE_LIST) { - assemble_external (TREE_VALUE (t)); - TREE_USED (t) = 1; + 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) { - 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)) @@ -1578,8 +1926,7 @@ hack_identifier (value, name, yychar) 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) @@ -1589,13 +1936,13 @@ hack_identifier (value, name, yychar) 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", 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)); @@ -1603,9 +1950,8 @@ hack_identifier (value, name, yychar) } } } - 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) { @@ -1617,437 +1963,167 @@ hack_identifier (value, name, yychar) 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); - return convert_from_reference (value); - } + if (TREE_CODE (type) == REFERENCE_TYPE && ! processing_template_decl) + value = convert_from_reference (value); return value; } -#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 - -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; + tree thunk_id; tree thunk; - char *func_name; - static int thunk_number = 0; tree func_decl; + if (TREE_CODE (function) != ADDR_EXPR) abort (); func_decl = TREE_OPERAND (function, 0); if (TREE_CODE (func_decl) != FUNCTION_DECL) abort (); - func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func_decl)); - if (delta<=0) - sprintf (buffer, "__thunk_%d_%s", -delta, func_name); + + OB_INIT (); + OB_PUTS ("__thunk_"); + if (delta > 0) + { + OB_PUTC ('n'); + icat (delta); + } else - sprintf (buffer, "__thunk_n%d_%s", delta, func_name); - thunk_id = get_identifier (buffer); + 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) { - error_with_decl ("implementation-reserved name `%s' used"); - IDENTIFIER_GLOBAL_VALUE (thunk_id) = thunk = NULL_TREE; + 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 (THUNK_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); + thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl)); + TREE_READONLY (thunk) = TREE_READONLY (func_decl); + TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl); + comdat_linkage (thunk); + TREE_SET_CODE (thunk, THUNK_DECL); DECL_INITIAL (thunk) = function; THUNK_DELTA (thunk) = delta; + DECL_EXTERNAL (thunk) = 1; + DECL_ARTIFICIAL (thunk) = 1; /* So that finish_file can write out any thunks that need to be: */ pushdecl_top_level (thunk); } return thunk; } +/* Emit the definition of a C++ multiple inheritance vtable thunk. */ + void emit_thunk (thunk_fndecl) - tree thunk_fndecl; + tree 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); - int tem; - int failure = 0; - int current_call_is_indirect = 0; /* needed for HPPA FUNCTION_ARG */ - - /* 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_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; - init_function_start (thunk_fndecl, input_filename, lineno); - pushlevel (0); - expand_start_bindings (1); - - /* Start updating where the next arg would go. */ - INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (function), NULL_RTX); - 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. */ - - { - 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: + TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL); - reload_completed = 0; - - /* Cancel the effect of rtl_in_current_obstack. */ - - resume_temporary_allocation (); + { +#ifdef ASM_OUTPUT_MI_THUNK + char *fnname; + current_function_decl = thunk_fndecl; + /* Make sure we build up its RTL before we go onto the + temporary obstack. */ + make_function_rtl (thunk_fndecl); + temporary_allocation (); + DECL_RESULT (thunk_fndecl) + = build_decl (RESULT_DECL, 0, integer_type_node); + fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); + init_function_start (thunk_fndecl, input_filename, lineno); + current_function_is_thunk = 1; + assemble_start_function (thunk_fndecl, fnname); + ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function); + assemble_end_function (thunk_fndecl, fnname); + permanent_allocation (1); + current_function_decl = 0; +#else /* ASM_OUTPUT_MI_THUNK */ + /* If we don't have the necessary macro for efficient thunks, generate a + thunk function that just makes a call to the real function. + Unfortunately, this doesn't work for varargs. */ + + tree a, t; + + if (varargs_function_p (function)) + cp_error ("generic thunk code fails for method `%#D' which uses `...'", + function); + + /* Set up clone argument trees for the thunk. */ + t = NULL_TREE; + for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) + { + tree x = copy_node (a); + TREE_CHAIN (x) = t; + DECL_CONTEXT (x) = thunk_fndecl; + t = x; + } + a = nreverse (t); + DECL_ARGUMENTS (thunk_fndecl) = a; + DECL_RESULT (thunk_fndecl) = NULL_TREE; + DECL_LANG_SPECIFIC (thunk_fndecl) = DECL_LANG_SPECIFIC (function); + copy_lang_decl (thunk_fndecl); + DECL_INTERFACE_KNOWN (thunk_fndecl) = 1; + DECL_NOT_REALLY_EXTERN (thunk_fndecl) = 1; + + start_function (NULL_TREE, thunk_fndecl, NULL_TREE, 1); + store_parm_decls (); + current_function_is_thunk = 1; + + /* Build up the call to the real function. */ + t = build_int_2 (delta, -1 * (delta < 0)); + TREE_TYPE (t) = signed_type (sizetype); + t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t)); + t = expr_tree_cons (NULL_TREE, t, NULL_TREE); + for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a)) + t = expr_tree_cons (NULL_TREE, a, t); + t = nreverse (t); + t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t); + c_expand_return (t); + + finish_function (lineno, 0, 0); + + /* Don't let the backend defer this function. */ + if (DECL_DEFER_OUTPUT (thunk_fndecl)) + { + output_inline_function (thunk_fndecl); + permanent_allocation (1); + } +#endif /* ASM_OUTPUT_MI_THUNK */ + } - decl_printable_name = save_decl_printable_name; - current_function_decl = 0; + TREE_SET_CODE (thunk_fndecl, THUNK_DECL); } /* Code for synthesizing methods which have default semantics defined. */ /* For the anonymous union in TYPE, return the member that is at least as large as the rest of the members, so we can copy it. */ + static tree largest_union_member (type) tree type; @@ -2064,7 +2140,8 @@ largest_union_member (type) } /* Generate code for default X(X&) constructor. */ -void + +static void do_build_copy_constructor (fndecl) tree fndecl; { @@ -2078,9 +2155,13 @@ do_build_copy_constructor (fndecl) parm = TREE_CHAIN (parm); parm = convert_from_reference (parm); - if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) + if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) + && is_empty_class (current_class_type)) + /* Don't copy the padding byte; it might not have been allocated + if *this is a base subobject. */; + else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) { - t = build (INIT_EXPR, void_type_node, C_C_D, parm); + t = build (INIT_EXPR, void_type_node, current_class_ref, parm); TREE_SIDE_EFFECTS (t) = 1; cplus_expand_expr_stmt (t); } @@ -2099,8 +2180,12 @@ do_build_copy_constructor (fndecl) (build_reference_type (basetype), parm, CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); p = convert_from_reference (p); - current_base_init_list = tree_cons (TYPE_NESTED_NAME (basetype), - p, current_base_init_list); + + 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) @@ -2113,17 +2198,25 @@ do_build_copy_constructor (fndecl) p = convert_to_reference (build_reference_type (basetype), parm, CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); - p = convert_from_reference (p); - current_base_init_list = tree_cons (TYPE_NESTED_NAME (basetype), - p, current_base_init_list); + + 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 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))) @@ -2136,14 +2229,22 @@ do_build_copy_constructor (fndecl) continue; } else if ((t = TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (t) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) + && ANON_UNION_TYPE_P (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 + && ANON_UNION_TYPE_P (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 @@ -2157,7 +2258,7 @@ do_build_copy_constructor (fndecl) pop_momentary (); } -void +static void do_build_assign_ref (fndecl) tree fndecl; { @@ -2168,9 +2269,13 @@ do_build_assign_ref (fndecl) parm = convert_from_reference (parm); - if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) + if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type) + && is_empty_class (current_class_type)) + /* Don't copy the padding byte; it might not have been allocated + if *this is a base subobject. */; + else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) { - tree t = build (MODIFY_EXPR, void_type_node, C_C_D, parm); + tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm); TREE_SIDE_EFFECTS (t) = 1; cplus_expand_expr_stmt (t); } @@ -2184,17 +2289,13 @@ do_build_assign_ref (fndecl) for (i = 0; i < n_bases; ++i) { tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i)); - if (TYPE_HAS_ASSIGN_REF (basetype)) - { - 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 (TYPE_NESTED_NAME (basetype), - ansi_opname [MODIFY_EXPR], - build_tree_list (NULL_TREE, p)); - expand_expr_stmt (p); - } + 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)) { @@ -2203,6 +2304,27 @@ do_build_assign_ref (fndecl) 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; + } + + comp = current_class_ref; + init = parm; + if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) @@ -2215,42 +2337,49 @@ do_build_assign_ref (fndecl) continue; } else if ((t = TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (t) == UNION_TYPE - && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) + && ANON_UNION_TYPE_P (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 + && ANON_UNION_TYPE_P (t) + && TYPE_FIELDS (t) != NULL_TREE); + } else continue; - comp = build (COMPONENT_REF, TREE_TYPE (field), C_C_D, 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)); } } - c_expand_return (C_C_D); + c_expand_return (current_class_ref); pop_momentary (); } -void push_cp_function_context (); -void pop_cp_function_context (); - void synthesize_method (fndecl) tree fndecl; { int nested = (current_function_decl != NULL_TREE); - tree context = decl_function_context (fndecl); - char *f = input_filename; - tree base = DECL_CLASS_CONTEXT (fndecl); + tree context = hack_decl_function_context (fndecl); + + if (at_eof) + import_export_decl (fndecl); - if (nested) + if (! context) + push_to_top_level (); + else if (nested) push_cp_function_context (context); - input_filename = DECL_SOURCE_FILE (fndecl); - interface_unknown = CLASSTYPE_INTERFACE_UNKNOWN (base); - interface_only = CLASSTYPE_INTERFACE_ONLY (base); - start_function (NULL_TREE, fndecl, NULL_TREE, NULL_TREE, 1); + interface_unknown = 1; + start_function (NULL_TREE, fndecl, NULL_TREE, 1); store_parm_decls (); if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR]) @@ -2270,18 +2399,9 @@ synthesize_method (fndecl) 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; - if (function_cannot_inline_p (fndecl) == 0) - DECL_INLINE (fndecl) = 1; - } - - input_filename = f; extract_interface_info (); - if (nested) + if (! context) + pop_from_top_level (); + else if (nested) pop_cp_function_context (context); } |
