fe7dee4700
GCC-2.6.1 COMES TO FREEBSD-current ---------------------------------- Everybody needs to 'make world'. Oakland, Nov 2nd 1994. In a surprise move this sunny afternoon, the release- engineer for the slightly delayed FreeBSD-2.0, Poul-Henning Kamp (28), decided to pull in the new version 2.6.1 of the GNU C-compiler. The new version of the compiler was release today at noon, and hardly 9 hours later it was committed into the FreeBSD-current source-repository. "It's is simply because we have had too much trouble with the version 2.6.0 of the compiler" Poul-Henning told the FreeBSD-Gazette, "we took a gamble when we decided to use that as our compiler for the 2.0 release, but it seems to pay of in the end now" he concludes. The move has not been discussed on the "core" list at all, and will come as a surprise for most Poul-Hennings peers. "I have only discussed it with Jordan [J. K. Hubbard, the FreeBSD's resident humourist], and we agreed that we needed to do it, so ... I did it!". After a breath he added with a grin: "My email will probably get an all time 'disk-full' now!". This will bring quite a flag-day to the FreeBSD developers, the patch-file is almost 1.4 Megabyte, and they will have to run "make world" to get entirely -current again. "Too bad, but we just had to do this." Was the only comment from Poul-Henning to these problems. When asked how this move would impact the 2.0 release-date, Poul-Hennings face grew dark, he mumbled some very Danish words while he moved his fingers in strange geometrical patterns. Immediately something ecclipsed the Sun, a minor tremor shook the buildings, and the temperature fell significantly. We decided not to pursure the question. ----------- JOB-SECTION ----------- Are you a dedicated GCC-hacker ? We BADLY need somebody to look at the 'freebsd' OS in gcc, sanitize it and carry the patches back to the GNU people. In particular, we need to get out of the "i386-only" spot we are in now. I have the stuff to take a gnu-dist into bmake-form, and will do that part. Please apply to phk@freebsd.org No Novice Need Apply.
1440 lines
32 KiB
C
1440 lines
32 KiB
C
/* Call-backs for C++ error reporting.
|
|
This code is non-reentrant.
|
|
Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, 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 _ (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, _, _, _, _, _, _, _, _, _, _, _, /* 0x50 */
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x60 */
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x70 */
|
|
};
|
|
#undef C
|
|
#undef D
|
|
#undef E
|
|
#undef L
|
|
#undef O
|
|
#undef P
|
|
#undef T
|
|
#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 (DECL_CONTEXT (name))
|
|
{
|
|
/* FUNCTION_DECL or RECORD_TYPE */
|
|
dump_decl (DECL_CONTEXT (name), 0);
|
|
OB_PUTC2 (':', ':');
|
|
}
|
|
|
|
/* kludge around wierd behavior on g++.brendan/line1.C */
|
|
if (TREE_CODE (name) != IDENTIFIER_NODE)
|
|
name = DECL_NAME (name);
|
|
|
|
if (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 (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 (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 (' ');
|
|
}
|
|
/* 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 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:
|
|
if (DESTRUCTOR_NAME_P (t))
|
|
{
|
|
OB_PUTC ('~');
|
|
dump_decl (DECL_NAME (ident_fndecl (t)), 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))
|
|
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)))
|
|
{
|
|
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 == char_type_node
|
|
|| type == signed_char_type_node
|
|
|| type == unsigned_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
|
|
{
|
|
sorry ("operand of SAVE_EXPR not understood");
|
|
goto error;
|
|
}
|
|
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 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);
|
|
}
|