/* Handle the hair of processing (but not expanding) inline functions. Also manage function and variable name overloading. Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.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 2, 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. */ #ifndef lint static char rcsid[] = "$Id: cp-method.c,v 1.2 1993/08/02 17:31:56 mycroft Exp $"; #endif /* not lint */ #ifndef PARM_CAN_BE_ARRAY_TYPE #define PARM_CAN_BE_ARRAY_TYPE 1 #endif /* Handle method declarations. */ #include #include "config.h" #include "tree.h" #include "cp-tree.h" #include "obstack.h" #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free /* TREE_LIST of the current inline functions that need to be processed. */ struct pending_inline *pending_inlines; /* Obstack where we build text strings for overloading, etc. */ static struct obstack scratch_obstack; static char *scratch_firstobj; # define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0) # define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C))) # define OB_PUTC2(C1,C2) \ (obstack_1grow (&scratch_obstack, (C1)), obstack_1grow (&scratch_obstack, (C2))) # define OB_PUTS(S) (obstack_grow (&scratch_obstack, (S), sizeof (S) - 1)) # define OB_PUTID(ID) \ (obstack_grow (&scratch_obstack, IDENTIFIER_POINTER (ID), \ IDENTIFIER_LENGTH (ID))) # define OB_PUTCP(S) (obstack_grow (&scratch_obstack, (S), strlen (S))) # define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0')) /* Counter to help build parameter names in case they were omitted. */ static int dummy_name; static int in_parmlist; /* This points to a safe place to resume processing in case an expression generates an error while we're trying to format it. */ static int scratch_error_offset; static void dump_type (), dump_decl (); static void dump_init (), dump_unary_op (), dump_binary_op (); #ifdef NO_AUTO_OVERLOAD int is_overloaded (); #endif void init_method () { gcc_obstack_init (&scratch_obstack); scratch_firstobj = (char *)obstack_alloc (&scratch_obstack, 0); } 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 (TYPE_READONLY (t)) OB_PUTS ("const "); if (TYPE_VOLATILE (t)) OB_PUTS ("volatile "); } static void dump_aggr_type (t) tree t; { tree name; char *aggr_string; char *context_string = 0; if (TYPE_READONLY (t)) OB_PUTS ("const "); if (TYPE_VOLATILE (t)) OB_PUTS ("volatile "); if (TREE_CODE (t) == ENUMERAL_TYPE) aggr_string = "enum"; else if (TREE_CODE (t) == UNION_TYPE) aggr_string = "union"; else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t)) aggr_string = "class"; else aggr_string = "struct"; name = TYPE_NAME (t); if (TREE_CODE (name) == TYPE_DECL) { #if 0 /* not yet, should get fixed properly later */ if (DECL_CONTEXT (name)) context_string = TYPE_NAME_STRING (DECL_CONTEXT (name)); #else if (DECL_LANG_SPECIFIC (name) && DECL_CLASS_CONTEXT (name)) context_string = TYPE_NAME_STRING (DECL_CLASS_CONTEXT (name)); #endif name = DECL_NAME (name); } obstack_grow (&scratch_obstack, aggr_string, strlen (aggr_string)); OB_PUTC (' '); if (context_string) { obstack_grow (&scratch_obstack, context_string, strlen (context_string)); OB_PUTC2 (':', ':'); } OB_PUTID (name); } /* This must be large enough to hold any anonymous parm name. */ static char anon_buffer[sizeof (ANON_PARMNAME_FORMAT) + 20]; /* This must be large enough to hold any printed integer or floatingpoint value. */ static char digit_buffer[128]; static void dump_type_prefix (t, p) tree t; int *p; { int old_p = 0; if (t == NULL_TREE) return; switch (TREE_CODE (t)) { case ERROR_MARK: sprintf (anon_buffer, ANON_PARMNAME_FORMAT, dummy_name++); OB_PUTCP (anon_buffer); 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 (TYPE_READONLY (t)) OB_PUTS ("const "); if (TYPE_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 (TYPE_READONLY (t) | TYPE_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 (TYPE_READONLY (t) | TYPE_VOLATILE (t)) dump_readonly_or_volatile (t); return; } case REFERENCE_TYPE: dump_type_prefix (TREE_TYPE (t), p); OB_PUTC ('&'); if (TYPE_READONLY (t) | TYPE_VOLATILE (t)) dump_readonly_or_volatile (t); return; case ARRAY_TYPE: if (TYPE_READONLY (t) | TYPE_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 (TYPE_READONLY (t) | TYPE_VOLATILE (t)) dump_readonly_or_volatile (t); return; case IDENTIFIER_NODE: OB_PUTID (t); OB_PUTC (' '); break; case RECORD_TYPE: case UNION_TYPE: case ENUMERAL_TYPE: dump_aggr_type (t); break; case TYPE_DECL: if (TYPE_READONLY (t)) OB_PUTS ("const "); if (TYPE_VOLATILE (t)) OB_PUTS ("volatile "); OB_PUTID (DECL_NAME (t)); OB_PUTC (' '); break; case INTEGER_TYPE: #if 0 /* Normally, `unsigned' is part of the deal. Not so if it comes with `const' or `volatile'. */ if (TYPE_MAIN_VARIANT (t) == unsigned_type (TYPE_MAIN_VARIANT (t)) && (TYPE_READONLY (t) || TYPE_VOLATILE (t))) OB_PUTS ("unsigned "); #endif /* fall through. */ case REAL_TYPE: case VOID_TYPE: if (TYPE_READONLY (t)) OB_PUTS ("const "); if (TYPE_VOLATILE (t)) OB_PUTS ("volatile "); OB_PUTID (TYPE_IDENTIFIER (t)); OB_PUTC (' '); break; default: my_friendly_abort (65); } } 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 (anon_buffer, ANON_PARMNAME_FORMAT, dummy_name++); OB_PUTCP (anon_buffer); 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 my_friendly_abort (66); #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: my_friendly_abort (67); } } static void dump_type (t, p) tree t; int *p; { int old_p = 0; if (t == NULL_TREE) return; switch (TREE_CODE (t)) { case ERROR_MARK: sprintf (anon_buffer, ANON_PARMNAME_FORMAT, dummy_name++); OB_PUTCP (anon_buffer); 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 (TYPE_READONLY (t) | TYPE_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 (TYPE_READONLY (t) | TYPE_VOLATILE (t)) dump_readonly_or_volatile (t); dump_type (TREE_TYPE (t), p); OB_PUTC ('&'); return; case ARRAY_TYPE: if (TYPE_READONLY (t) | TYPE_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: OB_PUTID (t); OB_PUTC (' '); break; case RECORD_TYPE: case UNION_TYPE: case ENUMERAL_TYPE: dump_aggr_type (t); break; case TYPE_DECL: if (TYPE_READONLY (t) | TYPE_VOLATILE (t)) dump_readonly_or_volatile (t); OB_PUTID (DECL_NAME (t)); OB_PUTC (' '); break; case INTEGER_TYPE: /* Normally, `unsigned' is part of the deal. Not so if it comes with `const' or `volatile'. */ if (TYPE_READONLY (t) | TYPE_VOLATILE (t)) dump_readonly_or_volatile (t); #if 0 if (TYPE_MAIN_VARIANT (t) == unsigned_type (TYPE_MAIN_VARIANT (t)) && (TYPE_READONLY (t) | TYPE_VOLATILE (t))) OB_PUTS ("unsigned "); #endif OB_PUTID (TYPE_IDENTIFIER (t)); OB_PUTC (' '); break; case REAL_TYPE: case VOID_TYPE: if (TYPE_READONLY (t) | TYPE_VOLATILE (t)) dump_readonly_or_volatile (t); OB_PUTID (TYPE_IDENTIFIER (t)); OB_PUTC (' '); break; case TEMPLATE_TYPE_PARM: OB_PUTS ("