diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1995-12-20 01:06:22 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1995-12-20 01:06:22 +0000 |
commit | c482518380683ee38d14024c1e362a0d681cf967 (patch) | |
tree | e69b4f6d3fee3aced20a41f3fdf543fc1c77fb5d /gnu/usr.bin/gcc/cp/error.c | |
parent | 76a62188d0db49c65b696d474c855a799fd96dce (diff) |
FSF GCC version 2.7.2
Diffstat (limited to 'gnu/usr.bin/gcc/cp/error.c')
-rw-r--r-- | gnu/usr.bin/gcc/cp/error.c | 1482 |
1 files changed, 1482 insertions, 0 deletions
diff --git a/gnu/usr.bin/gcc/cp/error.c b/gnu/usr.bin/gcc/cp/error.c new file mode 100644 index 00000000000..4eb196e3add --- /dev/null +++ b/gnu/usr.bin/gcc/cp/error.c @@ -0,0 +1,1482 @@ +/* Call-backs for C++ error reporting. + This code is non-reentrant. + Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + + 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "tree.h" +#include "cp-tree.h" +#include "obstack.h" +#include <ctype.h> + +typedef char* cp_printer (); + +#define A args_as_string +#define C code_as_string +#define D decl_as_string +#define E expr_as_string +#define L language_as_string +#define O op_as_string +#define P parm_as_string +#define T type_as_string +#define V cv_as_string + +#define _ (cp_printer *) 0 +cp_printer * cp_printers[256] = +{ +/*0 1 2 3 4 5 6 7 8 9 A B C D E F */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x00 */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x10 */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x20 */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x30 */ + _, A, _, C, D, E, _, _, _, _, _, _, L, _, _, O, /* 0x40 */ + P, _, _, _, T, _, V, _, _, _, _, _, _, _, _, _, /* 0x50 */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x60 */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x70 */ +}; +#undef C +#undef D +#undef E +#undef L +#undef O +#undef P +#undef T +#undef V +#undef _ + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +/* 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')) +# define OB_PUTI(CST) do { sprintf (digit_buffer, "%d", (CST)); \ + OB_PUTCP (digit_buffer); } while (0) +# define OB_UNPUT(N) obstack_blank (&scratch_obstack, - (N)); + +# define NEXT_CODE(t) (TREE_CODE (TREE_TYPE (t))) + +static void dump_type (), dump_decl (), dump_function_decl (); +static void dump_expr (), dump_unary_op (), dump_binary_op (); +static void dump_aggr_type (), dump_type_prefix (), dump_type_suffix (); +static void dump_function_name (); + +void +init_error () +{ + gcc_obstack_init (&scratch_obstack); + scratch_firstobj = (char *)obstack_alloc (&scratch_obstack, 0); +} + +enum pad { none, before, after }; + +static void +dump_readonly_or_volatile (t, p) + tree t; + enum pad p; +{ + if (TYPE_READONLY (t) || TYPE_VOLATILE (t)) + { + if (p == before) OB_PUTC (' '); + if (TYPE_READONLY (t)) + OB_PUTS ("const"); + if (TYPE_READONLY (t) && TYPE_VOLATILE (t)) + OB_PUTC (' '); + if (TYPE_VOLATILE (t)) + OB_PUTS ("volatile"); + if (p == after) OB_PUTC (' '); + } +} + +/* This must be large enough to hold any printed integer or floating-point + value. */ +static char digit_buffer[128]; + +/* Dump into the obstack a human-readable equivalent of TYPE. */ +static void +dump_type (t, v) + tree t; + int v; /* verbose? */ +{ + if (t == NULL_TREE) + return; + + if (TYPE_PTRMEMFUNC_P (t)) + goto offset_type; + + switch (TREE_CODE (t)) + { + case ERROR_MARK: + OB_PUTS ("{error}"); + break; + + case UNKNOWN_TYPE: + OB_PUTS ("{unknown type}"); + break; + + case TREE_LIST: + /* i.e. function taking no arguments */ + if (t != void_list_node) + { + dump_type (TREE_VALUE (t), v); + /* Can this happen other than for default arguments? */ + if (TREE_PURPOSE (t) && v) + { + OB_PUTS (" = "); + dump_expr (TREE_PURPOSE (t)); + } + if (TREE_CHAIN (t)) + { + if (TREE_CHAIN (t) != void_list_node) + { + OB_PUTC2 (',', ' '); + dump_type (TREE_CHAIN (t), v); + } + } + else OB_PUTS (" ..."); + } + break; + + case IDENTIFIER_NODE: + OB_PUTID (t); + break; + + case TREE_VEC: + dump_type (BINFO_TYPE (t), v); + break; + + case RECORD_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + if (TYPE_LANG_SPECIFIC (t) + && (IS_SIGNATURE_POINTER (t) || IS_SIGNATURE_REFERENCE (t))) + { + if (TYPE_READONLY (t) | TYPE_VOLATILE (t)) + dump_readonly_or_volatile (t); + dump_type (SIGNATURE_TYPE (t), v); + if (IS_SIGNATURE_POINTER (t)) + OB_PUTC ('*'); + else + OB_PUTC ('&'); + } + else + dump_aggr_type (t, v); + break; + + case TYPE_DECL: + dump_decl (t, v); + break; + + case INTEGER_TYPE: + if (!TREE_UNSIGNED (TYPE_MAIN_VARIANT (t)) && TREE_UNSIGNED (t)) + OB_PUTS ("unsigned "); + else if (TREE_UNSIGNED (TYPE_MAIN_VARIANT (t)) && !TREE_UNSIGNED (t)) + OB_PUTS ("signed "); + + /* fall through. */ + case REAL_TYPE: + case VOID_TYPE: + case BOOLEAN_TYPE: + dump_readonly_or_volatile (t, after); + OB_PUTID (TYPE_IDENTIFIER (t)); + break; + + case TEMPLATE_TYPE_PARM: + OB_PUTID (TYPE_IDENTIFIER (t)); + break; + + case UNINSTANTIATED_P_TYPE: + OB_PUTID (DECL_NAME (UPT_TEMPLATE (t))); + OB_PUTS ("<...>"); + break; + + /* This is not always necessary for pointers and such, but doing this + reduces code size. */ + case ARRAY_TYPE: + case POINTER_TYPE: + case REFERENCE_TYPE: + case OFFSET_TYPE: + offset_type: + case FUNCTION_TYPE: + case METHOD_TYPE: + dump_type_prefix (t, v); + dump_type_suffix (t, v); + break; + + default: + sorry ("`%s' not supported by dump_type", + tree_code_name[(int) TREE_CODE (t)]); + } +} + +static char * +aggr_variety (t) + tree t; +{ + if (TREE_CODE (t) == ENUMERAL_TYPE) + return "enum"; + else if (TREE_CODE (t) == UNION_TYPE) + return "union"; + else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t)) + return "class"; + else if (TYPE_LANG_SPECIFIC (t) && IS_SIGNATURE (t)) + return "signature"; + else + return "struct"; +} + +/* Print out a class declaration, in the form `class foo'. */ +static void +dump_aggr_type (t, v) + tree t; + int v; /* verbose? */ +{ + tree name; + char *variety = aggr_variety (t); + + dump_readonly_or_volatile (t, after); + + if (v > 0) + { + OB_PUTCP (variety); + OB_PUTC (' '); + } + + name = TYPE_NAME (t); + + if (name && DECL_CONTEXT (name)) + { + /* FUNCTION_DECL or RECORD_TYPE */ + dump_decl (DECL_CONTEXT (name), 0); + OB_PUTC2 (':', ':'); + } + + /* kludge around weird behavior on g++.brendan/line1.C */ + if (name && TREE_CODE (name) != IDENTIFIER_NODE) + name = DECL_NAME (name); + + if (name == 0 || ANON_AGGRNAME_P (name)) + { + OB_PUTS ("{anonymous"); + if (!v) + { + OB_PUTC (' '); + OB_PUTCP (variety); + } + OB_PUTC ('}'); + } + else + OB_PUTID (name); +} + +/* Dump into the obstack the initial part of the output for a given type. + This is necessary when dealing with things like functions returning + functions. Examples: + + return type of `int (* fee ())()': pointer -> function -> int. Both + pointer (and reference and offset) and function (and member) types must + deal with prefix and suffix. + + Arrays must also do this for DECL nodes, like int a[], and for things like + int *[]&. */ + +static void +dump_type_prefix (t, v) + tree t; + int v; /* verbosity */ +{ + if (TYPE_PTRMEMFUNC_P (t)) + { + t = TYPE_PTRMEMFUNC_FN_TYPE (t); + goto offset_type; + } + + switch (TREE_CODE (t)) + { + case POINTER_TYPE: + { + tree sub = TREE_TYPE (t); + + dump_type_prefix (sub, v); + /* A tree for a member pointer looks like pointer to offset, + so let the OFFSET_TYPE case handle it. */ + if (TREE_CODE (sub) != OFFSET_TYPE) + { + switch (TREE_CODE (sub)) + { + /* We don't want int ( *)() */ + case FUNCTION_TYPE: + case METHOD_TYPE: + break; + + case ARRAY_TYPE: + OB_PUTC2 (' ', '('); + break; + + case POINTER_TYPE: + /* We don't want "char * *" */ + if (! (TYPE_READONLY (sub) || TYPE_VOLATILE (sub))) + break; + /* But we do want "char *const *" */ + + default: + OB_PUTC (' '); + } + OB_PUTC ('*'); + dump_readonly_or_volatile (t, none); + } + } + break; + + case REFERENCE_TYPE: + { + tree sub = TREE_TYPE (t); + dump_type_prefix (sub, v); + + switch (TREE_CODE (sub)) + { + case ARRAY_TYPE: + OB_PUTC2 (' ', '('); + break; + + case POINTER_TYPE: + /* We don't want "char * &" */ + if (! (TYPE_READONLY (sub) || TYPE_VOLATILE (sub))) + break; + /* But we do want "char *const &" */ + + default: + OB_PUTC (' '); + } + } + OB_PUTC ('&'); + dump_readonly_or_volatile (t, none); + break; + + case OFFSET_TYPE: + offset_type: + dump_type_prefix (TREE_TYPE (t), v); + if (TREE_CODE (t) == OFFSET_TYPE) /* pmfs deal with this in d_t_p */ + { + OB_PUTC (' '); + dump_type (TYPE_OFFSET_BASETYPE (t), 0); + OB_PUTC2 (':', ':'); + } + OB_PUTC ('*'); + dump_readonly_or_volatile (t, none); + break; + + /* Can only be reached through function pointer -- this would not be + correct if FUNCTION_DECLs used it. */ + case FUNCTION_TYPE: + dump_type_prefix (TREE_TYPE (t), v); + OB_PUTC2 (' ', '('); + break; + + case METHOD_TYPE: + dump_type_prefix (TREE_TYPE (t), v); + OB_PUTC2 (' ', '('); + dump_aggr_type (TYPE_METHOD_BASETYPE (t), 0); + OB_PUTC2 (':', ':'); + break; + + case ARRAY_TYPE: + dump_type_prefix (TREE_TYPE (t), v); + break; + + case ENUMERAL_TYPE: + case ERROR_MARK: + case IDENTIFIER_NODE: + case INTEGER_TYPE: + case BOOLEAN_TYPE: + case REAL_TYPE: + case RECORD_TYPE: + case TEMPLATE_TYPE_PARM: + case TREE_LIST: + case TYPE_DECL: + case TREE_VEC: + case UNINSTANTIATED_P_TYPE: + case UNION_TYPE: + case UNKNOWN_TYPE: + case VOID_TYPE: + dump_type (t, v); + break; + + default: + sorry ("`%s' not supported by dump_type_prefix", + tree_code_name[(int) TREE_CODE (t)]); + } +} + +static void +dump_type_suffix (t, v) + tree t; + int v; /* verbose? */ +{ + if (TYPE_PTRMEMFUNC_P (t)) + t = TYPE_PTRMEMFUNC_FN_TYPE (t); + + switch (TREE_CODE (t)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + case OFFSET_TYPE: + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + OB_PUTC (')'); + dump_type_suffix (TREE_TYPE (t), v); + break; + + /* Can only be reached through function pointer */ + case FUNCTION_TYPE: + case METHOD_TYPE: + { + tree arg; + OB_PUTC2 (')', '('); + arg = TYPE_ARG_TYPES (t); + if (TREE_CODE (t) == METHOD_TYPE) + arg = TREE_CHAIN (arg); + + if (arg) + dump_type (arg, v); + else + OB_PUTS ("..."); + OB_PUTC (')'); + if (TREE_CODE (t) == METHOD_TYPE) + dump_readonly_or_volatile + (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))), before); + dump_type_suffix (TREE_TYPE (t), v); + break; + } + + case ARRAY_TYPE: + OB_PUTC ('['); + if (TYPE_DOMAIN (t)) + OB_PUTI (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (t))) + 1); + OB_PUTC (']'); + dump_type_suffix (TREE_TYPE (t), v); + break; + + case ENUMERAL_TYPE: + case ERROR_MARK: + case IDENTIFIER_NODE: + case INTEGER_TYPE: + case BOOLEAN_TYPE: + case REAL_TYPE: + case RECORD_TYPE: + case TEMPLATE_TYPE_PARM: + case TREE_LIST: + case TYPE_DECL: + case TREE_VEC: + case UNINSTANTIATED_P_TYPE: + case UNION_TYPE: + case UNKNOWN_TYPE: + case VOID_TYPE: + break; + + default: + sorry ("`%s' not supported by dump_type_suffix", + tree_code_name[(int) TREE_CODE (t)]); + } +} + +/* Return a function declaration which corresponds to the IDENTIFIER_NODE + argument. */ +tree +ident_fndecl (t) + tree t; +{ + tree n = lookup_name (t, 0); + + if (n == NULL_TREE) + return NULL_TREE; + + if (TREE_CODE (n) == FUNCTION_DECL) + return n; + else if (TREE_CODE (n) == TREE_LIST + && TREE_CODE (TREE_VALUE (n)) == FUNCTION_DECL) + return TREE_VALUE (n); + + my_friendly_abort (66); + return NULL_TREE; +} + +#ifndef NO_DOLLAR_IN_LABEL +# define GLOBAL_THING "_GLOBAL_$" +#else +# ifndef NO_DOT_IN_LABEL +# define GLOBAL_THING "_GLOBAL_." +# else +# define GLOBAL_THING "_GLOBAL__" +# endif +#endif + +#define GLOBAL_IORD_P(NODE) \ + !strncmp(IDENTIFIER_POINTER(NODE),GLOBAL_THING,sizeof(GLOBAL_THING)-1) + +void +dump_global_iord (t) + tree t; +{ + char *name = IDENTIFIER_POINTER (t); + + OB_PUTS ("(static "); + if (name [sizeof (GLOBAL_THING) - 1] == 'I') + OB_PUTS ("initializers"); + else if (name [sizeof (GLOBAL_THING) - 1] == 'D') + OB_PUTS ("destructors"); + else + my_friendly_abort (352); + + OB_PUTS (" for "); + OB_PUTCP (input_filename); + OB_PUTC (')'); +} + +static void +dump_decl (t, v) + tree t; + int v; /* verbosity */ +{ + if (t == NULL_TREE) + return; + + switch (TREE_CODE (t)) + { + case ERROR_MARK: + OB_PUTS (" /* decl error */ "); + break; + + case TYPE_DECL: + { + /* Don't say 'typedef class A' */ + tree type = TREE_TYPE (t); + if (((IS_AGGR_TYPE (type) && ! TYPE_PTRMEMFUNC_P (type)) + || TREE_CODE (type) == ENUMERAL_TYPE) + && type == TYPE_MAIN_VARIANT (type)) + { + dump_type (type, v); + break; + } + } + if (v > 0) + OB_PUTS ("typedef "); + goto general; + break; + + case VAR_DECL: + if (DECL_NAME (t) && VTABLE_NAME_P (DECL_NAME (t))) + { + OB_PUTS ("vtable for "); + dump_type (DECL_CONTEXT (t), v); + break; + } + /* else fall through */ + case FIELD_DECL: + case PARM_DECL: + general: + if (v > 0) + { + dump_type_prefix (TREE_TYPE (t), v); + OB_PUTC (' '); + dump_readonly_or_volatile (t, after); + } + /* DECL_CLASS_CONTEXT isn't being set in some cases. Hmm... */ + if (DECL_CONTEXT (t) + && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't') + { + dump_type (DECL_CONTEXT (t), 0); + OB_PUTC2 (':', ':'); + } + if (DECL_NAME (t)) + dump_decl (DECL_NAME (t), v); + else + OB_PUTS ("{anon}"); + if (v > 0) + dump_type_suffix (TREE_TYPE (t), v); + break; + + case NAMESPACE_DECL: + OB_PUTID (DECL_NAME (t)); + break; + + case ARRAY_REF: + dump_decl (TREE_OPERAND (t, 0), v); + OB_PUTC ('['); + dump_decl (TREE_OPERAND (t, 1), v); + OB_PUTC (']'); + break; + + /* So that we can do dump_decl in dump_aggr_type and have it work for + both class and function scope. */ + case RECORD_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + dump_type (t, v); + break; + + case TYPE_EXPR: + my_friendly_abort (69); + break; + + /* These special cases are duplicated here so that other functions + can feed identifiers to cp_error and get them demangled properly. */ + case IDENTIFIER_NODE: + { tree f; + if (DESTRUCTOR_NAME_P (t) + && (f = ident_fndecl (t)) + && DECL_LANGUAGE (f) == lang_cplusplus) + { + OB_PUTC ('~'); + dump_decl (DECL_NAME (f), 0); + } + else if (IDENTIFIER_TYPENAME_P (t)) + { + OB_PUTS ("operator "); + /* Not exactly IDENTIFIER_TYPE_VALUE. */ + dump_type (TREE_TYPE (t), 0); + break; + } + else if (IDENTIFIER_OPNAME_P (t)) + { + char *name_string = operator_name_string (t); + OB_PUTS ("operator "); + OB_PUTCP (name_string); + } + else + OB_PUTID (t); + } + break; + + case FUNCTION_DECL: + if (GLOBAL_IORD_P (DECL_ASSEMBLER_NAME (t))) + dump_global_iord (DECL_ASSEMBLER_NAME (t)); + else + dump_function_decl (t, v); + break; + + case TEMPLATE_DECL: + { + tree args = DECL_TEMPLATE_PARMS (t); + int i, len = args ? TREE_VEC_LENGTH (args) : 0; + OB_PUTS ("template <"); + for (i = 0; i < len; i++) + { + tree arg = TREE_VEC_ELT (args, i); + tree defval = TREE_PURPOSE (arg); + arg = TREE_VALUE (arg); + if (TREE_CODE (arg) == TYPE_DECL) + { + OB_PUTS ("class "); + OB_PUTID (DECL_NAME (arg)); + } + else + dump_decl (arg, 1); + + if (defval) + { + OB_PUTS (" = "); + dump_decl (defval, 1); + } + + OB_PUTC2 (',', ' '); + } + if (len != 0) + OB_UNPUT (2); + OB_PUTC2 ('>', ' '); + + if (DECL_TEMPLATE_IS_CLASS (t)) + { + OB_PUTS ("class "); + OB_PUTID (DECL_NAME (t)); + } + else switch (NEXT_CODE (t)) + { + case METHOD_TYPE: + case FUNCTION_TYPE: + dump_function_decl (t, v); + break; + + default: + my_friendly_abort (353); + } + } + break; + + case LABEL_DECL: + OB_PUTID (DECL_NAME (t)); + break; + + case CONST_DECL: + if (NEXT_CODE (t) == ENUMERAL_TYPE) + goto general; + else + dump_expr (DECL_INITIAL (t), 0); + break; + + default: + sorry ("`%s' not supported by dump_decl", + tree_code_name[(int) TREE_CODE (t)]); + } +} + +/* Pretty printing for announce_function. T is the declaration of the + function we are interested in seeing. V is non-zero if we should print + the type that this function returns. */ + +static void +dump_function_decl (t, v) + tree t; + int v; +{ + tree name = DECL_ASSEMBLER_NAME (t); + tree fntype = TREE_TYPE (t); + tree parmtypes = TYPE_ARG_TYPES (fntype); + tree cname = NULL_TREE; + + /* Friends have DECL_CLASS_CONTEXT set, but not DECL_CONTEXT. */ + if (DECL_CONTEXT (t)) + cname = DECL_CLASS_CONTEXT (t); + /* this is for partially instantiated template methods */ + else if (TREE_CODE (fntype) == METHOD_TYPE) + cname = TREE_TYPE (TREE_VALUE (parmtypes)); + + v = (v > 0); + + if (v) + { + if (DECL_STATIC_FUNCTION_P (t)) + OB_PUTS ("static "); + + if (! IDENTIFIER_TYPENAME_P (name) + && ! DECL_CONSTRUCTOR_P (t) + && ! DESTRUCTOR_NAME_P (name)) + { + dump_type_prefix (TREE_TYPE (fntype), 1); + OB_PUTC (' '); + } + } + + if (cname) + { + dump_type (cname, 0); + OB_PUTC2 (':', ':'); + if (TREE_CODE (fntype) == METHOD_TYPE && parmtypes) + parmtypes = TREE_CHAIN (parmtypes); + if (DECL_CONSTRUCTOR_FOR_VBASE_P (t)) + /* Skip past "in_charge" identifier. */ + parmtypes = TREE_CHAIN (parmtypes); + } + + if (DESTRUCTOR_NAME_P (name) && DECL_LANGUAGE (t) == lang_cplusplus) + parmtypes = TREE_CHAIN (parmtypes); + + dump_function_name (t); + + OB_PUTC ('('); + + if (parmtypes) + dump_type (parmtypes, v); + else + OB_PUTS ("..."); + + OB_PUTC (')'); + + if (v && ! IDENTIFIER_TYPENAME_P (name)) + dump_type_suffix (TREE_TYPE (fntype), 1); + + if (TREE_CODE (fntype) == METHOD_TYPE) + { + if (IS_SIGNATURE (cname)) + /* We look at the type pointed to by the `optr' field of `this.' */ + dump_readonly_or_volatile + (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_VALUE (TYPE_ARG_TYPES (fntype))))), before); + else + dump_readonly_or_volatile + (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))), before); + } +} + +/* Handle the function name for a FUNCTION_DECL node, grokking operators + and destructors properly. */ +static void +dump_function_name (t) + tree t; +{ + tree name = DECL_NAME (t); + + /* There ought to be a better way to find out whether or not something is + a destructor. */ + if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (t)) + && DECL_LANGUAGE (t) == lang_cplusplus) + { + OB_PUTC ('~'); + dump_decl (name, 0); + } + else if (IDENTIFIER_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 (t)), 0); + } + else if (IDENTIFIER_OPNAME_P (name)) + { + char *name_string = operator_name_string (name); + OB_PUTS ("operator "); + OB_PUTCP (name_string); + } + else + dump_decl (name, 0); +} + +static void +dump_char (c) + char c; +{ + switch (c) + { + case TARGET_NEWLINE: + OB_PUTS ("\\n"); + break; + case TARGET_TAB: + OB_PUTS ("\\t"); + break; + case TARGET_VT: + OB_PUTS ("\\v"); + break; + case TARGET_BS: + OB_PUTS ("\\b"); + break; + case TARGET_CR: + OB_PUTS ("\\r"); + break; + case TARGET_FF: + OB_PUTS ("\\f"); + break; + case TARGET_BELL: + OB_PUTS ("\\a"); + break; + case '\\': + OB_PUTS ("\\\\"); + break; + case '\'': + OB_PUTS ("\\'"); + break; + case '\"': + OB_PUTS ("\\\""); + break; + default: + if (isprint (c)) + OB_PUTC (c); + else + { + sprintf (digit_buffer, "\\%03o", (int) c); + OB_PUTCP (digit_buffer); + } + } +} + +/* Print out a list of initializers (subr of dump_expr) */ +static void +dump_expr_list (l) + tree l; +{ + while (l) + { + dump_expr (TREE_VALUE (l), 0); + if (TREE_CHAIN (l)) + OB_PUTC2 (',', ' '); + l = TREE_CHAIN (l); + } +} + +/* Print out an expression */ +static void +dump_expr (t, nop) + tree t; + int nop; /* suppress parens */ +{ + switch (TREE_CODE (t)) + { + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case CONST_DECL: + case FUNCTION_DECL: + dump_decl (t, -1); + break; + + case INTEGER_CST: + { + tree type = TREE_TYPE (t); + my_friendly_assert (type != 0, 81); + + /* If it's an enum, output its tag, rather than its value. */ + if (TREE_CODE (type) == ENUMERAL_TYPE) + { + char *p = enum_name_string (t, type); + OB_PUTCP (p); + } + else if (type == boolean_type_node) + { + if (t == boolean_false_node) + OB_PUTS ("false"); + else if (t == boolean_true_node) + OB_PUTS ("true"); + else + my_friendly_abort (366); + } + else if (type == char_type_node) + { + OB_PUTC ('\''); + dump_char (TREE_INT_CST_LOW (t)); + OB_PUTC ('\''); + } + else if (TREE_INT_CST_HIGH (t) + != (TREE_INT_CST_LOW (t) >> (HOST_BITS_PER_WIDE_INT - 1))) + { + tree val = t; + if (TREE_INT_CST_HIGH (val) < 0) + { + OB_PUTC ('-'); + val = build_int_2 (~TREE_INT_CST_LOW (val), + -TREE_INT_CST_HIGH (val)); + } + /* Would "%x%0*x" or "%x%*0x" get zero-padding on all + systems? */ + { + static char format[10]; /* "%x%09999x\0" */ + if (!format[0]) + sprintf (format, "%%x%%0%dx", HOST_BITS_PER_INT / 4); + sprintf (digit_buffer, format, TREE_INT_CST_HIGH (val), + TREE_INT_CST_LOW (val)); + OB_PUTCP (digit_buffer); + } + } + else + OB_PUTI (TREE_INT_CST_LOW (t)); + } + break; + + case REAL_CST: +#ifndef REAL_IS_NOT_DOUBLE + sprintf (digit_buffer, "%g", TREE_REAL_CST (t)); +#else + { + unsigned char *p = (unsigned char *) &TREE_REAL_CST (t); + int i; + strcpy (digit_buffer, "0x"); + for (i = 0; i < sizeof TREE_REAL_CST (t); i++) + sprintf (digit_buffer + 2 + 2*i, "%02x", *p++); + } +#endif + OB_PUTCP (digit_buffer); + break; + + case STRING_CST: + { + char *p = TREE_STRING_POINTER (t); + int len = TREE_STRING_LENGTH (t) - 1; + int i; + + OB_PUTC ('\"'); + for (i = 0; i < len; i++) + dump_char (p[i]); + OB_PUTC ('\"'); + } + break; + + case COMPOUND_EXPR: + dump_binary_op (",", t); + break; + + case COND_EXPR: + OB_PUTC ('('); + dump_expr (TREE_OPERAND (t, 0), 0); + OB_PUTS (" ? "); + dump_expr (TREE_OPERAND (t, 1), 0); + OB_PUTS (" : "); + dump_expr (TREE_OPERAND (t, 2), 0); + OB_PUTC (')'); + break; + + case SAVE_EXPR: + if (TREE_HAS_CONSTRUCTOR (t)) + { + OB_PUTS ("new "); + dump_type (TREE_TYPE (TREE_TYPE (t)), 0); + PARM_DECL_EXPR (t) = 1; + } + else + { + dump_expr (TREE_OPERAND (t, 0), 0); + } + break; + + case NEW_EXPR: + OB_PUTID (TYPE_IDENTIFIER (TREE_TYPE (t))); + OB_PUTC ('('); + dump_expr_list (TREE_CHAIN (TREE_OPERAND (t, 1))); + OB_PUTC (')'); + break; + + case CALL_EXPR: + { + tree fn = TREE_OPERAND (t, 0); + tree args = TREE_OPERAND (t, 1); + + if (TREE_CODE (fn) == ADDR_EXPR) + fn = TREE_OPERAND (fn, 0); + + if (NEXT_CODE (fn) == METHOD_TYPE) + { + tree ob = TREE_VALUE (args); + if (TREE_CODE (ob) == ADDR_EXPR) + { + dump_expr (TREE_OPERAND (ob, 0), 0); + OB_PUTC ('.'); + } + else if (TREE_CODE (ob) != PARM_DECL + || strcmp (IDENTIFIER_POINTER (DECL_NAME (ob)), "this")) + { + dump_expr (ob, 0); + OB_PUTC2 ('-', '>'); + } + args = TREE_CHAIN (args); + } + dump_expr (fn, 0); + OB_PUTC('('); + dump_expr_list (args); + OB_PUTC (')'); + } + break; + + case WITH_CLEANUP_EXPR: + /* Note that this only works for G++ cleanups. If somebody + builds a general cleanup, there's no way to represent it. */ + dump_expr (TREE_OPERAND (t, 0), 0); + break; + + case TARGET_EXPR: + /* Note that this only works for G++ target exprs. If somebody + builds a general TARGET_EXPR, there's no way to represent that + it initializes anything other that the parameter slot for the + default argument. Note we may have cleared out the first + operand in expand_expr, so don't go killing ourselves. */ + if (TREE_OPERAND (t, 1)) + dump_expr (TREE_OPERAND (t, 1), 0); + break; + + 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); + break; + + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + dump_binary_op ("/", t); + break; + + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + dump_binary_op ("%", t); + break; + + case COMPONENT_REF: + { + tree ob = TREE_OPERAND (t, 0); + if (TREE_CODE (ob) == INDIRECT_REF) + { + ob = TREE_OPERAND (ob, 0); + if (TREE_CODE (ob) != PARM_DECL + || strcmp (IDENTIFIER_POINTER (DECL_NAME (ob)), "this")) + { + dump_expr (ob, 0); + OB_PUTC2 ('-', '>'); + } + } + else + { + dump_expr (ob, 0); + OB_PUTC ('.'); + } + dump_expr (TREE_OPERAND (t, 1), 1); + } + break; + + case ARRAY_REF: + dump_expr (TREE_OPERAND (t, 0), 0); + OB_PUTC ('['); + dump_expr (TREE_OPERAND (t, 1), 0); + OB_PUTC (']'); + break; + + case CONVERT_EXPR: + dump_unary_op ("+", t, nop); + break; + + case ADDR_EXPR: + if (TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL + || TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST) + dump_expr (TREE_OPERAND (t, 0), 0); + else + dump_unary_op ("&", t, nop); + break; + + case INDIRECT_REF: + if (TREE_HAS_CONSTRUCTOR (t)) + { + t = TREE_OPERAND (t, 0); + my_friendly_assert (TREE_CODE (t) == CALL_EXPR, 237); + dump_expr (TREE_OPERAND (t, 0), 0); + OB_PUTC ('('); + dump_expr_list (TREE_CHAIN (TREE_OPERAND (t, 1))); + OB_PUTC (')'); + } + else + { + if (NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE) + dump_expr (TREE_OPERAND (t, 0), nop); + else + dump_unary_op ("*", t, nop); + } + break; + + 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, nop); + break; + + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + OB_PUTC ('('); + dump_expr (TREE_OPERAND (t, 0), 0); + OB_PUTCP (opname_tab[(int)TREE_CODE (t)]); + OB_PUTC (')'); + break; + + case NON_LVALUE_EXPR: + /* FIXME: This is a KLUDGE workaround for a parsing problem. There + should be another level of INDIRECT_REF so that I don't have to do + this. */ + if (NEXT_CODE (t) == POINTER_TYPE) + { + tree next = TREE_TYPE (TREE_TYPE (t)); + + while (TREE_CODE (next) == POINTER_TYPE) + next = TREE_TYPE (next); + + if (TREE_CODE (next) == FUNCTION_TYPE) + { + if (!nop) OB_PUTC ('('); + OB_PUTC ('*'); + dump_expr (TREE_OPERAND (t, 0), 1); + if (!nop) OB_PUTC (')'); + break; + } + /* else FALLTHRU */ + } + dump_expr (TREE_OPERAND (t, 0), 0); + break; + + case NOP_EXPR: + dump_expr (TREE_OPERAND (t, 0), nop); + break; + + case CONSTRUCTOR: + OB_PUTC ('{'); + dump_expr_list (CONSTRUCTOR_ELTS (t), 0); + OB_PUTC ('}'); + break; + + case OFFSET_REF: + { + tree ob = TREE_OPERAND (t, 0); + if (TREE_CODE (ob) == NOP_EXPR + && TREE_OPERAND (ob, 0) == error_mark_node + && TREE_CODE (TREE_OPERAND (t, 1)) == FUNCTION_DECL) + /* A::f */ + dump_expr (TREE_OPERAND (t, 1), 0); + else + { + sorry ("operand of OFFSET_REF not understood"); + goto error; + } + break; + } + + case TREE_LIST: + if (TREE_VALUE (t) && TREE_CODE (TREE_VALUE (t)) == FUNCTION_DECL) + { + OB_PUTID (DECL_NAME (TREE_VALUE (t))); + break; + } + /* else fall through */ + + /* 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 ("`%s' not supported by dump_expr", + tree_code_name[(int) TREE_CODE (t)]); + + /* fall through to ERROR_MARK... */ + case ERROR_MARK: + error: + OB_PUTCP ("{error}"); + break; + } +} + +static void +dump_binary_op (opstring, t) + char *opstring; + tree t; +{ + OB_PUTC ('('); + dump_expr (TREE_OPERAND (t, 0), 1); + OB_PUTC (' '); + OB_PUTCP (opstring); + OB_PUTC (' '); + dump_expr (TREE_OPERAND (t, 1), 1); + OB_PUTC (')'); +} + +static void +dump_unary_op (opstring, t, nop) + char *opstring; + tree t; + int nop; +{ + if (!nop) OB_PUTC ('('); + OB_PUTCP (opstring); + dump_expr (TREE_OPERAND (t, 0), 1); + if (!nop) OB_PUTC (')'); +} + +char * +fndecl_as_string (cname, fndecl, print_ret_type_p) + tree cname, fndecl; + int print_ret_type_p; +{ + return decl_as_string (fndecl, print_ret_type_p); +} + +/* Same, but handtype a _TYPE. + Called from convert_to_reference, mangle_class_name_for_template, + build_unary_op, and GNU_xref_decl. */ +char * +type_as_string (typ, v) + tree typ; + int v; +{ + OB_INIT (); + + dump_type (typ, v); + + OB_FINISH (); + + return (char *)obstack_base (&scratch_obstack); +} + +char * +expr_as_string (decl, v) + tree decl; + int v; +{ + OB_INIT (); + + dump_expr (decl, 1); + + OB_FINISH (); + + return (char *)obstack_base (&scratch_obstack); +} + +/* A cross between type_as_string and fndecl_as_string. + Only called from substitute_nice_name. */ +char * +decl_as_string (decl, v) + tree decl; + int v; +{ + OB_INIT (); + + dump_decl (decl, v); + + OB_FINISH (); + + return (char *)obstack_base (&scratch_obstack); +} + +char * +cp_file_of (t) + tree t; +{ + if (TREE_CODE (t) == PARM_DECL) + return DECL_SOURCE_FILE (DECL_CONTEXT (t)); + else if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') + return DECL_SOURCE_FILE (TYPE_NAME (t)); + else + return DECL_SOURCE_FILE (t); +} + +int +cp_line_of (t) + tree t; +{ + int line = 0; + if (TREE_CODE (t) == PARM_DECL) + line = DECL_SOURCE_LINE (DECL_CONTEXT (t)); + if (TREE_CODE (t) == TYPE_DECL && DECL_ARTIFICIAL (t)) + t = TREE_TYPE (t); + + if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') + { + if (IS_AGGR_TYPE (t)) + line = CLASSTYPE_SOURCE_LINE (t); + else + line = DECL_SOURCE_LINE (TYPE_NAME (t)); + } + else + line = DECL_SOURCE_LINE (t); + + if (line == 0) + return lineno; + + return line; +} + +char * +code_as_string (c, v) + enum tree_code c; + int v; +{ + return tree_code_name [c]; +} + +char * +language_as_string (c, v) + enum languages c; + int v; +{ + switch (c) + { + case lang_c: + return "C"; + + case lang_cplusplus: + return "C++"; + + default: + my_friendly_abort (355); + return 0; + } +} + +/* Return the proper printed version of a parameter to a C++ function. */ +char * +parm_as_string (p, v) + int p, v; +{ + if (p < 0) + return "`this'"; + + sprintf (digit_buffer, "%d", p+1); + return digit_buffer; +} + +char * +op_as_string (p, v) + enum tree_code p; + int v; +{ + static char buf[] = "operator "; + + if (p == 0) + return "{unknown}"; + + strcpy (buf + 9, opname_tab [p]); + return buf; +} + +char * +args_as_string (p, v) + tree p; + int v; +{ + if (p == NULL_TREE) + return "..."; + + return type_as_string (p, v); +} + +char * +cv_as_string (p, v) + tree p; + int v; +{ + OB_INIT (); + + dump_readonly_or_volatile (p, before); + + OB_FINISH (); + + return (char *)obstack_base (&scratch_obstack); +} |