From e5d68cee9c6406ea9c46daf4fd5f5f089e71d15b Mon Sep 17 00:00:00 2001 From: "William F. Jolitz" Date: Sun, 5 Aug 1990 20:31:37 -0800 Subject: [PATCH] 386BSD 0.1 development Work on file usr/src/usr.bin/g++/cc1plus/cplus-method.c Co-Authored-By: Lynne Greer Jolitz Synthesized-from: 386BSD-0.1 --- usr/src/usr.bin/g++/cc1plus/cplus-method.c | 2504 ++++++++++++++++++++ 1 file changed, 2504 insertions(+) create mode 100644 usr/src/usr.bin/g++/cc1plus/cplus-method.c diff --git a/usr/src/usr.bin/g++/cc1plus/cplus-method.c b/usr/src/usr.bin/g++/cc1plus/cplus-method.c new file mode 100644 index 0000000000..70b19410ce --- /dev/null +++ b/usr/src/usr.bin/g++/cc1plus/cplus-method.c @@ -0,0 +1,2504 @@ +/* Handle the hair of processing (but not expanding) inline functions. + Also manage function and varaible name overloading. + Copyright (C) 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + + This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Handle method declarations. */ +#include +#include "config.h" +#include "tree.h" +#include "cplus-tree.h" +#include "assert.h" + +/* TREE_LIST of the current inline functions that need to be + processed. */ +struct pending_inline *pending_inlines; + +# define MAX_INLINE_BUF_SIZE 8188 +# define OB_INIT() (inline_bufp = inline_buffer) +# define OB_PUTC(C) (*inline_bufp++ = (C)) +# define OB_PUTC2(C1,C2) (OB_PUTC (C1), OB_PUTC (C2)) +# define OB_PUTS(S) (strcpy (inline_bufp, S), inline_bufp += sizeof (S) - 1) +# define OB_PUTCP(S) (strcpy (inline_bufp, S), inline_bufp += strlen (S)) +# define OB_FINISH() (*inline_bufp++ = '\0') + +/* Counter to help build parameter names in case they were omitted. */ +static int dummy_name; +static int in_parmlist; +/* Just a pointer into INLINE_BUFFER. */ +static char *inline_bufp; +/* Also a pointer into INLINE_BUFFER. This points to a safe place to + cut back to if we assign it 0, in case of error. */ +static char *inline_errp; +static char *inline_buffer; +static void dump_type (), dump_decl (); +static void dump_init (), dump_unary_op (), dump_binary_op (); + +tree wrapper_name, wrapper_pred_name, anti_wrapper_name; + +#ifdef NO_AUTO_OVERLOAD +int is_overloaded (); +#endif + +void +init_method () +{ + char buf[sizeof (ANTI_WRAPPER_NAME_FORMAT) + 8]; + sprintf (buf, WRAPPER_NAME_FORMAT, ""); + wrapper_name = get_identifier (buf); + sprintf (buf, WRAPPER_PRED_NAME_FORMAT, ""); + wrapper_pred_name = get_identifier (buf); + sprintf (buf, ANTI_WRAPPER_NAME_FORMAT, ""); + anti_wrapper_name = get_identifier (buf); +} + +/* Return a pointer to the end of the new text in INLINE_BUFFER. + We cannot use `fatal' or `error' in here because that + might cause an infinite loop. */ +static char * +new_text_len (s) + char *s; +{ + while (*s++) ; + + if (s >= inline_buffer + MAX_INLINE_BUF_SIZE) + { + fprintf (stderr, "recompile c++ with larger MAX_INLINE_BUF_SIZE (%d)", MAX_INLINE_BUF_SIZE); + abort (); + } + return s - 1; +} + +/* Check that we have not overflowed INLINE_BUFFER. + We cannot use `fatal' or `error' in here because that + might cause an infinite loop. */ +static void +check_text_len (s) + char *s; +{ + if (s >= inline_buffer + MAX_INLINE_BUF_SIZE) + { + fprintf (stderr, "recompile c++ with larger MAX_INLINE_BUF_SIZE (%d)", MAX_INLINE_BUF_SIZE); + abort (); + } +} + +tree +make_anon_parm_name () +{ + char buf[32]; + + sprintf (buf, ANON_PARMNAME_FORMAT, dummy_name++); + return get_identifier (buf); +} + +void +clear_anon_parm_name () +{ + /* recycle these names. */ + dummy_name = 0; +} + +static void +dump_readonly_or_volatile (t) + tree t; +{ + if (TREE_READONLY (t)) + OB_PUTS ("const "); + if (TREE_VOLATILE (t)) + OB_PUTS ("volatile "); +} + +static void +dump_type_prefix (t, p) + tree t; + int *p; +{ + int old_p = 0; + int print_struct = 1; + tree name; + + if (t == NULL_TREE) + return; + + switch (TREE_CODE (t)) + { + case ERROR_MARK: + sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++); + break; + + case UNKNOWN_TYPE: + OB_PUTS (""); + return; + + case TREE_LIST: + dump_type (TREE_VALUE (t), &old_p); + if (TREE_CHAIN (t)) + { + if (TREE_CHAIN (t) != void_list_node) + { + OB_PUTC (','); + dump_type (TREE_CHAIN (t), &old_p); + } + } + else OB_PUTS ("..."); + return; + + case POINTER_TYPE: + *p += 1; + dump_type_prefix (TREE_TYPE (t), p); + while (*p) + { + OB_PUTC ('*'); + *p -= 1; + } + if (TREE_READONLY (t)) + OB_PUTS ("const "); + if (TREE_VOLATILE (t)) + OB_PUTS ("volatile "); + return; + + case OFFSET_TYPE: + { + tree type = TREE_TYPE (t); + if (TREE_CODE (type) == FUNCTION_TYPE) + { + type = TREE_TYPE (type); + if (in_parmlist) + OB_PUTS ("auto "); + } + + dump_type_prefix (type, &old_p); + + OB_PUTC ('('); + dump_type (TYPE_OFFSET_BASETYPE (t), &old_p); + OB_PUTC2 (':', ':'); + while (*p) + { + OB_PUTC ('*'); + *p -= 1; + } + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + return; + } + + case METHOD_TYPE: + { + tree type = TREE_TYPE (t); + if (in_parmlist) + OB_PUTS ("auto "); + + dump_type_prefix (type, &old_p); + + OB_PUTC ('('); + dump_type (TYPE_METHOD_BASETYPE (t), &old_p); + OB_PUTC2 (':', ':'); + while (*p) + { + OB_PUTC ('*'); + *p -= 1; + } + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + return; + } + + case REFERENCE_TYPE: + dump_type_prefix (TREE_TYPE (t), p); + OB_PUTC ('&'); + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + return; + + case ARRAY_TYPE: + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + dump_type_prefix (TREE_TYPE (t), p); + return; + + case FUNCTION_TYPE: + if (in_parmlist) + OB_PUTS ("auto "); + dump_type_prefix (TREE_TYPE (t), &old_p); + OB_PUTC ('('); + while (*p) + { + OB_PUTC ('*'); + *p -= 1; + } + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + return; + + case IDENTIFIER_NODE: + sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (t)); + break; + + case RECORD_TYPE: + if (TREE_READONLY (t)) + OB_PUTS ("const "); + if (TREE_VOLATILE (t)) + OB_PUTS ("volatile "); + if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t)) + print_struct = 0; + name = TYPE_NAME (t); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + if (print_struct) + sprintf (inline_bufp, "struct %s ", IDENTIFIER_POINTER (name)); + else + sprintf (inline_bufp, "class %s ", IDENTIFIER_POINTER (name)); + break; + + case UNION_TYPE: + if (TREE_READONLY (t)) + OB_PUTS ("const "); + if (TREE_VOLATILE (t)) + OB_PUTS ("volatile "); + name = TYPE_NAME (t); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + sprintf (inline_bufp, "union %s ", IDENTIFIER_POINTER (name)); + break; + + case ENUMERAL_TYPE: + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + name = TYPE_NAME (t); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + sprintf (inline_bufp, "enum %s ", IDENTIFIER_POINTER (name)); + break; + + case TYPE_DECL: + if (TREE_READONLY (t)) + OB_PUTS ("const "); + if (TREE_VOLATILE (t)) + OB_PUTS ("volatile "); + sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (DECL_NAME (t))); + break; + + case INTEGER_TYPE: + /* Normally, `unsigned' is part of the deal. Not so if it comes + with `const' or `volatile'. */ + if (TREE_UNSIGNED (t) + && (TREE_READONLY (t) || TREE_VOLATILE (t))) + OB_PUTS ("unsigned "); + /* fall through. */ + case REAL_TYPE: + case VOID_TYPE: + if (TREE_READONLY (t)) + OB_PUTS ("const "); + if (TREE_VOLATILE (t)) + OB_PUTS ("volatile "); + sprintf (inline_bufp, "%s ", TYPE_NAME_STRING (t)); + break; + + default: + abort (); + } + inline_bufp = new_text_len (inline_bufp); +} + +static void +dump_type_suffix (t, p) + tree t; + int *p; +{ + int old_p = 0; + + if (t == NULL_TREE) + return; + + switch (TREE_CODE (t)) + { + case ERROR_MARK: + sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++); + break; + + case UNKNOWN_TYPE: + return; + + case POINTER_TYPE: + dump_type_suffix (TREE_TYPE (t), p); + return; + + case OFFSET_TYPE: + { + tree type = TREE_TYPE (t); + + OB_PUTC (')'); + if (TREE_CODE (type) == FUNCTION_TYPE) + { +#if 0 + tree next_arg = TREE_CHAIN (TYPE_ARG_TYPES (type)); + OB_PUTC ('('); + if (next_arg) + { + if (next_arg != void_list_node) + { + in_parmlist++; + dump_type (next_arg, &old_p); + in_parmlist--; + } + } + else OB_PUTS ("..."); + OB_PUTC (')'); + dump_type_suffix (TREE_TYPE (type), p); +#else + abort (); +#endif + } + return; + } + + case METHOD_TYPE: + { + tree next_arg; + OB_PUTC (')'); + next_arg = TREE_CHAIN (TYPE_ARG_TYPES (t)); + OB_PUTC ('('); + if (next_arg) + { + if (next_arg != void_list_node) + { + in_parmlist++; + dump_type (next_arg, &old_p); + in_parmlist--; + } + } + else OB_PUTS ("..."); + OB_PUTC (')'); + dump_readonly_or_volatile (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t)))); + dump_type_suffix (TREE_TYPE (t), p); + return; + } + + case REFERENCE_TYPE: + dump_type_suffix (TREE_TYPE (t), p); + return; + + case ARRAY_TYPE: + dump_type_suffix (TREE_TYPE (t), p); + OB_PUTC2 ('[', ']'); + return; + + case FUNCTION_TYPE: + OB_PUTC2 (')', '('); + if (TYPE_ARG_TYPES (t) && TYPE_ARG_TYPES (t) != void_list_node) + { + in_parmlist++; + dump_type (TYPE_ARG_TYPES (t), &old_p); + in_parmlist--; + } + OB_PUTC (')'); + dump_type_suffix (TREE_TYPE (t), p); + return; + + case IDENTIFIER_NODE: + case RECORD_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + case TYPE_DECL: + case INTEGER_TYPE: + case REAL_TYPE: + case VOID_TYPE: + return; + + default: + abort (); + } + inline_bufp = new_text_len (inline_bufp); +} + +static void +dump_type (t, p) + tree t; + int *p; +{ + int old_p = 0; + int print_struct = 1; + + if (t == NULL_TREE) + return; + + switch (TREE_CODE (t)) + { + case ERROR_MARK: + sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++); + break; + + case UNKNOWN_TYPE: + OB_PUTS (""); + return; + + case TREE_LIST: + dump_type (TREE_VALUE (t), &old_p); + if (TREE_CHAIN (t)) + { + if (TREE_CHAIN (t) != void_list_node) + { + OB_PUTC (','); + dump_type (TREE_CHAIN (t), &old_p); + } + } + else OB_PUTS ("..."); + return; + + case POINTER_TYPE: + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + *p += 1; + dump_type (TREE_TYPE (t), p); + while (*p) + { + OB_PUTC ('*'); + *p -= 1; + } + return; + + case REFERENCE_TYPE: + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + dump_type (TREE_TYPE (t), p); + OB_PUTC ('&'); + return; + + case ARRAY_TYPE: + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + dump_type (TREE_TYPE (t), p); + OB_PUTC2 ('[', ']'); + return; + + case OFFSET_TYPE: + case METHOD_TYPE: + case FUNCTION_TYPE: + dump_type_prefix (t, p); + dump_type_suffix (t, p); + return; + + case IDENTIFIER_NODE: + sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (t)); + break; + + case RECORD_TYPE: + { + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t)) + print_struct = 0; + t = TYPE_NAME (t); + if (TREE_CODE (t) == TYPE_DECL) + t = DECL_NAME (t); + if (print_struct) + sprintf (inline_bufp, "struct %s ", IDENTIFIER_POINTER (t)); + else + sprintf (inline_bufp, "class %s ", IDENTIFIER_POINTER (t)); + break; + } + + case UNION_TYPE: + { + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + t = TYPE_NAME (t); + if (TREE_CODE (t) == TYPE_DECL) + t = DECL_NAME (t); + sprintf (inline_bufp, "union %s ", IDENTIFIER_POINTER (t)); + } + break; + + case ENUMERAL_TYPE: + { + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + t = TYPE_NAME (t); + if (TREE_CODE (t) == TYPE_DECL) + t = DECL_NAME (t); + sprintf (inline_bufp, "enum %s ", IDENTIFIER_POINTER (t)); + } + break; + + case TYPE_DECL: + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (DECL_NAME (t))); + break; + + case INTEGER_TYPE: + /* Normally, `unsigned' is part of the deal. Not so if it comes + with `const' or `volatile'. */ + if (TREE_READONLY (t) | TREE_VOLATILE (t)) + dump_readonly_or_volatile (t); + if (TREE_UNSIGNED (t) + && (TREE_READONLY (t) | TREE_VOLATILE (t))) + OB_PUTS ("unsigned "); + /* fall through. */ + case REAL_TYPE: + case VOID_TYPE: + sprintf (inline_bufp, "%s ", TYPE_NAME_STRING (t)); + break; + + default: + abort (); + } + inline_bufp = new_text_len (inline_bufp); +} + +static void +dump_decl (t) + tree t; +{ + int p = 0; + + if (t == NULL_TREE) + return; + + switch (TREE_CODE (t)) + { + case ERROR_MARK: + strcpy (inline_bufp, " /* decl error */ "); + break; + + case PARM_DECL: + dump_type_prefix (TREE_TYPE (t), &p); + if (DECL_NAME (t)) + dump_decl (DECL_NAME (t)); + else + { + sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++); + break; + } + dump_type_suffix (TREE_TYPE (t), &p); + return; + + case CALL_EXPR: + dump_decl (TREE_OPERAND (t, 0)); + OB_PUTC ('('); + in_parmlist++; + dump_decl (TREE_OPERAND (t, 1)); + in_parmlist--; + t = tree_last (TYPE_ARG_TYPES (TREE_TYPE (t))); + if (!t || t != void_list_node) + OB_PUTS ("..."); + OB_PUTC (')'); + return; + + case ARRAY_REF: + dump_decl (TREE_OPERAND (t, 0)); + OB_PUTC ('['); + dump_decl (TREE_OPERAND (t, 1)); + OB_PUTC (']'); + return; + + case TYPE_DECL: + sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (DECL_NAME (t))); + break; + + case TYPE_EXPR: + abort (); + break; + + case IDENTIFIER_NODE: + if (OPERATOR_NAME_P (t)) + sprintf (inline_bufp, "operator %s ", operator_name_string (t)); + else if (OPERATOR_TYPENAME_P (t)) + { + OB_PUTS ("operator "); + dump_type (TREE_TYPE (t), &p); + return; + } + else + sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (t)); + break; + + case BIT_NOT_EXPR: + OB_PUTC2 ('~', ' '); + dump_decl (TREE_OPERAND (t, 0)); + return; + + case SCOPE_REF: + sprintf (inline_bufp, "%s :: ", IDENTIFIER_POINTER (TREE_OPERAND (t, 0))); + inline_bufp += sizeof ("%s :: ") + IDENTIFIER_LENGTH (TREE_OPERAND (t, 0)); + dump_decl (TREE_OPERAND (t, 1)); + return; + + case INDIRECT_REF: + OB_PUTC ('*'); + dump_decl (TREE_OPERAND (t, 0)); + return; + + case ADDR_EXPR: + OB_PUTC ('&'); + dump_decl (TREE_OPERAND (t, 0)); + return; + + default: + abort (); + } + inline_bufp = new_text_len (inline_bufp); +} + +static void +dump_init_list (l) + tree l; +{ + while (l) + { + dump_init (TREE_VALUE (l)); + if (TREE_CHAIN (l)) + OB_PUTC (','); + l = TREE_CHAIN (l); + } +} + +static void +dump_init (t) + tree t; +{ + int dummy; + + switch (TREE_CODE (t)) + { + case VAR_DECL: + case PARM_DECL: + sprintf (inline_bufp, " %s ", IDENTIFIER_POINTER (DECL_NAME (t))); + break; + + case FUNCTION_DECL: + { + tree name = DECL_NAME (t); + + if (DESTRUCTOR_NAME_P (name)) + sprintf (inline_bufp, " ~%s ", + IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t))); + else if (OPERATOR_NAME_P (name)) + sprintf (inline_bufp, "operator %s ", operator_name_string (name)); + else if (OPERATOR_TYPENAME_P (name)) + { + dummy = 0; + OB_PUTS ("operator "); + dump_type (TREE_TYPE (name), &dummy); + } +#if 0 + else if (WRAPPER_NAME_P (name)) + sprintf (inline_bufp, " ()%s ", + IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t))); + else if (WRAPPER_PRED_NAME_P (name)) + sprintf (inline_bufp, " ()?%s ", + IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t))); + else if (ANTI_WRAPPER_NAME_P (name)) + sprintf (inline_bufp, " ~()%s ", + IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t))); +#endif + else sprintf (inline_bufp, " %s ", + IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t))); + } + break; + + case CONST_DECL: + dummy = 0; + OB_PUTC2 ('(', '('); + dump_type (TREE_TYPE (t), &dummy); + OB_PUTC (')'); + dump_init (DECL_INITIAL (t)); + OB_PUTC (')'); + return; + + case INTEGER_CST: + sprintf (inline_bufp, " %d ", TREE_INT_CST_LOW (t)); + break; + + case REAL_CST: + sprintf (inline_bufp, " %g ", TREE_REAL_CST (t)); + break; + + case STRING_CST: + { + char *p = TREE_STRING_POINTER (t); + int len = TREE_STRING_LENGTH (t) - 1; + int i; + + check_text_len (inline_bufp + len + 2); + OB_PUTC ('\"'); + for (i = 0; i < len; i++) + { + register char c = p[i]; + if (c == '\"' || c == '\\') + OB_PUTC ('\\'); + if (c >= ' ' && c < 0177) + OB_PUTC (c); + else + { + sprintf (inline_bufp, "\\%03o", c); + inline_bufp = new_text_len (inline_bufp); + } + } + OB_PUTC ('\"'); + } + return; + + case COMPOUND_EXPR: + dump_binary_op (",", t, 1); + break; + + case COND_EXPR: + OB_PUTC ('('); + dump_init (TREE_OPERAND (t, 0)); + OB_PUTS (" ? "); + dump_init (TREE_OPERAND (t, 1)); + OB_PUTS (" : "); + dump_init (TREE_OPERAND (t, 2)); + OB_PUTC (')'); + return; + + case SAVE_EXPR: + if (TREE_HAS_CONSTRUCTOR (t)) + { + dummy = 0; + OB_PUTS ("new "); + dump_type (TREE_TYPE (TREE_TYPE (t)), &dummy); + PARM_DECL_EXPR (t) = 1; + } + else + { + sorry ("operand of SAVE_EXPR not understood"); + *inline_errp = '\0'; + inline_bufp = inline_errp + 1; + } + return; + + case NEW_EXPR: + strcpy (inline_bufp, TYPE_NAME_STRING (TREE_TYPE (t))); + inline_bufp = new_text_len (inline_bufp); + OB_PUTC ('('); + dump_init_list (TREE_CHAIN (TREE_OPERAND (t, 1))); + OB_PUTC (')'); + return; + + case CALL_EXPR: + OB_PUTC ('('); + dump_init (TREE_OPERAND (t, 0)); + dump_init_list (TREE_OPERAND (t, 1)); + OB_PUTC (')'); + return; + + case MODIFY_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + case MIN_EXPR: + case MAX_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case BIT_ANDTC_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + dump_binary_op (opname_tab[(int) TREE_CODE (t)], t, + strlen (opname_tab[(int) TREE_CODE (t)])); + return; + + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + dump_binary_op ("/", t, 1); + return; + + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + dump_binary_op ("%", t, 1); + return; + + case COMPONENT_REF: + dump_binary_op (".", t, 1); + return; + + case CONVERT_EXPR: + dump_unary_op ("+", t, 1); + return; + + case ADDR_EXPR: + if (TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL + || TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST) + dump_init (TREE_OPERAND (t, 0)); + else + dump_unary_op ("&", t, 1); + return; + + case INDIRECT_REF: + dump_unary_op ("*", t, 1); + return; + + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + dump_unary_op (opname_tab [(int)TREE_CODE (t)], t, + strlen (opname_tab[(int) TREE_CODE (t)])); + return; + + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + OB_PUTC ('('); + dump_init (TREE_OPERAND (t, 0)); + OB_PUTCP (opname_tab[(int)TREE_CODE (t)]); + OB_PUTC (')'); + return; + + case NOP_EXPR: + dummy = 0; + OB_PUTC2 ('(', '('); + dump_type (TREE_TYPE (t), &dummy); + OB_PUTC (')'); + dump_init (TREE_OPERAND (t, 0)); + OB_PUTC (')'); + return; + + case CONSTRUCTOR: + OB_PUTC ('{'); + dump_init_list (CONSTRUCTOR_ELTS (t)); + OB_PUTC ('}'); + return; + + /* This list is incomplete, but should suffice for now. + It is very important that `sorry' does not call + `report_error_function'. That could cause an infinite loop. */ + default: + sorry ("that operation not supported for default parameters"); + + /* fall through to ERROR_MARK... */ + case ERROR_MARK: + *inline_errp = '\0'; + inline_bufp = inline_errp + 1; + return; + } + inline_bufp = new_text_len (inline_bufp); +} + +static void +dump_binary_op (opstring, t, len) + char *opstring; + tree t; + int len; +{ + OB_PUTC ('('); + dump_init (TREE_OPERAND (t, 0)); + sprintf (inline_bufp, " %s ", opstring); + inline_bufp += len + 2; + dump_init (TREE_OPERAND (t, 1)); + OB_PUTC (')'); + check_text_len (inline_bufp); +} + +static void +dump_unary_op (opstring, t, len) + char *opstring; + tree t; + int len; +{ + OB_PUTC ('('); + sprintf (inline_bufp, " %s ", opstring); + inline_bufp += len + 2; + dump_init (TREE_OPERAND (t, 0)); + OB_PUTC (')'); + check_text_len (inline_bufp); +} + +#ifdef DO_METHODS_THE_OLD_WAY +/* Process the currently pending inline function definitions. + This entails: + (1) Creating a temporary file which contains return type, + delarator name, and argment names and types of the + function to be inlined. + (2) Reading that file into a buffer which can then be + made to look line another piece of inline code to + process, stuffing that on the top of the inline + stack, then letting the lexer and parser read from those + two. +*/ + +static struct pending_inline * +stash_inline_prefix (cname, field) + tree cname, field; +{ + extern int lineno; + struct pending_inline *t; + tree name, fndecl, fntype; + int p = 0; + inline_buffer = (char *)alloca (MAX_INLINE_BUF_SIZE + 4); + dummy_name = 0; + + name = DECL_ORIGINAL_NAME (field); + /* We still don't do friends right. */ + fndecl = field; + fntype = TREE_TYPE (fndecl); + + if (TREE_INLINE (fndecl)) + strcpy (inline_buffer, "inline "); + else + strcpy (inline_buffer, "static "); + inline_bufp = inline_buffer + strlen (inline_buffer); + if (! OPERATOR_TYPENAME_P (name)) + dump_type_prefix (TREE_TYPE (fntype), &p); + if (TREE_CODE (fntype) == METHOD_TYPE) + { + dump_type (cname, &p); + inline_bufp[-1] = ':'; + *inline_bufp++ = ':'; + if (DESTRUCTOR_NAME_P (DECL_NAME (fndecl))) + OB_PUTC ('~'); +#if 0 + else if (WRAPPER_NAME_P (DECL_NAME (fndecl))) + OB_PUTC2 ('(', ')'); + else if (WRAPPER_PRED_NAME_P (DECL_NAME (fndecl))) + OB_PUTS ("()?"); + else if (ANTI_WRAPPER_NAME_P (DECL_NAME (fndecl))) + OB_PUTS ("~()"); +#endif + } + dump_decl (name); + OB_PUTC ('('); + if (! DESTRUCTOR_NAME_P (DECL_NAME (fndecl))) + { + tree parmlist = DECL_ARGUMENTS (fndecl); + tree typelist = TYPE_ARG_TYPES (fntype); + + if (TREE_CODE (field) == FIELD_DECL) + { + parmlist = TREE_CHAIN (parmlist); + typelist = TREE_CHAIN (typelist); + } + + in_parmlist++; + while (parmlist) + { + dump_decl (parmlist); +#if 0 + if (TREE_PURPOSE (typelist)) + { + inline_errp = inline_bufp; + OB_PUTS (" = ("); + dump_init (TREE_PURPOSE (typelist)); + OB_PUTC (')'); + if (*inline_errp == '\0') + inline_bufp = inline_errp; + } +#endif + if (TREE_CHAIN (parmlist)) + OB_PUTC (','); + parmlist = TREE_CHAIN (parmlist); + typelist = TREE_CHAIN (typelist); + } + in_parmlist--; + if (!typelist || typelist != void_list_node) + OB_PUTS ("..."); + } + OB_PUTC (')'); + + if (! OPERATOR_TYPENAME_P (name)) + dump_type_suffix (TREE_TYPE (fntype), &p); + if (TREE_CODE (fntype) == METHOD_TYPE) + dump_readonly_or_volatile (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype)))); + { + extern tree value_identifier; + + if (DECL_RESULT (fndecl) != value_identifier) + { + tree result = DECL_RESULT (fndecl); + + OB_PUTS ("return "); + OB_PUTS (IDENTIFIER_POINTER (DECL_NAME (result))); + if (DECL_INITIAL (result)) + { + OB_PUTC ('='); + dump_init (DECL_INITIAL (result)); + OB_PUTC (';'); + } + } + } + OB_FINISH (); + check_text_len (inline_bufp); + + t = (struct pending_inline *)xmalloc (sizeof (struct pending_inline)); + t->len = inline_bufp - inline_buffer; + t->buf = (char *)xmalloc (t->len); + bcopy (inline_buffer, t->buf, t->len); + t->lineno = lineno; + t->filename = input_filename; + t->token = 0; + return t; +} +#endif + +#define OVERLOAD_MAX_LEN 1024 + +/* Pretty printing for announce_function. If BUF is nonzero, then + the text is written there. The buffer is assued to be of size + OVERLOAD_MAX_LEN. CNAME is the name of the class that FNDECL + belongs to, if we could not figure that out from FNDECL + itself. FNDECL is the declaration of the function we + are interested in seeing. PRINT_RET_TYPE_P is non-zero if + we should print the type that this function returns. */ +char * +fndecl_as_string (buf, cname, fndecl, print_ret_type_p) + char *buf; + tree cname, fndecl; + int print_ret_type_p; +{ + tree name = DECL_NAME (fndecl); + tree fntype = TREE_TYPE (fndecl); + tree parmtypes = TYPE_ARG_TYPES (fntype); + int p = 0; + int spaces = 0; + + inline_buffer = buf; + OB_INIT (); + + if (DECL_STATIC_FUNCTION_P (fndecl)) + cname = TYPE_NAME (DECL_STATIC_CONTEXT (fndecl)); + else if (! cname && TREE_CODE (fntype) == METHOD_TYPE) + cname = TYPE_NAME (TYPE_METHOD_BASETYPE (fntype)); + + if (print_ret_type_p && ! OPERATOR_TYPENAME_P (name)) + dump_type_prefix (TREE_TYPE (fntype), &p); + if (DECL_STATIC_FUNCTION_P (fndecl)) + OB_PUTS ("static "); + + if (cname) + { + dump_type (cname, &p); + inline_bufp[-1] = ':'; + *inline_bufp++ = ':'; + if (TREE_CODE (fntype) == METHOD_TYPE && parmtypes) + parmtypes = TREE_CHAIN (parmtypes); + if (DECL_CONSTRUCTOR_FOR_VBASE_P (fndecl)) + parmtypes = TREE_CHAIN (parmtypes); + } + + if (DESTRUCTOR_NAME_P (name)) + { + OB_PUTC ('~'); + parmtypes = TREE_CHAIN (parmtypes); + dump_decl (DECL_ORIGINAL_NAME (fndecl)); + } + else if (OPERATOR_NAME_P (name)) + { + sprintf (inline_bufp, "operator %s ", operator_name_string (name)); + inline_bufp += strlen (inline_bufp); + } + else if (OPERATOR_TYPENAME_P (name)) + { + /* This cannot use the hack that the operator's return + type is stashed off of its name because it may be + used for error reporting. In the case of conflicting + declarations, both will have the same name, yet + the types will be different, hence the TREE_TYPE field + of the first name will be clobbered by the second. */ + OB_PUTS ("operator "); + dump_type (TREE_TYPE (TREE_TYPE (fndecl)), &p); + } + else if (DECL_CONSTRUCTOR_P (fndecl)) + { +#ifdef SOS + if (TYPE_DYNAMIC (TREE_TYPE (TREE_TYPE (DECL_ORIGINAL_NAME (fndecl))))) + { + OB_PUTS ("dynamic "); + parmtypes = TREE_CHAIN (parmtypes); + } +#endif + dump_decl (DECL_ORIGINAL_NAME (fndecl)); + /* Skip past "in_charge" identifier. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (cname))) + parmtypes = TREE_CHAIN (parmtypes); + } + else + { +#if 0 + if (WRAPPER_NAME_P (name)) + OB_PUTC2 ('(', ')'); + if (WRAPPER_PRED_NAME_P (name)) + OB_PUTS ("()?"); + else if (ANTI_WRAPPER_NAME_P (name)) + OB_PUTS ("~()"); +#endif + dump_decl (DECL_ORIGINAL_NAME (fndecl)); + } + + OB_PUTC ('('); + if (parmtypes) + { + in_parmlist++; + if (parmtypes != void_list_node) + spaces = 2; + while (parmtypes && parmtypes != void_list_node) + { + dump_type (TREE_VALUE (parmtypes), &p); + while (inline_bufp[-1] == ' ') + inline_bufp--; + if (TREE_PURPOSE (parmtypes)) + { + inline_errp = inline_bufp; + OB_PUTS (" (= "); + dump_init (TREE_PURPOSE (parmtypes)); + OB_PUTC (')'); + } + OB_PUTC2 (',', ' '); + parmtypes = TREE_CHAIN (parmtypes); + } + in_parmlist--; + } + + if (parmtypes) + inline_bufp -= spaces; + else + OB_PUTS ("..."); + + OB_PUTC (')'); + + if (print_ret_type_p && ! OPERATOR_TYPENAME_P (name)) + dump_type_suffix (TREE_TYPE (fntype), &p); + + if (TREE_CODE (fntype) == METHOD_TYPE) + dump_readonly_or_volatile (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype)))); + + OB_FINISH (); + check_text_len (inline_bufp); + + if (strlen (buf) >= OVERLOAD_MAX_LEN) + { + fprintf (stderr, "fndecl_as_string returns something too large"); + abort (); + } + return buf; +} + +#ifdef FIELD_XREF + +char * +type_as_string (buf, typ) + char *buf; + tree typ; +{ + int p = 0; + int spaces = 0; + + inline_buffer = buf; + OB_INIT (); + + dump_type(typ,&p); + + OB_FINISH (); + + return buf; +} + +#endif + +/* Move inline function defintions out of structure so that they + can be processed normally. CNAME is the name of the class + we are working from, METHOD_LIST is the list of method lists + of the structure. We delete friend methods here, after + saving away their inline function definitions (if any). */ + +/* Subroutine of `do_inline_function_hair'. */ +static void +prepare_inline (cname, fndecl) + tree cname, fndecl; +{ + if (DECL_PENDING_INLINE_INFO (fndecl)) + { + struct pending_inline *t1, *t2; + tree args; + + t2 = DECL_PENDING_INLINE_INFO (fndecl); + t2->next = pending_inlines; + t2->fndecl = fndecl; + args = DECL_ARGUMENTS (fndecl); + while (args) + { + DECL_CONTEXT (args) = fndecl; + args = TREE_CHAIN (args); + } +#ifdef DO_METHODS_THE_OLD_WAY + t1 = stash_inline_prefix (cname, methods); + t1->next = t2; +#else + t1 = t2; +#endif + pending_inlines = t1; + + /* Allow this decl to be seen in global scope */ + IDENTIFIER_GLOBAL_VALUE (DECL_NAME (fndecl)) = fndecl; + } +} + +void +do_inline_function_hair (type, friend_list) + tree type, friend_list; +{ + tree cname = DECL_NAME (TYPE_NAME (type)); + tree method_vec = CLASSTYPE_METHOD_VEC (type); + if (method_vec != 0) + { + tree *methods = &TREE_VEC_ELT (method_vec, 0); + tree *end = TREE_VEC_END (method_vec); + while (methods != end) + { + /* Do inline member functions. */ + tree method = *methods; + while (method) + { + prepare_inline (cname, method); + method = TREE_CHAIN (method); + } + methods++; + } + } + while (friend_list) + { + prepare_inline (NULL_TREE, TREE_VALUE (friend_list)); + friend_list = TREE_CHAIN (friend_list); + } +} + +/* Report a 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, err_name) + struct candidate *cp; + tree parmtypes; + char *name_kind, *err_name; +{ + char buf[OVERLOAD_MAX_LEN]; + int i = cp->u.bad_arg; + tree ttf, tta; + + if (i == -3) + { + if (TREE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes)))) + error ("call to const %s `%s' with non-const object", name_kind, err_name); + else + error ("call to non-const %s `%s' with const object", name_kind, err_name); + return; + } + if (i == -2) + { + error ("too few arguments for %s `%s'", name_kind, err_name); + return; + } + else if (i == -1) + { + error ("too many arguments for %s `%s'", name_kind, err_name); + return; + } + if (i == 0) + { + if (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE) + { + /* Happens when we have an ambiguous base class. */ + assert (get_base_type (DECL_CONTEXT (cp->function), TREE_TYPE (TREE_TYPE (TREE_VALUE (parmtypes))), 1) == error_mark_node); + return; + } + } + ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function)); + tta = parmtypes; + + while (i-- > 0) + { + ttf = TREE_CHAIN (ttf); + tta = TREE_CHAIN (tta); + } + fndecl_as_string (buf, 0, cp->function, 0); + inline_bufp = inline_buffer + strlen (inline_buffer) + 1; + inline_buffer = inline_bufp; + + /* 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 instatiation)"); + else + { + i = (code == FUNCTION_TYPE || code == METHOD_TYPE); + dump_type (TREE_TYPE (TREE_VALUE (tta)), &i); + } + } + else OB_PUTS ("void"); + + OB_FINISH (); + sprintf (inline_bufp, "bad argument %d for function `%s' (type was %s)", + cp->u.bad_arg - (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE), buf, inline_buffer); + strcpy (buf, inline_bufp); + error (buf); +} + +/* Here is where overload code starts. */ + +#define OVERLOAD_MAX_LEN 1024 + +/* Array of types seen so far in top-level call to `build_overload_name'. + Allocated and deallocated by caller. */ +static tree *typevec; + +/* Number of types interned by `build_overload_name' so far. */ +static int maxtype; + +/* Number of occurances of last type seen. */ +static int nrepeats; + +/* 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) + +#define DEALLOCATE_TYPEVEC(PARMTYPES) \ + do { tree t = (PARMTYPES); \ + while (t) { TREE_USED (TREE_VALUE (t)) = 0; t = TREE_CHAIN (t); } \ + } while (0) + +/* Code to concatenate an asciified integer to a string, + and return the end of the string. */ +static +#ifdef __GNUC__ +__inline +#endif +char * +icat (s, i) + char *s; + int i; +{ + if (i < 10) + { + *s++ = '0' + i; + return s; + } + s = icat (s, i / 10); + *s++ = '0' + (i % 10); + return s; +} + +static +#ifdef __GNUC__ +__inline +#endif +char * +flush_repeats (s, type) + char *s; + tree type; +{ + int tindex = 0; + char *rval; + + while (typevec[tindex] != type) + tindex++; + + if (nrepeats > 1) + { + *s++ = 'N'; + s = icat (s, nrepeats); + if (nrepeats > 9) + *s++ = '_'; + } + else + *s++ = 'T'; + nrepeats = 0; + rval = icat (s, tindex); + if (tindex > 9) + *rval++ = '_'; + return rval; +} + +/* Given a list of parameters in PARMS, and a buffer in TEXT, of + length LEN bytes, create an unambiguous overload string. Should + distinguish any type that C (or C++) can distinguish. I.e., + pointers to functions are treated correctly. + + Caller must deal with whether a final `e' goes on the end or not. + + Any default conversions must take place before this function + is called. */ + +static char * +build_overload_name (parmtypes, text, text_end) + tree parmtypes; + char *text, *text_end; +{ + char *textp = text; + int just_one; + tree parmtype; + + if (just_one = (TREE_CODE (parmtypes) != TREE_LIST)) + { + parmtype = parmtypes; + goto only_one; + } + + while (parmtypes) + { + if (text_end - text < 4) + fatal ("Out of string space in build_overload_name!"); + parmtype = TREE_VALUE (parmtypes); + + only_one: + + if (! nofold) + { + if (! just_one) + /* Every argument gets counted. */ + typevec[maxtype++] = parmtype; + + if (TREE_USED (parmtype)) + { + if (! just_one && parmtype == typevec[maxtype-2]) + nrepeats++; + else + { + if (nrepeats) + textp = flush_repeats (textp, parmtype); + if (! just_one && TREE_CHAIN (parmtypes) + && parmtype == TREE_VALUE (TREE_CHAIN (parmtypes))) + nrepeats++; + else + { + int tindex = 0; + + while (typevec[tindex] != parmtype) + tindex++; + *textp++ = 'T'; + textp = icat (textp, tindex); + if (tindex > 9) + *textp++ = '_'; + } + } + goto next; + } + if (nrepeats) + textp = flush_repeats (textp, 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))) + TREE_USED (parmtype) = 1; + } + + if (TREE_READONLY (parmtype)) + *textp++ = 'C'; + if (TREE_CODE (parmtype) == INTEGER_TYPE && TREE_UNSIGNED (parmtype)) + *textp++ = 'U'; + if (TREE_VOLATILE (parmtype)) + *textp++ = 'V'; + + switch (TREE_CODE (parmtype)) + { + case OFFSET_TYPE: + *textp++ = 'O'; + textp = build_overload_name (TYPE_OFFSET_BASETYPE (parmtype), textp, text_end); + *textp++ = '_'; + textp = build_overload_name (TREE_TYPE (parmtype), textp, text_end); + break; + + case REFERENCE_TYPE: + *textp++ = 'R'; + goto more; + + case ARRAY_TYPE: +#ifdef PARM_CAN_BE_ARRAY_TYPE + { + tree length; + + *textp++ = 'A'; + length = array_type_nelts (parmtype); + if (TREE_CODE (length) == INTEGER_CST) + textp = icat (textp, TREE_INT_CST_LOW (length)); + *textp++ = '_'; + goto more; + } +#else + *textp++ = 'P'; + goto more; +#endif + + case POINTER_TYPE: + *textp++ = 'P'; + more: + textp = build_overload_name (TREE_TYPE (parmtype), textp, text_end); + 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) + textp = flush_repeats (textp, 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) + { + *textp++ = 'F'; + if (firstarg == NULL_TREE) + *textp++ = 'e'; + else if (firstarg == void_list_node) + *textp++ = 'v'; + else + textp = build_overload_name (firstarg, textp, text_end); + } + else + { + int constp = TREE_READONLY (TREE_TYPE (TREE_VALUE (firstarg))); + int volatilep = TREE_VOLATILE (TREE_TYPE (TREE_VALUE (firstarg))); + *textp++ = 'M'; + firstarg = TREE_CHAIN (firstarg); + + textp = build_overload_name (TYPE_METHOD_BASETYPE (parmtype), textp, text_end); + if (constp) + *textp++ = 'C'; + if (volatilep) + *textp++ = 'V'; + + /* For cfront 2.0 compatability. */ + *textp++ = 'F'; + + if (firstarg == NULL_TREE) + *textp++ = 'e'; + else if (firstarg == void_list_node) + *textp++ = 'v'; + else + textp = build_overload_name (firstarg, textp, text_end); + } + + /* Separate args from return type. */ + *textp++ = '_'; + textp = build_overload_name (TREE_TYPE (parmtype), textp, text_end); + nofold = old_nofold; + break; + } + + case INTEGER_TYPE: + parmtype = TYPE_MAIN_VARIANT (parmtype); + switch (TYPE_MODE (parmtype)) + { + case TImode: + if (parmtype == long_integer_type_node + || parmtype == long_unsigned_type_node) + *textp++ = 'l'; + else + *textp++ = 'q'; + break; + case DImode: + if (parmtype == long_integer_type_node + || parmtype == long_unsigned_type_node) + *textp++ = 'l'; + else if (parmtype == integer_type_node + || parmtype == unsigned_type_node) + *textp++ = 'i'; + else if (parmtype == short_integer_type_node + || parmtype == short_unsigned_type_node) + *textp++ = 's'; + else + *textp++ = 'x'; + break; + case SImode: + if (parmtype == long_integer_type_node + || parmtype == long_unsigned_type_node) + *textp++ = 'l'; + else if (parmtype == short_integer_type_node + || parmtype == short_unsigned_type_node) + *textp++ = 's'; + else + *textp++ = 'i'; + break; + case HImode: + if (parmtype == integer_type_node + || parmtype == unsigned_type_node) + *textp++ = 'i'; + else + *textp++ = 's'; + break; + case QImode: + *textp++ = 'c'; + break; + default: + abort (); + } + break; + + case REAL_TYPE: + parmtype = TYPE_MAIN_VARIANT (parmtype); + if (parmtype == long_double_type_node) + *textp++ = 'r'; + else if (parmtype == double_type_node) + *textp++ = 'd'; + else if (parmtype == float_type_node) + *textp++ = 'f'; + else abort (); + break; + + case VOID_TYPE: + if (! just_one) + { +#if 0 + extern tree void_list_node; + + /* See if anybody is wasting memory. */ + assert (parmtypes == void_list_node); +#endif + /* This is the end of a parameter list. */ + *textp = '\0'; + return textp; + } + *textp++ = '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. */ + *textp++ = 'G'; + goto common; + case ENUMERAL_TYPE: + common: + { + tree name = TYPE_NAME (parmtype); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + assert (TREE_CODE (name) == IDENTIFIER_NODE); + textp = icat (textp, IDENTIFIER_LENGTH (name)); + strcpy (textp, IDENTIFIER_POINTER (name)); + textp += IDENTIFIER_LENGTH (name); + break; + } + + case UNKNOWN_TYPE: + /* This will take some work. */ + *textp++ = '?'; + break; + + default: + abort (); + } + + next: + if (just_one) break; + parmtypes = TREE_CHAIN (parmtypes); + } + if (! just_one) + { + if (nrepeats) + textp = flush_repeats (textp, typevec[maxtype-1]); + + /* To get here, parms must end with `...'. */ + *textp++ = 'e'; + } + + *textp = '\0'; + return textp; +} + +/* 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 (name, parms, for_method) + char *name; + tree parms; + int for_method; +{ + int tmp; + char tname[OVERLOAD_MAX_LEN]; + + if (for_method == 2) + /* We can divine that this is a constructor, + and figure out its name without any extra encoding. */ + tmp = 0; + else + { + strcpy (tname, name); + tmp = strlen (tname); + } + tname[tmp++] = '_'; + tname[tmp++] = '_'; + if (for_method) + { +#if 0 + /* We can get away without doing this. */ + tname[tmp++] = 'M'; +#endif + parms = temp_tree_cons (NULL_TREE, TREE_TYPE (TREE_VALUE (parms)), TREE_CHAIN (parms)); + } + else + tname[tmp++] = 'F'; + + if (parms == NULL_TREE) + tname[tmp++] = 'e', tname[tmp] = '\0'; + else if (parms == void_list_node) + tname[tmp++] = 'v', tname[tmp] = '\0'; + else + { + ALLOCATE_TYPEVEC (parms); + nofold = 0; + if (for_method) + { + tmp = build_overload_name (TREE_VALUE (parms), tname+tmp, &tname[OVERLOAD_MAX_LEN]) - tname; + +#ifndef LONGERNAMES + typevec[maxtype++] = TREE_VALUE (parms); + TREE_USED (TREE_VALUE (parms)) = 1; +#endif + + if (TREE_CHAIN (parms)) + build_overload_name (TREE_CHAIN (parms), tname+tmp, &tname[OVERLOAD_MAX_LEN]); + else + { + tname[tmp++] = 'e'; + tname[tmp] = '\0'; + } + } + else + build_overload_name (parms, tname+tmp, &tname[OVERLOAD_MAX_LEN]); + DEALLOCATE_TYPEVEC (parms); + } + return get_identifier (tname); +} + +/* Build an overload name for the type expression TYPE. */ +tree +build_typename_overload (type) + tree type; +{ + char tname[OVERLOAD_MAX_LEN]; + int i = sizeof (OPERATOR_TYPENAME_FORMAT) - 1; + sprintf (tname, OPERATOR_TYPENAME_FORMAT); +#if 0 + /* We can get away without doing this--it really gets + overloaded later. */ + tname[i++] = '_'; + tname[i++] = '_'; + tname[i++] = 'M'; +#endif + nofold = 1; + build_overload_name (type, tname + i, &tname[OVERLOAD_MAX_LEN]); + return get_identifier (tname); +} + +/* 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 redundanly 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 + abort (); +#endif +} + +#ifdef NO_AUTO_OVERLOAD +/* Check to see if NAME is overloaded. For first approximation, + check to see if its TREE_OVERLOADED is set. This is used on + IDENTIFIER nodes. */ +int +is_overloaded (name) + tree name; +{ + /* @@ */ + return (TREE_OVERLOADED (name) + && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0) + && ! IDENTIFIER_LOCAL_VALUE (name)); +} +#endif + +/* Given a tree_code CODE, and some arguments (at least one), + attempt to use an overloaded operator on the arguments. + + For unary operators, only the first argument need be checked. + For binary operators, both arguments may need to be checked. + + Member functions can convert class references to class pointers, + for one-level deep indirection. More than that is not supported. + Operators [](), ()(), and ->() must be member functions. + + We call function call building calls with nonzero complain if + they are our only hope. This is true when we see a vanilla operator + applied to something of aggregate type. If this fails, we are free to + return `error_mark_node', because we will have reported the error. + + Operators NEW and DELETE overload in funny ways: operator new takes + a single `size' parameter, and operator delete takes a pointer to the + storage being deleted. When overloading these operators, success is + assumed. If there is a failure, report an error message and return + `error_mark_node'. */ + +/* NOSTRICT */ +tree +build_opfncall (code, flags, xarg1, xarg2, arg3) + enum tree_code code; + tree xarg1, xarg2; + tree 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: + code = POSTINCREMENT_EXPR; + binary_is_unary = 1; + try_second = 0; + break; + + case POSTDECREMENT_EXPR: + code = PREDECREMENT_EXPR; + binary_is_unary = 1; + try_second = 0; + break; + + case PREDECREMENT_EXPR: + case POSTINCREMENT_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 NEW_EXPR: + { + /* For operators `new' (`delete'), only check visibility + if we are in a constructor (destructor), and we are + allocating for that constructor's (destructor's) type. */ + + fnname = get_identifier (OPERATOR_NEW_FORMAT); + if (flags & LOOKUP_GLOBAL) + return build_overload_call (fnname, tree_cons (NULL_TREE, xarg2, arg3), + flags & LOOKUP_COMPLAIN, 0); + + if (current_function_decl == NULL_TREE + || !DECL_CONSTRUCTOR_P (current_function_decl) + || current_class_type != TYPE_MAIN_VARIANT (type1)) + flags = LOOKUP_COMPLAIN; + rval = build_method_call (build1 (NOP_EXPR, xarg1, error_mark_node), + fnname, tree_cons (NULL_TREE, xarg2, arg3), + 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 DELETE_EXPR: + { + /* See comment above. */ + + fnname = get_identifier (OPERATOR_DELETE_FORMAT); + if (flags & LOOKUP_GLOBAL) + return build_overload_call (fnname, build_tree_list (NULL_TREE, xarg1), + flags & LOOKUP_COMPLAIN, 0); + + if (current_function_decl == NULL_TREE + || !DESTRUCTOR_NAME_P (DECL_NAME (current_function_decl)) + || current_class_type != TYPE_MAIN_VARIANT (type1)) + flags = LOOKUP_COMPLAIN; + rval = build_method_call (build1 (NOP_EXPR, TREE_TYPE (xarg1), error_mark_node), + fnname, build_tree_list (NULL_TREE, xarg1), + NULL_TREE, flags); + /* This happens when the user mis-declares `operator delete'. + Should now be impossible. */ + assert (rval != error_mark_node); + TREE_TYPE (rval) = void_type_node; + return rval; + } + break; + + default: + binary_is_unary = 0; + try_second = tree_code_length [(int) code] == 2; + if (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)) + { + /* 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 forseeable future. */ + return rval; + } + + if (code == MODIFY_EXPR) + { + tree op_id = build_opid (MODIFY_EXPR, arg3); + fnname = build_operator_fnname (&op_id, 0, 2); + } + else + { + tree op_id = build_opid (0, code); + if (binary_is_unary) + fnname = build_operator_fnname (&op_id, 0, 1); + else + fnname = build_operator_fnname (&op_id, 0, + tree_code_length [(int) code]); + } + + global_fn = IDENTIFIER_GLOBAL_VALUE (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 (CLASSTYPE_AS_LIST (type1), fnname, 0); + + 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 uncommited 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 (0, 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 & LOOKUP_COMPLAIN, 0); + } + + /* If we did not win, do not lose yet, since type conversion may work. */ + if (TREE_CODE (rval) == ERROR_MARK) + { + if (flags & LOOKUP_COMPLAIN) + return rval; + return 0; + } + + return rval; +} + +/* This function takes an identifier, ID, and attempts to figure out what + it means. There are a number of possible scenarios, presented in increasing + order of hair: + + 1) not in a class's scope + 2) in class's scope, member name of the class's method + 3) in class's scope, but not a member name of the class + 4) in class's scope, member name of a class's variable + + NAME is $1 from the bison rule. It is an IDENTIFIER_NODE. + VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1) + 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. + + Values which are declared as being of REFERENCE_TYPE are + automatically dereferenced here (as a hack to make the + compiler faster). */ + +tree +hack_identifier (value, name, yychar) + tree value, name; +{ + tree type; + + if (TREE_CODE (value) == ERROR_MARK) + { + if (current_class_name) + { + tree fields = lookup_fnfields (CLASSTYPE_AS_LIST (current_class_type), name, 0); + if (fields) + { + fields = TREE_VALUE (fields); + assert (TREE_CODE (fields) == FUNCTION_DECL); + if (TREE_CHAIN (fields) == NULL_TREE) + { + warning ("methods cannot be converted to function pointers"); + return fields; + } + else + { + error ("ambiguous request for method pointer `%s'", + IDENTIFIER_POINTER (name)); + return error_mark_node; + } + } + } + if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name)) + { + return IDENTIFIER_LABEL_VALUE (name); + } + return error_mark_node; + } + + type = TREE_TYPE (value); + if (TREE_NONLOCAL (value)) + { + if (TREE_CODE (value) == FIELD_DECL) + { + if (current_class_decl == 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 + && (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; + } + /* 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); + } + if (DECL_CONTEXT (value) != current_class_type + && (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == CONST_DECL)) + { + tree path; + enum visibility_type visibility; + + get_base_distance (DECL_CONTEXT (value), current_class_type, 0, &path); + visibility = compute_visibility (path, value); + if (visibility != visibility_public) + { + if (TREE_CODE (value) == VAR_DECL) + error ("static member `%s' is from private base class", + IDENTIFIER_POINTER (name)); + else + error ("enum `%s' is from private base class", + IDENTIFIER_POINTER (name)); + return error_mark_node; + } + } + else if (TREE_CODE (value) == TREE_LIST && type == 0) + { + error ("request for member `%s' is ambiguous in multiple inheritance lattice", + IDENTIFIER_POINTER (name)); + return error_mark_node; + } + + return value; + } + + if (! TREE_USED (value)) + { + if (TREE_EXTERNAL (value)) + assemble_external (value); + TREE_USED (value) = 1; + } + if (TREE_CODE (type) == REFERENCE_TYPE) + { + assert (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL + || TREE_CODE (value) == RESULT_DECL); + if (DECL_REFERENCE_SLOT (value)) + return DECL_REFERENCE_SLOT (value); + } + return value; +} + +tree +hack_operator (op) + tree op; +{ + if (op == NULL_TREE) + return error_mark_node; + + if (TREE_CODE (op) != TYPE_EXPR) + return grokopexpr (&op, NULL_TREE, 0, 0, 0); + + return op; +} + +/* NONWRAPPER is nonzero if this call is not to be wrapped. + TYPE is the type that the wrapper belongs to (in case + it should be non-virtual). + DECL is the function will will be (not be) wrapped. */ +tree +hack_wrapper (nonwrapper, type, decl) + int nonwrapper; + tree type, decl; +{ + if (type == NULL_TREE || is_aggr_typedef (type, 1)) + { + if (type) + type = TREE_TYPE (type); + + switch (nonwrapper) + { + case 0: + return build_nt (WRAPPER_EXPR, type, decl); + case 1: + return build_nt (ANTI_WRAPPER_EXPR, type, decl); + case 2: + return build_nt (WRAPPER_EXPR, type, + build_nt (COND_EXPR, decl, NULL_TREE, NULL_TREE)); + default: + assert (0 <= nonwrapper && nonwrapper <= 2); + } + } + return error_mark_node; +} + +/* Return an IDENTIFIER which can be used as a name for + anonymous structs and unions. */ +tree +make_anon_name () +{ + static int cnt = 0; + char buf[32]; + + sprintf (buf, ANON_AGGRNAME_FORMAT, cnt++); + return get_identifier (buf); +} + +/* 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; + + assert (IS_AGGR_TYPE (TREE_TYPE (of))); + assert (TREE_CODE (component) == TYPE_EXPR); + + 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); + if (TREE_OPERAND (tmp, 0) + && TREE_OPERAND (tmp, 0) != void_list_node) + { + error ("operator requires empty parameter list"); + TREE_OPERAND (tmp, 0) = NULL_TREE; + } + 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) + return build_method_call (of, name, NULL_TREE, NULL_TREE, flags); + else if (of) + { + tree this_this; + + if (current_class_decl == NULL_TREE) + { + error ("object required for `operator ' call"); + return error_mark_node; + } + + this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl); + 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); + + error ("object required for `operator ' call"); + return error_mark_node; + + case INDIRECT_REF: + case ADDR_EXPR: + case ARRAY_REF: + break; + + case SCOPE_REF: + assert (cname == 0); + cname = TREE_OPERAND (tmp, 0); + tmp = TREE_OPERAND (tmp, 1); + break; + + default: + abort (); + } + 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 assert (cname == DECL_NAME (of)); + } + + if (of) + { + tree this_this; + + if (current_class_decl == NULL_TREE) + { + error ("object required for `operator ' call"); + 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); + + error ("object required for `operator ' member reference"); + return error_mark_node; +} -- 2.20.1