Category : UNIX Files
Archive   : GPLUS5.ZIP
Filename : G5

 
Output of file : G5 contained in archive : GPLUS5.ZIP

#!/bin/sh
# This is a shell archive.
# remove everything above the "#!/bin/sh" line
# and feed to /bin/sh
#
# Contents:
# init_main.c
# tree.c
# cplus-cvt.c
# cplus-typeck.c
# init_main.h
# tree.def
# cplus-decl.c
# packed: Wed Jan 01 23:08:49 EST 1992
# by: [email protected]
#
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo "Extracting init_main.c..."
sed 's/^X//' >init_main.c << '!EOF'
X/* Startup code needed by GCC C++ output code. */
X/* Copyright (C) 1991 Free Software Foundation, Inc.
X
XThis file is part of GNU CC.
X
XGNU CC is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 2, or (at your option)
Xany later version.
X
XGNU CC is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU CC; see the file COPYING. If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X/* As a special exception, if you link this file with files
X compiled with GCC to produce an executable, this does not cause
X the resulting executable to be covered by the GNU General Public License.
X This exception does not however invalidate any other reasons why
X the executable file might be covered by the GNU General Public License. */
X
X/* init_main.c: Originally developed by James Kempf for SUN,
X * adapted and commented for FSF by Heinz Seidl ([email protected])
X */
X
X#include
X#include "init_main.h"
X#include "config.h"
X
X/* define NO_ATEXIT in config.h if there isn't one */
X
X#ifndef NO_ATEXIT
X #define ATEXIT(FCTNP) 0
X#else
X #ifdef sun
X extern int on_exit( void (*)(), int);
X #define ATEXIT(FCTNP) on_exit( FCTNP, 0)
X #else

X extern int atexit( void (*)()); /* defined in stdlib.h */
X #define ATEXIT(FCTNP) atexit( FCTNP)
X #endif
X#endif /* NO_ATEXIT
X
X/*
X * The main module and all shared modules have each their own __C/DTOR_LIST__.
X * When a module is to be final/initialized, `__function_list_addr' gets the
X * address of the __C/DTOR_LIST__ of that module.
X * (For the main module we can simple take the globals __C/DTOR_LIST__, for
X * shared objects, we have to use functionality of the runtime linker ld.so
X * to get the addresses. All this has to be done in the main program, since
X * a lot of functionality of ld.so does not work as documented).
X */
X
Xep_fp * __function_list_addr = 0;
X
Xextern ep_fp __CTOR_LIST__[];
Xextern ep_fp __DTOR_LIST__[];
X
Xint __main();
Xvoid INITIALIZE_MODULE();
Xvoid FINALIZE_MODULE();
Xvoid __initialize_libraries();
Xvoid __finalize_libraries();
Xvoid exit(/*int*/);
Xvoid _exit(/*int*/);
Xvoid _cleanup();
X
Xentry_pt INIT_START;
Xentry_pt INIT_END;
X
X
X/*************************************************************************
X * Main initialization and finalization
X ************************************************************************/
X
X/*
X * Initialize first (dynamically linked) libraries, then the main module.
X * Finalize first the main module then (dynamically linked) libraries.
X */
X
X
X
Xvoid __initialize_main()
X{
X __function_list_addr = __CTOR_LIST__;
X INITIALIZE_MODULE();
X}
X
Xvoid __finalize_main()
X{
X __function_list_addr = __DTOR_LIST__;
X FINALIZE_MODULE();
X}
X
X
Xint __main()
X{
X int ret = 0;
X
X INIT_START(); /* user supplied function */
X
X __initialize_libraries(); /* first the libraries */
X __initialize_main(); /* second main module */
X
X INIT_END(); /* user supplied function */
X
X ret = ATEXIT( __finalize_main); assert( ret == 0);
X ret = ATEXIT( __finalize_libraries); assert( ret == 0);
X return(ret);
X}
X
X
X#ifndef HAVE_ATEXIT
Xvoid exit( int status)
X{
X __finalize_main(); /* first main module */
X __finalize_libraries(); /* second the libraries */
X#ifdef GPROF
X _mcleanup();
X#endif
X _cleanup();
X _exit(status);
X}
X#endif
!EOF
echo "Extracting tree.c..."
sed 's/^X//' >tree.c << '!EOF'
X/* Language-independent node constructors for parse phase of GNU compiler.
X Copyright (C) 1987, 1988 Free Software Foundation, Inc.
X
XThis file is part of GNU CC.
X
XGNU CC is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU CC is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU CC; see the file COPYING. If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X
X/* This file contains the low level primitives for operating on tree nodes,
X including allocation, list operations, interning of identifiers,
X construction of data type nodes and statement nodes,
X and construction of type conversion nodes. It also contains
X tables index by tree code that describe how to take apart
X nodes of that code.
X
X It is intended to be language-independent, but occasionally
X calls language-dependent routines defined (for C) in typecheck.c.
X
X The low-level allocation routines oballoc and permalloc
X are used also for allocating many other kinds of objects
X by all passes of the compiler. */
X
X#include "config.h"
X#include
X#include "tree.h"
X#include "obstack.h"
X#include "gvarargs.h"
X#include "flags.h"
X
X#define obstack_chunk_alloc xmalloc
X#define obstack_chunk_free free
X
Xextern int xmalloc ();
Xextern void free ();
X
X/* Tree nodes of permanent duration are allocated in this obstack.
X They are the identifier nodes, and everything outside of
X the bodies and parameters of function definitions. */
X
Xstruct obstack permanent_obstack;
X
X/* The initial RTL, and all ..._TYPE nodes, in a function
X are allocated in this obstack. Usually they are freed at the
X end of the function, but if the function is inline they are saved. */
X
Xstruct obstack maybepermanent_obstack;
X
X/* The contents of the current function definition are allocated
X in this obstack, and all are freed at the end of the function. */
X
Xstruct obstack temporary_obstack;
X
X/* The tree nodes of an expression are allocated
X in this obstack, and all are freed at the end of the expression. */
X
Xstruct obstack momentary_obstack;
X
X/* The tree nodes of a declarator are allocated
X in this obstack, and all are freed when the declarator
X has been parsed. */
X
Xstatic struct obstack temp_decl_obstack;
X
X/* This points at either permanent_obstack or maybepermanent_obstack. */
X
Xstruct obstack *saveable_obstack;
X
X/* This is same as saveable_obstack during parse and expansion phase;
X it points to temporary_obstack during optimization.
X This is the obstack to be used for creating rtl objects. */
X
Xstruct obstack *rtl_obstack;
X
X/* This points at either permanent_obstack or temporary_obstack. */
X
Xstruct obstack *current_obstack;
X
X/* This points at either permanent_obstack or temporary_obstack
X or momentary_obstack. */
X
Xstruct obstack *expression_obstack;
X
X/* Addresses of first objects in some obstacks.
X This is for freeing their entire contents. */
Xchar *maybepermanent_firstobj;
Xchar *temporary_firstobj;
Xchar *momentary_firstobj;
Xchar *temp_decl_firstobj;
X
X/* Nonzero means all ..._TYPE nodes should be allocated permanently. */
X
Xint all_types_permanent;
X
X/* Stack of places to restore the momentary obstack back to. */
X
Xstruct momentary_level
X{
X /* Pointer back to previous such level. */
X struct momentary_level *prev;
X /* First object allocated within this level. */
X char *base;
X /* Value of expression_obstack saved at entry to this level. */
X struct obstack *obstack;
X};
X
Xstruct momentary_level *momentary_stack;
X
X/* Table indexed by tree code giving a string containing a character
X classifying the tree code. Possibilities are
X t, d, s, c, r and e. See tree.def for details. */
X
X#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
X
Xchar *standard_tree_code_type[] = {
X#include "tree.def"
X};
X#undef DEFTREECODE
X
X/* Table indexed by tree code giving number of expression
X operands beyond the fixed part of the node structure.
X Not used for types or decls. */
X
X#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
X
Xint standard_tree_code_length[] = {
X#include "tree.def"
X};
X#undef DEFTREECODE
X
X/* Names of tree components.
X Used for printing out the tree and error messages. */
X#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
X
Xchar *standard_tree_code_name[] = {
X#include "tree.def"
X};
X#undef DEFTREECODE
X
X/* Table indexed by tree code giving a string containing a character
X classifying the tree code. Possibilities are
X t, d, s, c, r and e. See tree.def for details. */
X
Xchar **tree_code_type;
X
X/* Table indexed by tree code giving number of expression
X operands beyond the fixed part of the node structure.
X Not used for types or decls. */
X
Xint *tree_code_length;
X
X/* Table indexed by tree code giving name of tree code, as a string. */
X
Xchar **tree_code_name;
X
X/* Counter for assigning unique ids to all tree nodes. */
X
Xint tree_node_counter = 0;
X
X/* Statistics-gathering stuff. */
Xtypedef enum
X{
X d_kind, t_kind, s_kind, r_kind, e_kind, c_kind,
X id_kind, op_id_kind, perm_list_kind, temp_list_kind,
X x_kind, lang_decl, lang_type, all_kinds
X} tree_node_kind;
Xint tree_node_kinds[(int)all_kinds];
Xint tree_node_sizes[(int)all_kinds];
Xint id_string_size = 0;
Xchar *tree_node_kind_names[] = { "decls", "types", "stmts", "refs", "exprs", "constants",
X "identifiers", "op_identifiers", "perm_tree_lists", "temp_tree_lists",
X "random kinds", "lang_decl kinds", "lang_type kinds" };
X
X/* Hash table for uniquizing IDENTIFIER_NODEs by name. */
X
X#define MAX_HASH_TABLE 1009
Xstatic tree hash_table[MAX_HASH_TABLE]; /* id hash buckets */
X
X/* 0 while creating built-in identifiers. */
Xstatic int do_identifier_warnings;
X
X/* Init data for node creation, at the beginning of compilation. */
X
Xvoid
Xinit_tree ()
X{
X obstack_init (&permanent_obstack);
X
X obstack_init (&temporary_obstack);
X temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
X obstack_init (&momentary_obstack);
X momentary_firstobj = (char *) obstack_alloc (&momentary_obstack, 0);
X obstack_init (&maybepermanent_obstack);
X maybepermanent_firstobj
X = (char *) obstack_alloc (&maybepermanent_obstack, 0);
X obstack_init (&temp_decl_obstack);
X temp_decl_firstobj = (char *) obstack_alloc (&temp_decl_obstack, 0);
X
X current_obstack = &permanent_obstack;
X expression_obstack = &permanent_obstack;
X rtl_obstack = saveable_obstack = &permanent_obstack;
X tree_node_counter = 1;
X /* bzero (hash_table, sizeof hash_table); */
X
X tree_code_type = (char **) xmalloc (sizeof (standard_tree_code_type));
X tree_code_length = (int *) xmalloc (sizeof (standard_tree_code_length));
X tree_code_name = (char **) xmalloc (sizeof (standard_tree_code_name));
X bcopy (standard_tree_code_type, tree_code_type,
X sizeof (standard_tree_code_type));
X bcopy (standard_tree_code_length, tree_code_length,
X sizeof (standard_tree_code_length));
X bcopy (standard_tree_code_name, tree_code_name,
X sizeof (standard_tree_code_name));
X}
X#if 0
X/* Save all variables describing the current status into the structure *P.
X This is used before starting a nested function. */
X
Xvoid
Xsave_tree_status (p)
X struct function *p;
X{
X p->all_types_permanent = all_types_permanent;
X p->momentary_stack = momentary_stack;
X p->maybepermanent_firstobj = maybepermanent_firstobj;
X p->temporary_firstobj = temporary_firstobj;
X p->momentary_firstobj = momentary_firstobj;
X p->current_obstack = current_obstack;
X p->expression_obstack = expression_obstack;
X p->saveable_obstack = saveable_obstack;
X p->rtl_obstack = rtl_obstack;
X
X current_obstack = &permanent_obstack;
X expression_obstack = &permanent_obstack;
X rtl_obstack = saveable_obstack = &permanent_obstack;
X
X maybepermanent_firstobj = (char *) obstack_finish (&maybepermanent_obstack);
X temporary_firstobj = (char *) obstack_finish (&temporary_obstack);
X momentary_firstobj = (char *) obstack_finish (&momentary_obstack);
X}
X
X/* Restore all variables describing the current status from the structure *P.
X This is used after a nested function. */
X
Xvoid
Xrestore_tree_status (p)
X struct function *p;
X{
X all_types_permanent = p->all_types_permanent;
X momentary_stack = p->momentary_stack;
X
X obstack_free (&maybepermanent_obstack, maybepermanent_firstobj);
X obstack_free (&temporary_obstack, temporary_firstobj);
X obstack_free (&momentary_obstack, momentary_firstobj);
X
X maybepermanent_firstobj = p->maybepermanent_firstobj;
X temporary_firstobj = p->temporary_firstobj;
X momentary_firstobj = p->momentary_firstobj;
X current_obstack = p->current_obstack;
X expression_obstack = p->expression_obstack;
X saveable_obstack = p->saveable_obstack;
X rtl_obstack = p->rtl_obstack;
X}
X#endif
X
X/* Start allocating on the temporary (per function) obstack.
X This is done in start_function before parsing the function body,
X and before each initialization at top level, and to go back
X to temporary allocation after doing end_temporary_allocation. */
X
Xvoid
Xtemporary_allocation ()
X{
X current_obstack = &temporary_obstack;
X expression_obstack = &temporary_obstack;
X rtl_obstack = saveable_obstack = &maybepermanent_obstack;
X momentary_stack = 0;
X}
X
X/* Start allocating on the permanent obstack but don't
X free the temporary data. After calling this, call
X `permanent_allocation' to fully resume permanent allocation status. */
X
Xvoid
Xend_temporary_allocation ()
X{
X current_obstack = &permanent_obstack;
X expression_obstack = &permanent_obstack;
X rtl_obstack = saveable_obstack = &permanent_obstack;
X}
X
X/* Resume allocating on the temporary obstack, undoing
X effects of `end_temporary_allocation'. */
X
Xvoid
Xresume_temporary_allocation ()
X{
X current_obstack = &temporary_obstack;
X expression_obstack = &temporary_obstack;
X rtl_obstack = saveable_obstack = &maybepermanent_obstack;
X}
X
X/* Nonzero if temporary allocation is currently in effect.
X Zero if currently doing permanent allocation. */
X
Xint
Xallocation_temporary_p ()
X{
X return current_obstack == &temporary_obstack;
X}
X
X/* Go back to allocating on the permanent obstack
X and free everything in the temporary obstack.
X This is done in finish_function after fully compiling a function. */
X
Xvoid
Xpermanent_allocation ()
X{
X /* Free up previous temporary obstack data */
X obstack_free (&temporary_obstack, temporary_firstobj);
X obstack_free (&momentary_obstack, momentary_firstobj);
X obstack_free (&maybepermanent_obstack, maybepermanent_firstobj);
X obstack_free (&temp_decl_obstack, temp_decl_firstobj);
X
X current_obstack = &permanent_obstack;
X expression_obstack = &permanent_obstack;
X rtl_obstack = saveable_obstack = &permanent_obstack;
X}
X
X/* Save permanently everything on the maybepermanent_obstack. */
X
Xvoid
Xpreserve_data ()
X{
X maybepermanent_firstobj
X = (char *) obstack_alloc (&maybepermanent_obstack, 0);
X}
X
Xvoid
Xpreserve_initializer ()
X{
X temporary_firstobj
X = (char *) obstack_alloc (&temporary_obstack, 0);
X momentary_firstobj
X = (char *) obstack_alloc (&momentary_obstack, 0);
X maybepermanent_firstobj
X = (char *) obstack_alloc (&maybepermanent_obstack, 0);
X}
X
X/* Allocate SIZE bytes in the current obstack
X and return a pointer to them.
X In practice the current obstack is always the temporary one. */
X
Xchar *
Xoballoc (size)
X int size;
X{
X return (char *) obstack_alloc (current_obstack, size);
X}
X
X/* Free the object PTR in the current obstack
X as well as everything allocated since PTR.
X In practice the current obstack is always the temporary one. */
X
Xvoid
Xobfree (ptr)
X char *ptr;
X{
X obstack_free (current_obstack, ptr);
X}
X
X/* Allocate SIZE bytes in the permanent obstack
X and return a pointer to them. */
X
Xchar *
Xpermalloc (size)
X long size;
X{
X return (char *) obstack_alloc (&permanent_obstack, size);
X}
X
X/* Allocate SIZE bytes in the saveable obstack
X and return a pointer to them. */
X

Xchar *
Xsavealloc (size)
X int size;
X{
X return (char *) obstack_alloc (saveable_obstack, size);
X}
X
X/* Start a level of momentary allocation.
X In C, each compound statement has its own level
X and that level is freed at the end of each statement.
X All expression nodes are allocated in the momentary allocation level. */
X
Xvoid
Xpush_momentary ()
X{
X struct momentary_level *tem
X = (struct momentary_level *) obstack_alloc (&momentary_obstack,
X sizeof (struct momentary_level));
X tem->prev = momentary_stack;
X tem->base = (char *) obstack_base (&momentary_obstack);
X tem->obstack = expression_obstack;
X momentary_stack = tem;
X expression_obstack = &momentary_obstack;
X}
X
X/* Free all the storage in the current momentary-allocation level.
X In C, this happens at the end of each statement. */
X
Xvoid
Xclear_momentary ()
X{
X obstack_free (&momentary_obstack, momentary_stack->base);
X}
X
X/* Discard a level of momentary allocation.
X In C, this happens at the end of each compound statement.
X Restore the status of expression node allocation
X that was in effect before this level was created. */
X
Xvoid
Xpop_momentary ()
X{
X struct momentary_level *tem = momentary_stack;
X momentary_stack = tem->prev;
X obstack_free (&momentary_obstack, tem);
X expression_obstack = tem->obstack;
X}
X
X/* Call when starting to parse a declaration:
X make expressions in the declaration last the length of the function.
X Returns an argument that should be passed to resume_momentary later. */
X
Xint
Xsuspend_momentary ()
X{
X register int tem = expression_obstack == &momentary_obstack;
X expression_obstack = saveable_obstack;
X return tem;
X}
X
X/* Call when finished parsing a declaration:
X restore the treatment of node-allocation that was
X in effect before the suspension.
X YES should be the value previously returned by suspend_momentary. */
X
Xvoid
Xresume_momentary (yes)
X int yes;
X{
X if (yes)
X expression_obstack = &momentary_obstack;
X}
X
X/* Return a newly allocated node of code CODE.
X Initialize the node's unique id and its TREE_PERMANENT flag.
X For decl and type nodes, some other fields are initialized.
X The rest of the node is initialized to zero.
X
X Achoo! I got a code in the node. */
X
Xtree
Xmake_node (code)
X enum tree_code code;
X{
X register tree t;
X register int type = *tree_code_type[(int) code];
X register int length;
X register struct obstack *obstack = current_obstack;
X register int i;
X register tree_node_kind kind;
X
X switch (type)
X {
X case 'd': /* A decl node */
X length = sizeof (struct tree_decl)
X + tree_code_length[(int) code] * sizeof (char *);
X kind = d_kind;
X /* All decls in an inline function need to be saved. */
X if (obstack != &permanent_obstack)
X obstack = saveable_obstack;
X /* PARM_DECLs always go on the saveable_obstack, not permanent
X even though we may make them before the function turns
X on temporary allocation. */
X else if (code == PARM_DECL)
X obstack = &maybepermanent_obstack;
X break;
X
X case 't': /* a type node */
X length = sizeof (struct tree_type);
X kind = t_kind;
X /* All data types are put where we can preserve them if nec. */
X if (obstack != &permanent_obstack)
X obstack = all_types_permanent ? &permanent_obstack : saveable_obstack;
X break;
X
X case 's': /* a stmt node */
X length = sizeof (struct tree_common)
X + 2 * sizeof (int)
X + tree_code_length[(int) code] * sizeof (char *);
X kind = s_kind;
X /* All stmts are put where we can preserve them if nec. */
X if (obstack != &permanent_obstack)
X obstack = saveable_obstack;
X break;
X
X case 'r': /* a reference */
X obstack = expression_obstack;
X length = sizeof (struct tree_exp)
X + (tree_code_length[(int) code] - 1) * sizeof (char *);
X kind = r_kind;
X break;
X
X case 'e': /* an expression */
X obstack = expression_obstack;
X length = sizeof (struct tree_exp)
X + (tree_code_length[(int) code] - 1) * sizeof (char *);
X kind = e_kind;
X break;
X
X case 'c': /* a constant */
X obstack = expression_obstack;
X /* We can't use tree_code_length for this, since the number of words
X is machine-dependent due to varying alignment of `double'. */
X if (code == REAL_CST)
X {
X length = sizeof (struct tree_real_cst);
X kind = c_kind;
X break;
X }
X length = sizeof (struct tree_common)
X + tree_code_length[(int) code] * sizeof (char *);
X kind = c_kind;
X break;
X
X case 'x': /* something random, like an identifier. */
X length = sizeof (struct tree_common)
X + tree_code_length[(int) code] * sizeof (char *);
X /* Identifier nodes are always permanent since they are
X unique in a compiler run. */
X if (code == IDENTIFIER_NODE)
X {
X kind = id_kind;
X obstack = &permanent_obstack;
X }
X else if (code == OP_IDENTIFIER)
X kind = op_id_kind;
X else
X kind = x_kind;
X }
X
X t = (tree) obstack_alloc (obstack, length);
X
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)kind]++;
X tree_node_sizes[(int)kind] += length;
X#endif
X
X TREE_UID (t) = tree_node_counter++;
X TREE_TYPE (t) = 0;
X TREE_CHAIN (t) = 0;
X for (i = (length / sizeof (int)) - 1;
X i >= sizeof (struct tree_common) / sizeof (int) - 1;
X i--)
X ((int *) t)[i] = 0;
X
X TREE_SET_CODE (t, code);
X if (obstack == &permanent_obstack)
X TREE_PERMANENT (t) = 1;
X
X if (type == 'd')
X {
X extern int lineno;
X
X DECL_ALIGN (t) = 1;
X DECL_SIZE_UNIT (t) = 1;
X DECL_VOFFSET_UNIT (t) = 1;
X if (code == PARM_DECL)
X DECL_CONTEXT (t) = current_function_decl;
X else
X {
X DECL_SOURCE_LINE (t) = lineno;
X DECL_SOURCE_FILE (t)
X = (input_filename) ? input_filename : "";
X }
X }
X
X if (type == 't')
X {
X TYPE_ALIGN (t) = 1;
X TYPE_SIZE_UNIT (t) = 1;
X TYPE_MAIN_VARIANT (t) = t;
X }
X
X if (type == 'c')
X {
X TREE_LITERAL (t) = 1;
X }
X
X return t;
X}
X
X/* Return a new node with the same contents as NODE
X except that its TREE_CHAIN is zero and it has a fresh uid. */
X
Xtree
Xcopy_node (node)
X tree node;
X{
X register tree t;
X register enum tree_code code = TREE_CODE (node);
X register int length;
X register int i;
X
X switch (*tree_code_type[(int) code])
X {
X case 'd': /* A decl node */
X length = sizeof (struct tree_decl)
X + tree_code_length[(int) code] * sizeof (char *);
X break;
X
X case 't': /* a type node */
X length = sizeof (struct tree_type);
X break;
X
X case 's':
X length = sizeof (struct tree_common)
X + 2 * sizeof (int)
X + tree_code_length[(int) code] * sizeof (char *);
X break;
X
X case 'r': /* a reference */
X case 'e': /* a expression */
X length = sizeof (struct tree_exp)
X + (tree_code_length[(int) code] - 1) * sizeof (char *);
X break;
X
X case 'c': /* a constant */
X /* We can't use tree_code_length for this, since the number of words
X is machine-dependent due to varying alignment of `double'. */
X if (code == REAL_CST)
X {
X length = sizeof (struct tree_real_cst);
X break;
X }
X
X case 'x': /* something random, like an identifier. */
X length = sizeof (struct tree_common)
X + tree_code_length[(int) code] * sizeof (char *);
X if (code == TREE_VEC)
X length += (TREE_VEC_LENGTH (node) - 1) * sizeof (char *);
X }
X
X t = (tree) obstack_alloc (current_obstack, length);
X
X for (i = ((length + sizeof (int) - 1) / sizeof (int)) - 1;
X i >= 0;
X i--)
X ((int *) t)[i] = ((int *) node)[i];
X
X TREE_UID (t) = tree_node_counter++;
X TREE_CHAIN (t) = 0;
X
X TREE_PERMANENT (t) = (current_obstack == &permanent_obstack);
X
X return t;
X}
X

X/* Return a copy of a chain of nodes, chained through the TREE_CHAIN field.
X For example, this can copy a list made of TREE_LIST nodes. */
X
Xtree
Xcopy_list (list)
X tree list;
X{
X tree head;
X register tree prev, next;
X
X if (list == 0)
X return 0;
X
X head = prev = copy_node (list);
X next = TREE_CHAIN (list);
X while (next)
X {
X TREE_CHAIN (prev) = copy_node (next);
X prev = TREE_CHAIN (prev);
X next = TREE_CHAIN (next);
X }
X return head;
X}
X
X#define HASHBITS 30
X
X/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
X If an identifier with that name has previously been referred to,
X the same node is returned this time. */
X
Xtree
Xget_identifier (text)
X register char *text;
X{
X register int hi;
X register int i;
X register tree idp;
X register int len, hash_len;
X
X /* Compute length of text in len. */
X for (len = 0; text[len]; len++);
X
X /* Decide how much of that length to hash on */
X hash_len = len;
X if (warn_id_clash && len > id_clash_len)
X hash_len = id_clash_len;
X
X /* Compute hash code */
X hi = 17 * (unsigned)(text[0]) + len;
X for (i = 1; i < hash_len; i += 2)
X hi = ((hi * 613) + (unsigned)(text[i]));
X
X hi &= (1 << HASHBITS) - 1;
X hi %= MAX_HASH_TABLE;
X
X /* Search table for identifier */
X for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
X if (IDENTIFIER_LENGTH (idp) == len
X && IDENTIFIER_POINTER (idp)[0] == text[0]
X && !bcmp (IDENTIFIER_POINTER (idp), text, len))
X return idp; /* <-- return if found */
X
X /* Not found; optionally warn about a similar identifier */
X if (warn_id_clash && do_identifier_warnings && len > id_clash_len)
X for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
X if (!strncmp (IDENTIFIER_POINTER (idp), text, id_clash_len))
X {
X warning ("`%s' and `%s' identical in first n characters",
X IDENTIFIER_POINTER (idp), text);
X break;
X }
X
X if (tree_code_length[(int) IDENTIFIER_NODE] < 0)
X abort (); /* set_identifier_size hasn't been called. */
X
X /* Not found, create one, add to chain */
X idp = make_node (IDENTIFIER_NODE);
X IDENTIFIER_LENGTH (idp) = len;
X id_string_size += len;
X
X IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
X
X TREE_CHAIN (idp) = hash_table[hi];
X hash_table[hi] = idp;
X return idp; /* <-- return if created */
X}
X
X/* Enable warnings on similar identifiers (if requested).
X Done after the built-in identifiers are created. */
X
Xvoid
Xstart_identifier_warnings ()
X{
X do_identifier_warnings = 1;
X}
X
X/* Record the size of an identifier node for the language in use.
X SIZE is the total size in bytes.
X This is called by the language-specific files. This must be
X called before allocating any identifiers. */
X
Xvoid
Xset_identifier_size (size)
X int size;
X{
X tree_code_length[(int) IDENTIFIER_NODE]
X = (size - sizeof (struct tree_common)) / sizeof (tree);
X}
X
X/* Return a newly constructed INTEGER_CST node whose constant value
X is specified by the two ints LOW and HI.
X The TREE_TYPE is set to `int'. */
X
Xtree
Xbuild_int_2 (low, hi)
X int low, hi;
X{
X register tree t = make_node (INTEGER_CST);
X TREE_INT_CST_LOW (t) = low;
X TREE_INT_CST_HIGH (t) = hi;
X TREE_TYPE (t) = integer_type_node;
X return t;
X}
X
X/* Return a new REAL_CST node whose type is TYPE and value is D. */
X
Xtree
Xbuild_real (type, d)
X tree type;
X REAL_VALUE_TYPE d;
X{
X tree v;
X
X /* Check for valid float value for this type on this target machine;
X if not, can print error message and store a valid value in D. */
X#ifdef CHECK_FLOAT_VALUE
X CHECK_FLOAT_VALUE (TYPE_MODE (type), d);
X#endif
X
X v = make_node (REAL_CST);
X TREE_TYPE (v) = type;
X TREE_REAL_CST (v) = d;
X return v;
X}
X
X/* Return a new REAL_CST node whose type is TYPE
X and whose value is the integer value of the INTEGER_CST node I. */
X
X#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
X
XREAL_VALUE_TYPE
Xreal_value_from_int_cst (i)
X tree i;
X{
X REAL_VALUE_TYPE d;
X#ifdef REAL_ARITHMETIC
X REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i));
X#else /* not REAL_ARITHMETIC */
X if (TREE_INT_CST_HIGH (i) < 0)
X {
X d = (double) (~ TREE_INT_CST_HIGH (i));
X d *= ((double) (1 << (HOST_BITS_PER_INT / 2))
X * (double) (1 << (HOST_BITS_PER_INT / 2)));
X d += (double) (unsigned) (~ TREE_INT_CST_LOW (i));
X d = (- d - 1.0);
X }
X else
X {
X d = (double) TREE_INT_CST_HIGH (i);
X d *= ((double) (1 << (HOST_BITS_PER_INT / 2))
X * (double) (1 << (HOST_BITS_PER_INT / 2)));
X d += (double) (unsigned) TREE_INT_CST_LOW (i);
X }
X#endif /* not REAL_ARITHMETIC */
X return d;
X}
X
X/* This function can't be implemented if we can't do arithmetic
X on the float representation. */
X
Xtree
Xbuild_real_from_int_cst (type, i)
X tree type;
X tree i;
X{
X tree v;
X REAL_VALUE_TYPE d;
X
X v = make_node (REAL_CST);
X TREE_TYPE (v) = type;
X
X d = real_value_from_int_cst (i);
X /* Check for valid float value for this type on this target machine;
X if not, can print error message and store a valid value in D. */
X#ifdef CHECK_FLOAT_VALUE
X CHECK_FLOAT_VALUE (TYPE_MODE (type), d);
X#endif
X
X TREE_REAL_CST (v) = d;
X return v;
X}
X
X#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
X
X/* Return a newly constructed STRING_CST node whose value is
X the LEN characters at STR.
X The TREE_TYPE is not initialized. */
X
Xtree
Xbuild_string (len, str)
X int len;
X char *str;
X{
X register tree s = make_node (STRING_CST);
X TREE_STRING_LENGTH (s) = len;
X TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
X return s;
X}
X
X/* Return a newly constructed COMPLEX_CST node whose value is
X specified by the real and imaginary parts REAL and IMAG.
X Both REAL and IMAG should be constant nodes.
X The TREE_TYPE is not initialized. */
X
Xtree
Xbuild_complex (real, imag)
X tree real, imag;
X{
X register tree t = make_node (COMPLEX_CST);
X TREE_REALPART (t) = real;
X TREE_IMAGPART (t) = imag;
X return t;
X}
X
X/* Build a newly constructed TREE_VEC node of length LEN. */
Xtree
Xmake_tree_vec (len)
X int len;
X{
X register tree t;
X register int length = (len-1) * sizeof (tree) + sizeof (struct tree_vec);
X register struct obstack *obstack = current_obstack;
X register int i;
X
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)x_kind]++;
X tree_node_sizes[(int)x_kind] += length;
X#endif
X
X t = (tree) obstack_alloc (obstack, length);
X
X TREE_UID (t) = tree_node_counter++;
X TREE_TYPE (t) = 0;
X TREE_CHAIN (t) = 0;
X for (i = (length / sizeof (int)) - 1;
X i >= sizeof (struct tree_common) / sizeof (int) - 1;
X i--)
X ((int *) t)[i] = 0;
X TREE_SET_CODE (t, TREE_VEC);

X TREE_VEC_LENGTH (t) = len;
X if (obstack == &permanent_obstack)
X TREE_PERMANENT (t) = 1;
X
X return t;
X}
X
X/* Return 1 if EXPR is the integer constant zero. */
X
Xint
Xinteger_zerop (expr)
X tree expr;
X{
X return (TREE_CODE (expr) == INTEGER_CST
X && TREE_INT_CST_LOW (expr) == 0
X && TREE_INT_CST_HIGH (expr) == 0);
X}
X
X/* Return 1 if EXPR is the integer constant one. */
X
Xint
Xinteger_onep (expr)
X tree expr;
X{
X return (TREE_CODE (expr) == INTEGER_CST
X && TREE_INT_CST_LOW (expr) == 1
X && TREE_INT_CST_HIGH (expr) == 0);
X}
X
X/* Return 1 if EXPR is an integer containing all 1's
X in as much precision as it contains. */
X
Xint
Xinteger_all_onesp (expr)
X tree expr;
X{
X register int prec;
X register int uns;
X
X if (TREE_CODE (expr) != INTEGER_CST)
X return 0;
X
X uns = TREE_UNSIGNED (TREE_TYPE (expr));
X if (!uns)
X return TREE_INT_CST_LOW (expr) == -1 && TREE_INT_CST_HIGH (expr) == -1;
X
X prec = TYPE_PRECISION (TREE_TYPE (expr));
X if (prec >= HOST_BITS_PER_INT)
X return TREE_INT_CST_LOW (expr) == -1
X && TREE_INT_CST_HIGH (expr) == (1 << (prec - HOST_BITS_PER_INT)) - 1;
X else
X return TREE_INT_CST_LOW (expr) == (1 << prec) - 1;
X}
X
X/* Return list element whose TREE_VALUE is ELEM.
X Return 0 if ELEM is not in LIST. */
Xtree
Xvalue_member (elem, list)
X tree elem, list;
X{
X while (list)
X {
X if (elem == TREE_VALUE (list))
X return list;
X list = TREE_CHAIN (list);
X }
X return NULL_TREE;
X}
X
X/* Return list element whose TREE_PURPOSE is ELEM.
X Return 0 if ELEM is not in LIST. */
Xtree
Xpurpose_member (elem, list)
X tree elem, list;
X{
X while (list)
X {
X if (elem == TREE_PURPOSE (list))
X return list;
X list = TREE_CHAIN (list);
X }
X return NULL_TREE;
X}
X
X/* Return the length of a chain of nodes chained through TREE_CHAIN.
X We expect a null pointer to mark the end of the chain.
X This is the Lisp primitive `length'. */
X
Xint
Xlist_length (t)
X tree t;
X{
X register tree tail;
X register int len = 0;
X
X for (tail = t; tail; tail = TREE_CHAIN (tail))
X len++;
X
X return len;
X}
X
X/* Concatenate two chains of nodes (chained through TREE_CHAIN)
X by modifying the last node in chain 1 to point to chain 2.
X This is the Lisp primitive `nconc'. */
X
Xtree
Xchainon (op1, op2)
X tree op1, op2;
X{
X tree t;
X
X if (op1)
X {
X for (t = op1; TREE_CHAIN (t); t = TREE_CHAIN (t))
X if (t == op2) abort (); /* Circularity being created */
X TREE_CHAIN (t) = op2;
X return op1;
X }
X else return op2;
X}
X
X/* Return a newly created TREE_LIST node whose
X purpose and value fields are PARM and VALUE. */
X
Xtree
Xbuild_tree_list (parm, value)
X tree parm, value;
X{
X#if 0
X register tree t = make_node (TREE_LIST);
X#else
X register tree t;
X register struct obstack *obstack = current_obstack;
X register int i;

X
X t = (tree) obstack_alloc (obstack, sizeof (struct tree_list));
X TREE_UID (t) = tree_node_counter++;
X TREE_TYPE (t) = 0;
X TREE_CHAIN (t) = 0;
X ((int *) t)[3] = 0;
X
X TREE_SET_CODE (t, TREE_LIST);
X if (obstack == &permanent_obstack)
X {
X TREE_PERMANENT (t) = 1;
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)perm_list_kind]++;
X tree_node_sizes[(int)perm_list_kind] += sizeof (struct tree_list);
X#endif
X }
X else
X {
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)temp_list_kind]++;
X tree_node_sizes[(int)temp_list_kind] += sizeof (struct tree_list);
X#endif
X }
X#endif
X
X TREE_PURPOSE (t) = parm;
X TREE_VALUE (t) = value;
X return t;
X}
X
X/* Similar, but build on the temp_decl_obstack. */
Xtree
Xbuild_decl_list (parm, value)
X tree parm, value;
X{
X register tree node;
X register struct obstack *ambient_obstack = current_obstack;
X current_obstack = &temp_decl_obstack;
X node = build_tree_list (parm, value);
X current_obstack = ambient_obstack;
X return node;
X}
X
X/* Return a newly created TREE_LIST node whose
X purpose and value fields are PARM and VALUE
X and whose TREE_CHAIN is CHAIN. */
X
Xtree
Xtree_cons (purpose, value, chain)
X tree purpose, value, chain;
X{
X#if 0
X register tree t = make_node (TREE_LIST);
X#else
X register tree t;
X register struct obstack *obstack = current_obstack;
X register int i;
X
X t = (tree) obstack_alloc (obstack, sizeof (struct tree_list));
X TREE_UID (t) = tree_node_counter++;
X TREE_TYPE (t) = 0;
X ((int *) t)[3] = 0;
X
X TREE_SET_CODE (t, TREE_LIST);
X if (obstack == &permanent_obstack)
X {
X TREE_PERMANENT (t) = 1;
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)perm_list_kind]++;
X tree_node_sizes[(int)perm_list_kind] += sizeof (struct tree_list);
X#endif
X }
X else
X {
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)temp_list_kind]++;
X tree_node_sizes[(int)temp_list_kind] += sizeof (struct tree_list);
X#endif
X }
X#endif
X
X TREE_CHAIN (t) = chain;
X TREE_PURPOSE (t) = purpose;
X TREE_VALUE (t) = value;
X return t;
X}
X
X/* Similar, but build on the temp_decl_obstack. */
Xtree
Xdecl_tree_cons (purpose, value, chain)
X tree purpose, value, chain;
X{
X register tree node;
X register struct obstack *ambient_obstack = current_obstack;
X current_obstack = &temp_decl_obstack;
X
X node = tree_cons (purpose, value, chain);
X current_obstack = ambient_obstack;
X return node;
X}
X
X/* Same as `tree_cons' but make a permanent object. */
X
Xtree
Xperm_tree_cons (purpose, value, chain)
X tree purpose, value, chain;
X{
X register tree node;
X register struct obstack *ambient_obstack = current_obstack;
X current_obstack = &permanent_obstack;
X
X node = tree_cons (purpose, value, chain);
X current_obstack = ambient_obstack;
X return node;
X}
X
X/* Same as `tree_cons', but make this node temporary, regardless. */
X
Xtree
Xtemp_tree_cons (purpose, value, chain)
X tree purpose, value, chain;
X{
X register tree node;
X register struct obstack *ambient_obstack = current_obstack;
X current_obstack = &temporary_obstack;
X
X node = tree_cons (purpose, value, chain);
X current_obstack = ambient_obstack;
X return node;
X}
X
X/* Same as `tree_cons', but save this node if the function's RTL is saved. */
X
Xtree
Xsaveable_tree_cons (purpose, value, chain)
X tree purpose, value, chain;
X{
X register tree node;
X register struct obstack *ambient_obstack = current_obstack;
X current_obstack = saveable_obstack;
X
X node = tree_cons (purpose, value, chain);
X current_obstack = ambient_obstack;
X return node;
X}
X
X/* Return the last node in a chain of nodes (chained through TREE_CHAIN). */
X
Xtree
Xtree_last (chain)
X register tree chain;
X{
X register tree next;
X if (chain)
X while (next = TREE_CHAIN (chain))
X chain = next;
X return chain;
X}
X
X/* Reverse the order of elements in the chain T,
X and return the new head of the chain (old last element). */
X
Xtree
Xnreverse (t)
X tree t;
X{
X register tree prev = 0, decl, next;
X for (decl = t; decl; decl = next)
X {
X next = TREE_CHAIN (decl);
X TREE_CHAIN (decl) = prev;
X prev = decl;
X }
X return prev;
X}
X
X/* Given a chain CHAIN of tree nodes,
X construct and return a list of those nodes. */
X
Xtree
Xlistify (chain)
X tree chain;
X{
X tree result = NULL_TREE;
X tree in_tail = chain;
X tree out_tail = NULL_TREE;
X
X while (in_tail)
X {
X tree next = tree_cons (NULL_TREE, in_tail, NULL_TREE);
X if (out_tail)
X TREE_CHAIN (out_tail) = next;
X else
X result = next;
X out_tail = next;
X in_tail = TREE_CHAIN (in_tail);
X }
X
X return result;
X}
X
X/* Return the size nominally occupied by an object of type TYPE
X when it resides in memory. The value is measured in units of bytes,
X and its data type is that normally used for type sizes
X (which is the first type created by make_signed_type or
X make_unsigned_type). */
X
Xtree
Xsize_in_bytes (type)
X tree type;
X{
X if (type == error_mark_node)
X return integer_zero_node;
X type = TYPE_MAIN_VARIANT (type);
X if (TYPE_SIZE (type) == 0)
X {
X incomplete_type_error (0, type);
X return integer_zero_node;
X }
X return convert_units (TYPE_SIZE (type), TYPE_SIZE_UNIT (type),
X BITS_PER_UNIT);
X}
X
X/* Return the size of TYPE (in bytes) as an integer,
X or return -1 if the size can vary. */
X
Xint
Xint_size_in_bytes (type)
X tree type;
X{
X int size;
X if (type == error_mark_node)
X return 0;
X type = TYPE_MAIN_VARIANT (type);
X if (TYPE_SIZE (type) == 0)
X return -1;
X if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
X return -1;
X size = TREE_INT_CST_LOW (TYPE_SIZE (type)) * TYPE_SIZE_UNIT (type);
X return (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
X}
X
X/* Return, as an INTEGER_CST node, the number of elements for
X TYPE (which is an ARRAY_TYPE). */
X
Xtree
Xarray_type_nelts (type)
X tree type;
X{
X tree index_type = TYPE_DOMAIN (type);
X if (index_type == NULL_TREE)
X {
X incomplete_type_error (NULL_TREE, type);
X return error_mark_node;
X }
X return (tree_int_cst_equal (TYPE_MIN_VALUE (index_type), integer_zero_node)
X ? TYPE_MAX_VALUE (index_type)
X : fold (build (MINUS_EXPR, integer_type_node,
X TYPE_MAX_VALUE (index_type),
X TYPE_MIN_VALUE (index_type))));
X}
X
X/* Return nonzero if arg is static -- a reference to an object in
X static storage. This is not the same as the C meaning of `static'. */
X
Xint
Xstaticp (arg)
X tree arg;
X{
X register enum tree_code code = TREE_CODE (arg);
X
X if ((code == VAR_DECL || code == FUNCTION_DECL || code == CONSTRUCTOR)
X && (TREE_STATIC (arg) || TREE_EXTERNAL (arg)))
X return 1;
X
X if (code == STRING_CST)
X return 1;
X
X if (code == COMPONENT_REF)
X return (DECL_VOFFSET (TREE_OPERAND (arg, 1)) == 0
X && staticp (TREE_OPERAND (arg, 0)));
X
X if (code == INDIRECT_REF)
X return TREE_LITERAL (TREE_OPERAND (arg, 0));
X
X if (code == ARRAY_REF)
X {
X if (TREE_CODE (TYPE_SIZE (TREE_TYPE (arg))) == INTEGER_CST
X && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST)
X return staticp (TREE_OPERAND (arg, 0));
X }
X
X return 0;
X}
X
X/* This should be applied to any node which may be used in more than one place,
X but must be evaluated only once. Normally, the code generator would
X reevaluate the node each time; this forces it to compute it once and save
X the result. This is done by encapsulating the node in a SAVE_EXPR. */
X
Xtree
Xsave_expr (expr)
X tree expr;
X{
X register tree t = fold (expr);
X
X /* If the tree evaluates to a constant, then we don't want to hide that
X fact (i.e. this allows further folding, and direct checks for constants).
X Since it is no problem to reevaluate literals, we just return the
X literal node. */
X
X if (TREE_LITERAL (t) || TREE_READONLY (t) || TREE_CODE (t) == SAVE_EXPR)
X return t;
X
X return build (SAVE_EXPR, TREE_TYPE (expr), t, NULL);
X}
X
X/* Stabilize a reference so that we can use it any number of times
X without causing its operands to be evaluated more than once.
X Returns the stabilized reference.
X
X Also allows conversion expressions whose operands are references.
X Any other kind of expression is returned unchanged. */
X
Xtree
Xstabilize_reference (ref)
X tree ref;
X{
X register tree result;
X register enum tree_code code = TREE_CODE (ref);
X
X switch (code)
X {
X case VAR_DECL:
X case PARM_DECL:
X case RESULT_DECL:
X result = ref;
X break;
X
X case NOP_EXPR:
X case CONVERT_EXPR:
X case FLOAT_EXPR:
X case FIX_TRUNC_EXPR:
X case FIX_FLOOR_EXPR:
X case FIX_ROUND_EXPR:
X case FIX_CEIL_EXPR:
X result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0)));
X break;
X
X case INDIRECT_REF:
X result = build_nt (INDIRECT_REF, save_expr (TREE_OPERAND (ref, 0)));
X break;
X
X case COMPONENT_REF:
X result = build_nt (COMPONENT_REF,
X stabilize_reference (TREE_OPERAND (ref, 0)),
X TREE_OPERAND (ref, 1));
X break;
X
X case ARRAY_REF:
X result = build_nt (ARRAY_REF, stabilize_reference (TREE_OPERAND (ref, 0)),
X save_expr (TREE_OPERAND (ref, 1)));
X break;
X
X /* If arg isn't a kind of lvalue we recognize, make no change.
X Caller should recognize the error for an invalid lvalue. */
X default:
X return ref;
X
X case ERROR_MARK:
X return error_mark_node;
X }
X
X TREE_TYPE (result) = TREE_TYPE (ref);
X TREE_READONLY (result) = TREE_READONLY (ref);
X TREE_VOLATILE (result) = TREE_VOLATILE (ref);
X TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
X TREE_RAISES (result) = TREE_RAISES (ref);
X
X return result;
X}
X
X/* Low-level constructors for expressions. */
X
X/* Build an expression of code CODE, data type TYPE,
X and operands as specified by the arguments ARG1 and following arguments.
X Expressions and reference nodes can be created this way.
X Constants, decls, types and misc nodes cannot be. */
X
Xtree
Xbuild (va_alist)
X va_dcl
X{
X register va_list p;
X enum tree_code code;
X register tree t;
X register int length;
X register int i;
X
X va_start (p);
X
X code = va_arg (p, enum tree_code);
X t = make_node (code);
X length = tree_code_length[(int) code];
X TREE_TYPE (t) = va_arg (p, tree);
X
X if (length == 2)
X {
X /* This is equivalent to the loop below, but faster. */
X register tree arg0 = va_arg (p, tree);
X register tree arg1 = va_arg (p, tree);
X TREE_OPERAND (t, 0) = arg0;
X TREE_OPERAND (t, 1) = arg1;
X TREE_VOLATILE (t)
X = (arg0 && TREE_VOLATILE (arg0)) || (arg1 && TREE_VOLATILE (arg1));
X TREE_RAISES (t)
X = (arg0 && TREE_RAISES (arg0)) || (arg1 && TREE_RAISES (arg1));
X }
X else
X {
X for (i = 0; i < length; i++)
X {
X register tree operand = va_arg (p, tree);
X TREE_OPERAND (t, i) = operand;
X if (operand)
X {
X if (TREE_VOLATILE (operand))
X TREE_VOLATILE (t) = 1;
X if (TREE_RAISES (operand))
X TREE_RAISES (t) = 1;
X }
X }
X }
X va_end (p);
X return t;
X}
X
X/* Same as above, but only builds for unary operators.
X Saves lions share of calls to `build'; cuts down use
X of varargs, which is expensive for RISC machines. */
Xtree
Xbuild1 (code, type, node)
X enum tree_code code;
X tree type;
X tree node;
X{
X register struct obstack *obstack = current_obstack;
X register int i, length;
X register tree_node_kind kind;
X register tree t;
X
X if (*tree_code_type[(int) code] == 'r')
X kind = r_kind;
X else if (*tree_code_type[(int) code] == 'e')
X kind = e_kind;
X else
X abort ();
X
X obstack = expression_obstack;
X length = sizeof (struct tree_exp);
X
X t = (tree) obstack_alloc (obstack, length);
X
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)kind]++;
X tree_node_sizes[(int)kind] += length;
X#endif
X
X TREE_UID (t) = tree_node_counter++;
X TREE_TYPE (t) = type;
X TREE_CHAIN (t) = 0;
X
X for (i = (length / sizeof (int)) - 2;
X i >= sizeof (struct tree_common) / sizeof (int) - 1;
X i--)
X ((int *) t)[i] = 0;
X TREE_SET_CODE (t, code);
X
X if (obstack == &permanent_obstack)
X TREE_PERMANENT (t) = 1;
X
X TREE_OPERAND (t, 0) = node;
X if (node)
X {
X if (TREE_VOLATILE (node))
X TREE_VOLATILE (t) = 1;
X if (TREE_RAISES (node))
X TREE_RAISES (t) = 1;
X }
X return t;
X}
X
X/* Similar except don't specify the TREE_TYPE
X and leave the TREE_VOLATILE as 0.
X It is permissible for arguments to be null,
X or even garbage if their values do not matter. */
X
Xtree
Xbuild_nt (va_alist)
X va_dcl
X{
X register va_list p;
X register enum tree_code code;
X register tree t;
X register int length;
X register int i;
X
X va_start (p);
X
X code = va_arg (p, enum tree_code);
X t = make_node (code);
X length = tree_code_length[(int) code];
X
X for (i = 0; i < length; i++)
X TREE_OPERAND (t, i) = va_arg (p, tree);
X
X va_end (p);
X return t;
X}
X
X/* Similar to `build_nt', except we build
X on the temp_decl_obstack, regardless. */
X
Xtree
Xbuild_parse_node (va_alist)
X va_dcl
X{
X register struct obstack *ambient_obstack = expression_obstack;
X register va_list p;
X register enum tree_code code;
X register tree t;
X register int length;
X register int i;
X
X expression_obstack = &temp_decl_obstack;
X
X va_start (p);
X
X code = va_arg (p, enum tree_code);
X t = make_node (code);
X length = tree_code_length[(int) code];
X
X for (i = 0; i < length; i++)
X TREE_OPERAND (t, i) = va_arg (p, tree);
X
X va_end (p);
X expression_obstack = ambient_obstack;
X return t;
X}
X
X#if 0
X/* Commented out because this wants to be done very
X differently. See cplus-lex.c. */
Xtree
Xbuild_op_identifier (op1, op2)
X tree op1, op2;
X{
X register tree t = make_node (OP_IDENTIFIER);
X TREE_PURPOSE (t) = op1;
X TREE_VALUE (t) = op2;
X return t;
X}
X#endif
X
X/* Create a DECL_... node of code CODE, name NAME and data type TYPE.
X We do NOT enter this node in any sort of symbol table.
X
X layout_decl is used to set up the decl's storage layout.
X Other slots are initialized to 0 or null pointers. */
X
Xtree
Xbuild_decl (code, name, type)
X enum tree_code code;
X tree name, type;
X{
X register tree t;
X
X t = make_node (code);
X
X/* if (type == error_mark_node)
X type = integer_type_node; */
X/* That is not done, deliberately, so that having error_mark_node
X as the type can suppress useless errors in the use of this variable. */
X
X DECL_NAME (t) = name;
X if (name)
X {
X#if 0
X DECL_PRINT_NAME (t) = IDENTIFIER_POINTER (name);
X#endif
X if (code != PARM_DECL)
X DECL_ASSEMBLER_NAME (t) = IDENTIFIER_POINTER (name);
X }
X TREE_TYPE (t) = type;
X
X /* A freshly built node has these properties anyway. */
X#if 0
X DECL_ARGUMENTS (t) = NULL_TREE;
X DECL_INITIAL (t) = NULL_TREE;
X#endif /* 0 */
X
X if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
X layout_decl (t, 0);
X else if (code == FUNCTION_DECL)
X DECL_MODE (t) = FUNCTION_MODE;
X
X return t;
X}
X
X/* Low-level constructors for statements.
X These constructors all expect source file name and line number
X as arguments, as well as enough arguments to fill in the data
X in the statement node. */
X
Xtree
Xbuild_goto (filename, line, label)
X char *filename;
X int line;
X tree label;
X{
X register tree t = make_node (GOTO_STMT);
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_BODY (t) = label;
X return t;
X}
X
Xtree
Xbuild_return (filename, line, arg)
X char *filename;
X int line;
X tree arg;
X{
X register tree t = make_node (RETURN_STMT);
X
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_BODY (t) = arg;
X return t;
X}
X
Xtree
Xbuild_expr_stmt (filename, line, expr)
X char *filename;
X int line;
X tree expr;
X{
X register tree t = make_node (EXPR_STMT);
X
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_BODY (t) = expr;
X return t;
X}
X
Xtree
Xbuild_if (filename, line, cond, thenclause, elseclause)
X char *filename;
X int line;
X tree cond, thenclause, elseclause;
X{
X register tree t = make_node (IF_STMT);
X
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_COND (t) = cond;
X STMT_THEN (t) = thenclause;
X STMT_ELSE (t) = elseclause;
X return t;
X}
X
Xtree
Xbuild_exit (filename, line, cond)
X char *filename;
X int line;
X tree cond;
X{
X register tree t = make_node (EXIT_STMT);
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_BODY (t) = cond;
X return t;
X}
X
Xtree
Xbuild_asm_stmt (filename, line, asmcode)
X char *filename;
X int line;
X tree asmcode;
X{
X register tree t = make_node (ASM_STMT);
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_BODY (t) = asmcode;
X return t;
X}
X
Xtree
Xbuild_case (filename, line, object, cases)
X char *filename;
X int line;
X tree object, cases;
X{
X register tree t = make_node (CASE_STMT);
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_CASE_INDEX (t) = object;
X STMT_CASE_LIST (t) = cases;
X return t;
X}
X
Xtree
Xbuild_compound (filename, line, body)
X char *filename;
X int line;
X tree body;
X{
X register tree t = make_node (COMPOUND_STMT);
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_BODY (t) = body;
X return t;
X}
X
Xtree
Xbuild_loop (filename, line, vars, cond, body)
X char *filename;
X int line;
X tree vars, cond, body;
X{
X register tree t = make_node (LOOP_STMT);
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_LOOP_VARS (t) = vars;
X STMT_LOOP_COND (t) = cond;
X STMT_LOOP_BODY (t) = body;
X return t;
X}
X
X/* LET_STMT nodes are used to represent the structure of binding contours
X and declarations, once those contours have been exited and their contents
X compiled. This information is used for outputting debugging info. */
X
Xtree
Xbuild_let (filename, line, vars, subblocks, supercontext, tags)
X char *filename;
X int line;
X tree vars, subblocks, supercontext, tags;
X{
X register tree t = make_node (LET_STMT);
X STMT_SOURCE_FILE (t) = filename;
X STMT_SOURCE_LINE (t) = line;
X STMT_VARS (t) = vars;
X STMT_SUBBLOCKS (t) = subblocks;
X STMT_SUPERCONTEXT (t) = supercontext;
X STMT_BIND_SIZE (t) = 0;
X STMT_TYPE_TAGS (t) = tags;
X return t;
X}
X
X/* Return a type like TYPE except that its TREE_READONLY is CONSTP
X and its TREE_VOLATILE is VOLATILEP.
X
X Such variant types already made are recorded so that duplicates
X are not made.
X
X A variant types should never be used as the type of an expression.
X Always copy the variant information into the TREE_READONLY
X and TREE_VOLATILE of the expression, and then give the expression
X as its type the "main variant", the variant whose TREE_READONLY
X and TREE_VOLATILE are zero. Use TYPE_MAIN_VARIANT to find the
X main variant. */
X
Xtree
Xbuild_type_variant (type, constp, volatilep)
X tree type;
X int constp, volatilep;
X{
X register tree t, m = TYPE_MAIN_VARIANT (type);
X register struct obstack *ambient_obstack = current_obstack;
X
X /* Treat any nonzero argument as 1. */
X constp = !!constp;
X volatilep = !!volatilep;
X
X /* First search the chain variants for one that is what we want. */
X
X for (t = m; t; t = TYPE_NEXT_VARIANT (t))
X if (constp == TREE_READONLY (t)
X && volatilep == TREE_VOLATILE (t))
X return t;
X
X /* We need a new one. */
X current_obstack
X = TREE_PERMANENT (type) ? &permanent_obstack : saveable_obstack;
X
X t = copy_node (type);
X TREE_READONLY (t) = constp;
X TREE_VOLATILE (t) = volatilep;
X TYPE_POINTER_TO (t) = 0;
X TYPE_REFERENCE_TO (t) = 0;
X
X /* Add this type to the chain of variants of TYPE. */
X TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
X TYPE_NEXT_VARIANT (m) = t;
X
X current_obstack = ambient_obstack;
X return t;
X}
X
X/* Hashing of types so that we don't make duplicates.
X The entry point is `type_hash_canon'. */
X
X/* Each hash table slot is a bucket containing a chain
X of these structures. */
X
Xstruct type_hash
X{
X struct type_hash *next; /* Next structure in the bucket. */
X int hashcode; /* Hash code of this type. */
X tree type; /* The type recorded here. */
X};

X
X/* Now here is the hash table. When recording a type, it is added
X to the slot whose index is the hash code mod the table size.
X Note that the hash table is used for several kinds of types
X (function types, array types and array index range types, for now).
X While all these live in the same table, they are completely independent,
X and the hash code is computed differently for each of these. */
X
X#define TYPE_HASH_SIZE 59
Xstruct type_hash *type_hash_table[TYPE_HASH_SIZE];
X
X/* Here is how primitive or already-canonicalized types' hash
X codes are made. */
X#define TYPE_HASH(TYPE) TREE_UID (TYPE)
X
X/* Compute a hash code for a list of types (chain of TREE_LIST nodes
X with types in the TREE_VALUE slots), by adding the hash codes
X of the individual types. */
X
Xint
Xtype_hash_list (list)
X tree list;
X{
X register int hashcode;
X register tree tail;
X for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))
X hashcode += TYPE_HASH (TREE_VALUE (tail));
X return hashcode;
X}
X
X/* Look in the type hash table for a type isomorphic to TYPE.
X If one is found, return it. Otherwise return 0. */
X
Xtree
Xtype_hash_lookup (hashcode, type)
X int hashcode;
X tree type;
X{
X register struct type_hash *h;
X for (h = type_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
X if (h->hashcode == hashcode
X && TREE_CODE (h->type) == TREE_CODE (type)
X && TREE_TYPE (h->type) == TREE_TYPE (type)
X && (TYPE_MAX_VALUE (h->type) == TYPE_MAX_VALUE (type)
X || tree_int_cst_equal (TYPE_MAX_VALUE (h->type),
X TYPE_MAX_VALUE (type)))
X && (TYPE_MIN_VALUE (h->type) == TYPE_MIN_VALUE (type)
X || tree_int_cst_equal (TYPE_MIN_VALUE (h->type),
X TYPE_MIN_VALUE (type)))
X && (TYPE_DOMAIN (h->type) == TYPE_DOMAIN (type)
X || (TREE_CODE (TYPE_DOMAIN (h->type)) == TREE_LIST
X && TREE_CODE (TYPE_DOMAIN (type)) == TREE_LIST
X && type_list_equal (TYPE_DOMAIN (h->type), TYPE_DOMAIN (type)))))
X return h->type;
X return 0;
X}
X
X/* Add an entry to the type-hash-table
X for a type TYPE whose hash code is HASHCODE. */
X
Xvoid
Xtype_hash_add (hashcode, type)
X int hashcode;
X tree type;
X{
X register struct type_hash *h;
X
X h = (struct type_hash *) oballoc (sizeof (struct type_hash));
X h->hashcode = hashcode;
X h->type = type;
X h->next = type_hash_table[hashcode % TYPE_HASH_SIZE];
X type_hash_table[hashcode % TYPE_HASH_SIZE] = h;
X}
X
X/* Given TYPE, and HASHCODE its hash code, return the canonical
X object for an identical type if one already exists.
X Otherwise, return TYPE, and record it as the canonical object
X if it is a permanent object.
X
X To use this function, first create a type of the sort you want.
X Then compute its hash code from the fields of the type that
X make it different from other similar types.
X Then call this function and use the value.
X This function frees the type you pass in if it is a duplicate. */
X
X/* Set to 1 to debug without canonicalization. Never set by program. */
Xint debug_no_type_hash = 0;
X
Xtree
Xtype_hash_canon (hashcode, type)
X int hashcode;
X tree type;
X{
X tree t1;
X
X if (debug_no_type_hash)
X return type;
X
X t1 = type_hash_lookup (hashcode, type);
X if (t1 != 0)
X {
X struct obstack *o
X = TREE_PERMANENT (type) ? &permanent_obstack : saveable_obstack;
X obstack_free (o, type);
X#ifdef GATHER_STATISTICS
X tree_node_kinds[(int)t_kind]--;
X tree_node_sizes[(int)t_kind] -= sizeof (struct tree_type);
X#endif
X return t1;
X }
X
X /* If this is a new type, record it for later reuse. */
X if (current_obstack == &permanent_obstack)
X type_hash_add (hashcode, type);
X
X return type;
X}
X
X/* Given two lists of types
X (chains of TREE_LIST nodes with types in the TREE_VALUE slots)
X return 1 if the lists contain the same types in the same order.
X Also, the TREE_PURPOSEs must match. */
X
Xint
Xtype_list_equal (l1, l2)
X tree l1, l2;
X{
X register tree t1, t2;
X for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
X {
X if (TREE_VALUE (t1) != TREE_VALUE (t2))
X return 0;
X if (TREE_PURPOSE (t1) != TREE_PURPOSE (t2))
X {
X int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
X if (cmp < 0)
X abort ();
X if (cmp == 0)
X return 0;
X }
X }
X
X return t1 == t2;
X}
X
X/* Nonzero if integer constants T1 and T2
X represent the same constant value. */
X
Xint
Xtree_int_cst_equal (t1, t2)
X tree t1, t2;
X{
X if (t1 == t2)
X return 1;
X if (t1 == 0 || t2 == 0)
X return 0;
X if (TREE_CODE (t1) == INTEGER_CST
X && TREE_CODE (t2) == INTEGER_CST
X && TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
X && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2))
X return 1;
X return 0;
X}
X
X/* Nonzero if integer constants T1 and T2 represent values that satisfy <.
X The precise way of comparison depends on their data type. */
X
Xint
Xtree_int_cst_lt (t1, t2)
X tree t1, t2;
X{
X if (t1 == t2)
X return 0;
X
X if (!TREE_UNSIGNED (TREE_TYPE (t1)))
X return INT_CST_LT (t1, t2);
X return INT_CST_LT_UNSIGNED (t1, t2);
X}
X
X/* Compare two constructor-element-type constants. */
Xint
Xsimple_cst_list_equal (l1, l2)
X tree l1, l2;
X{
X while (l1 != NULL_TREE && l2 != NULL_TREE)
X {
X int cmp = simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2));
X if (cmp < 0)
X abort ();
X if (cmp == 0)
X return 0;
X l1 = TREE_CHAIN (l1);
X l2 = TREE_CHAIN (l2);
X }
X return (l1 == l2);
X}
X
X/* Return truthvalue of whether T1 is the same tree structure as T2.
X Return 1 if they are the same.
X Return 0 if they are understandably different.
X Return -1 if either contains tree structure not understood by
X this function. */
Xint
Xsimple_cst_equal (t1, t2)
X tree t1, t2;
X{
X register enum tree_code code1, code2;
X int cmp;
X
X if (t1 == t2)
X return 1;
X if (t1 == 0 || t2 == 0)
X return 0;
X
X code1 = TREE_CODE (t1);
X code2 = TREE_CODE (t2);
X
X if (code1 == NOP_EXPR || code1 == CONVERT_EXPR)
X if (code2 == NOP_EXPR || code2 == CONVERT_EXPR)
X return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
X else
X return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
X else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR)
X return simple_cst_equal (t1, TREE_OPERAND (t2, 0));
X
X if (code1 != code2)
X return 0;
X
X switch (code1)
X {
X case INTEGER_CST:
X return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
X && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
X
X case REAL_CST:
X return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
X
X case STRING_CST:
X return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
X && !bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
X TREE_STRING_LENGTH (t1));
X
X case CONSTRUCTOR:
X abort ();
X
X case SAVE_EXPR:
X return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
X
X case NEW_EXPR:
X return simple_cst_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
X
X case CALL_EXPR:
X cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
X if (cmp <= 0)
X return cmp;
X return simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
X
X case COMPONENT_REF:
X if (TREE_OPERAND (t1, 1) == TREE_OPERAND (t2, 1))
X return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
X return 0;
X
X case VAR_DECL:
X case PARM_DECL:
X case CONST_DECL:
X case FUNCTION_DECL:
X return 0;
X
X case PLUS_EXPR:
X case MINUS_EXPR:
X case MULT_EXPR:
X case TRUNC_DIV_EXPR:
X case TRUNC_MOD_EXPR:
X case LSHIFT_EXPR:
X case RSHIFT_EXPR:
X cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
X if (cmp <= 0)
X return cmp;
X return simple_cst_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
X
X case NEGATE_EXPR:
X case ADDR_EXPR:
X case REFERENCE_EXPR:
X case INDIRECT_REF:
X return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
X
X default:
X return lang_simple_cst_equal (t1, t2);
X }
X}
X
X/* Constructors for pointer, array and function types.
X (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
X constructed by language-dependent code, not here.) */
X
X/* Construct, lay out and return the type of pointers to TO_TYPE.
X If such a type has already been constructed, reuse it. */
X
Xtree
Xbuild_pointer_type (to_type)
X tree to_type;
X{
X register tree t = TYPE_POINTER_TO (to_type);
X register struct obstack *ambient_obstack = current_obstack;
X register struct obstack *ambient_saveable_obstack = saveable_obstack;
X
X /* First, if we already have a type for pointers to TO_TYPE, use it. */
X
X if (t)
X return t;
X
X /* We need a new one. If TO_TYPE is permanent, make this permanent too. */
X if (TREE_PERMANENT (to_type))
X {
X current_obstack = &permanent_obstack;
X saveable_obstack = &permanent_obstack;
X }
X
X t = make_node (POINTER_TYPE);
X TREE_TYPE (t) = to_type;
X
X /* Record this type as the pointer to TO_TYPE. */
X TYPE_POINTER_TO (to_type) = t;
X
X /* Lay out the type. This function has many callers that are concerned
X with expression-construction, and this simplifies them all.
X Also, it guarantees the TYPE_SIZE is permanent if the type is. */
X layout_type (t);
X
X current_obstack = ambient_obstack;
X saveable_obstack = ambient_saveable_obstack;
X return t;
X}
X
X/* Create a type of integers to be the TYPE_DOMAIN of an ARRAY_TYPE.
X MAXVAL should be the maximum value in the domain
X (one less than the length of the array). */
X
Xtree
Xbuild_index_type (maxval)
X tree maxval;
X{
X register tree itype = make_node (INTEGER_TYPE);
X int maxint = TREE_INT_CST_LOW (maxval);
X TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
X TYPE_MIN_VALUE (itype) = build_int_2 (0, 0);
X TREE_TYPE (TYPE_MIN_VALUE (itype)) = sizetype;
X TYPE_MAX_VALUE (itype) = convert (sizetype, maxval);
X TYPE_MODE (itype) = SImode;
X TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
X TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
X TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
X return type_hash_canon (maxint > 0 ? maxint : - maxint, itype);
X}
X
X/* Construct, lay out and return the type of arrays of elements with ELT_TYPE
X and number of elements specified by the range of values of INDEX_TYPE.
X If such a type has already been constructed, reuse it. */
X
Xtree
Xbuild_array_type (elt_type, index_type)
X tree elt_type, index_type;
X{
X register tree t = make_node (ARRAY_TYPE);
X int hashcode;
X
X if (TREE_CODE (elt_type) == FUNCTION_TYPE)
X {
X error ("arrays of functions are not meaningful");
X elt_type = integer_type_node;
X }
X
X TREE_TYPE (t) = elt_type;
X TYPE_DOMAIN (t) = index_type;
X
X /* Make sure TYPE_POINTER_TO (elt_type) is filled in. */
X build_pointer_type (elt_type);
X
X if (index_type == 0)
X return t;
X
X hashcode = TYPE_HASH (elt_type) + TYPE_HASH (index_type);
X t = type_hash_canon (hashcode, t);
X
X if (TYPE_SIZE (t) == 0)
X layout_type (t);
X return t;
X}
X
X/* Construct, lay out and return
X the type of functions returning type VALUE_TYPE
X given arguments of types ARG_TYPES.
X ARG_TYPES is a chain of TREE_LIST nodes whose TREE_VALUEs
X are data type nodes for the arguments of the function.
X If such a type has already been constructed, reuse it. */
X
Xtree
Xbuild_function_type (value_type, arg_types)
X tree value_type, arg_types;
X{
X register tree t;
X int hashcode;
X
X if (TREE_CODE (value_type) == FUNCTION_TYPE
X || TREE_CODE (value_type) == ARRAY_TYPE)
X {
X error ("function return type cannot be function or array");
X value_type = integer_type_node;
X }
X
X /* Make a node of the sort we want. */
X t = make_node (FUNCTION_TYPE);
X TREE_TYPE (t) = value_type;
X TYPE_ARG_TYPES (t) = arg_types;
X
X /* If we already have such a type, use the old one and free this one. */
X hashcode = TYPE_HASH (value_type) + type_hash_list (arg_types);
X t = type_hash_canon (hashcode, t);
X
X if (TYPE_SIZE (t) == 0)
X layout_type (t);
X return t;
X}
X
X/* Build the node for the type of references-to-TO_TYPE. */
X
Xtree
Xbuild_reference_type (to_type)
X tree to_type;
X{
X register tree t = TYPE_REFERENCE_TO (to_type);
X register struct obstack *ambient_obstack = current_obstack;
X register struct obstack *ambient_saveable_obstack = saveable_obstack;
X
X /* First, if we already have a type for pointers to TO_TYPE, use it. */
X
X if (t)
X return t;
X
X /* We need a new one. If TO_TYPE is permanent, make this permanent too. */
X if (TREE_PERMANENT (to_type))
X {
X current_obstack = &permanent_obstack;
X saveable_obstack = &permanent_obstack;
X }
X
X t = make_node (REFERENCE_TYPE);
X TREE_TYPE (t) = to_type;
X
X /* Record this type as the pointer to TO_TYPE. */
X TYPE_REFERENCE_TO (to_type) = t;
X
X layout_type (t);
X
X current_obstack = ambient_obstack;
X saveable_obstack = ambient_saveable_obstack;
X return t;
X}
X
X/* Construct, lay out and return the type of methods belonging to class
X BASETYPE and whose arguments and values are described by TYPE.
X If that type exists already, reuse it.
X TYPE must be a FUNCTION_TYPE node. */
X
Xtree
Xbuild_method_type (basetype, type)
X tree basetype, type;
X{
X register tree t;
X int hashcode;
X
X /* Make a node of the sort we want. */
X t = make_node (METHOD_TYPE);
X
X if (TREE_CODE (type) != FUNCTION_TYPE)
X abort ();
X
X TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
X TREE_TYPE (t) = TREE_TYPE (type);
X
X /* The actual arglist for this function includes a "hidden" argument
X which is "this". Put it into the list of argument types. */
X
X TYPE_ARG_TYPES (t)
X = tree_cons (NULL, build_pointer_type (basetype), TYPE_ARG_TYPES (type));
X
X /* If we already have such a type, use the old one and free this one. */
X hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
X t = type_hash_canon (hashcode, t);
X
X if (TYPE_SIZE (t) == 0)
X layout_type (t);
X
X return t;
X}
X
X/* Construct, lay out and return the type of methods belonging to class
X BASETYPE and whose arguments and values are described by TYPE.
X If that type exists already, reuse it.
X TYPE must be a FUNCTION_TYPE node. */
X
Xtree
Xbuild_offset_type (basetype, type)
X tree basetype, type;
X{
X register tree t;
X int hashcode;
X
X /* Make a node of the sort we want. */
X t = make_node (OFFSET_TYPE);
X
X TYPE_OFFSET_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
X TREE_TYPE (t) = type;

X
X /* If we already have such a type, use the old one and free this one. */
X hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
X t = type_hash_canon (hashcode, t);
X
X if (TYPE_SIZE (t) == 0)
X layout_type (t);
X
X return t;
X}
X
X/* Return the innermost context enclosing FNDECL that is
X a RECORD_TYPE or UNION_TYPE, or zero if none.
X TYPE_DECLs and FUNCTION_DECLs are transparent to this function. */
X
Xtree
Xdecl_type_context (fndecl)
X tree fndecl;
X{
X tree context = DECL_CONTEXT (fndecl);
X
X while (context)
X {
X if (TREE_CODE (context) == RECORD_TYPE
X || TREE_CODE (context) == UNION_TYPE)
X return context;
X if (TREE_CODE (context) == TYPE_DECL
X || TREE_CODE (context) == FUNCTION_DECL)
X context = DECL_CONTEXT (context);
X else if (TREE_CODE (context) == LET_STMT)
X context = STMT_SUPERCONTEXT (context);
X else
X /* Unhandled CONTEXT!? */
X abort ();
X }
X return NULL_TREE;
X}
X
X/* Return OP, stripped of any conversions to wider types as much as is safe.
X Converting the value back to OP's type makes a value equivalent to OP.
X
X If FOR_TYPE is nonzero, we return a value which, if converted to
X type FOR_TYPE, would be equivalent to converting OP to type FOR_TYPE.
X
X If FOR_TYPE is nonzero, unaligned bit-field references may be changed to the
X narrowest type that can hold the value, even if they don't exactly fit.
X Otherwise, bit-field references are changed to a narrower type
X only if they can be fetched directly from memory in that type.
X
X OP must have integer, real or enumeral type. Pointers are not allowed!
X
X There are some cases where the obvious value we could return
X would regenerate to OP if converted to OP's type,
X but would not extend like OP to wider types.
X If FOR_TYPE indicates such extension is contemplated, we eschew such values.
X For example, if OP is (unsigned short)(signed char)-1,
X we avoid returning (signed char)-1 if FOR_TYPE is int,
X even though extending that to an unsigned short would regenerate OP,
X since the result of extending (signed char)-1 to (int)
X is different from (int) OP. */
X
Xtree
Xget_unwidened (op, for_type)
X register tree op;
X tree for_type;
X{
X /* Set UNS initially if converting OP to FOR_TYPE is a zero-extension. */
X /* TYPE_PRECISION is safe in place of type_precision since
X pointer types are not allowed. */
X register tree type = TREE_TYPE (op);
X register int final_prec = TYPE_PRECISION (for_type != 0 ? for_type : type);
X register int uns
X = (for_type != 0 && for_type != type
X && final_prec > TYPE_PRECISION (type)
X && TREE_UNSIGNED (type));
X register tree win = op;
X
X while (TREE_CODE (op) == NOP_EXPR)
X {
X register int bitschange
X = TYPE_PRECISION (TREE_TYPE (op))
X - TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0)));
X
X /* Truncations are many-one so cannot be removed.
X Unless we are later going to truncate down even farther. */
X if (bitschange < 0
X && final_prec > TYPE_PRECISION (TREE_TYPE (op)))
X break;
X
X /* See what's inside this conversion. If we decide to strip it,
X we will set WIN. */
X op = TREE_OPERAND (op, 0);
X
X /* If we have not stripped any zero-extensions (uns is 0),
X we can strip any kind of extension.
X If we have previously stripped a zero-extension,
X only zero-extensions can safely be stripped.
X Any extension can be stripped if the bits it would produce
X are all going to be discarded later by truncating to FOR_TYPE. */
X
X if (bitschange > 0)
X {
X if (! uns || final_prec <= TYPE_PRECISION (TREE_TYPE (op)))
X win = op;
X /* TREE_UNSIGNED says whether this is a zero-extension.
X Let's avoid computing it if it does not affect WIN
X and if UNS will not be needed again. */
X if ((uns || TREE_CODE (op) == NOP_EXPR)
X && TREE_UNSIGNED (TREE_TYPE (op)))
X {
X uns = 1;
X win = op;
X }
X }
X }
X
X if (TREE_CODE (op) == COMPONENT_REF
X /* Since type_for_size always gives an integer type. */
X && TREE_CODE (type) != REAL_TYPE)
X {
X int innerprec = (TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)))
X * DECL_SIZE_UNIT (TREE_OPERAND (op, 1)));
X type = type_for_size (innerprec, TREE_UNSIGNED (TREE_OPERAND (op, 1)));
X
X /* We can get this structure field in the narrowest type it fits in.
X If FOR_TYPE is 0, do this only for a field that matches the
X narrower type exactly and is aligned for it (i.e. mode isn't BI).
X The resulting extension to its nominal type (a fullword type)
X must fit the same conditions as for other extensions. */
X
X if (innerprec < TYPE_PRECISION (TREE_TYPE (op))
X && (for_type || DECL_MODE (TREE_OPERAND (op, 1)) != BImode)
X && (! uns || final_prec <= innerprec
X || TREE_UNSIGNED (TREE_OPERAND (op, 1)))
X && type != 0)
X {
X win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0),
X TREE_OPERAND (op, 1));
X TREE_VOLATILE (win) = TREE_VOLATILE (op);
X TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
X TREE_RAISES (win) = TREE_RAISES (op);
X }
X }
X return win;
X}
X
X/* Return OP or a simpler expression for a narrower value
X which can be sign-extended or zero-extended to give back OP.
X Store in *UNSIGNEDP_PTR either 1 if the value should be zero-extended
X or 0 if the value should be sign-extended. */
X
Xtree
Xget_narrower (op, unsignedp_ptr)
X register tree op;
X int *unsignedp_ptr;
X{
X register int uns = 0;
X int first = 1;
X register tree win = op;
X
X while (TREE_CODE (op) == NOP_EXPR)
X {
X register int bitschange
X = TYPE_PRECISION (TREE_TYPE (op))
X - TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0)));
X
X /* Truncations are many-one so cannot be removed. */
X if (bitschange < 0)
X break;
X
X /* See what's inside this conversion. If we decide to strip it,
X we will set WIN. */
X op = TREE_OPERAND (op, 0);
X
X if (bitschange > 0)
X {
X /* An extension: the outermost one can be stripped,
X but remember whether it is zero or sign extension. */
X if (first)
X uns = TREE_UNSIGNED (TREE_TYPE (op));
X /* Otherwise, if a sign extension has been stripped,
X only sign extensions can now be stripped;
X if a zero extension has been stripped, only zero-extensions. */
X else if (uns != TREE_UNSIGNED (TREE_TYPE (op)))
X break;
X first = 0;
X }
X /* A change in nominal type can always be stripped. */
X
X win = op;
X }
X
X if (TREE_CODE (op) == COMPONENT_REF
X /* Since type_for_size always gives an integer type. */
X && TREE_CODE (TREE_TYPE (op)) != REAL_TYPE)
X {
X int innerprec = (TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)))
X * DECL_SIZE_UNIT (TREE_OPERAND (op, 1)));
X tree type = type_for_size (innerprec, TREE_UNSIGNED (op));
X
X /* We can get this structure field in a narrower type that fits it,
X but the resulting extension to its nominal type (a fullword type)
X must satisfy the same conditions as for other extensions.
X
X Do this only for fields that are aligned (not BImode),
X because when bit-field insns will be used there is no
X advantage in doing this. */
X
X if (innerprec < TYPE_PRECISION (TREE_TYPE (op))
X && DECL_MODE (TREE_OPERAND (op, 1)) != BImode
X && (first || uns == TREE_UNSIGNED (TREE_OPERAND (op, 1)))
X && type != 0)
X {
X if (first)
X uns = TREE_UNSIGNED (TREE_OPERAND (op, 1));
X win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0),
X TREE_OPERAND (op, 1));
X TREE_VOLATILE (win) = TREE_VOLATILE (op);
X TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
X TREE_RAISES (win) = TREE_RAISES (op);
X }
X }
X *unsignedp_ptr = uns;
X return win;
X}
X
X/* Return the precision of a type, for arithmetic purposes.
X Supports all types on which arithmetic is possible
X (including pointer types).
X It's not clear yet what will be right for complex types. */
X
Xint
Xtype_precision (type)
X register tree type;
X{
X return ((TREE_CODE (type) == INTEGER_TYPE
X || TREE_CODE (type) == ENUMERAL_TYPE
X || TREE_CODE (type) == REAL_TYPE)
X ? TYPE_PRECISION (type) : POINTER_SIZE);
X}
X
X/* Nonzero if integer constant C has a value that is permissible
X for type TYPE (an INTEGER_TYPE). */
X
Xint
Xint_fits_type_p (c, type)
X tree c, type;
X{
X if (TREE_UNSIGNED (type))
X return (!INT_CST_LT_UNSIGNED (TYPE_MAX_VALUE (type), c)
X && !INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type)));
X else
X return (!INT_CST_LT (TYPE_MAX_VALUE (type), c)
X && !INT_CST_LT (c, TYPE_MIN_VALUE (type)));
X}
X
Xvoid
Xprint_obstack_statistics (str, o)
X char *str;
X struct obstack *o;
X{
X struct _obstack_chunk *chunk = o->chunk;
X int n_chunks = 0;
X int n_alloc = 0;
X
X while (chunk)
X {
X n_chunks += 1;
X n_alloc += chunk->limit - &chunk->contents[0];
X chunk = chunk->prev;
X }
X fprintf (stderr, "obstack %s: %d bytes, %d chunks\n",
X str, n_alloc, n_chunks);
X}
X
Xvoid
Xdump_tree_statistics ()
X{
X int i;
X int total_nodes, total_bytes;
X extern struct obstack class_obstack;
X
X fprintf (stderr, "\n%d tree nodes created\n\n", tree_node_counter);
X#ifdef GATHER_STATISTICS
X fprintf (stderr, "Kind Nodes Bytes\n");
X fprintf (stderr, "-------------------------------------\n");
X total_nodes = total_bytes = 0;
X for (i = 0; i < (int) all_kinds; i++)
X {
X fprintf (stderr, "%-20s %6d %9d\n", tree_node_kind_names[i],
X tree_node_kinds[i], tree_node_sizes[i]);
X total_nodes += tree_node_kinds[i];
X total_bytes += tree_node_sizes[i];
X }
X fprintf (stderr, "%-20s %9d\n", "identifier names", id_string_size);
X fprintf (stderr, "-------------------------------------\n");
X fprintf (stderr, "%-20s %6d %9d\n", "Total", total_nodes, total_bytes);
X fprintf (stderr, "-------------------------------------\n");
X#else
X fprintf (stderr, "(No per-node statistics)\n");
X#endif
X print_obstack_statistics ("class_obstack", &class_obstack);
X print_obstack_statistics ("permanent_obstack", &permanent_obstack);
X print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack);
X print_search_statistics ();
X print_class_statistics ();
X}
!EOF
echo "Extracting cplus-cvt.c..."
sed 's/^X//' >cplus-cvt.c << '!EOF'
X/* Language-level data type conversion for GNU C++.
X Copyright (C) 1987, 1988 Free Software Foundation, Inc.
X Hacked by Michael Tiemann ([email protected])
X
XThis file is part of GNU CC.
X
XGNU CC is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU CC is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU CC; see the file COPYING. If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X
X/* This file contains the functions for converting C expressions
X to different data types. The only entry point is `convert'.
X Every language front end must have a `convert' function
X but what kind of conversions it does will depend on the language. */
X
X#include "config.h"
X#include "tree.h"
X#include "cplus-tree.h"
X#include "assert.h"
X
X#define NULL 0
X
X/* Change of width--truncation and extension of integers or reals--
X is represented with NOP_EXPR. Proper functioning of many things
X assumes that no other conversions can be NOP_EXPRs.
X
X Conversion between integer and pointer is represented with CONVERT_EXPR.
X Converting integer to real uses FLOAT_EXPR
X and real to integer uses FIX_TRUNC_EXPR.
X
X Here is a list of all the functions that assume that widening and
X narrowing is always done with a NOP_EXPR:
X In c-convert.c, convert_to_integer.
X In c-typeck.c, build_binary_op_nodefault (boolean ops),
X and truthvalue_conversion.
X In expr.c: expand_expr, for operands of a MULT_EXPR.
X In fold-const.c: fold.
X In tree.c: get_narrower and get_unwidened.
X
X C++: in multiple-inheritance, converting between pointers may involve
X adjusting them by a delta stored within the class definition. */
X
X/* Subroutines of `convert'. */
X
Xstatic tree
Xconvert_to_pointer (type, expr)
X tree type, expr;
X{
X register tree intype = TREE_TYPE (expr);
X register enum tree_code form = TREE_CODE (intype);
X
X if (integer_zerop (expr))
X {
X if (type == TREE_TYPE (null_pointer_node))
X return null_pointer_node;
X expr = build_int_2 (0, 0);
X TREE_TYPE (expr) = type;
X return expr;
X }
X
X if (form == POINTER_TYPE)
X {
X intype = TYPE_MAIN_VARIANT (intype);
X
X if (TYPE_MAIN_VARIANT (type) != intype
X && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)))
X {
X enum tree_code code = PLUS_EXPR;
X tree basetype = get_base_type (TREE_TYPE (TYPE_MAIN_VARIANT (type)),
X TREE_TYPE (intype), 1);
X if (basetype == error_mark_node)
X return error_mark_node;
X if (basetype == NULL_TREE)
X {
X basetype = get_base_type (TREE_TYPE (intype),
X TREE_TYPE (TYPE_MAIN_VARIANT (type)), 1);
X if (basetype == error_mark_node)
X return error_mark_node;
X code = MINUS_EXPR;
X }
X if (basetype)
X {
X if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (type))
X || TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (intype))
X || DECL_OFFSET (TYPE_NAME (basetype)) != 0)
X {
X /* Need to get the path we took. */
X tree path;
X
X if (code == PLUS_EXPR)
X get_base_distance (TREE_TYPE (type), TREE_TYPE (intype), 0, &path);
X else
X get_base_distance (TREE_TYPE (intype), TREE_TYPE (type), 0, &path);
X return build_vbase_path (code, type, expr, path, 0);
X }
X }
X }
X return build1 (NOP_EXPR, type, expr);
X }
X
X if (form == INTEGER_TYPE || form == ENUMERAL_TYPE)
X {
X if (type_precision (intype) == POINTER_SIZE)
X return build1 (CONVERT_EXPR, type, expr);
X return convert_to_pointer (type,
X convert (type_for_size (POINTER_SIZE, 0),
X expr));
X }
X
X assert (form != OFFSET_TYPE);
X
X if (IS_AGGR_TYPE (intype))
X {
X /* If we cannot convert to the specific pointer type,
X try to convert to the type `void *'. */
X tree rval;
X rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
X if (rval)
X {
X if (rval == error_mark_node)
X error ("ambiguous pointer conversion");
X return rval;
X }
X }
X
X error ("cannot convert to a pointer type");
X
X return null_pointer_node;
X}
X
X/* Like convert, except permit conversions to take place which
X are not normally allowed due to visibility restrictions
X (such as conversion from sub-type to private super-type). */
Xstatic tree
Xconvert_to_pointer_force (type, expr)
X tree type, expr;
X{
X register tree intype = TREE_TYPE (expr);
X register enum tree_code form = TREE_CODE (intype);
X
X if (integer_zerop (expr))
X {
X if (type == TREE_TYPE (null_pointer_node))
X return null_pointer_node;
X expr = build_int_2 (0, 0);
X TREE_TYPE (expr) = type;
X return expr;
X }
X
X if (form == POINTER_TYPE)
X {
X intype = TYPE_MAIN_VARIANT (intype);
X
X if (TYPE_MAIN_VARIANT (type) != intype
X && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)))
X {
X enum tree_code code = PLUS_EXPR;
X tree path, basetype;
X int distance = get_base_distance (TREE_TYPE (type),
X TYPE_MAIN_VARIANT (TREE_TYPE (intype)), 0, &path);
X if (distance == -2)
X {
X ambig:
X error_with_aggr_type (TREE_TYPE (type), "type `%s' is ambiguous baseclass of `%s'",
X TYPE_NAME_STRING (TREE_TYPE (intype)));
X return error_mark_node;
X }
X if (distance == -1)
X {
X distance = get_base_distance (TREE_TYPE (intype),
X TYPE_MAIN_VARIANT (TREE_TYPE (type)), 0, &path);
X if (distance == -2)
X goto ambig;
X if (distance < 0)
X /* Doesn't need any special help from us. */
X return build1 (NOP_EXPR, type, expr);
X
X code = MINUS_EXPR;
X }
X return build_vbase_path (code, type, expr, path, 0);
X }
X return build1 (NOP_EXPR, type, expr);
X }
X
X return convert_to_pointer (type, expr);
X}
X
X/* We are passing something to a function which requires a reference.
X The type we are interested in is in TYPE. The initial
X value we have to begin with is in ARG.
X
X FLAGS controls how we manage visibility checking. */
Xstatic tree
Xbuild_up_reference (type, arg, flags)
X tree type, arg;
X int flags;
X{
X tree rval, targ;
X int literal_flag = 0;
X tree argtype = TREE_TYPE (arg), basetype = argtype;
X tree target_type = TREE_TYPE (type);
X
X assert (TREE_CODE (type) == REFERENCE_TYPE);
X if (flags != 0
X && TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type)
X && IS_AGGR_TYPE (argtype)
X && IS_AGGR_TYPE (target_type))
X {
X basetype = get_base_type (target_type, TYPE_MAIN_VARIANT (argtype),
X (flags & LOOKUP_PROTECTED_OK) ? 3 : 2);
X if ((flags & LOOKUP_PROTECT) && basetype == error_mark_node)
X return error_mark_node;
X if (basetype == NULL_TREE)
X {
X error_not_base_type (target_type, argtype);
X return error_mark_node;
X }
X }
X
X targ = arg;
X if (TREE_CODE (targ) == SAVE_EXPR)
X targ = TREE_OPERAND (targ, 0);
X
X switch (TREE_CODE (targ))
X {
X case INDIRECT_REF:
X /* This is a call to a constructor which did not know what it was
X initializing until now: it needs to initialize a temporary. */
X if (TYPE_HAS_CONSTRUCTOR (arg))
X {
X tree temp = build_cplus_new (argtype, TREE_OPERAND (targ, 0), 1);
X TYPE_HAS_CONSTRUCTOR (targ) = 0;
X return build_up_reference (type, temp, flags);
X }
X /* Let &* cancel out to simplify resulting code.
X Also, throw away intervening NOP_EXPRs. */
X arg = TREE_OPERAND (targ, 0);
X if (TREE_CODE (arg) == NOP_EXPR || TREE_CODE (arg) == REFERENCE_EXPR)
X arg = TREE_OPERAND (arg, 0);
X
X rval = build1 (REFERENCE_EXPR, type, arg);
X literal_flag = TREE_LITERAL (arg);
X goto done;
X
X /* Get this out of a register if we happened to be in one by accident.
X Also, build up references to non-lvalues it we must. */
X /* For &x[y], return (&) x+y */
X case ARRAY_REF:
X if (mark_addressable (TREE_OPERAND (targ, 0)) == 0)
X return error_mark_node;
X rval = build_binary_op (PLUS_EXPR, TREE_OPERAND (targ, 0),
X TREE_OPERAND (targ, 1));
X TREE_TYPE (rval) = type;
X if (TREE_LITERAL (TREE_OPERAND (targ, 1))
X && staticp (TREE_OPERAND (targ, 0)))
X TREE_LITERAL (rval) = 1;
X return rval;
X
X case SCOPE_REF:
X /* Could be a reference to a static member. */
X {
X tree field = TREE_OPERAND (targ, 1);
X if (TREE_STATIC (field))
X {
X rval = build1 (ADDR_EXPR, type, field);
X literal_flag = 1;
X goto done;
X }
X }
X /* we should have farmed out member pointers above. */
X assert (0);
X
X case COMPONENT_REF:
X rval = build_component_addr (targ, build_pointer_type (argtype),
X "attempt to make a reference to bit-field structure member `%s'");
X TREE_TYPE (rval) = type;
X literal_flag = staticp (TREE_OPERAND (targ, 0));
X#if 0
X goto done_but_maybe_warn;
X#else
X goto done;
X#endif
X
X /* Anything not already handled and not a true memory reference
X needs to have a reference built up. Do so silently for
X things like integers and return values from function,
X but complain if we need a reference to something declared
X as `register'. */
X
X case RESULT_DECL:
X if (staticp (targ))
X literal_flag = 1;
X TREE_ADDRESSABLE (targ) = 1;
X put_var_into_stack (targ);
X break;
X
X case PARM_DECL:
X if (targ == current_class_decl)
X {
X error ("address of `this' not available");
X TREE_ADDRESSABLE (targ) = 1; /* so compiler doesn't die later */
X put_var_into_stack (targ);
X break;
X }
X /* Fall through. */
X case VAR_DECL:
X case CONST_DECL:
X if (TREE_REGDECL (targ) && !TREE_ADDRESSABLE (targ))
X warning ("address needed to build reference for `%s', which is declared `register'",
X IDENTIFIER_POINTER (DECL_NAME (targ)));
X else if (staticp (targ))
X literal_flag = 1;
X
X TREE_ADDRESSABLE (targ) = 1;
X put_var_into_stack (targ);
X break;
X
X case COMPOUND_EXPR:
X {
X tree real_reference = build_up_reference (type, TREE_OPERAND (targ, 1),
X LOOKUP_PROTECT);
X rval = build (COMPOUND_EXPR, type, TREE_OPERAND (targ, 0), real_reference);
X TREE_LITERAL (rval) = staticp (TREE_OPERAND (targ, 1));
X return rval;
X }
X
X case MODIFY_EXPR:
X case INIT_EXPR:
X {
X tree real_reference = build_up_reference (type, TREE_OPERAND (targ, 0),
X LOOKUP_PROTECT);
X rval = build (COMPOUND_EXPR, type, arg, real_reference);
X TREE_LITERAL (rval) = staticp (TREE_OPERAND (targ, 0));
X return rval;
X }
X
X case COND_EXPR:
X return build (COND_EXPR, type,
X TREE_OPERAND (targ, 0),
X build_up_reference (type, TREE_OPERAND (targ, 1), LOOKUP_PROTECT),
X build_up_reference (type, TREE_OPERAND (targ, 2), LOOKUP_PROTECT));
X
X case WITH_CLEANUP_EXPR:
X return build (WITH_CLEANUP_EXPR, type,
X build_up_reference (type, TREE_OPERAND (targ, 0), LOOKUP_PROTECT),
X 0, TREE_OPERAND (targ, 2));
X
X default:
X break;
X }
X
X if (TREE_ADDRESSABLE (targ) == 0)
X {
X tree temp;
X
X if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (argtype))
X {
X temp = build_cplus_new (argtype, targ, 1);
X rval = build1 (ADDR_EXPR, type, temp);
X goto done;
X }
X else
X {
X temp = get_temp_name (argtype, 0);
X if (global_bindings_p ())
X {
X /* Give this new temp some rtl and initialize it. */
X DECL_INITIAL (temp) = targ;
X TREE_STATIC (temp) = 1;
X finish_decl (temp, targ, NULL_TREE);
X /* Do this after declaring it static. */
X rval = build_unary_op (ADDR_EXPR, temp, 0);
X literal_flag = TREE_LITERAL (rval);
X goto done;
X }
X else
X {
X rval = build_unary_op (ADDR_EXPR, temp, 0);
X /* Put a value into the rtl. */
X if (IS_AGGR_TYPE (argtype))
X {
X /* This may produce surprising results,
X since we commit to initializing the temp
X when the temp may not actually get used. */
X expand_aggr_init (temp, targ, 0);
X TREE_TYPE (rval) = type;
X literal_flag = TREE_LITERAL (rval);
X goto done;
X }
X else
X {
X if (basetype != argtype)
X rval = convert_pointer_to (target_type, rval);
X else
X TREE_TYPE (rval) = type;
X return build (COMPOUND_EXPR, type,
X build (MODIFY_EXPR, argtype, temp, arg), rval);
X }
X }
X }
X }
X else
X {
X if (TREE_CODE (arg) == SAVE_EXPR)
X abort ();
X rval = build1 (ADDR_EXPR, type, arg);
X }
X
X done_but_maybe_warn:
X if (TREE_READONLY (arg)
X && ! TREE_READONLY (target_type))
X readonly_warning_or_error (arg, "conversion to reference");
X
X done:
X if (TYPE_LANG_SPECIFIC (argtype)
X && (TYPE_USES_MULTIPLE_INHERITANCE (argtype)
X || TYPE_USES_VIRTUAL_BASECLASSES (argtype)))
X {
X TREE_TYPE (rval) = TYPE_POINTER_TO (argtype);
X rval = convert_pointer_to (target_type, rval);
X TREE_TYPE (rval) = type;
X }
X TREE_LITERAL (rval) = literal_flag;
X return rval;
X}
X
X/* For C++: Only need to do one-level references, but cannot
X get tripped up on signed/unsigned differences.
X
X If DECL is NULL_TREE it means convert as though casting (by force).
X If it is ERROR_MARK_NODE, it means the conversion is implicit,
X and that temporaries may be created.
X Otherwise, DECL is a _DECL node which can be used in error reporting. */
Xtree
Xconvert_to_reference (decl, reftype, expr, strict, flags)
X tree decl;
X tree reftype, expr;
X int strict, flags;
X{
X register tree type = TYPE_MAIN_VARIANT (TREE_TYPE (reftype));
X register tree intype = TREE_TYPE (expr);
X register enum tree_code form = TREE_CODE (intype);
X
X assert (TREE_CODE (reftype) == REFERENCE_TYPE);
X
X if (form == REFERENCE_TYPE)
X intype = TREE_TYPE (intype);
X intype = TYPE_MAIN_VARIANT (intype);
X
X /* @@ Probably need to have a check for X(X&) here. */
X
X if (IS_AGGR_TYPE (intype))
X {
X tree rval = build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
X if (rval)
X {
X if (rval == error_mark_node)
X error ("ambiguous pointer conversion");
X return rval;
X }
X else if (rval = build_type_conversion (CONVERT_EXPR, type, expr, 1))
X {
X if (TYPE_NEEDS_DESTRUCTOR (type))
X {
X rval = cleanup_after_call (rval);
X rval = convert_to_reference (NULL_TREE, reftype, rval, strict, flags);
X }
X else
X {
X decl = get_temp_name (type, 0);
X rval = build (INIT_EXPR, type, decl, rval);
X rval = build (COMPOUND_EXPR, reftype, rval,
X convert_to_reference (NULL_TREE, reftype, decl,
X strict, flags));
X }
X return rval;
X }
X
X if (form == REFERENCE_TYPE
X && type != intype
X && TYPE_LANG_SPECIFIC (intype)
X && (TYPE_USES_VIRTUAL_BASECLASSES (intype)
X || TYPE_USES_MULTIPLE_INHERITANCE (intype)))
X {
X /* If it may move around, build a fresh reference. */
X expr = convert_from_reference (expr);
X form = TREE_CODE (TREE_TYPE (expr));
X }
X }
X
X /* @@ Perhaps this should try to go through a constructor first
X @@ for proper initialization, but I am not sure when that
X @@ is needed or desirable.
X
X @@ The second disjunct is provided to make references behave
X @@ as some people think they should, i.e., an interconvertability
X @@ between references to builtin types (such as short and
X @@ unsigned short). There should be no conversion between
X @@ types whose codes are different, or whose sizes are different. */
X
X if (((IS_AGGR_TYPE (type) || IS_AGGR_TYPE (intype))
X && comptypes (type, intype, strict))
X || (!IS_AGGR_TYPE (type)
X && TREE_CODE (type) == TREE_CODE (intype)
X && int_size_in_bytes (type) == int_size_in_bytes (intype)))
X {
X /* If EXPR is of aggregate type, and is really a CALL_EXPR,
X then we don't need to convert it to reference type if
X it is only being used to initialize DECL which is also
X of the same aggregate type. */
X if (form == REFERENCE_TYPE
X || (decl != NULL_TREE && decl != error_mark_node
X && IS_AGGR_TYPE (type)
X && TREE_CODE (expr) == CALL_EXPR
X && TYPE_MAIN_VARIANT (type) == intype))
X {
X if (decl && decl != error_mark_node)
X {
X tree e1 = build (INIT_EXPR, void_type_node, decl, expr);
X tree e2;
X
X TREE_VOLATILE (e1) = 1;
X if (form == REFERENCE_TYPE)
X e2 = build1 (NOP_EXPR, reftype, decl);
X else
X {
X e2 = build_unary_op (ADDR_EXPR, decl, 0);
X e2 = build1 (REFERENCE_EXPR, reftype, e2);
X }
X return build_compound_expr (tree_cons (NULL_TREE, e1,
X build_tree_list (NULL_TREE, e2)));
X }
X expr = copy_node (expr);
X TREE_TYPE (expr) = reftype;
X return expr;
X }
X if (decl == error_mark_node)
X flags |= LOOKUP_PROTECTED_OK;
X return build_up_reference (reftype, expr, flags);
X }
X
X /* Definitely need to go through a constructor here. */
X if (TYPE_HAS_CONSTRUCTOR (type))
X {
X tree init = build_method_call (NULL_TREE, DECL_NAME (TYPE_NAME (type)), build_tree_list (NULL_TREE, expr), CLASSTYPE_AS_LIST (type), LOOKUP_NORMAL);
X tree rval;
X
X if (init == error_mark_node)
X return error_mark_node;
X rval = build_cplus_new (type, init, 1);
X if (decl == error_mark_node)
X flags |= LOOKUP_PROTECTED_OK;
X return build_up_reference (reftype, rval, flags);
X }
X
X assert (form != OFFSET_TYPE);
X
X error ("cannot convert to a reference type");
X
X return error_mark_node;
X}
X
X/* We are using a reference VAL for its value. Bash that reference all the
X way down to its lowest form. */
Xtree
Xconvert_from_reference (val)
X tree val;
X{
X tree type = TREE_TYPE (val);
X
X if (TREE_CODE (type) == OFFSET_TYPE)
X type = TREE_TYPE (type);
X if (TREE_CODE (type) == REFERENCE_TYPE)
X {
X tree target_type = TREE_TYPE (type);
X
X /* This can happen if we cast to a reference type. */
X if (TREE_CODE (val) == ADDR_EXPR)
X {
X val = build1 (NOP_EXPR, build_pointer_type (target_type), val);
X val = build_indirect_ref (val, 0);
X return val;
X }
X
X val = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (target_type), val);
X
X TREE_THIS_VOLATILE (val) = TREE_VOLATILE (target_type);
X TREE_READONLY (val) = TREE_READONLY (target_type);
X }
X return val;
X}
X
Xstatic tree
Xconvert_to_real (type, expr)
X tree type, expr;
X{
X register enum tree_code form = TREE_CODE (TREE_TYPE (expr));
X extern int flag_float_store;
X
X if (form == REAL_TYPE)
X return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
X type, expr);
X
X if (form == INTEGER_TYPE || form == ENUMERAL_TYPE)
X return build1 (FLOAT_EXPR, type, expr);
X
X assert (form != OFFSET_TYPE);
X
X if (form == POINTER_TYPE)
X error ("pointer value used where a floating point value was expected");
X /* C++: check to see if we can convert this aggregate type
X into the required scalar type. */
X else if (IS_AGGR_TYPE (TREE_TYPE (expr)))
X {
X tree rval;
X rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
X if (rval)
X return rval;
X else
X error ("aggregate value used where a floating point value was expected");
X }
X
X {
X register tree tem = make_node (REAL_CST);
X TREE_TYPE (tem) = type;
X TREE_REAL_CST (tem) = 0;
X return tem;
X }
X}
X
X/* The result of this is always supposed to be a newly created tree node
X not in use in any existing structure. */
X
Xstatic tree
Xconvert_to_integer (type, expr)
X tree type, expr;
X{
X register tree intype = TREE_TYPE (expr);
X register enum tree_code form = TREE_CODE (intype);
X extern tree build_binary_op_nodefault ();
X extern tree build_unary_op ();
X
X if (form == POINTER_TYPE)
X {
X if (integer_zerop (expr))
X expr = integer_zero_node;
X else
X expr = fold (build1 (CONVERT_EXPR,
X type_for_size (POINTER_SIZE, 0), expr));
X intype = TREE_TYPE (expr);
X form = TREE_CODE (intype);
X if (intype == type)
X return expr;
X }
X
X if (form == INTEGER_TYPE || form == ENUMERAL_TYPE)
X {
X register int outprec = TYPE_PRECISION (type);
X register int inprec = TYPE_PRECISION (intype);
X register enum tree_code ex_form = TREE_CODE (expr);
X
X if (outprec >= inprec)
X return build1 (NOP_EXPR, type, expr);
X
X/* Here detect when we can distribute the truncation down past some arithmetic.
X For example, if adding two longs and converting to an int,
X we can equally well convert both to ints and then add.
X For the operations handled here, such truncation distribution
X is always safe.
X It is desirable in these cases:
X 1) when truncating down to full-word from a larger size
X 2) when truncating takes no work.
X 3) when at least one operand of the arithmetic has been extended
X (as by C's default conversions). In this case we need two conversions
X if we do the arithmetic as already requested, so we might as well
X truncate both and then combine. Perhaps that way we need only one.
X
X Note that in general we cannot do the arithmetic in a type
X shorter than the desired result of conversion, even if the operands
X are both extended from a shorter type, because they might overflow
X if combined in that type. The exceptions to this--the times when
X two narrow values can be combined in their narrow type even to
X make a wider result--are handled by "shorten" in build_binary_op. */
X
X switch (ex_form)
X {
X case RSHIFT_EXPR:
X /* We can pass truncation down through right shifting
X when the shift count is a negative constant. */
X if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST
X || TREE_INT_CST_LOW (TREE_OPERAND (expr, 1)) > 0)
X break;
X goto trunc1;
X
X case LSHIFT_EXPR:

X /* We can pass truncation down through left shifting
X when the shift count is a positive constant. */
X if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST
X || TREE_INT_CST_LOW (TREE_OPERAND (expr, 1)) < 0)
X break;
X /* In this case, shifting is like multiplication. */
X goto trunc1;
X
X case MAX_EXPR:
X case MIN_EXPR:
X case MULT_EXPR:
X {
X tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
X tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
X
X /* Don't distribute unless the output precision is at least as big
X as the actual inputs. Otherwise, the comparison of the
X truncated values will be wrong. */
X if (outprec >= TYPE_PRECISION (TREE_TYPE (arg0))
X && outprec >= TYPE_PRECISION (TREE_TYPE (arg1))
X /* If signedness of arg0 and arg1 don't match,
X we can't necessarily find a type to compare them in. */
X && (TREE_UNSIGNED (TREE_TYPE (arg0))
X == TREE_UNSIGNED (TREE_TYPE (arg1))))
X goto trunc1;
X break;
X }
X
X case PLUS_EXPR:
X case MINUS_EXPR:
X case BIT_AND_EXPR:
X case BIT_IOR_EXPR:
X case BIT_XOR_EXPR:
X case BIT_ANDTC_EXPR:
X trunc1:
X {
X tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
X tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
X
X if (outprec >= BITS_PER_WORD
X || TRULY_NOOP_TRUNCATION (outprec, inprec)
X || inprec > TYPE_PRECISION (TREE_TYPE (arg0))
X || inprec > TYPE_PRECISION (TREE_TYPE (arg1)))
X {
X /* Do the arithmetic in type TYPEX,
X then convert result to TYPE. */
X register tree typex = type;
X
X /* Can't do arithmetic in enumeral types
X so use an integer type that will hold the values. */
X if (TREE_CODE (typex) == ENUMERAL_TYPE)
X typex = type_for_size (TYPE_PRECISION (typex),
X TREE_UNSIGNED (typex));
X
X /* But now perhaps TYPEX is as wide as INPREC.
X In that case, do nothing special here.
X (Otherwise would recurse infinitely in convert. */

X if (TYPE_PRECISION (typex) != inprec)
X {
X /* Don't do unsigned arithmetic where signed was wanted,
X or vice versa.
X Exception: if the original operands were unsigned
X then can safely do the work as unsigned.
X And we may need to do it as unsigned
X if we truncate to the original size. */
X typex = ((TREE_UNSIGNED (TREE_TYPE (expr))
X || TREE_UNSIGNED (TREE_TYPE (arg0)))
X ? unsigned_type (typex) : signed_type (typex));
X return convert (type,
X build_binary_op_nodefault (ex_form,
X convert (typex, arg0),
X convert (typex, arg1),
X ex_form));
X }
X }
X }
X break;
X
X case EQ_EXPR:
X case NE_EXPR:
X case GT_EXPR:
X case GE_EXPR:
X case LT_EXPR:
X case LE_EXPR:
X case TRUTH_AND_EXPR:
X case TRUTH_ANDIF_EXPR:
X case TRUTH_OR_EXPR:
X case TRUTH_ORIF_EXPR:
X case TRUTH_NOT_EXPR:
X /* If we want result of comparison converted to a byte,
X we can just regard it as a byte, since it is 0 or 1. */
X TREE_TYPE (expr) = type;
X return expr;
X
X case NEGATE_EXPR:
X case BIT_NOT_EXPR:
X case ABS_EXPR:
X {
X register tree typex = type;
X
X /* Can't do arithmetic in enumeral types
X so use an integer type that will hold the values. */
X if (TREE_CODE (typex) == ENUMERAL_TYPE)
X typex = type_for_size (TYPE_PRECISION (typex),
X TREE_UNSIGNED (typex));
X
X /* But now perhaps TYPEX is as wide as INPREC.
X In that case, do nothing special here.
X (Otherwise would recurse infinitely in convert. */
X if (TYPE_PRECISION (typex) != inprec)
X {
X /* Don't do unsigned arithmetic where signed was wanted,
X or vice versa. */
X typex = (TREE_UNSIGNED (TREE_TYPE (expr))
X ? unsigned_type (typex) : signed_type (typex));
X return convert (type,
X build_unary_op (ex_form,
X convert (typex, TREE_OPERAND (expr, 0)),
X 1));
X }
X }
X
X case NOP_EXPR:
X /* If truncating after truncating, might as well do all at once.
X If truncating after extending, we may get rid of wasted work. */
X return convert (type, get_unwidened (TREE_OPERAND (expr, 0), type));
X
X case COND_EXPR:
X /* Can treat the two alternative values like the operands
X of an arithmetic expression. */
X {
X tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
X tree arg2 = get_unwidened (TREE_OPERAND (expr, 2), type);
X
X if (outprec >= BITS_PER_WORD
X || TRULY_NOOP_TRUNCATION (outprec, inprec)
X || inprec > TYPE_PRECISION (TREE_TYPE (arg1))
X || inprec > TYPE_PRECISION (TREE_TYPE (arg2)))
X {
X /* Do the arithmetic in type TYPEX,
X then convert result to TYPE. */
X register tree typex = type;
X
X /* Can't do arithmetic in enumeral types
X so use an integer type that will hold the values. */
X if (TREE_CODE (typex) == ENUMERAL_TYPE)
X typex = type_for_size (TYPE_PRECISION (typex),
X TREE_UNSIGNED (typex));
X
X /* But now perhaps TYPEX is as wide as INPREC.
X In that case, do nothing special here.
X (Otherwise would recurse infinitely in convert. */
X if (TYPE_PRECISION (typex) != inprec)
X {
X /* Don't do unsigned arithmetic where signed was wanted,
X or vice versa. */
X typex = (TREE_UNSIGNED (TREE_TYPE (expr))
X ? unsigned_type (typex) : signed_type (typex));
X return convert (type,
X fold (build (COND_EXPR, typex,
X TREE_OPERAND (expr, 0),
X convert (typex, arg1),
X convert (typex, arg2))));
X }
X }
X }
X
X }
X
X return build1 (NOP_EXPR, type, expr);
X }
X
X if (form == REAL_TYPE)
X return build1 (FIX_TRUNC_EXPR, type, expr);
X
X if (form == OFFSET_TYPE)
X error_with_decl (TYPE_NAME (TYPE_OFFSET_BASETYPE (intype)),
X "pointer-to-member expression object not composed with type `%s' object");
X else
X {
X if (IS_AGGR_TYPE (intype))
X {
X tree rval;
X rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
X if (rval) return rval;
X }
X
X error ("aggregate value used where an integer was expected");
X }
X
X {
X register tree tem = build_int_2 (0, 0);
X TREE_TYPE (tem) = type;
X return tem;
X }
X}
X
X/* See if there is a constructor of type TYPE which will convert
X EXPR. The reference manual seems to suggest (8.5.6) that we need
X not worry about finding constructors for base classes, then converting
X to the derived class.
X
X MSGP is a pointer to a message that would be an appropriate error
X string. If MSGP is NULL, then we are not interested in reporting
X errors. */
Xtree
Xconvert_to_aggr (type, expr, msgp, protect)
X tree type, expr;
X char **msgp;
X{
X tree basetype = TYPE_MAIN_VARIANT (type);
X tree name = DECL_NAME (TYPE_NAME (basetype));
X tree function, fndecl, fntype, parmtypes, parmlist, result;
X tree method_name;
X enum visibility_type visibility;
X int can_be_private, can_be_protected;
X
X if (! TYPE_HAS_CONSTRUCTOR (basetype))
X {
X if (msgp)
X *msgp = "type `%s' does not have a constructor";
X return error_mark_node;
X }
X
X visibility = visibility_public;
X can_be_private = 0;
X can_be_protected = IDENTIFIER_CLASS_VALUE (name) || name == current_class_name;
X
X parmlist = build_tree_list (NULL_TREE, expr);
X parmtypes = tree_cons (NULL_TREE, TREE_TYPE (expr), void_list_node);
X
X if (TYPE_USES_VIRTUAL_BASECLASSES (basetype))
X {
X parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
X parmlist = tree_cons (NULL_TREE, integer_one_node, parmlist);
X }
X
X /* The type of the first argument will be filled in inside the loop. */
X parmlist = tree_cons (NULL_TREE, integer_zero_node, parmlist);
X parmtypes = tree_cons (NULL_TREE, TYPE_POINTER_TO (basetype), parmtypes);
X
X method_name = build_decl_overload (IDENTIFIER_POINTER (name), parmtypes, 1);
X
X /* constructors are up front. */
X fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
X if (TYPE_HAS_DESTRUCTOR (basetype))
X fndecl = TREE_CHAIN (fndecl);
X
X while (fndecl)
X {
X if (DECL_NAME (fndecl) == method_name)
X {
X function = fndecl;
X if (protect)
X {
X if (TREE_PRIVATE (fndecl))
X {
X can_be_private =
X (basetype == current_class_type
X || is_friend (basetype, current_function_decl)
X || purpose_member (basetype, DECL_VISIBILITY (fndecl)));
X if (! can_be_private)
X goto found;
X }
X else if (TREE_PROTECTED (fndecl))
X {
X if (! can_be_protected)
X goto found;
X }
X }
X goto found_and_ok;
X }
X fndecl = TREE_CHAIN (fndecl);
X }
X
X /* No exact conversion was found. See if an approximate
X one will do. */
X fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
X if (TYPE_HAS_DESTRUCTOR (basetype))
X fndecl = TREE_CHAIN (fndecl);
X
X {
X int saw_private = 0;
X int saw_protected = 0;
X struct candidate *candidates =
X (struct candidate *) alloca ((list_length (fndecl)+1) * sizeof (struct candidate));
X struct candidate *cp = candidates;
X
X while (fndecl)
X {
X function = fndecl;
X cp->harshness = (unsigned short *)alloca (3 * sizeof (short));
X compute_conversion_costs (fndecl, parmlist, cp, 2);
X if (cp->evil == 0)
X {
X cp->u.field = fndecl;
X if (protect)
X {
X if (TREE_PRIVATE (fndecl))
X visibility = visibility_private;
X else if (TREE_PROTECTED (fndecl))
X visibility = visibility_protected;
X else
X visibility = visibility_public;
X }
X else
X visibility = visibility_public;
X
X if (visibility == visibility_private
X ? (basetype == current_class_type
X || is_friend (basetype, cp->function)
X || purpose_member (basetype, DECL_VISIBILITY (fndecl)))
X : visibility == visibility_protected
X ? (can_be_protected
X || purpose_member (basetype, DECL_VISIBILITY (fndecl)))
X : 1)
X {
X if (cp->user == 0 && cp->b_or_d == 0
X && cp->easy <= 1)
X {
X goto found_and_ok;
X }
X cp++;
X }
X else
X {
X if (visibility == visibility_private)
X saw_private = 1;
X else
X saw_protected = 1;
X }
X }
X fndecl = TREE_CHAIN (fndecl);
X }
X if (cp - candidates)
X {
X /* Rank from worst to best. Then cp will point to best one.
X Private fields have their bits flipped. For unsigned
X numbers, this should make them look very large.
X If the best alternate has a (signed) negative value,
X then all we ever saw were private members. */
X if (cp - candidates > 1)
X qsort (candidates, /* char *base */
X cp - candidates, /* int nel */
X sizeof (struct candidate), /* int width */
X rank_for_overload); /* int (*compar)() */
X
X --cp;
X if (cp->evil > 1)
X {
X if (msgp)
X *msgp = "ambiguous type conversion possible for `%s'";
X return error_mark_node;
X }
X
X function = cp->function;
X fndecl = cp->u.field;
X goto found_and_ok;
X }
X else if (msgp)
X {
X if (saw_private)
X if (saw_protected)
X *msgp = "only private and protected conversions apply";
X else
X *msgp = "only private conversions apply";
X else if (saw_protected)
X *msgp = "only protected conversions apply";
X }
X return error_mark_node;
X }
X /* NOTREACHED */
X
X not_found:
X if (msgp) *msgp = "no appropriate conversion to type `%s'";
X return error_mark_node;
X found:
X if (visibility == visibility_private)
X if (! can_be_private)
X {
X if (msgp)
X *msgp = TREE_PRIVATE (fndecl)
X ? "conversion to type `%s' is private"
X : "conversion to type `%s' is from private base class";
X return error_mark_node;
X }
X if (visibility == visibility_protected)
X if (! can_be_protected)
X {
X if (msgp)
X *msgp = TREE_PRIVATE (fndecl)
X ? "conversion to type `%s' is protected"
X : "conversion to type `%s' is from protected base class";
X return error_mark_node;
X }
X function = fndecl;
X found_and_ok:
X
X /* It will convert, but we don't do anything about it yet. */
X if (msgp == 0)
X return NULL_TREE;
X
X fntype = TREE_TYPE (function);
X if (TREE_INLINE (function) && TREE_CODE (function) == FUNCTION_DECL)
X function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
X else
X function = default_conversion (function);
X
X result = build_nt (CALL_EXPR, function,
X actualparameterlist (NULL_TREE, TYPE_ARG_TYPES (fntype), parmlist, NULL_TREE, LOOKUP_NORMAL),
X NULL_TREE);
X TREE_TYPE (result) = TREE_TYPE (fntype);
X TREE_VOLATILE (result) = 1;
X TREE_RAISES (result) = !! TYPE_RAISES_EXCEPTIONS (fntype);
X return result;
X}
X
X/* Call this when we know (for any reason) that expr is
X not, in fact, zero. */
Xtree
Xconvert_pointer_to (type, expr)
X tree type, expr;
X{
X register tree intype = TREE_TYPE (expr);
X register enum tree_code form = TREE_CODE (intype);
X tree ptr_type = build_pointer_type (type);
X tree rval;
X
X if (TYPE_MAIN_VARIANT (ptr_type) == TYPE_MAIN_VARIANT (intype))
X return expr;
X
X if (intype == error_mark_node)
X return error_mark_node;
X
X assert (form == POINTER_TYPE);
X assert (!integer_zerop (expr));
X
X if (IS_AGGR_TYPE (type)
X && IS_AGGR_TYPE (TREE_TYPE (intype))
X && TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (TREE_TYPE (intype)))
X {
X tree path, basetype;
X int distance = get_base_distance (type, TYPE_MAIN_VARIANT (TREE_TYPE (intype)), 0, &path);
X
X /* This function shouldn't be called with
X unqualified arguments. */
X assert (distance >= 0);
X
X return build_vbase_path (PLUS_EXPR, ptr_type, expr, path, 1);
X }
X rval = build1 (NOP_EXPR, ptr_type,
X TREE_CODE (expr) == NOP_EXPR
X ? TREE_OPERAND (expr, 0) : expr);
X TREE_LITERAL (rval) = TREE_LITERAL (expr);
X return rval;
X}
X
X/* Same as above, but don't abort if we get an "ambiguous" baseclass.
X There's only one virtual baseclass we are looking for, and once
X we find one such virtual baseclass, we have found them all. */
X
Xtree
Xconvert_pointer_to_vbase (type, expr)
X tree type;
X tree expr;
X{
X tree intype = TREE_TYPE (TREE_TYPE (expr));
X int i;
X
X for (i = CLASSTYPE_N_BASECLASSES (intype); i > 0; i--)
X {
X tree basetype = CLASSTYPE_BASECLASS (intype, i);
X if (type == basetype)
X return convert_pointer_to (type, expr);
X if (value_member (TYPE_MAIN_VARIANT (type),
X CLASSTYPE_VBASECLASSES (basetype)))
X return convert_pointer_to_vbase (type, convert_pointer_to (TYPE_MAIN_VARIANT (basetype), expr));
X }
X abort ();
X}
X
X/* Create an expression whose value is that of EXPR,
X converted to type TYPE. The TREE_TYPE of the value
X is always TYPE. This function implements all reasonable
X conversions; callers should filter out those that are
X not permitted by the language being compiled. */
X
Xtree
Xconvert (type, expr)
X tree type, expr;
X{
X register tree e = expr;
X register enum tree_code code = TREE_CODE (type);
X
X if (type == TREE_TYPE (expr) || TREE_CODE (expr) == ERROR_MARK)
X return expr;
X if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
X return error_mark_node;
X if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE)
X {
X error ("void value not ignored as it ought to be");
X return error_mark_node;
X }
X if (code == VOID_TYPE)
X {
X tree rval = build_type_conversion (NOP_EXPR, type, e, 0);
X /* If we can convert to void type via a type conversion, do so. */
X if (rval)
X return rval;
X return build1 (CONVERT_EXPR, type, e);
X }
X#if 0
X /* This is incorrect. A truncation can't be stripped this way.
X Extensions will be stripped by the use of get_unwidened. */
X if (TREE_CODE (expr) == NOP_EXPR)
X return convert (type, TREE_OPERAND (expr, 0));
X#endif
X
X /* Just convert to the type of the member. */
X if (code == OFFSET_TYPE)
X {
X type = TREE_TYPE (type);
X code = TREE_CODE (type);
X }
X
X /* C++ */
X if (code == REFERENCE_TYPE)
X return fold (convert_to_reference (error_mark_node, type, e, -1, LOOKUP_NORMAL));
X else if (TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
X e = convert_from_reference (e);
X
X if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
X return fold (convert_to_integer (type, e));
X if (code == POINTER_TYPE)
X return fold (convert_to_pointer (type, e));
X if (code == REAL_TYPE)
X return fold (convert_to_real (type, e));
X
X /* New C++ semantics: since assignment is now based on
X memberwise copying, if the rhs type is derived from the
X lhs type, then we may still do a conversion. */
X if (IS_AGGR_TYPE_CODE (code))
X {
X tree dtype = TREE_TYPE (e);
X
X if (TREE_CODE (dtype) == REFERENCE_TYPE)
X {
X e = convert_from_reference (e);
X dtype = TREE_TYPE (e);
X }
X dtype = TYPE_MAIN_VARIANT (dtype);
X
X /* Conversion between aggregate types. New C++ semantics allow
X objects of derived type to be cast to objects of base type.
X Old semantics only allowed this bwteen pointers.
X
X There may be some ambiguity between using a constructor
X vs. using a type conversion operator when both apply. */
X
X if (IS_AGGR_TYPE (dtype))
X {
X tree basetype;
X
X tree conversion = TYPE_HAS_CONVERSION (dtype)
X ? build_type_conversion (CONVERT_EXPR, type, e, 1) : NULL_TREE;
X
X if (TYPE_HAS_CONSTRUCTOR (type))
X {
X tree rval = build_method_call (NULL_TREE, DECL_NAME (TYPE_NAME (type)), build_tree_list (NULL_TREE, e), CLASSTYPE_AS_LIST (type),
X conversion ? LOOKUP_NO_CONVERSION : 0);
X
X if (rval != error_mark_node)
X {
X if (conversion)
X {
X error ("both constructor and type conversion operator apply");
X return error_mark_node;
X }
X /* call to constructor successful. */
X rval = build_cplus_new (type, rval, 0);
X return rval;
X }
X }
X /* Type conversion successful/applies. */
X if (conversion)
X {
X if (conversion == error_mark_node)
X error ("ambiguous pointer conversion");
X return conversion;
X }
X
X /* now try normal C++ assignment semantics. */
X basetype = dtype;
X if (type == basetype
X || (basetype = get_base_type (type, dtype, 1)))
X {
X if (basetype == error_mark_node)
X return error_mark_node;
X
X#if 0
X if (TYPE_VIRTUAL_P (type))
X warning ("assignment to virtual aggregate type");
X#endif
X return build (COMPONENT_REF, type, e, TYPE_NAME (basetype));
X }
X error ("conversion between incompatible aggregate types requested");
X return error_mark_node;
X }
X /* conversion from non-aggregate to aggregate type requires constructor. */
X else if (TYPE_HAS_CONSTRUCTOR (type))
X {
X tree rval;
X tree init = build_method_call (NULL_TREE, DECL_NAME (TYPE_NAME (type)), build_tree_list (NULL_TREE, e), CLASSTYPE_AS_LIST (type), LOOKUP_NORMAL);
X if (init == error_mark_node)
X {
X error_with_aggr_type (type, "in conversion to type `%s'");
X return error_mark_node;
X }
X rval = build_cplus_new (type, init, 0);
X return rval;
X }
X }
X
X error ("conversion to non-scalar type requested");
X return error_mark_node;
X}
X
X/* Like convert, except permit conversions to take place which
X are not normally allowed due to visibility restrictions
X (such as conversion from sub-type to private super-type). */
Xtree
Xconvert_force (type, expr)
X tree type;
X tree expr;
X{
X register tree e = expr;
X register enum tree_code code = TREE_CODE (type);
X
X if (code == REFERENCE_TYPE)
X return fold (convert_to_reference (0, type, e, -1, 0));
X else if (TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
X e = convert_from_reference (e);
X
X if (code == POINTER_TYPE)
X return fold (convert_to_pointer_force (type, e));
X return convert (type, e);
X}
X
X/* Subroutine of build_type_conversion. */
Xstatic tree
Xbuild_type_conversion_1 (xtype, basetype, expr, typename, for_sure)
X tree xtype, basetype;
X tree expr;
X tree typename;
X int for_sure;
X{
X tree first_arg = expr;
X tree rval;
X int flags;
X
X if (for_sure == 0)
X {
X if (! lvalue_p (expr))
X first_arg = build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node);
X flags = LOOKUP_PROTECT;
X }
X else
X flags = LOOKUP_NORMAL;
X
X rval = build_method_call (first_arg, typename, NULL_TREE, NULL_TREE, flags);
X if (rval == error_mark_node)
X {
X if (for_sure == 0)
X return NULL_TREE;
X return error_mark_node;
X }
X if (first_arg != expr)
X {
X expr = build_up_reference (build_reference_type (TREE_TYPE (expr)), expr,
X LOOKUP_COMPLAIN);
X TREE_VALUE (TREE_OPERAND (rval, 1)) = build_unary_op (ADDR_EXPR, expr, 0);
X }
X if (TREE_CODE (TREE_TYPE (rval)) == REFERENCE_TYPE
X && TREE_CODE (xtype) != REFERENCE_TYPE)
X rval = default_conversion (rval);
X return convert (xtype, rval);
X}
X
X/* Convert an aggregate EXPR to type XTYPE. If a conversion
X exists, return the attempted conversion. This may
X return ERROR_MARK_NODE if the conversion is not
X allowed (references private members, etc).
X If no conversion exists, NULL_TREE is returned.
X
X If (FOR_SURE & 1) is non-zero, then we allow this type conversion
X to take place immediately. Otherwise, we build a SAVE_EXPR
X which can be evaluated if the results are ever needed.
X
X If FOR_SURE >= 2, then we only look for exact conversions.
X
X TYPE may be a reference type, in which case we first look
X for something that will convert to a reference type. If
X that fails, we will try to look for something of the
X reference's target type, and then return a reference to that. */
Xtree
Xbuild_type_conversion (code, xtype, expr, for_sure)
X enum tree_code code;
X tree xtype, expr;
X int for_sure;
X{
X /* C++: check to see if we can convert this aggregate type
X into the required scalar type. */
X tree type, type_default;
X tree typename = build_typename_overload (xtype), *typenames;
X int n_variants = 0;
X tree basetype, save_basetype;
X tree rval;
X int exact_conversion = for_sure >= 2;
X for_sure &= 1;
X
X if (expr == error_mark_node)
X return error_mark_node;
X
X basetype = TREE_TYPE (expr);
X if (TREE_CODE (basetype) == REFERENCE_TYPE)
X basetype = TREE_TYPE (basetype);
X
X basetype = TYPE_MAIN_VARIANT (basetype);
X if (! TYPE_LANG_SPECIFIC (basetype) || ! TYPE_HAS_CONVERSION (basetype))
X return 0;
X
X if (TREE_CODE (xtype) == POINTER_TYPE
X || TREE_CODE (xtype) == REFERENCE_TYPE)
X {
X /* Prepare to match a variant of this type. */
X type = TYPE_MAIN_VARIANT (TREE_TYPE (xtype));
X for (n_variants = 0; type; type = TYPE_NEXT_VARIANT (type))
X n_variants++;
X typenames = (tree *)alloca (n_variants * sizeof (tree));
X for (n_variants = 0, type = TYPE_MAIN_VARIANT (TREE_TYPE (xtype));
X type; n_variants++, type = TYPE_NEXT_VARIANT (type))
X {
X if (type == TREE_TYPE (xtype))
X typenames[n_variants] = typename;
X else if (TREE_CODE (xtype) == POINTER_TYPE)
X typenames[n_variants] = build_typename_overload (build_pointer_type (type));
X else
X typenames[n_variants] = build_typename_overload (build_reference_type (type));
X }
X }
X
X save_basetype = basetype;
X type = xtype;
X
X while (TYPE_HAS_CONVERSION (basetype))
X {
X int i;
X if (lookup_fnfields (CLASSTYPE_AS_LIST (basetype), typename, 0))
X return build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X for (i = 0; i < n_variants; i++)
X if (typenames[i] != typename
X && lookup_fnfields (CLASSTYPE_AS_LIST (basetype), typenames[i], 0))
X return build_type_conversion_1 (xtype, basetype, expr, typenames[i], for_sure);
X
X if (CLASSTYPE_N_BASECLASSES (basetype))
X basetype = CLASSTYPE_BASECLASS (basetype, 1);
X else break;
X }
X
X if (TREE_CODE (type) == REFERENCE_TYPE)
X {
X tree first_arg = expr;
X type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
X basetype = save_basetype;
X
X /* May need to build a temporary for this. */
X while (TYPE_HAS_CONVERSION (basetype))
X {
X if (lookup_fnfields (CLASSTYPE_AS_LIST (basetype), typename, 0))
X {
X int flags;
X
X if (for_sure == 0)
X {
X if (! lvalue_p (expr))
X first_arg = build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node);
X flags = LOOKUP_PROTECT;
X }
X else
X flags = LOOKUP_NORMAL;
X rval = build_method_call (first_arg, typename, NULL_TREE, NULL_TREE, flags);
X if (rval == error_mark_node)
X {
X if (for_sure == 0)
X return NULL_TREE;
X return error_mark_node;
X }
X TREE_VALUE (TREE_OPERAND (rval, 1)) = expr;
X
X if (IS_AGGR_TYPE (type))
X {
X tree init = build_method_call (NULL_TREE, DECL_NAME (TYPE_NAME (type)), build_tree_list (NULL_TREE, rval), NULL_TREE, LOOKUP_NORMAL);
X tree temp = build_cplus_new (type, init, 1);
X return build_up_reference (TYPE_REFERENCE_TO (type), temp,
X LOOKUP_COMPLAIN);
X }
X return convert (xtype, rval);
X }
X if (CLASSTYPE_N_BASECLASSES (basetype))
X basetype = CLASSTYPE_BASECLASS (basetype, 1);
X else break;
X }
X /* No free conversions for reference types, right?. */
X return NULL_TREE;
X }
X
X if (exact_conversion)
X return NULL_TREE;
X
X /* No perfect match found, try default. */
X if (code == CONVERT_EXPR && TREE_CODE (type) == POINTER_TYPE)
X type_default = ptr_type_node;
X else if (type == void_type_node)
X return NULL_TREE;
X else
X {
X extern tree default_conversion ();
X tree tmp = default_conversion (build1 (NOP_EXPR, type, integer_zero_node));
X if (tmp == error_mark_node)
X return NULL_TREE;
X type_default = TREE_TYPE (tmp);
X }
X
X basetype = save_basetype;
X
X if (type_default != type)
X {
X type = type_default;
X typename = build_typename_overload (type);
X
X while (TYPE_HAS_CONVERSION (basetype))
X {
X if (lookup_fnfields (CLASSTYPE_AS_LIST (basetype), typename, 0))
X return build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X if (CLASSTYPE_N_BASECLASSES (basetype))
X basetype = CLASSTYPE_BASECLASS (basetype, 1);
X else break;
X }
X }
X
X try_pointer:
X
X if (type == ptr_type_node)
X {
X /* Try converting to some other pointer type
X with which void* is compatible, or in situations
X in which void* is appropriate (such as &&,||, and !). */
X
X while (TYPE_HAS_CONVERSION (basetype))
X {
X if (CLASSTYPE_CONVERSION (basetype, ptr_conv) != 0)
X {
X if (CLASSTYPE_CONVERSION (basetype, ptr_conv) == error_mark_node)
X return error_mark_node;
X typename = DECL_ORIGINAL_NAME (CLASSTYPE_CONVERSION (basetype, ptr_conv));
X return build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X }
X if (CLASSTYPE_N_BASECLASSES (basetype))
X basetype = CLASSTYPE_BASECLASS (basetype, 1);
X else break;
X }
X }
X if (TREE_CODE (type) == POINTER_TYPE
X && TREE_READONLY (TREE_TYPE (type))
X && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
X {
X /* Try converting to some other pointer type
X with which const void* is compatible. */
X
X while (TYPE_HAS_CONVERSION (basetype))
X {
X if (CLASSTYPE_CONVERSION (basetype, constptr_conv) != 0)
X {
X if (CLASSTYPE_CONVERSION (basetype, constptr_conv) == error_mark_node)
X return error_mark_node;
X typename = DECL_ORIGINAL_NAME (CLASSTYPE_CONVERSION (basetype, constptr_conv));
X return build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X }
X if (CLASSTYPE_N_BASECLASSES (basetype))
X basetype = CLASSTYPE_BASECLASS (basetype, 1);
X else break;
X }
X }
X /* Use the longer or shorter conversion that is appropriate. */
X if (TREE_CODE (type) == INTEGER_TYPE
X && TYPE_HAS_INT_CONVERSION (basetype)
X && CLASSTYPE_CONVERSION (basetype, int_conv) != error_mark_node)
X {
X typename = DECL_ORIGINAL_NAME (CLASSTYPE_CONVERSION (basetype, int_conv));
X return build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X }
X if (TREE_CODE (type) == REAL_TYPE
X && TYPE_HAS_REAL_CONVERSION (basetype)
X && CLASSTYPE_CONVERSION (basetype, real_conv) != error_mark_node)
X {
X typename = DECL_ORIGINAL_NAME (CLASSTYPE_CONVERSION (basetype, real_conv));
X return build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X }
X
X /* THIS IS A KLUDGE. */
X if (TREE_CODE (type) != POINTER_TYPE
X && (code == TRUTH_ANDIF_EXPR
X || code == TRUTH_ORIF_EXPR
X || code == TRUTH_NOT_EXPR))
X {
X /* Here's when we can convert to a pointer. */
X type = ptr_type_node;
X goto try_pointer;
X }
X
X /* THESE ARE TOTAL KLUDGES. */
X /* Default promotion yields no new alternatives, try
X conversions which are anti-default, such as
X
X double -> float or int -> unsigned or unsigned -> long
X
X */
X if (type_default == type)
X {
X int not_again = 0;
X
X if (type == double_type_node)
X typename = build_typename_overload (float_type_node);
X else if (type == integer_type_node)
X typename = build_typename_overload (unsigned_type_node);
X else if (type == unsigned_type_node)
X typename = build_typename_overload (long_integer_type_node);
X
X again:
X basetype = save_basetype;
X while (TYPE_HAS_CONVERSION (basetype))
X {
X if (lookup_fnfields (CLASSTYPE_AS_LIST (basetype), typename, 0))
X return build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X if (CLASSTYPE_N_BASECLASSES (basetype))
X basetype = CLASSTYPE_BASECLASS (basetype, 1);
X else break;
X }
X if (! not_again && type == integer_type_node)
X {
X typename = build_typename_overload (long_integer_type_node);
X not_again = 1;
X goto again;
X }
X }
X
X /* Now, try C promotions...
X
X float -> int
X int -> float, void *
X void * -> int
X
X Truthvalue conversions let us try to convert
X to pointer if we were going for int, and to int
X if we were looking for pointer. */
X
X basetype = save_basetype;
X if (TREE_CODE (type) == REAL_TYPE
X || (TREE_CODE (type) == POINTER_TYPE
X && (code == TRUTH_ANDIF_EXPR
X || code == TRUTH_ORIF_EXPR
X || code == TRUTH_NOT_EXPR)))
X type = integer_type_node;
X else if (TREE_CODE (type) == INTEGER_TYPE)
X if (TYPE_HAS_REAL_CONVERSION (basetype))
X type = double_type_node;
X else
X return NULL_TREE;
X else
X return NULL_TREE;
X
X typename = build_typename_overload (type);
X while (TYPE_HAS_CONVERSION (basetype))
X {
X if (lookup_fnfields (CLASSTYPE_AS_LIST (basetype), typename, 0))
X {
X rval = build_type_conversion_1 (xtype, basetype, expr, typename, for_sure);
X return rval;
X }
X if (CLASSTYPE_N_BASECLASSES (basetype))
X basetype = CLASSTYPE_BASECLASS (basetype, 1);
X else
X break;
X }
X
X return NULL_TREE;
X}
X
X/* Must convert two aggregate types to non-aggregate type.
X Attempts to find a non-ambiguous, "best" type conversion.
X
X Return 1 on success, 0 on failure.
X
X @@ What are the real semantics of this supposed to be??? */
Xint
Xbuild_default_binary_type_conversion (code, arg1, arg2)
X enum tree_code code;
X tree *arg1, *arg2;
X{
X tree type1 = TREE_TYPE (*arg1);
X tree type2 = TREE_TYPE (*arg2);
X char *name1, *name2;
X
X if (TREE_CODE (type1) == REFERENCE_TYPE)
X type1 = TREE_TYPE (type1);
X if (TREE_CODE (type2) == REFERENCE_TYPE)
X type2 = TREE_TYPE (type2);
X
X if (TREE_CODE (TYPE_NAME (type1)) != TYPE_DECL)
X {
X tree decl = typedecl_for_tag (type1);
X if (decl)
X error ("type conversion nonexistant for type `%s'",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X else
X error ("type conversion nonexistant for non-C++ type");
X return 0;
X }
X if (TREE_CODE (TYPE_NAME (type2)) != TYPE_DECL)
X {
X tree decl = typedecl_for_tag (type2);
X if (decl)
X error ("type conversion nonexistant for type `%s'",
X IDENTIFIER_POINTER (decl));
X else
X error ("type conversion nonexistant for non-C++ type");
X return 0;
X }
X
X name1 = TYPE_NAME_STRING (type1);
X name2 = TYPE_NAME_STRING (type2);
X
X if (!IS_AGGR_TYPE (type1) || !TYPE_HAS_CONVERSION (type1))
X {
X if (!IS_AGGR_TYPE (type2) || !TYPE_HAS_CONVERSION (type2))
X error ("type conversion required for binary operation on types `%s' and `%s'",
X name1, name2);
X else
X error ("type conversion required for type `%s'", name1);
X return 0;
X }
X else if (!IS_AGGR_TYPE (type2) || !TYPE_HAS_CONVERSION (type2))
X {
X error ("type conversion required for type `%s'", name2);
X return 0;
X }
X
X if (TYPE_HAS_INT_CONVERSION (type1) && TYPE_HAS_REAL_CONVERSION (type1))
X warning ("ambiguous type conversion for type `%s', defaulting to int", name1);
X if (TYPE_HAS_INT_CONVERSION (type1))
X {
X *arg1 = build_type_conversion (code, integer_type_node, *arg1, 1);
X *arg2 = build_type_conversion (code, integer_type_node, *arg2, 1);
X }
X else if (TYPE_HAS_REAL_CONVERSION (type1))
X {
X *arg1 = build_type_conversion (code, double_type_node, *arg1, 1);
X *arg2 = build_type_conversion (code, double_type_node, *arg2, 1);
X }
X else
X {
X *arg1 = build_type_conversion (code, ptr_type_node, *arg1, 1);
X if (*arg1 == error_mark_node)
X error ("ambiguous pointer conversion");
X *arg2 = build_type_conversion (code, ptr_type_node, *arg2, 1);
X if (*arg1 != error_mark_node && *arg2 == error_mark_node)
X error ("ambiguous pointer conversion");
X }
X if (*arg1 == 0)
X {
X if (*arg2 == 0 && type1 != type2)
X error ("default type conversion for types `%s' and `%s' failed",
X name1, name2);
X else
X error ("default type conversion for type `%s' failed", name1);
X return 0;
X }
X else if (*arg2 == 0)
X {
X error ("default type conversion for type `%s' failed", name2);
X return 0;
X }
X return 1;
X}
X
X/* Must convert two aggregate types to non-aggregate type.
X Attempts to find a non-ambiguous, "best" type conversion.
X
X Return 1 on success, 0 on failure.
X
X The type of the argument is expected to be of aggregate type here.
X
X @@ What are the real semantics of this supposed to be??? */
Xint
Xbuild_default_unary_type_conversion (code, arg)
X enum tree_code code;
X tree *arg;
X{
X tree type = TREE_TYPE (*arg);
X tree id = TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
X ? DECL_NAME (TYPE_NAME (type)) : TYPE_NAME (type);
X char *name = IDENTIFIER_POINTER (id);
X
X if (! TYPE_HAS_CONVERSION (type))
X {
X error ("type conversion required for type `%s'", name);
X return 0;
X }
X
X if (TYPE_HAS_INT_CONVERSION (type) && TYPE_HAS_REAL_CONVERSION (type))
X warning ("ambiguous type conversion for type `%s', defaulting to int", name);
X if (TYPE_HAS_INT_CONVERSION (type))
X *arg = build_type_conversion (code, integer_type_node, *arg, 1);
X else if (TYPE_HAS_REAL_CONVERSION (type))
X *arg = build_type_conversion (code, double_type_node, *arg, 1);
X else
X {
X *arg = build_type_conversion (code, ptr_type_node, *arg, 1);
X if (*arg == error_mark_node)
X error ("ambiguous pointer conversion");
X }
X if (*arg == 0)
X {
X error ("default type conversion for type `%s' failed", name);
X return 0;
X }
X return 1;
X}
!EOF
echo "Extracting cplus-typeck.c..."
sed 's/^X//' >cplus-typeck.c << '!EOF'
X/* Build expressions with type checking for C compiler.
X Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
X Hacked by Michael Tiemann ([email protected])
X
XThis file is part of GNU CC.
X
XGNU CC is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU CC is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU CC; see the file COPYING. If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X
X/* This file is part of the C front end.
X It contains routines to build C expressions given their operands,
X including computing the types of the result, C-specific error checks,
X and some optimization.
X
X There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
X and to process initializations in declarations (since they work
X like a strange sort of assignment). */
X
Xextern void error ();
Xextern void warning ();
X
X#include "config.h"
X#include
X#include "tree.h"
X#include "cplus-tree.h"
X#include "flags.h"
X#include "assert.h"
X
X#include "obstack.h"
X#define obstack_chunk_alloc xmalloc
X#define obstack_chunk_free free
X
Xextern int xmalloc ();
Xextern void free ();
X
Xextern struct obstack *current_obstack;
X
Xint mark_addressable ();
Xstatic tree convert_for_assignment ();
X/* static */ tree convert_for_initialization ();
Xint compparms ();
Xint compparms1 ();
Xint comp_target_types ();
Xstatic tree shorten_compare ();
Xstatic void binary_op_error ();
Xstatic tree pointer_int_sum ();
Xstatic tree pointer_diff ();
Xstatic tree convert_sequence ();
X/* static */ tree unary_complex_lvalue ();
Xtree truthvalue_conversion ();
Xstatic tree invert_truthvalue ();
Xextern void readonly_warning_or_error ();
Xstatic void pedantic_lvalue_warning ();
X
Xstatic void
Xmessage_2_types (pfn, s, type1, type2)
X void (*pfn) ();
X char *s;
X tree type1, type2;
X{
X tree name1 = TYPE_NAME (type1);
X tree name2 = TYPE_NAME (type2);
X if (TREE_CODE (name1) == TYPE_DECL)
X name1 = DECL_NAME (name1);
X if (TREE_CODE (name2) == TYPE_DECL)
X name2 = DECL_NAME (name2);
X (*pfn) (s, IDENTIFIER_POINTER (name1), IDENTIFIER_POINTER (name2));
X}
X
X/* Return the _TYPE node describing the data type
X of the data which NODE represents as a C expression.
X Arrays and functions are converted to pointers
X just as they are when they appear as C expressions.
X
X C++: Member types are converted to the data
X type of the member they are. */
X
Xtree
Xdatatype (node)
X tree node;
X{
X register tree type = TREE_TYPE (node);
X if (TREE_CODE (type) == ARRAY_TYPE)
X return TYPE_POINTER_TO (TREE_TYPE (type));
X if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
X return build_pointer_type (type);
X if (TREE_CODE (type) == OFFSET_TYPE)
X return datatype (type);
X return type;
X}
X
X/* Return the target type of TYPE, which meas return T for:
X T*, T&, T[], T (...), and otherwise, just T. */
Xtree
Xtarget_type (type)
X tree type;
X{
X if (TREE_CODE (type) == REFERENCE_TYPE)
X type = TREE_TYPE (type);
X while (TREE_CODE (type) == POINTER_TYPE
X || TREE_CODE (type) == ARRAY_TYPE
X || TREE_CODE (type) == FUNCTION_TYPE
X || TREE_CODE (type) == METHOD_TYPE
X || TREE_CODE (type) == OFFSET_TYPE)
X type = TREE_TYPE (type);
X return type;
X}
X
X/* Do `exp = require_complete_type (exp);' to make sure exp
X does not have an incomplete type. (That includes void types.) */
X
Xtree
Xrequire_complete_type (value)
X tree value;
X{
X tree type = TREE_TYPE (value);
X
X /* First, detect a valid value with a complete type. */
X if (TYPE_SIZE (type) != 0
X && type != void_type_node)
X return value;
X
X /* If we see X::Y, we build an OFFSET_TYPE which has
X not been laid out. Try to avoid an error by interpreting
X it as this->X::Y, if reasonable. */
X if (TREE_CODE (value) == OFFSET_REF
X && C_C_D != 0
X && TREE_OPERAND (value, 0) == C_C_D)
X {
X tree base, member = TREE_OPERAND (value, 1);
X tree basetype = TYPE_OFFSET_BASETYPE (type);
X assert (TREE_CODE (member) == FIELD_DECL);
X base = convert_pointer_to (basetype, current_class_decl);
X value = build (COMPONENT_REF, TREE_TYPE (TREE_OPERAND (value, 1)),
X build_indirect_ref (base, 0),
X TREE_OPERAND (value, 1));
X return require_complete_type (value);
X }
X
X incomplete_type_error (value, type);
X return error_mark_node;
X}
X
X/* Return truthvalue of whether type of EXP is instantiated. */
Xint
Xtype_unknown_p (exp)
X tree exp;
X{
X return (TREE_CODE (exp) == TREE_LIST
X || TREE_TYPE (exp) == unknown_type_node
X || (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
X && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node));
X}
X
X/* Do `exp = require_instantiated_type (type, exp);' to make sure EXP
X does not have an uninstantiated type.
X TYPE is type to instantiate with, if uninstantiated. */
Xtree
Xrequire_instantiated_type (type, exp, errval)
X tree type, exp, errval;
X{
X if (TREE_TYPE (exp) == unknown_type_node
X || (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
X && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node))
X {
X exp = instantiate_type (type, exp, 1);
X if (TREE_TYPE (exp) == error_mark_node)
X return errval;
X }
X return exp;
X}
X
X/* Return a variant of TYPE which has all the type qualifiers of LIKE
X as well as those of TYPE. */
X
Xstatic tree
Xqualify_type (type, like)
X tree type, like;
X{
X int constflag = TREE_READONLY (type) || TREE_READONLY (like);
X int volflag = TREE_VOLATILE (type) || TREE_VOLATILE (like);
X /* @@ Must do member pointers here. */
X return build_type_variant (type, constflag, volflag);
X}
X
X/* Return the common type of two parameter lists.
X
X As an optimization, free the space we allocate if the parameter
X lists are already common. */
X
Xtree
Xcommonparms (p1, p2)
X tree p1, p2;
X{
X tree oldargs = p1, newargs, n;
X int i, len;
X int any_change = 0;
X char *first_obj = (char *)obstack_alloc (current_obstack, 0);
X
X len = list_length (p1);
X newargs = 0;
X
X for (i = 0; i < len; i++)
X newargs = tree_cons (0, 0, newargs);
X
X n = newargs;
X
X for (i = 0; p1;
X p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n), i++)
X {
X if (TREE_PURPOSE (p1) && !TREE_PURPOSE (p2))
X {
X#if 0
X if (! any_warning)
X {
X warning ("default argument given in prototype and not in declaration of function");
X any_warning++;
X }
X#endif
X TREE_PURPOSE (n) = TREE_PURPOSE (p1);
X any_change = 1;
X }
X else if (! TREE_PURPOSE (p1))
X {
X if (TREE_PURPOSE (p2))
X {
X TREE_PURPOSE (n) = TREE_PURPOSE (p2);
X any_change = 1;
X }
X }
X else
X {
X int cmp = simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2));
X if (cmp < 0)
X abort ();
X if (cmp == 0)
X {
X error ("redeclaration of default argument %d", i);
X any_change = 1;
X }
X TREE_PURPOSE (n) = TREE_PURPOSE (p2);
X }
X if (TREE_VALUE (p1) != TREE_VALUE (p2))
X {
X any_change = 1;
X TREE_VALUE (n) = commontype (TREE_VALUE (p1), TREE_VALUE (p2));
X }
X else
X TREE_VALUE (n) = TREE_VALUE (p1);
X }
X if (! any_change)
X {
X obstack_free (current_obstack, first_obj);
X return oldargs;
X }
X
X return newargs;
X}
X
X/* Return the common type of two types.
X We assume that comptypes has already been done and returned 1;
X if that isn't so, this may crash.
X
X This is the type for the result of most arithmetic operations
X if the operands have the given two types.
X
X We do not deal with enumeral types here because they have already been
X converted to integer types. */
X
Xtree
Xcommontype (t1, t2)
X tree t1, t2;
X{
X register enum tree_code form1;
X register enum tree_code form2;
X
X /* Save time if the two types are the same. */
X
X if (t1 == t2) return t1;
X
X /* Treat an enum type as the unsigned integer type of the same width. */
X
X if (TREE_CODE (t1) == ENUMERAL_TYPE)
X t1 = type_for_size (TYPE_PRECISION (t1), 1);
X if (TREE_CODE (t2) == ENUMERAL_TYPE)
X t2 = type_for_size (TYPE_PRECISION (t2), 1);
X
X form1 = TREE_CODE (t1);
X form2 = TREE_CODE (t2);
X
X switch (form1)
X {
X case INTEGER_TYPE:
X case REAL_TYPE:
X /* If only one is real, use it as the result. */
X
X if (form1 == REAL_TYPE && form2 != REAL_TYPE)
X return t1;
X
X if (form2 == REAL_TYPE && form1 != REAL_TYPE)
X return t2;
X
X /* Both real or both integers; use the one with greater precision. */
X
X if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
X return t1;
X else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
X return t2;
X
X /* Same precision. Prefer longs to ints even when same size. */
X
X if (t1 == long_unsigned_type_node
X || t2 == long_unsigned_type_node)
X return long_unsigned_type_node;
X
X if (t1 == long_integer_type_node
X || t2 == long_integer_type_node)
X {
X /* But preserve unsignedness from the other type,
X since long cannot hold all the values of an unsigned int. */
X if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
X return long_unsigned_type_node;
X return long_integer_type_node;
X }
X
X /* Otherwise prefer the unsigned one. */
X
X if (TREE_UNSIGNED (t1))
X return t1;
X else return t2;
X
X#if 1
X case POINTER_TYPE:
X case REFERENCE_TYPE:
X /* For two pointers, do this recursively on the target type,
X and combine the qualifiers of the two types' targets. */
X {
X tree target = commontype (TYPE_MAIN_VARIANT (TREE_TYPE (t1)),
X TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
X int constp
X = TREE_READONLY (TREE_TYPE (t1)) || TREE_READONLY (TREE_TYPE (t2));
X int volatilep
X = TREE_VOLATILE (TREE_TYPE (t1)) || TREE_VOLATILE (TREE_TYPE (t2));
X target = build_type_variant (target, constp, volatilep);
X if (form1 == POINTER_TYPE)
X return build_pointer_type (target);
X else
X return build_reference_type (target);
X }
X#else
X case POINTER_TYPE:
X return build_pointer_type (commontype (TREE_TYPE (t1), TREE_TYPE (t2)));
X
X case REFERENCE_TYPE:
X return build_reference_type (commontype (TREE_TYPE (t1), TREE_TYPE (t2)));
X#endif
X
X case ARRAY_TYPE:
X {
X tree elt = commontype (TREE_TYPE (t1), TREE_TYPE (t2));
X /* Save space: see if the result is identical to one of the args. */
X if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
X return t1;
X if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
X return t2;
X /* Merge the element types, and have a size if either arg has one. */
X return build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
X }
X
X case FUNCTION_TYPE:
X /* Function types: prefer the one that specified arg types.
X If both do, merge the arg types. Also merge the return types. */
X {
X tree valtype = commontype (TREE_TYPE (t1), TREE_TYPE (t2));
X tree p1 = TYPE_ARG_TYPES (t1);
X tree p2 = TYPE_ARG_TYPES (t2);
X tree rval, raises;
X
X /* Save space: see if the result is identical to one of the args. */
X if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2))
X return t1;
X if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1))
X return t2;
X
X /* Simple way if one arg fails to specify argument types. */
X if (TYPE_ARG_TYPES (t1) == 0)
X {
X rval = build_function_type (valtype, TYPE_ARG_TYPES (t2));
X if (raises = TYPE_RAISES_EXCEPTIONS (t2))
X rval = build_exception_variant (NULL_TREE, rval, raises);
X return rval;
X }
X raises = TYPE_RAISES_EXCEPTIONS (t1);
X if (TYPE_ARG_TYPES (t2) == 0)
X {
X rval = build_function_type (valtype, TYPE_ARG_TYPES (t1));
X if (raises)
X rval = build_exception_variant (NULL_TREE, rval, raises);
X return rval;
X }
X
X /* If both args specify argument types, we must merge the two
X lists, argument by argument. */
X rval = build_function_type (valtype, commonparms (p1, p2));
X return build_exception_variant (NULL_TREE, rval, raises);
X }
X
X case RECORD_TYPE:
X case UNION_TYPE:
X assert (TYPE_MAIN_VARIANT (t1) == t1 && TYPE_MAIN_VARIANT (t2) == t2);
X
X if (basetype_or_else (t1, t2))
X return t1;
X compiler_error ("commontype called with uncommon aggregate types");
X return t1;
X
X case METHOD_TYPE:
X if (TYPE_METHOD_BASETYPE (t1) == TYPE_METHOD_BASETYPE (t2)
X && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
X {
X /* Get this value the long way, since TYPE_METHOD_BASETYPE
X is just the main variant of this. */
X tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
X tree raises, t3;
X
X raises = TYPE_RAISES_EXCEPTIONS (t1);
X
X /* If this was a member function type, get back to the
X original type of type member function (i.e., without
X the class instance variable up front. */
X t1 = build_function_type (TREE_TYPE (t1), TREE_CHAIN (TYPE_ARG_TYPES (t1)));
X t2 = build_function_type (TREE_TYPE (t2), TREE_CHAIN (TYPE_ARG_TYPES (t2)));
X t3 = commontype (t1, t2);
X t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), TYPE_ARG_TYPES (t3));
X return build_exception_variant (basetype, t3, raises);
X }
X compiler_error ("commontype called with uncommon method types");
X return t1;
X
X case OFFSET_TYPE:
X if (TYPE_OFFSET_BASETYPE (t1) == TYPE_OFFSET_BASETYPE (t2)
X && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
X {
X tree basetype = TYPE_OFFSET_BASETYPE (t1);
X return build_member_type (basetype,
X commontype (TREE_TYPE (t1), TREE_TYPE (t2)));
X }
X compiler_error ("commontype called with uncommon member types");
X return t1;
X
X default:
X return t1;
X }
X}
X
X/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
Xint
Xcompexcepttypes (t1, t2, strict)
X tree t1, t2;
X int strict;
X{
X return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
X}
X
Xstatic int
Xcomp_array_types (cmp, t1, t2, strict)
X register int (*cmp)();
X tree t1, t2;
X{
X tree d1 = TYPE_DOMAIN (t1);
X tree d2 = TYPE_DOMAIN (t2);
X
X if (!(TREE_TYPE (t1) == TREE_TYPE (t2)
X || (*cmp) (TREE_TYPE (t1), TREE_TYPE (t2), strict)))
X return 0;
X
X /* Sizes must match unless one is missing or variable. */
X if (d1 == 0 || d2 == 0 || d1 == d2
X || TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
X || TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
X || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST
X || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)
X return 1;
X
X return ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (d1))
X == TREE_INT_CST_LOW (TYPE_MIN_VALUE (d2)))
X && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d1))
X == TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d2)))
X && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (d1))
X == TREE_INT_CST_LOW (TYPE_MAX_VALUE (d2)))
X && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d1))
X == TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d2))));
X}
X
X/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
X or various other operations. This is what ANSI C speaks of as
X "being the same".
X
X For C++: argument STRICT says we should be strict about this
X comparison:
X
X 1 : strict (compared according to ANSI C)
X 0 : <= (compared according to C++)
X -1: <= or >= (relaxed)
X
X Otherwise, pointers involving base classes and derived classes
X can be mixed as legal: i.e. a pointer to a base class may be assigned
X to a pointer to one of its derived classes, as per C++. A pointer to
X a derived class may be passed as a paramter to a function expecting a
X pointer to a base classes. These allowances do not commute. In this
X case, TYPE1 is assumed to be the base class, and TYPE2 is assumed to
X be the derived class. */
Xint
Xcomptypes (type1, type2, strict)
X tree type1, type2;
X int strict;
X{
X register tree t1 = type1;
X register tree t2 = type2;
X
X /* Suppress errors caused by previously reported errors */
X
X if (t1 == t2)
X return 1;
X /* This should never happen. */
X assert (t1 != error_mark_node);
X
X /* We don't want this to happen. */
X if (t2 == error_mark_node)
X {
X warning ("t2 == error_mark_node in `comptypes'");
X return 0;
X }
X
X if (strict < 0)
X {
X /* Treat an enum type as the unsigned integer type of the same width. */
X
X if (TREE_CODE (t1) == ENUMERAL_TYPE)
X t1 = type_for_size (TYPE_PRECISION (t1), 1);
X if (TREE_CODE (t2) == ENUMERAL_TYPE)
X t2 = type_for_size (TYPE_PRECISION (t2), 1);
X }
X
X if (t1 == t2)
X return 1;
X
X /* Different classes of types can't be compatible. */
X
X if (TREE_CODE (t1) != TREE_CODE (t2)) return 0;
X
X /* Qualifiers must match. */
X
X if (TREE_READONLY (t1) != TREE_READONLY (t2))
X return 0;
X if (TREE_THIS_VOLATILE (t1) != TREE_THIS_VOLATILE (t2))
X return 0;
X
X switch (TREE_CODE (t1))
X {
X case RECORD_TYPE:
X case UNION_TYPE:
X if (t1 == t2)
X return 1;
X if (strict <= 0)
X goto look_hard;
X return 0;
X
X case OFFSET_TYPE:
X return (comptypes (TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t1)),
X TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t2)), strict)
X && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
X
X case METHOD_TYPE:
X if (! compexcepttypes (t1, t2, strict))
X return 0;
X
X /* This case is anti-symmetrical!
X One can pass a base member (or member function)
X to something expecting a derived member (or member function),
X but not vice-versa! */
X
X return (comptypes (TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t2)),
X TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t1)), strict)
X && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
X && compparms (TREE_CHAIN (TYPE_ARG_TYPES (t1)),
X TREE_CHAIN (TYPE_ARG_TYPES(t2)), strict));
X case POINTER_TYPE:
X case REFERENCE_TYPE:
X t1 = TREE_TYPE (t1);
X t2 = TREE_TYPE (t2);
X if (t1 == t2)
X return 1;
X if (strict <= 0)
X {
X if (IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2))
X {
X int rval;
X look_hard:
X rval = t1 == t2 || get_base_distance (t1, t2, 0, 0) >= 0;
X
X if (rval)
X return 1;
X if (strict < 0)
X return (get_base_type (t2, t1, 0) != 0);
X }
X return 0;
X }
X else
X return comptypes (t1, t2, strict);
X
X case FUNCTION_TYPE:
X if (! compexcepttypes (t1, t2, strict))
X return 0;
X
X return ((TREE_TYPE (t1) == TREE_TYPE (t2)
X || comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
X && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2), strict));
X
X case ARRAY_TYPE:
X /* Target types must match incl. qualifiers. */
X return comp_array_types (&comptypes, t1, t2, strict);
X
X }
X return 0;
X}
X
X/* Return 1 if TTL and TTR are pointers to types that are equivalent,
X ignoring their qualifiers.
X
X NPTRS is the number of pointers we can strip off and keep cool.
X This is used to permit (for aggr A, aggr B) A, B* to convert to A*,
X but to not permit B** to convert to A**. */
X
Xint
Xcomp_target_types (ttl, ttr, nptrs)
X tree ttl, ttr;
X int nptrs;
X{
X ttl = TYPE_MAIN_VARIANT (ttl);
X ttr = TYPE_MAIN_VARIANT (ttr);
X if (ttl == ttr)
X return 1;
X
X if (TREE_CODE (ttr) != TREE_CODE (ttl))
X return 0;
X
X if (TREE_CODE (ttr) == POINTER_TYPE)
X return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs - 1);
X
X if (TREE_CODE (ttr) == REFERENCE_TYPE)
X return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
X if (TREE_CODE (ttr) == ARRAY_TYPE)
X return comp_array_types (&comp_target_types, ttl, ttr, 0);
X else if (TREE_CODE (ttr) == FUNCTION_TYPE || TREE_CODE (ttr) == METHOD_TYPE)
X if (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
X switch (comp_target_parms (TYPE_ARG_TYPES (ttl), TYPE_ARG_TYPES (ttr), -1))
X {
X case 0:
X return 0;
X case 1:
X return 1;
X case 2:
X warning ("contravariance violation for method types ignored");
X return 1;
X default:
X abort ();
X }
X else
X return 0;
X
X /* for C++ */
X else if (TREE_CODE (ttr) == OFFSET_TYPE)
X {
X /* Contravariance: we can assign a pointer to base member to a pointer
X to derived member. Note difference from simple pointer case, where
X we can pass a pointer to derived to a pointer to base. */
X if (comptypes (TYPE_OFFSET_BASETYPE (ttr), TYPE_OFFSET_BASETYPE (ttl), 0))
X return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
X else if (comptypes (TYPE_OFFSET_BASETYPE (ttl), TYPE_OFFSET_BASETYPE (ttr), 0)
X && comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
X {
X warning ("contravariance violation for member types ignored");
X return 1;
X }
X }
X else if (IS_AGGR_TYPE (ttl))
X {
X if (nptrs < 0)
X return 0;
X return comptypes (TYPE_POINTER_TO (ttl), TYPE_POINTER_TO (ttr), 0);
X }
X
X return 0;
X}
X
X/* If two types share a common base type, return that basetype.
X There is not a unique most-derived base type, this function
X returns ERROR_MARK_NODE. */
Xtree
Xcommon_base_type (tt1, tt2)
X tree tt1, tt2;
X{
X tree first = NULL_TREE, second = NULL_TREE, tmp;
X int i;
X
X for (i = CLASSTYPE_N_BASECLASSES (tt1); i > 0; i--)
X {
X tree basetype = CLASSTYPE_BASECLASS (tt1, i);
X switch (get_base_distance (basetype, tt2, 0, 0))
X {
X case -1:
X tmp = common_base_type (basetype, tt2);
X if (tmp == NULL_TREE)
X break;
X if (tmp == error_mark_node)
X return error_mark_node;
X if (first != NULL_TREE)
X return error_mark_node;
X first = tmp;
X break;
X
X case -2:
X first = error_mark_node;
X break;
X
X default:
X if (first != NULL_TREE)
X return error_mark_node;
X first = CLASSTYPE_BASECLASS (tt1, i);
X break;
X }
X }
X
X for (i = CLASSTYPE_N_BASECLASSES (tt2); i > 0; i--)
X {
X tree basetype = CLASSTYPE_BASECLASS (tt2, i);
X switch (get_base_distance (basetype, tt1, 0, 0))
X {
X case -1:
X tmp = common_base_type (basetype, tt1);
X if (tmp == NULL_TREE)
X break;
X if (tmp == error_mark_node)
X return error_mark_node;
X if (second != NULL_TREE)
X return error_mark_node;
X second = tmp;
X break;
X
X case -2:
X second = error_mark_node;
X break;
X
X default:
X if (second != NULL_TREE)
X return error_mark_node;
X second = CLASSTYPE_BASECLASS (tt2, i);
X break;
X }
X }
X
X if (first != NULL_TREE
X && second != NULL_TREE
X && TYPE_MAIN_VARIANT (first) == TYPE_MAIN_VARIANT (second))
X return first;
X if (first)
X return first;
X if (second)
X return second;
X
X return NULL_TREE;
X}
X
X/* Subroutines of `comptypes'. */
X
X/* Return 1 if two parameter type lists PARMS1 and PARMS2
X are equivalent in the sense that functions with those parameter types
X can have equivalent types.
X If either list is empty, we win.
X Otherwise, the two lists must be equivalent, element by element.
X
X C++: See comment above about TYPE1, TYPE2, STRICT.
X If STRICT == 3, it means checking is strict, but do not compare
X default parameter values. */
Xint
Xcompparms (parms1, parms2, strict)
X tree parms1, parms2;
X int strict;
X{
X register tree t1 = parms1, t2 = parms2;
X
X /* An unspecified parmlist matches any specified parmlist
X whose argument types don't need default promotions. */
X
X if (t1 == 0)
X return compparms1 (t2);
X if (t2 == 0)
X return compparms1 (t1);
X
X while (1)
X {
X if (t1 == 0 && t2 == 0)
X return 1;
X /* If one parmlist is shorter than the other,
X they fail to match, unless STRICT is <= 0. */
X if (t1 == 0 || t2 == 0)
X {
X if (strict > 0)
X return 0;
X if (strict < 0)
X return 1;
X if (strict == 0)
X return t1 && TREE_PURPOSE (t1);
X return ((t1 && TREE_PURPOSE (t1)) || TREE_PURPOSE (t2));
X }
X if (! comptypes (TREE_VALUE (t2), TREE_VALUE (t1), strict))
X {
X if (strict > 0)
X return 0;
X if (strict == 0)
X return t2 == void_list_node && TREE_PURPOSE (t1);
X return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
X }
X if (strict != 3 && TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
X {
X int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
X if (cmp < 0)
X abort ();
X if (cmp == 0)
X return 0;
X }
X
X t1 = TREE_CHAIN (t1);
X t2 = TREE_CHAIN (t2);
X }
X}
X
X/* This really wants return whether or not parameter type lists
X would make their owning functions assignment compatible or not. */
Xint
Xcomp_target_parms (parms1, parms2, strict)
X tree parms1, parms2;
X int strict;
X{
X register tree t1 = parms1, t2 = parms2;
X int warn_contravariance = 0;
X
X /* An unspecified parmlist matches any specified parmlist
X whose argument types don't need default promotions. */
X
X if (t1 == 0)
X return compparms1 (t2);
X if (t2 == 0)
X return compparms1 (t1);
X
X for (; t1 || t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
X {
X tree p1, p2;
X
X /* If one parmlist is shorter than the other,
X they fail to match, unless STRICT is <= 0. */
X if (t1 == 0 || t2 == 0)
X {
X if (strict > 0)
X return 0;
X if (strict < 0)
X return 1 + warn_contravariance;
X return ((t1 && TREE_PURPOSE (t1)) + warn_contravariance);
X }
X p1 = TREE_VALUE (t1);
X p2 = TREE_VALUE (t2);
X if (p1 == p2)
X continue;
X if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE)
X || (TREE_CODE (p1) == REFERENCE_TYPE && TREE_CODE (p2) == REFERENCE_TYPE))
X {
X /* The following is wrong for contravariance,
X but many programs depend on it. */
X if (TREE_TYPE (p1) == void_type_node)
X {
X warn_contravariance = 1;
X continue;
X }
X if (TREE_TYPE (p2) == void_type_node)
X continue;
X if (IS_AGGR_TYPE (TREE_TYPE (p1)))
X {
X if (comptypes (p2, p1, 0) == 0)
X {
X if (comptypes (p1, p2, 0) != 0)
X warn_contravariance = 1;
X else
X return 0;
X }
X continue;
X }
X }
X /* Note backwards order due to contravariance. */
X if (comp_target_types (p2, p1, 1) == 0)
X {
X if (comp_target_types (p1, p2, 1))
X {
X warn_contravariance = 1;
X continue;
X }
X if (strict > 0)
X return 0;
X#if 0
X /* What good do these cases do? */
X if (strict == 0)
X return p2 == void_type_node && TREE_PURPOSE (t1);
X return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
X#endif
X }
X /* Target types are compatible--just make sure that if
X we use parameter lists, that they are ok as well. */
X if (TREE_CODE (p1) == FUNCTION_TYPE || TREE_CODE (p1) == METHOD_TYPE)
X switch (comp_target_parms (TYPE_ARG_TYPES (p1), TYPE_ARG_TYPES (p2), strict))
X {
X case 0:
X return 0;
X case 1:
X break;
X case 2:
X warn_contravariance = 1;
X }
X
X if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
X {
X int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
X if (cmp < 0)
X abort ();
X if (cmp == 0)
X return 0;
X }
X }
X return 1 + warn_contravariance;
X}
X
X/* Return 1 if PARMS specifies a fixed number of parameters
X and none of their types is affected by default promotions. */
X
Xint
Xcompparms1 (parms)
X tree parms;
X{
X register tree t;
X for (t = parms; t; t = TREE_CHAIN (t))
X {
X register tree type = TREE_VALUE (t);
X
X if (TREE_CHAIN (t) == 0 && type != void_type_node)
X return 0;
X
X if (type == float_type_node)
X return 0;
X
X if (TREE_CODE (type) == INTEGER_TYPE
X && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
X return 0;
X }
X return 1;
X}
X
X/* Return an unsigned type the same as TYPE in other respects.
X
X C++: must make these work for type variants as well. */
X
Xtree
Xunsigned_type (type)
X tree type;
X{
X type = TYPE_MAIN_VARIANT (type);
X
X if (type == signed_char_type_node || type == char_type_node)
X return unsigned_char_type_node;
X if (type == integer_type_node)
X return unsigned_type_node;
X if (type == short_integer_type_node)
X return short_unsigned_type_node;
X if (type == long_integer_type_node)
X return long_unsigned_type_node;
X if (type == long_long_integer_type_node)
X return long_long_unsigned_type_node;
X return type;
X}
X
X/* Return a signed type the same as TYPE in other respects. */
X
Xtree
Xsigned_type (type)
X tree type;
X{
X if (type == unsigned_char_type_node || type == char_type_node)
X return signed_char_type_node;
X if (type == unsigned_type_node)
X return integer_type_node;
X if (type == short_unsigned_type_node)
X return short_integer_type_node;
X if (type == long_unsigned_type_node)
X return long_integer_type_node;
X if (type == long_long_unsigned_type_node)
X return long_long_integer_type_node;
X return type;
X}
X
X/* Return a type the same as TYPE except unsigned or
X signed according to UNSIGNEDP. */
X
Xtree
Xsigned_or_unsigned_type (unsignedp, type)
X int unsignedp;
X tree type;
X{
X if (TREE_CODE (type) != INTEGER_TYPE)
X return type;
X if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
X return unsignedp ? unsigned_char_type_node : signed_char_type_node;
X if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
X return unsignedp ? unsigned_type_node : integer_type_node;
X if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
X return unsignedp ? short_unsigned_type_node : short_integer_type_node;
X if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
X return unsignedp ? long_unsigned_type_node : long_integer_type_node;
X if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
X return (unsignedp ? long_long_unsigned_type_node
X : long_long_integer_type_node);
X return type;
X}
X
X/* Return an integer type with BITS bits of precision,
X that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
X
Xtree
Xtype_for_size (bits, unsignedp)
X int bits;
X int unsignedp;
X{
X if (bits <= TYPE_PRECISION (signed_char_type_node))
X return unsignedp ? unsigned_char_type_node : signed_char_type_node;
X
X if (bits <= TYPE_PRECISION (short_integer_type_node))
X return unsignedp ? short_unsigned_type_node : short_integer_type_node;
X
X if (bits <= TYPE_PRECISION (integer_type_node))
X return unsignedp ? unsigned_type_node : integer_type_node;
X
X if (bits <= TYPE_PRECISION (long_integer_type_node))
X return unsignedp ? long_unsigned_type_node : long_integer_type_node;
X
X if (bits <= TYPE_PRECISION (long_long_integer_type_node))
X return (unsignedp ? long_long_unsigned_type_node
X : long_long_integer_type_node);
X
X return 0;
X}
X
Xtree
Xget_floating_type (mode)
X enum machine_mode mode;
X{
X if (mode == TYPE_MODE (float_type_node))
X return float_type_node;
X if (mode == TYPE_MODE (double_type_node))
X return double_type_node;
X if (mode == TYPE_MODE (long_double_type_node))
X return long_double_type_node;
X abort ();
X}
X
Xtree
Xc_sizeof (type)
X tree type;
X{
X enum tree_code code = TREE_CODE (type);
X
X if (code == FUNCTION_TYPE)
X {
X if (pedantic || warn_pointer_arith)
X warning ("sizeof applied to a function type");
X return build_int (1);
X }
X if (code == METHOD_TYPE)
X {
X if (pedantic || warn_pointer_arith)
X warning ("sizeof applied to a method type");
X return build_int (1);
X }
X if (code == VOID_TYPE)
X {
X if (pedantic || warn_pointer_arith)
X warning ("sizeof applied to a void type");
X return build_int (1);
X }
X
X /* C++: this is really correct! */
X if (code == REFERENCE_TYPE)
X type = TREE_TYPE (type);
X
X return size_in_bytes (type);
X}
X
Xtree
Xc_sizeof_nowarn (type)
X tree type;
X{
X enum tree_code code = TREE_CODE (type);
X
X if (code == FUNCTION_TYPE
X || code == METHOD_TYPE
X || code == VOID_TYPE)
X return build_int (1);
X if (code == REFERENCE_TYPE)
X type = TREE_TYPE (type);
X
X return size_in_bytes (type);
X}
X
X/* Implement the __alignof keyword: Return the minimum required
X alignment of TYPE, measured in bytes. */
X
Xtree
Xc_alignof (type)
X tree type;
X{
X enum tree_code code = TREE_CODE (type);
X
X if (code == FUNCTION_TYPE || code == METHOD_TYPE)
X return build_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
X
X if (code == VOID_TYPE)
X return build_int (1);
X
X /* C++: this is really correct! */
X if (code == REFERENCE_TYPE)
X type = TREE_TYPE (type);
X
X return build_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
X}
X
X/* Perform default promotions for C data used in expressions.
X Arrays and functions are converted to pointers;
X enumeral types or short or char, to int.
X In addition, manifest constants symbols are replaced by their values.
X
X C++: this will automatically bash references to their target type. */
X
Xtree
Xdefault_conversion (exp)
X tree exp;
X{
X register tree dt = TREE_TYPE (exp);
X register enum tree_code form = TREE_CODE (dt);
X
X if (form == OFFSET_TYPE)
X {
X#if 0
X warning ("conversion from member type");
X#endif
X if (TREE_CODE (exp) == OFFSET_REF)
X return default_conversion (resolve_offset_ref (exp));
X
X dt = TREE_TYPE (dt);
X form = TREE_CODE (dt);
X }
X
X if (form == REFERENCE_TYPE)
X {
X exp = convert_from_reference (exp);
X dt = TREE_TYPE (exp);
X form = TREE_CODE (dt);
X }
X
X if (TREE_CODE (exp) == CONST_DECL)
X exp = DECL_INITIAL (exp);
X else if (TREE_READONLY_DECL_P (exp))
X {
X exp = decl_constant_value (exp);
X dt = TREE_TYPE (exp);
X }
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since EXP is being used in non-lvalue context. */
X if (TREE_CODE (exp) == NOP_EXPR
X && TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0)))
X exp = TREE_OPERAND (exp, 0);
X
X if (form == ENUMERAL_TYPE
X || (form == INTEGER_TYPE
X && (TYPE_PRECISION (dt)
X < TYPE_PRECISION (integer_type_node))))
X {
X /* Traditionally, unsignedness is preserved in default promotions. */
X if (flag_traditional && TREE_UNSIGNED (dt))
X return convert (unsigned_type_node, exp);
X return convert (integer_type_node, exp);
X }
X if (flag_traditional && dt == float_type_node)
X return convert (double_type_node, exp);
X if (form == VOID_TYPE)
X {
X error ("void value not ignored as it ought to be");
X return error_mark_node;
X }
X if (form == FUNCTION_TYPE || form == METHOD_TYPE)
X {
X return build_unary_op (ADDR_EXPR, exp, 0);
X }
X if (form == ARRAY_TYPE)
X {
X register tree adr;
X tree restype = TREE_TYPE (dt);
X tree ptrtype;
X
X if (TREE_CODE (exp) == INDIRECT_REF)
X {
X /* Stripping away the INDIRECT_REF is not the right
X thing to do for references... */
X tree inner = TREE_OPERAND (exp, 0);
X if (TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE)
X inner = build1 (REFERENCE_EXPR,
X build_pointer_type (TREE_TYPE (TREE_TYPE (inner))),
X inner);
X return convert (TYPE_POINTER_TO (TREE_TYPE (dt)), inner);
X }
X
X if (TREE_CODE (exp) == COMPOUND_EXPR)
X {
X tree op1 = default_conversion (TREE_OPERAND (exp, 1));
X return build (COMPOUND_EXPR, TREE_TYPE (op1),
X TREE_OPERAND (exp, 0), op1);
X }
X
X if (!lvalue_p (exp)
X && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
X {
X error ("invalid use of non-lvalue array");
X return error_mark_node;
X }
X
X if (TREE_READONLY (exp) || TREE_THIS_VOLATILE (exp))
X restype = build_type_variant (restype, TREE_READONLY (exp),
X TREE_THIS_VOLATILE (exp));
X
X ptrtype = build_pointer_type (restype);
X
X if (TREE_CODE (exp) == VAR_DECL)
X {
X /* ??? This is not really quite correct
X in that the type of the operand of ADDR_EXPR
X is not the target type of the type of the ADDR_EXPR itself.
X Question is, can this lossage be avoided? */
X adr = build1 (ADDR_EXPR, ptrtype, exp);
X if (mark_addressable (exp) == 0)
X return error_mark_node;
X TREE_LITERAL (adr) = staticp (exp);
X TREE_VOLATILE (adr) = 0; /* Default would be, same as EXP. */
X return adr;
X }
X /* This way is better for a COMPONENT_REF since it can
X simplify the offset for a component. */
X adr = build_unary_op (ADDR_EXPR, exp, 1);
X return convert (ptrtype, adr);
X }
X return exp;
X}
X
X/* Like `build_component_ref, but uses an already found field.
X Must compute visibility for C_C_D. Otherwise, ok. */
Xtree
Xbuild_component_ref_1 (datum, field, protect)
X tree datum, field;
X int protect;
X{
X register tree basetype = TREE_TYPE (datum);
X register enum tree_code form = TREE_CODE (basetype);
X register tree ref;
X
X if (form == REFERENCE_TYPE)
X {
X datum = convert_from_reference (datum);
X basetype = TREE_TYPE (datum);
X form = TREE_CODE (basetype);
X }
X
X if (! IS_AGGR_TYPE_CODE (form))
X {
X if (form != ERROR_MARK)
X error_with_decl (field, "request for member `%s' in something not a class, structure or union");
X return error_mark_node;
X }
X
X if (TYPE_SIZE (basetype) == 0)
X {
X incomplete_type_error (0, basetype);
X return error_mark_node;
X }
X
X /* Look up component name in the structure type definition. */
X
X if (field == error_mark_node)
X abort ();
X
X if (TREE_STATIC (field))
X return field;
X
X if (datum == C_C_D && ! TREE_FIELD_PUBLIC (field))
X {
X enum visibility_type visibility
X = compute_visibility (build_tree_list (NULL_TREE, current_class_type),
X field);
X
X if (visibility == visibility_private)
X {
X error_with_decl (field, "field `%s' is private");
X return error_mark_node;
X }
X else if (visibility == visibility_protected)
X {
X error_with_decl (field, "field `%s' is protected");
X return error_mark_node;
X }
X }
X
X ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
X
X if (TREE_READONLY (datum) || TREE_READONLY (field))
X TREE_READONLY (ref) = 1;
X if (TREE_THIS_VOLATILE (datum) || TREE_VOLATILE (field))
X TREE_THIS_VOLATILE (ref) = 1;
X
X return ref;
X}
X
Xtree
Xbuild_component_ref (datum, component, basetype_path, protect)
X tree datum, component, basetype_path;
X int protect;
X{
X tree basetypes;
X register tree basetype = TREE_TYPE (datum);
X register enum tree_code code = TREE_CODE (basetype);
X register tree field = NULL;
X register tree ref;
X
X if (code == REFERENCE_TYPE)
X {
X#if 0
X /* REFERENCE_EXPRs are not converted by `convert_from_reference'.
X @@ Maybe that is not right. */
X if (TREE_CODE (datum) == REFERENCE_EXPR)
X datum = build1 (INDIRECT_REF, TREE_TYPE (basetype), datum);
X else
X#endif
X datum = convert_from_reference (datum);
X basetype = TREE_TYPE (datum);
X code = TREE_CODE (basetype);
X }
X
X /* First, see if there is a field or component with name COMPONENT. */
X if (TREE_CODE (component) == TREE_LIST)
X {
X assert (!(TREE_CHAIN (component) == NULL_TREE && TREE_CHAIN (TREE_VALUE (component)) == NULL_TREE));
X return build (COMPONENT_REF, TREE_TYPE (component), datum, component);
X }
X if (TREE_CODE (component) == TYPE_EXPR)
X return build_component_type_expr (datum, component, NULL_TREE, protect);
X
X if (! IS_AGGR_TYPE_CODE (code))
X {
X if (code != ERROR_MARK)
X error ("request for member `%s' in something not a class, structure or union",
X IDENTIFIER_POINTER (component));
X return error_mark_node;
X }
X
X if (TYPE_SIZE (basetype) == 0)
X {
X incomplete_type_error (0, basetype);
X return error_mark_node;
X }
X
X if (TREE_CODE (component) == BIT_NOT_EXPR)
X {
X if (DECL_NAME (TYPE_NAME (basetype)) != TREE_OPERAND (component, 0))
X {
X error_with_aggr_type (basetype,
X "destructor specifier `%s::~%s' must have matching names",
X IDENTIFIER_POINTER (TREE_OPERAND (component, 0)));
X return error_mark_node;
X }
X if (! TYPE_HAS_DESTRUCTOR (basetype))
X {
X error_with_aggr_type (basetype, "type `%s' has no destructor");
X return error_mark_node;
X }
X return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
X }
X
X /* Look up component name in the structure type definition. */
X if (basetype_path == NULL_TREE)
X basetype_path = CLASSTYPE_AS_LIST (basetype);
X basetypes = basetype_path;
X field = lookup_field (basetypes, component,
X protect && ! VFIELD_NAME_P (component));
X
X if (field == error_mark_node)
X return error_mark_node;
X
X if (field == NULL_TREE)
X {
X /* Not found as a data field, look for it as a method. If found,
X then if this is the only possible one, return it, else
X report ambiguity error. */
X tree fndecls = lookup_fnfields (basetype_path, component, 1);
X if (fndecls)
X {
X if (TREE_CHAIN (fndecls) == NULL_TREE
X && TREE_CHAIN (TREE_VALUE (fndecls)) == NULL_TREE)
X {
X enum visibility_type visibility;
X tree fndecl;
X
X /* Unique, so use this one now. */
X basetype = TREE_PURPOSE (fndecls);
X fndecl = TREE_VALUE (fndecls);
X visibility = compute_visibility (TREE_PURPOSE (fndecls), fndecl);
X if (visibility == visibility_public)
X {
X if (DECL_VIRTUAL_P (fndecl)
X && ! resolves_to_fixed_type_p (datum))
X {
X tree addr = build_unary_op (ADDR_EXPR, datum, 0);
X addr = convert_pointer_to (DECL_VCONTEXT (fndecl), addr);
X datum = build_indirect_ref (addr);
X assert (datum != error_mark_node);
X fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
X }
X return fndecl;
X }
X if (visibility == visibility_protected)
X error_with_decl (fndecl, "member function `%s' is protected");
X else
X error_with_decl (fndecl, "member function `%s' is private");
X return error_mark_node;
X }
X else
X return build (COMPONENT_REF, unknown_type_node, datum, fndecls);
X }
X
X if (OPERATOR_TYPENAME_P (component))
X error ("%s has no such type conversion operator",
X code == RECORD_TYPE ? "structure" : "union");
X else if (TREE_CODE (component) == BIT_NOT_EXPR)
X error ("%s has no destructor",
X code == RECORD_TYPE ? "structure" : "union");
X else
X error (code == RECORD_TYPE
X ? "structure has no member named `%s'"
X : "union has no member named `%s'",
X IDENTIFIER_POINTER (component));
X return error_mark_node;
X }
X else if (TREE_TYPE (field) == error_mark_node)
X return error_mark_node;
X
X if (TREE_CODE (field) != FIELD_DECL)
X {
X TREE_USED (field) = 1;
X return field;
X }
X
X if (DECL_FIELD_CONTEXT (field) != basetype
X && (TYPE_USES_MULTIPLE_INHERITANCE (basetype)
X || TYPE_USES_VIRTUAL_BASECLASSES (basetype)))
X {
X tree addr = build_unary_op (ADDR_EXPR, datum, 0);
X if (integer_zerop (addr))
X {
X error ("invalid reference to NULL ptr, use ptr-to-member instead");
X return error_mark_node;
X }
X addr = convert_pointer_to (DECL_FIELD_CONTEXT (field), addr);
X datum = build_indirect_ref (addr);
X assert (datum != error_mark_node);
X }
X ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
X
X if (TREE_READONLY (datum) || TREE_READONLY (field))
X TREE_READONLY (ref) = 1;
X if (TREE_THIS_VOLATILE (datum) || TREE_VOLATILE (field))
X TREE_THIS_VOLATILE (ref) = 1;
X
X return ref;
X}
X
X/* Given an expression PTR for a pointer, return an expression
X for the value pointed to.
X ERRORSTRING is the name of the operator to appear in error messages.
X
X This function may need to overload OPERATOR_FNNAME.
X Must also handle REFERENCE_TYPEs for C++. */
X
Xtree
Xbuild_x_indirect_ref (ptr, errorstring)
X tree ptr;
X char *errorstring;
X{
X tree rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr);
X
X if (rval) return rval;
X return build_indirect_ref (ptr, errorstring);
X}
X
Xtree
Xbuild_indirect_ref (ptr, errorstring)
X tree ptr;
X char *errorstring;
X{
X register tree pointer = default_conversion (ptr);
X register tree dt = TREE_TYPE (pointer);
X
X if (ptr == current_class_decl)
X return C_C_D;
X
X if (TREE_CODE (dt) == POINTER_TYPE || TREE_CODE (dt) == REFERENCE_TYPE)
X if (TREE_CODE (pointer) == ADDR_EXPR
X && (TREE_TYPE (TREE_OPERAND (pointer, 0))
X == TREE_TYPE (dt)))
X return TREE_OPERAND (pointer, 0);
X else
X {
X tree t = TREE_TYPE (dt);
X register tree ref = build1 (INDIRECT_REF,
X TYPE_MAIN_VARIANT (t), pointer);
X
X TREE_READONLY (ref) = TREE_READONLY (t);
X TREE_VOLATILE (ref) = TREE_VOLATILE (t) || TREE_VOLATILE (pointer);
X TREE_THIS_VOLATILE (ref) = TREE_VOLATILE (t);
X return ref;
X }
X else if (pointer != error_mark_node)
X error ("invalid type argument of `%s'", errorstring);
X return error_mark_node;
X}
X
X/* This handles expressions of the form "a[i]", which denotes
X an array reference.
X
X This is logically equivalent in C to *(a+i), but we may do it differently.
X If A is a variable or a member, we generate a primitive ARRAY_REF.
X This avoids forcing the array out of registers, and can work on
X arrays that are not lvalues (for example, members of structures returned
X by functions).
X
X If INDEX is of some user-defined type, it must be converted to
X integer type. Otherwise, to make a compatible PLUS_EXPR, it
X will inherit the type of the array, which will be some pointer type. */
X
Xtree
Xbuild_x_array_ref (array, index)
X tree array, index;
X{
X tree rval;
X
X rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, index);
X if (rval)
X return rval;
X return build_array_ref (array, index);
X}
X
Xtree
Xbuild_array_ref (array, index)
X tree array, index;
X{
X tree itype;
X tree rval;
X
X if (index == 0)
X {
X error ("subscript missing in array reference");
X return error_mark_node;
X }
X
X itype = TREE_TYPE (index);
X if (TREE_CODE (itype) == REFERENCE_TYPE)
X {
X index = convert_from_reference (index);
X itype = TREE_TYPE (index);
X }
X
X if (IS_AGGR_TYPE (itype))
X if (TYPE_HAS_INT_CONVERSION (itype))
X index = build_type_conversion (CONVERT_EXPR, integer_type_node, index, 1);
X else
X {
X error_with_aggr_type (itype, "type `%s' requires integer conversion for array indexing");
X return error_mark_node;
X }
X
X if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
X && TREE_CODE (array) != INDIRECT_REF)
X {
X index = default_conversion (index);
X if (index != error_mark_node
X && TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE)
X {
X error ("array subscript is not an integer");
X return error_mark_node;
X }
X
X /* An array that is indexed by a non-constant
X cannot be stored in a register; we must be able to do
X address arithmetic on its address.
X Likewise an array of elements of variable size. */
X if (TREE_CODE (index) != INTEGER_CST
X || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0
X && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST))
X {
X if (mark_addressable (array) == 0)
X return error_mark_node;
X }
X
X if (pedantic && !lvalue_p (array))
X warning ("ANSI C forbids subscripting non-lvalue array");
X
X if (pedantic)
X {
X tree foo = array;
X while (TREE_CODE (foo) == COMPONENT_REF)
X foo = TREE_OPERAND (foo, 0);
X if (TREE_CODE (foo) == VAR_DECL && TREE_REGDECL (foo))
X warning ("ANSI C forbids subscripting non-lvalue array");
X }
X
X rval = build (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)), array, index);
X /* Array ref is const/volatile if the array elements are. */
X TREE_READONLY (rval) |= TREE_READONLY (TREE_TYPE (TREE_TYPE (array)));
X TREE_VOLATILE (rval) |= TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array)));
X TREE_THIS_VOLATILE (rval) |= TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array)));
X return require_complete_type (fold (rval));
X }
X
X {
X tree ar = default_conversion (array);
X tree ind = default_conversion (index);
X
X if ((TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE
X && TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE)
X || (TREE_CODE (TREE_TYPE (ind)) == POINTER_TYPE
X && TREE_CODE (TREE_TYPE (ar)) != INTEGER_TYPE))
X {
X error ("array subscript is not an integer");
X return error_mark_node;
X }
X
X return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar, ind, PLUS_EXPR),
X "array indexing");
X }
X}
X
X/* Build a function call to function FUNCTION with parameters PARAMS.
X PARAMS is a list--a chain of TREE_LIST nodes--in which the
X TREE_VALUE of each node is a parameter-expression.
X FUNCTION's data type may be a function type or a pointer-to-function.
X
X For C++: If FUNCTION's data type is a TREE_LIST, then the tree list
X is the list of possible methods that FUNCTION could conceivably
X be. If the list of methods comes from a class, then it will be
X a list of lists (where each element is associated with the class
X that produced it), otherwise it will be a simple list (for
X functions overloaded in global scope).
X
X In the first case, TREE_VALUE (function) is the head of one of those
X lists, and TREE_PURPOSE is the name of the function.
X
X In the second case, TREE_PURPOSE (function) is the function's
X name directly.
X
X DECL is the class instance variable, usually CURRENT_CLASS_DECL. */
X
Xtree
Xbuild_x_function_call (function, params, decl)
X tree function, params, decl;
X{
X tree type = TREE_TYPE (function);
X int may_be_method
X = ((TREE_CODE (function) == TREE_LIST
X && current_class_type != NULL_TREE
X && IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function)) == function)
X || TREE_CODE (function) == IDENTIFIER_NODE
X || TREE_CODE (type) == METHOD_TYPE);
X
X /* Handle methods, friends, and overloaded functions, respectively. */
X if (may_be_method)
X {
X if (TREE_CODE (function) == FUNCTION_DECL)
X function = DECL_ORIGINAL_NAME (function);
X else if (TREE_CODE (function) == TREE_LIST)
X {
X#if 0
X if (TREE_CODE (TREE_VALUE (function)) == TREE_LIST)
X function = TREE_PURPOSE (TREE_VALUE (function));
X else
X function = TREE_PURPOSE (function);
X#else
X assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL);
X function = TREE_PURPOSE (function);
X#endif
X }
X else if (TREE_CODE (function) != IDENTIFIER_NODE)
X {
X /* Call via a pointer to member function. */
X if (decl == NULL_TREE)
X {
X error ("pointer to member function called, but not in class scope");
X return error_mark_node;
X }
X function = build (OFFSET_REF, TREE_TYPE (type), NULL_TREE, function);
X goto do_x_function;
X }
X
X /* this is an abbreviated method call.
X must go through here in case it is a virtual function.
X @@ Perhaps this could be optimized. */
X
X if (decl == NULL_TREE)
X {
X if (current_class_type == NULL_TREE)
X {
X error ("object missing in call to method `%s'",
X IDENTIFIER_POINTER (function));
X return error_mark_node;
X }
X /* Yow: call from a static member function. */
X decl = build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), error_mark_node);
X }
X
X return build_method_call (decl, function, params, NULL_TREE, LOOKUP_NORMAL);
X }
X else if (TREE_CODE (function) == COMPONENT_REF
X && type == unknown_type_node)
X {
X function = TREE_PURPOSE (TREE_OPERAND (function, 1));
X return build_method_call (decl, function, params, NULL_TREE, LOOKUP_NORMAL);
X }
X else if (TREE_CODE (function) == TREE_LIST)
X {
X if (TREE_CHAIN (function) != NULL_TREE)
X return build_overload_call (TREE_PURPOSE (function), params, 1, 0);
X else if (TREE_VALUE (function) != NULL_TREE)
X function = TREE_VALUE (function);
X else
X {
X error ("function `%s' declared overloaded, but no definitions appear with which to resolve it",
X IDENTIFIER_POINTER (TREE_PURPOSE (function)));
X return error_mark_node;
X }
X }
X else if (TREE_CODE (type) == POINTER_TYPE
X && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
X && (TREE_CODE (function) == VAR_DECL
X || TREE_CODE (function) == PARM_DECL
X || TREE_CODE (function) == FIELD_DECL))
X {
X error_with_decl (function, "call via pointer-to-member-function `%s' must be composed with object");
X return error_mark_node;
X }
X
X do_x_function:
X if (TREE_CODE (function) == OFFSET_REF)
X {
X /* If the component is a data element (or a virtual function), we play
X games here to make things work. */
X tree decl_addr;
X
X if (TREE_OPERAND (function, 0))
X decl = TREE_OPERAND (function, 0);
X else
X decl = C_C_D;
X
X decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
X function = get_member_function (&decl_addr, decl, TREE_OPERAND (function, 1));
X params = tree_cons (NULL_TREE, decl_addr, params);
X return build_function_call (function, params);
X }
X
X type = TREE_TYPE (function);
X if (TREE_CODE (type) == REFERENCE_TYPE)
X type = TREE_TYPE (type);
X
X if (TYPE_LANG_SPECIFIC (type) && TYPE_OVERLOADS_CALL_EXPR (type))
X return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params);
X
X if (may_be_method)
X {
X tree ctypeptr = TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (TREE_TYPE (function)));
X if (decl == NULL_TREE)
X {
X if (current_function_decl
X && DECL_STATIC_FUNCTION_P (current_function_decl))
X error ("invalid call to member function needing `this' in static member function scope");
X else
X error ("pointer to member function called, but not in class scope");
X return error_mark_node;
X }
X if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE)
X {
X decl = build_unary_op (ADDR_EXPR, decl, 0);
X decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
X }
X else
X decl = build_c_cast (ctypeptr, decl);
X params = tree_cons (NULL_TREE, decl, params);
X }
X
X return build_function_call (function, params);
X}
X
Xtree
Xbuild_function_call (function, params)
X tree function, params;
X{
X register tree fntype, fndecl;
X register tree value_type;
X register tree coerced_params;
X tree actualparameterlist ();
X int is_method;
X
X#ifdef FIELD_XREF
X if (TREE_CODE(function) == FUNCTION_DECL)
X FIELD_xref_call(current_function_decl,
X IDENTIFIER_POINTER(DECL_NAME(function)));
X#endif
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since FUNCTION is used in non-lvalue context. */
X if (TREE_CODE (function) == NOP_EXPR
X && TREE_TYPE (function) == TREE_TYPE (TREE_OPERAND (function, 0)))
X function = TREE_OPERAND (function, 0);
X
X if (TREE_CODE (function) == FUNCTION_DECL)
X fndecl = function;
X else
X fndecl = NULL_TREE;
X
X /* Convert anything with function type to a pointer-to-function. */
X if (TREE_CODE (function) == FUNCTION_DECL)
X {
X if (pedantic
X && IDENTIFIER_LENGTH (DECL_NAME (function)) == 4
X && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (function)), "main"))
X {
X error ("cannot call `main' from within program");
X return error_mark_node;
X }
X
X /* Differs from default_conversion by not setting TREE_ADDRESSABLE
X (because calling an inline function does not mean the function
X needs to be separately compiled). */
X
X if (! TREE_INLINE (function))
X TREE_USED (function) = 1;
X
X function = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (function)),
X function);
X }
X else
X {
X if (function == error_mark_node)
X return error_mark_node;
X function = default_conversion (function);
X }
X
X fntype = TREE_TYPE (function);
X
X is_method = (TREE_CODE (fntype) == POINTER_TYPE
X && TREE_CODE (TREE_TYPE (fntype)) == METHOD_TYPE);
X
X if (!(TREE_CODE (fntype) == POINTER_TYPE
X && (TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE || is_method)))
X {
X error ("called object is not a function");
X return error_mark_node;
X }
X
X /* fntype now gets the type of function pointed to. */
X fntype = TREE_TYPE (fntype);
X
X /* Convert the parameters to the types declared in the
X function prototype, or apply default promotions. */
X
X coerced_params = actualparameterlist (NULL_TREE, TYPE_ARG_TYPES (fntype), params, fndecl, LOOKUP_NORMAL);
X
X /* Recognize certain built-in functions so we can make tree-codes
X other than CALL_EXPR. We do this when it enables fold-const.c
X to do something useful. */
X
X if (TREE_CODE (function) == ADDR_EXPR
X && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
X switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
X {
X case BUILT_IN_ABS:
X case BUILT_IN_LABS:
X case BUILT_IN_FABS:
X if (coerced_params == 0)
X return integer_zero_node;
X return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
X }
X
X value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
X
X if (is_method)
X {
X tree parm = TREE_VALUE (coerced_params);
X tree parmtype = TREE_TYPE (parm);
X if (parmtype == error_mark_node)
X return error_mark_node;
X
X parmtype = TREE_TYPE (parmtype);
X if (TYPE_NEEDS_WRAPPER (parmtype))
X {
X if (fndecl == NULL_TREE || ! WRAPPER_NAME_P (DECL_NAME (fndecl)))
X {
X int bytecount = get_arglist_len_in_bytes (coerced_params);
X
X params = tree_cons (NULL_TREE, build_int_2 (bytecount, 0),
X tree_cons (NULL_TREE, function, TREE_CHAIN (coerced_params)));
X
X return build_method_call (TREE_VALUE (coerced_params),
X wrapper_name, params,
X NULL_TREE, LOOKUP_NORMAL);
X }
X }
X }
X {
X register tree result =
X build (CALL_EXPR, value_type, function, coerced_params, NULL_TREE);
X
X TREE_VOLATILE (result) = 1;
X TREE_RAISES (result) |= !! TYPE_RAISES_EXCEPTIONS (fntype);
X if (value_type == void_type_node)
X return result;
X return require_complete_type (result);
X }
X}
X
X/* Convert the actual parameter expressions in the list VALUES
X to the types in the list TYPELIST.
X If parmdecls is exhausted, or when an element has NULL as its type,
X perform the default conversions.
X
X RETURN_LOC is the location of the return value, if known, NULL_TREE
X otherwise. This is useful in the case where we can avoid creating
X a temporary variable in the case where we can initialize the return
X value directly. If we are not eliding constructors, then we set this
X to NULL_TREE to avoid this avoidance.
X
X NAME is an IDENTIFIER_NODE or 0. It is used only for error messages.
X
X This is also where warnings about wrong number of args are generated.
X
X Return a list of expressions for the parameters as converted.
X
X Both VALUES and the returned value are chains of TREE_LIST nodes
X with the elements of the list in the TREE_VALUE slots of those nodes.
X
X In C++, unspecified trailing parameters can be filled in with their
X default arguments, if such were specified. Do so here. */
X
Xtree
Xactualparameterlist (return_loc, typelist, values, fndecl, flags)
X tree return_loc, typelist, values, fndecl;
X int flags;
X{
X register tree typetail, valtail;
X register tree result = NULL_TREE;
X char *called_thing;
X int maybe_raises = 0;
X
X if (! flag_elide_constructors)
X return_loc = 0;
X
X if (fndecl)
X if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
X if (TREE_TYPE (DECL_ORIGINAL_NAME (fndecl)))
X called_thing = "constructor";
X else
X called_thing = "member function";
X else
X called_thing = "function";
X
X for (valtail = values, typetail = typelist;
X valtail;
X valtail = TREE_CHAIN (valtail))
X {
X register tree type = typetail ? TREE_VALUE (typetail) : 0;
X register tree val = TREE_VALUE (valtail);
X register tree parm;
X
X if (type == void_type_node)
X {
X if (fndecl)
X {
X char *buf = (char *)alloca (80);
X sprintf (buf, "too many arguments to %s `%%s'", called_thing);
X error_with_decl (fndecl, buf);
X error ("at this point in file");
X }
X else
X error ("too many arguments to function");
X /* In case anybody wants to know if this argument
X list is valid. */
X if (result)
X TREE_TYPE (result) = error_mark_node;
X break;
X }
X
X /* The tree type of the parameter being passed may not yet be
X known. In this case, its type is TYPE_UNKNOWN, and will
X be instantiated by the type given by TYPE. If TYPE
X is also NULL, the tree type of VAL is ERROR_MARK_NODE. */
X if (type && type_unknown_p (val))
X val = require_instantiated_type (type, val, integer_zero_node);
X else if (type_unknown_p (val))
X {
X
X if (TREE_CODE (val) == TREE_LIST
X && TREE_CHAIN (val) == NULL_TREE
X && TREE_TYPE (TREE_VALUE (val)) != NULL_TREE
X && (TREE_TYPE (val) == unknown_type_node
X || TREE_CHAIN (TREE_VALUE (val)) == NULL_TREE))
X /* Instantiates automatically. */
X val = TREE_VALUE (val);
X else
X {
X error ("insufficient type information in parameter list");
X val = integer_zero_node;
X }
X }
X
X {
X /* Convert FUNCTION_DECLs for virtual functions
X to proper representation. */
X tree basetype = NULL_TREE;
X tree ttype = TREE_TYPE (val);
X
X if (TREE_CODE (ttype) == METHOD_TYPE)
X basetype = TYPE_METHOD_BASETYPE (ttype);
X else if (TREE_CODE (ttype) == OFFSET_TYPE)
X basetype = TYPE_OFFSET_BASETYPE (ttype);
X
X /* If BASETYPE is set here, default_conversion will do the
X actual conversion for us. */
X if (basetype && TREE_CODE (val) != OFFSET_REF)
X {
X val = build (OFFSET_REF, ttype,
X build1 (NOP_EXPR, basetype, error_mark_node), val);
X type = build_pointer_type (ttype);
X }
X else if (TREE_CODE (ttype) == FUNCTION_TYPE
X && (type == NULL_TREE
X || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (type)) == VOID_TYPE))
X type = build_pointer_type (ttype);
X }
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since VAL is used in non-lvalue context. */
X if (TREE_CODE (val) == NOP_EXPR
X && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
X val = TREE_OPERAND (val, 0);
X
X if ((type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
X && (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
X || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE))
X val = default_conversion (val);
X
X val = require_complete_type (val);
X
X maybe_raises |= TREE_RAISES (val);
X
X if (type != 0)
X {
X /* Formal parm type is specified by a function prototype. */
X tree parmval;
X
X if (TYPE_SIZE (type) == 0)
X {
X error ("parameter type of called function is incomplete");
X parmval = val;
X }
X else
X {
X#ifdef PROMOTE_PROTOTYPES
X /* Rather than truncating and then reextending,
X convert directly to int, if that's the type we will want. */
X if (! flag_traditional
X && TREE_CODE (type) == INTEGER_TYPE
X && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
X type = integer_type_node;
X#endif
X parmval = convert_for_initialization (return_loc, type, val,
X "argument passing", flags);
X#ifdef PROMOTE_PROTOTYPES
X if (TREE_CODE (type) == INTEGER_TYPE
X && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
X parmval = default_conversion (parmval);
X#endif
X }
X parm = build_tree_list (0, parmval);
X }
X else
X {
X if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
X val = convert_from_reference (val);
X
X if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
X && (TYPE_PRECISION (TREE_TYPE (val))
X < TYPE_PRECISION (double_type_node)))
X /* Convert `float' to `double'. */
X parm = build_tree_list (NULL_TREE, convert (double_type_node, val));
X else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
X && (TYPE_GETS_INIT_REF (TREE_TYPE (val))
X || TYPE_GETS_ASSIGN_REF (TREE_TYPE (val))))
X {
X if (pedantic)
X error_with_aggr_type (TREE_TYPE (val), "cannot pass objects of type `%s' through `...'");
X else
X warning ("cannot pass objects of type `%s' through `...'",
X TYPE_NAME_STRING (TREE_TYPE (val)));
X parm = build_tree_list (NULL_TREE, val);
X }
X else
X /* Convert `short' and `char' to full-size `int'. */
X parm = build_tree_list (NULL_TREE, default_conversion (val));
X }
X
X result = chainon (result, parm);
X if (typetail)
X typetail = TREE_CHAIN (typetail);
X }
X
X if (typetail != 0 && typetail != void_list_node)
X {
X /* See if there are default arguments that can be used */
X if (TREE_PURPOSE (typetail))
X {
X while (typetail != void_list_node)
X {
X tree type = TREE_VALUE (typetail);
X tree val = TREE_PURPOSE (typetail);
X tree parm, parmval;
X
X if (val == NULL_TREE)
X parmval = error_mark_node;
X else if (TREE_CODE (val) == CONSTRUCTOR)
X {
X parmval = digest_init (type, val, NULL_TREE);
X parmval = convert_for_initialization (return_loc, type, parmval, "default constructor", flags);
X }
X else
X {
X parmval = convert_for_initialization (return_loc, type, val,
X "default argument", flags);
X#ifdef PROMOTE_PROTOTYPES
X if (TREE_CODE (type) == INTEGER_TYPE
X && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
X parmval = default_conversion (parmval);
X#endif
X }
X maybe_raises |= TREE_RAISES (parmval);
X parm = build_tree_list (0, parmval);
X result = chainon (result, parm);
X typetail = TREE_CHAIN (typetail);
X /* ends with `...'. */
X if (typetail == NULL_TREE)
X break;
X }
X }
X else
X {
X if (fndecl)
X {
X char *buf = (char *)alloca (32 + strlen (called_thing));
X sprintf (buf, "too few arguments to %s `%%s'", called_thing);
X error_with_decl (fndecl, buf);
X error ("at this point in file");
X }
X else
X error ("too few arguments to function");
X return error_mark_list;
X }
X }
X if (result)
X TREE_RAISES (result) = maybe_raises;
X
X return result;
X}
X
X/* Build a binary-operation expression, after performing default
X conversions on the operands. CODE is the kind of expression to build. */
X
Xtree
Xbuild_x_binary_op (code, arg1, arg2)
X enum tree_code code;
X tree arg1, arg2;
X{
X tree rval;
X
X if (rval = build_opfncall (code, LOOKUP_PROTECT, arg1, arg2))
X return rval;
X rval = build_binary_op (code, arg1, arg2);
X if (rval == error_mark_node)
X build_opfncall (code, LOOKUP_NORMAL, arg1, arg2);
X return rval;
X}
X
Xtree
Xbuild_binary_op (code, arg1, arg2)
X enum tree_code code;
X tree arg1, arg2;
X{
X tree type1, type2;
X tree args[2];
X arg1 = default_conversion (arg1);
X arg2 = default_conversion (arg2);
X
X if (type_unknown_p (arg1))
X {
X arg1 = instantiate_type (TREE_TYPE (arg2), arg1, 1);
X arg1 = default_conversion (arg1);
X }
X else
X {
X arg2 = require_instantiated_type (TREE_TYPE (arg1), arg2, error_mark_node);
X arg2 = default_conversion (arg2);
X }
X
X type1 = TREE_TYPE (arg1);
X type2 = TREE_TYPE (arg2);
X
X args[0] = arg1;
X args[1] = arg2;
X
X if (IS_AGGR_TYPE (type1) && IS_AGGR_TYPE (type2))
X {
X /* Try to convert this to something reasonable. */
X if (! build_default_binary_type_conversion (code, &args[0], &args[1]))
X return error_mark_node;
X }
X else if (IS_AGGR_TYPE (type1) || IS_AGGR_TYPE (type2))
X {
X int convert_index = IS_AGGR_TYPE (type2);
X /* Avoid being tripped up by things like (ARG1 != 0). */
X tree types[2], try;
X
X types[0] = type1; types[1] = type2;
X try = build_type_conversion (code, types[convert_index ^ 1],
X args[convert_index], 1);
X
X if (try == 0
X && arg2 == integer_zero_node
X && (code == NE_EXPR || code == EQ_EXPR))
X try = build_type_conversion (code, ptr_type_node,
X args[convert_index], 1);
X if (try == 0)
X {
X error_with_aggr_type (types[convert_index], "type conversion required for type `%s'");
X return error_mark_node;
X }
X if (try == error_mark_node)
X error ("ambiguous pointer conversion");
X args[convert_index] = try;
X }
X
X return build_binary_op_nodefault (code, args[0], args[1], code);
X}
X
X/* Build a binary-operation expression without default conversions.
X CODE is the kind of expression to build.
X This function differs from `build' in several ways:
X the data type of the result is computed and recorded in it,
X warnings are generated if arg data types are invalid,
X special handling for addition and subtraction of pointers is known,
X and some optimization is done (operations on narrow ints
X are done in the narrower type when that gives the same result).
X Constant folding is also done before the result is returned.
X
X ERROR_CODE is the code that determines what to say in error messages.
X It is usually, but not always, the same as CODE.
X
X Note that the operands will never have enumeral types
X because either they have just had the default conversions performed
X or they have both just been converted to some other type in which
X the arithmetic is to be done.
X
X C++: must do special pointer arithmetic when implementing
X multiple inheritance. */
X
Xtree
Xbuild_binary_op_nodefault (code, op0, op1, error_code)
X enum tree_code code;
X tree op0, op1;
X enum tree_code error_code;
X{
X tree dt0 = datatype (op0), dt1 = datatype (op1);
X
X /* The expression codes of the data types of the arguments tell us
X whether the arguments are integers, floating, pointers, etc. */
X register enum tree_code code0 = TREE_CODE (dt0);
X register enum tree_code code1 = TREE_CODE (dt1);
X
X /* Expression code to give to the expression when it is built.
X Normally this is CODE, which is what the caller asked for,
X but in some special cases we change it. */
X register enum tree_code resultcode = code;
X
X /* Data type in which the computation is to be performed.
X In the simplest cases this is the common type of the arguments. */
X register tree result_type = NULL;
X
X /* Nonzero means operands have already been type-converted
X in whatever way is necessary.
X Zero means they need to be converted to RESULT_TYPE. */
X int converted = 0;
X
X /* Nonzero means after finally constructing the expression
X give it this type. Otherwise, give it type RESULT_TYPE. */
X tree final_type = 0;
X
X /* Nonzero if this is an operation like MIN or MAX which can
X safely be computed in short if both args are promoted shorts.
X Also implies COMMON.
X -1 indicates a bitwise operation; this makes a difference
X in the exact conditions for when it is safe to do the operation
X in a narrower mode. */
X int shorten = 0;
X
X /* Nonzero if this is a comparison operation;
X if both args are promoted shorts, compare the original shorts.
X Also implies COMMON. */
X int short_compare = 0;
X
X /* Nonzero if this is a right-shift operation, which can be computed on the
X original short and then promoted if the operand is a promoted short. */
X int short_shift = 0;
X
X /* Nonzero means set RESULT_TYPE to the common type of the args. */
X int common = 0;
X
X /* If an error was already reported for one of the arguments,
X avoid reporting another error. */
X
X if (code0 == ERROR_MARK || code1 == ERROR_MARK)
X return error_mark_node;
X
X switch (code)
X {
X case PLUS_EXPR:
X /* Handle the pointer + int case. */
X if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
X return pointer_int_sum (PLUS_EXPR, op0, op1);
X else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
X return pointer_int_sum (PLUS_EXPR, op1, op0);
X else
X common = 1;
X break;
X
X case MINUS_EXPR:
X /* Subtraction of two similar pointers.
X We must subtract them as integers, then divide by object size. */
X if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
X && comp_target_types (dt0, dt1, 1))
X return pointer_diff (op0, op1);
X /* Handle pointer minus int. Just like pointer plus int. */
X else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
X return pointer_int_sum (MINUS_EXPR, op0, op1);
X else
X common = 1;
X break;
X
X case MULT_EXPR:
X common = 1;
X break;
X
X case TRUNC_DIV_EXPR:
X case CEIL_DIV_EXPR:
X case FLOOR_DIV_EXPR:
X case ROUND_DIV_EXPR:
X case EXACT_DIV_EXPR:
X if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
X && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
X {
X if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
X resultcode = RDIV_EXPR;
X else
X shorten = 1;
X common = 1;
X }
X break;
X
X case BIT_AND_EXPR:
X case BIT_ANDTC_EXPR:
X case BIT_IOR_EXPR:
X case BIT_XOR_EXPR:
X if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
X shorten = -1;
X /* If one operand is a constant, and the other is a short type
X that has been converted to an int,
X really do the work in the short type and then convert the
X result to int. If we are lucky, the constant will be 0 or 1
X in the short type, making the entire operation go away. */
X if (TREE_CODE (op0) == INTEGER_CST
X && TREE_CODE (op1) == NOP_EXPR
X && TYPE_PRECISION (dt1) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))
X && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0))))
X {
X final_type = result_type;
X op1 = TREE_OPERAND (op1, 0);
X result_type = TREE_TYPE (op1);
X }
X if (TREE_CODE (op1) == INTEGER_CST
X && TREE_CODE (op0) == NOP_EXPR
X && TYPE_PRECISION (dt0) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))
X && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
X {
X final_type = result_type;
X op0 = TREE_OPERAND (op0, 0);
X result_type = TREE_TYPE (op0);
X }
X break;
X
X case TRUNC_MOD_EXPR:
X if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
X shorten = 1;
X break;
X
X case TRUTH_ANDIF_EXPR:
X case TRUTH_ORIF_EXPR:
X case TRUTH_AND_EXPR:
X case TRUTH_OR_EXPR:
X if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE || code0 == REAL_TYPE)
X && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE || code1 == REAL_TYPE))
X {
X /* Result of these operations is always an int,
X but that does not mean the operands should be
X converted to ints! */
X result_type = integer_type_node;
X op0 = truthvalue_conversion (op0);
X op1 = truthvalue_conversion (op1);
X converted = 1;
X
X /* If these two expressions perform the same operation
X on what are (or could be given alignment constraints) parts of
X the same word, try chaining the operations. */
X if (optimize)
X {
X tree rval;
X
X if (TREE_CODE (op0) == TREE_CODE (op1))
X {
X /* Do they look like (x.p == y.p && x.q == y.q)
X or (x.p != y.p || x.q != y.q). */
X if (((code == TRUTH_ANDIF_EXPR && TREE_CODE (op0) == EQ_EXPR)
X || (code == TRUTH_ORIF_EXPR && TREE_CODE (op0) == NE_EXPR))
X && (rval = merge_component_comparisons (code, op0, op1)))
X return rval;
X }
X if (TREE_CODE (op0) == code
X && TREE_CODE (TREE_OPERAND (op0, 1)) == TREE_CODE (op1))
X /* Associate the operation. */
X {
X /* Now try to simplify right-hand term. */
X if (((code == TRUTH_ANDIF_EXPR && TREE_CODE (op1) == EQ_EXPR)
X || (code == TRUTH_ORIF_EXPR && TREE_CODE (op1) == NE_EXPR))
X && (rval = merge_component_comparisons (code, TREE_OPERAND (op0, 1), op1)))
X {
X TREE_OPERAND (op0, 1) = rval;
X return op0;
X }
X }
X }
X }
X break;
X
X /* Shift operations: result has same type as first operand;
X always convert second operand to int.
X Also set SHORT_SHIFT if shifting rightward. */
X
X case RSHIFT_EXPR:
X if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
X {
X result_type = dt0;
X if (TREE_CODE (op1) == INTEGER_CST
X && TREE_INT_CST_LOW (op1) > 0)
X short_shift = 1;
X /* Convert the shift-count to an integer, regardless of
X size of value being shifted. */
X if (TREE_TYPE (op1) != integer_type_node)
X op1 = convert (integer_type_node, op1);
X }
X break;
X
X case LSHIFT_EXPR:
X if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
X {
X result_type = dt0;
X if (TREE_CODE (op1) == INTEGER_CST
X && TREE_INT_CST_LOW (op1) < 0)
X short_shift = 1;
X /* Convert the shift-count to an integer, regardless of
X size of value being shifted. */
X if (TREE_TYPE (op1) != integer_type_node)
X op1 = convert (integer_type_node, op1);
X }
X break;
X
X case RROTATE_EXPR:
X case LROTATE_EXPR:
X if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
X {
X result_type = dt0;
X /* Convert the shift-count to an integer, regardless of
X size of value being shifted. */
X if (TREE_TYPE (op1) != integer_type_node)
X op1 = convert (integer_type_node, op1);
X }
X break;
X
X case EQ_EXPR:
X case NE_EXPR:
X /* Result of comparison is always int,
X but don't convert the args to int! */
X result_type = integer_type_node;
X converted = 1;
X if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
X && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
X short_compare = 1;
X else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
X {
X register tree tt0 = TYPE_MAIN_VARIANT (TREE_TYPE (dt0));
X register tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (dt1));
X /* Anything compares with void *. void * compares with anything.
X Otherwise, the targets must be the same. */
X if (tt0 != tt1 && IS_AGGR_TYPE (tt0) && IS_AGGR_TYPE (tt1))
X {
X tree base = common_base_type (tt0, tt1);
X if (base == NULL_TREE)
X warning ("comparison of distinct object pointer types");
X else if (base == error_mark_node)
X {
X message_2_types (error, "comparison of pointer types `%s*' and `%s*' requires conversion to ambiguous supertype", tt0, tt1);
X return error_mark_node;
X }
X op0 = convert (TYPE_POINTER_TO (base), op0);
X op1 = convert (TYPE_POINTER_TO (base), op1);
X }
X else if (comp_target_types (dt0, dt1, 1))
X ;
X else if (tt0 == void_type_node)
X {
X if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
X warning ("ANSI C forbids comparison of `void *' with function pointer");
X }
X else if (tt1 == void_type_node)
X {
X if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
X warning ("ANSI C forbids comparison of `void *' with function pointer");
X }
X else
X warning ("comparison of distinct pointer types lacks a cast");
X }
X else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
X && integer_zerop (op1))
X op1 = null_pointer_node;
X else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
X && integer_zerop (op0))
X op0 = null_pointer_node;
X else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
X {
X error ("comparison between pointer and integer");
X op1 = convert (TREE_TYPE (op0), op1);
X }
X else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
X {
X error ("comparison between pointer and integer");
X op0 = convert (TREE_TYPE (op1), op0);
X }
X else
X /* If args are not valid, clear out RESULT_TYPE
X to cause an error message later. */
X result_type = 0;
X break;
X
X case MAX_EXPR:
X case MIN_EXPR:
X if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
X && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
X shorten = 1;
X else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
X {
X if (! comp_target_types (dt0, dt1, 1))
X warning ("comparison of distinct pointer types lacks a cast");
X else if (pedantic
X && TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE)
X warning ("ANSI C forbids ordered comparisons of pointers to functions");
X result_type = commontype (dt0, dt1);
X }
X break;
X
X case LE_EXPR:
X case GE_EXPR:
X case LT_EXPR:
X case GT_EXPR:
X if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
X && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
X short_compare = 1;
X else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
X {
X if (! comp_target_types (dt0, dt1, 1))
X warning ("comparison of distinct pointer types lacks a cast");
X else if (pedantic
X && TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE)
X warning ("ANSI C forbids ordered comparisons of pointers to functions");
X result_type = integer_type_node;
X }
X else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
X && integer_zerop (op1))
X {
X result_type = integer_type_node;
X op1 = null_pointer_node;
X if (! flag_traditional)
X warning ("ordered comparison of pointer with integer zero");
X }
X else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
X && integer_zerop (op0))
X {
X result_type = integer_type_node;
X op0 = null_pointer_node;
X if (pedantic)
X warning ("ordered comparison of pointer with integer zero");
X }
X else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
X {
X result_type = integer_type_node;
X if (! flag_traditional)
X warning ("comparison between pointer and integer");
X op1 = convert (TREE_TYPE (op0), op1);
X }
X else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
X {
X result_type = integer_type_node;
X if (! flag_traditional)
X warning ("comparison between pointer and integer");
X op0 = convert (TREE_TYPE (op1), op0);
X }
X converted = 1;
X break;
X }
X
X if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
X && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
X {
X if (shorten || common || short_compare)
X result_type = commontype (dt0, dt1);
X
X /* For certain operations (which identify themselves by shorten != 0)
X if both args were extended from the same smaller type,
X do the arithmetic in that type and then extend.
X
X shorten !=0 and !=1 indicates a bitwise operation.
X For them, this optimization is safe only if
X both args are zero-extended or both are sign-extended.
X Otherwise, we might change the result.
X Eg, (short)-1 | (unsigned short)-1 is (int)-1
X but calculated in (unsigned short) it would be (unsigned short)-1. */
X
X if (shorten)
X {
X int unsigned0, unsigned1;
X tree arg0 = get_narrower (op0, &unsigned0);
X tree arg1 = get_narrower (op1, &unsigned1);
X /* UNS is 1 if the operation to be done is an unsigned one. */
X int uns = TREE_UNSIGNED (result_type);
X tree type;
X
X final_type = result_type;
X
X /* Handle the case that OP0 does not *contain* a conversion
X but it *requires* conversion to FINAL_TYPE. */
X
X if (op0 == arg0 && TREE_TYPE (op0) != final_type)
X unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0));
X if (op1 == arg1 && TREE_TYPE (op1) != final_type)
X unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1));
X
X /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */
X
X /* For bitwise operations, signedness of nominal type
X does not matter. Consider only how operands were extended. */
X if (shorten == -1)
X uns = unsigned0;
X
X /* Note that in all three cases below we refrain from optimizing
X an unsigned operation on sign-extended args.
X That would not be valid. */
X
X /* Both args variable: if both extended in same way
X from same width, do it in that width.
X Do it unsigned if args were zero-extended. */
X if ((TYPE_PRECISION (TREE_TYPE (arg0))
X < TYPE_PRECISION (result_type))
X && (TYPE_PRECISION (TREE_TYPE (arg1))
X == TYPE_PRECISION (TREE_TYPE (arg0)))
X && unsigned0 == unsigned1
X && (unsigned0 || !uns))
X result_type
X = signed_or_unsigned_type (unsigned0,
X commontype (TREE_TYPE (arg0), TREE_TYPE (arg1)));
X else if (TREE_CODE (arg0) == INTEGER_CST
X && (unsigned1 || !uns)
X && (TYPE_PRECISION (TREE_TYPE (arg1))
X < TYPE_PRECISION (result_type))
X && (type = signed_or_unsigned_type (unsigned1,
X TREE_TYPE (arg1)),
X int_fits_type_p (arg0, type)))
X result_type = type;
X else if (TREE_CODE (arg1) == INTEGER_CST
X && (unsigned0 || !uns)
X && (TYPE_PRECISION (TREE_TYPE (arg0))
X < TYPE_PRECISION (result_type))
X && (type = signed_or_unsigned_type (unsigned0,
X TREE_TYPE (arg0)),
X int_fits_type_p (arg1, type)))
X result_type = type;
X }
X
X /* Shifts can be shortened if shifting right. */
X
X if (short_shift)
X {
X int unsigned_arg;
X tree arg0 = get_narrower (op0, &unsigned_arg);
X
X final_type = result_type;
X
X if (arg0 == op0 && final_type == TREE_TYPE (op0))
X unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
X
X if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
X /* If arg is sign-extended and then unsigned-shifted,
X we can simulate this with a signed shift in arg's type
X only if the extended result is at least twice as wide
X as the arg. Otherwise, the shift could use up all the
X ones made by sign-extension and bring in zeros.
X We can't optimize that case at all, but in most machines
X it never happens because available widths are 2**N. */
X && (!TREE_UNSIGNED (final_type)
X || unsigned_arg
X || 2 * TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (result_type)))
X {
X /* Do an unsigned shift if the operand was zero-extended. */
X result_type
X = signed_or_unsigned_type (unsigned_arg,
X TREE_TYPE (arg0));
X /* Convert value-to-be-shifted to that type. */
X if (TREE_TYPE (op0) != result_type)
X op0 = convert (result_type, op0);
X converted = 1;
X }
X }
X
X /* Comparison operations are shortened too but differently.
X They identify themselves by setting short_compare = 1. */
X
X if (short_compare)
X {
X /* Don't write &op0, etc., because that would prevent op0
X from being kept in a register.
X Instead, make copies of the our local variables and
X pass the copies by reference, then copy them back afterward. */
X tree xop0 = op0, xop1 = op1, xresult_type = result_type;
X enum tree_code xresultcode = resultcode;
X tree val
X = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
X if (val != 0)
X return val;
X op0 = xop0, op1 = xop1, result_type = xresult_type;
X resultcode = xresultcode;
X }
X }
X
X /* At this point, RESULT_TYPE must be nonzero to avoid an error message.
X If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
X Then the expression will be built.
X It will be given type FINAL_TYPE if that is nonzero;
X otherwise, it will be given type RESULT_TYPE. */
X
X if (!result_type)
X {
X binary_op_error (error_code);
X return error_mark_node;
X }
X
X if (! converted)
X {
X if (TREE_TYPE (op0) != result_type)
X op0 = convert (result_type, op0);
X if (TREE_TYPE (op1) != result_type)
X op1 = convert (result_type, op1);
X }
X
X {
X register tree result = build (resultcode, result_type, op0, op1);
X register tree folded;
X
X folded = fold (result);
X if (folded == result)
X TREE_LITERAL (folded) = TREE_LITERAL (op0) & TREE_LITERAL (op1);
X if (final_type != 0)
X return convert (final_type, folded);
X return folded;
X }
X}
X
X/* Return a tree for the sum or difference (RESULTCODE says which)
X of pointer PTROP and integer INTOP. */
X
Xstatic tree
Xpointer_int_sum (resultcode, ptrop, intop)
X enum tree_code resultcode;
X register tree ptrop, intop;
X{
X tree size_exp;
X
X register tree result;
X register tree folded = fold (intop);
X
X /* The result is a pointer of the same type that is being added. */
X
X register tree result_type = datatype (ptrop);
X
X /* Needed to make OOPS V2R3 work. */
X intop = folded;
X if (TREE_CODE (intop) == INTEGER_CST
X && TREE_INT_CST_LOW (intop) == 0
X && TREE_INT_CST_HIGH (intop) == 0)
X return ptrop;
X
X if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
X {
X if (pedantic || warn_pointer_arith)
X warning ("pointer of type `void *' used in arithmetic");
X size_exp = integer_one_node;
X }
X else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
X {
X if (pedantic || warn_pointer_arith)
X warning ("pointer to a function used in arithmetic");
X size_exp = integer_one_node;
X }
X else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
X {
X if (pedantic)
X warning ("pointer to a method used in arithmetic");
X size_exp = integer_one_node;
X }
X else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
X {
X if (pedantic)
X warning ("pointer to a member used in arithmetic");
X size_exp = integer_one_node;
X }
X else
X size_exp = size_in_bytes (TREE_TYPE (result_type));
X
X /* If what we are about to multiply by the size of the elements
X contains a constant term, apply distributive law
X and multiply that constant term separately.
X This helps produce common subexpressions. */
X
X if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
X && ! TREE_LITERAL (intop)
X && TREE_LITERAL (TREE_OPERAND (intop, 1))
X && TREE_LITERAL (size_exp))
X {
X enum tree_code subcode = resultcode;
X if (TREE_CODE (intop) == MINUS_EXPR)
X subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
X ptrop = build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1));
X intop = TREE_OPERAND (intop, 0);
X }
X
X /* Convert the integer argument to a type the same size as a pointer
X so the multiply won't overflow spuriously. */
X
X if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
X intop = convert (type_for_size (POINTER_SIZE, 0), intop);
X
X /* Replace the integer argument
X with a suitable product by the object size. */
X
X intop = build_binary_op (MULT_EXPR, intop, size_exp);
X
X /* Create the sum or difference. */
X
X result = build (resultcode, result_type, ptrop, intop);
X
X folded = fold (result);
X if (folded == result)
X TREE_LITERAL (folded) = TREE_LITERAL (ptrop) & TREE_LITERAL (intop);
X return folded;
X}
X
X/* Return a tree for the difference of pointers OP0 and OP1.
X The resulting tree has type int. */
X
Xstatic tree
Xpointer_diff (op0, op1)
X register tree op0, op1;
X{
X tree dt0 = datatype (op0);
X register tree result, folded;
X tree restype = type_for_size (POINTER_SIZE, 0);
X
X if (pedantic)
X {
X if (TREE_CODE (TREE_TYPE (dt0)) == VOID_TYPE)
X warning ("pointer of type `void *' used in subtraction");
X if (TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE)
X warning ("pointer to a function used in subtraction");
X if (TREE_CODE (TREE_TYPE (dt0)) == METHOD_TYPE)
X warning ("pointer to a method used in subtraction");
X if (TREE_CODE (TREE_TYPE (dt0)) == OFFSET_TYPE)
X warning ("pointer to a member used in subtraction");
X }
X
X /* First do the subtraction as integers;
X then drop through to build the divide operator. */
X
X op0 = build_binary_op (MINUS_EXPR,
X convert (restype, op0), convert (restype, op1));
X op1 = ((TREE_CODE (TREE_TYPE (dt0)) == VOID_TYPE
X || TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (dt0)) == METHOD_TYPE
X || TREE_CODE (TREE_TYPE (dt0)) == OFFSET_TYPE)
X ? integer_one_node
X : size_in_bytes (TREE_TYPE (dt0)));
X
X /* Create the sum or difference. */
X
X result = build (EXACT_DIV_EXPR, restype, op0, op1);
X
X folded = fold (result);
X if (folded == result)
X TREE_LITERAL (folded) = TREE_LITERAL (op0) & TREE_LITERAL (op1);
X return folded;
X}
X
X/* Print an error message for invalid operands to arith operation CODE.
X NOP_EXPR is used as a special case (see truthvalue_conversion). */
X
Xstatic void
Xbinary_op_error (code)
X enum tree_code code;
X{
X register char *opname;
X switch (code)
X {
X case NOP_EXPR:
X error ("invalid truth-value expression");
X return;
X
X case PLUS_EXPR:
X opname = "+"; break;
X case MINUS_EXPR:
X opname = "-"; break;
X case MULT_EXPR:
X opname = "*"; break;
X case MAX_EXPR:
X opname = "max"; break;
X case MIN_EXPR:
X opname = "min"; break;
X case EQ_EXPR:
X opname = "=="; break;
X case NE_EXPR:
X opname = "!="; break;
X case LE_EXPR:
X opname = "<="; break;
X case GE_EXPR:
X opname = ">="; break;
X case LT_EXPR:
X opname = "<"; break;
X case GT_EXPR:
X opname = ">"; break;
X case LSHIFT_EXPR:
X opname = "<<"; break;
X case RSHIFT_EXPR:
X opname = ">>"; break;
X case TRUNC_MOD_EXPR:
X opname = "%"; break;
X case TRUNC_DIV_EXPR:
X opname = "/"; break;
X case BIT_AND_EXPR:
X opname = "&"; break;
X case BIT_IOR_EXPR:
X opname = "|"; break;

X case TRUTH_ANDIF_EXPR:
X opname = "&&"; break;
X case TRUTH_ORIF_EXPR:
X opname = "||"; break;
X case BIT_XOR_EXPR:
X opname = "^"; break;
X }
X error ("invalid operands to binary %s", opname);
X}
X
X/* Subroutine of build_binary_op_nodefault, used for comparison operations.
X See if the operands have both been converted from subword integer types
X and, if so, perhaps change them both back to their original type.
X
X The arguments of this function are all pointers to local variables
X of build_binary_op_nodefault: OP0_PTR is &OP0, OP1_PTR is &OP1,
X RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE.
X
X If this function returns nonzero, it means that the comparison has
X a constant value. What this function returns is an expression for
X that value. */
X
Xstatic tree
Xshorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
X tree *op0_ptr, *op1_ptr;
X tree *restype_ptr;
X enum tree_code *rescode_ptr;
X{
X register tree type;
X tree op0 = *op0_ptr;
X tree op1 = *op1_ptr;
X int unsignedp0, unsignedp1;
X int real1, real2;
X tree primop0, primop1;
X enum tree_code code = *rescode_ptr;
X
X /* Throw away any conversions to wider types
X already present in the operands. */
X
X primop0 = get_narrower (op0, &unsignedp0);
X primop1 = get_narrower (op1, &unsignedp1);
X
X /* Handle the case that OP0 does not *contain* a conversion
X but it *requires* conversion to FINAL_TYPE. */
X
X if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr)
X unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0));
X if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr)
X unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1));
X
X /* If one of the operands must be floated, we cannot optimize. */
X real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
X real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
X
X /* If first arg is constant, swap the args (changing operation
X so value is preserved), for canonicalization. */
X
X if (TREE_LITERAL (primop0))
X {
X register tree tem = primop0;
X register int temi = unsignedp0;
X primop0 = primop1;
X primop1 = tem;
X tem = op0;
X op0 = op1;
X op1 = tem;
X *op0_ptr = op0;
X *op1_ptr = op1;
X unsignedp0 = unsignedp1;
X unsignedp1 = temi;
X temi = real1;
X real1 = real2;
X real2 = temi;
X
X switch (code)
X {
X case LT_EXPR:
X code = GT_EXPR;
X break;
X case GT_EXPR:
X code = LT_EXPR;
X break;
X case LE_EXPR:
X code = GE_EXPR;
X break;
X case GE_EXPR:
X code = LE_EXPR;
X break;
X }
X *rescode_ptr = code;
X }
X
X /* If comparing an integer against a constant more bits wide,
X maybe we can deduce a value of 1 or 0 independent of the data.
X Or else truncate the constant now
X rather than extend the variable at run time.
X
X This is only interesting if the constant is the wider arg.
X Also, it is not safe if the constant is unsigned and the
X variable arg is signed, since in this case the variable
X would be sign-extended and then regarded as unsigned.
X Our technique fails in this case because the lowest/highest
X possible unsigned results don't follow naturally from the
X lowest/highest possible values of the variable operand.
X For just EQ_EXPR and NE_EXPR there is another technique that
X could be used: see if the constant can be faithfully represented
X in the other operand's type, by truncating it and reextending it
X and see if that preserves the constant's value. */
X
X if (!real1 && !real2
X && TREE_CODE (primop1) == INTEGER_CST
X && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
X {
X int min_gt, max_gt, min_lt, max_lt;
X tree maxval, minval;
X /* 1 if comparison is nominally unsigned. */
X int unsignedp = TREE_UNSIGNED (*restype_ptr);
X tree val;
X
X type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
X
X maxval = TYPE_MAX_VALUE (type);
X minval = TYPE_MIN_VALUE (type);
X
X if (unsignedp && !unsignedp0)
X *restype_ptr = signed_type (*restype_ptr);
X
X if (TREE_TYPE (primop1) != *restype_ptr)
X primop1 = convert (*restype_ptr, primop1);
X if (type != *restype_ptr)
X {
X minval = convert (*restype_ptr, minval);
X maxval = convert (*restype_ptr, maxval);
X }
X
X if (unsignedp && unsignedp0)
X {
X min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
X max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
X min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
X max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
X }
X else
X {
X min_gt = INT_CST_LT (primop1, minval);
X max_gt = INT_CST_LT (primop1, maxval);
X min_lt = INT_CST_LT (minval, primop1);
X max_lt = INT_CST_LT (maxval, primop1);
X }
X
X val = 0;
X switch (code)
X {
X case NE_EXPR:
X if (max_lt || min_gt)
X val = integer_one_node;
X break;
X
X case EQ_EXPR:
X if (max_lt || min_gt)
X val = integer_zero_node;
X break;
X
X case LT_EXPR:
X if (max_lt)
X val = integer_one_node;
X if (!min_lt)
X val = integer_zero_node;
X break;
X
X case GT_EXPR:
X if (min_gt)
X val = integer_one_node;
X if (!max_gt)
X val = integer_zero_node;
X break;
X
X case LE_EXPR:
X if (!max_gt)
X val = integer_one_node;
X if (min_gt)
X val = integer_zero_node;
X break;
X
X case GE_EXPR:
X if (!min_lt)
X val = integer_one_node;
X if (max_lt)
X val = integer_zero_node;
X break;
X }
X
X /* If primop0 was sign-extended and unsigned comparison specd,
X we did a signed comparison above using the signed type bounds.
X But the comparison we output must be unsigned.
X
X Also, for inequalities, VAL is no good; but if the signed
X comparison had *any* fixed result, it follows that the
X unsigned comparison just tests the sign in reverse
X (positive values are LE, negative ones GE).
X So we can generate an unsigned comparison
X against an extreme value of the signed type. */
X
X if (unsignedp && !unsignedp0)
X {
X if (val != 0)
X switch (code)
X {
X case LT_EXPR:
X case GE_EXPR:
X primop1 = TYPE_MIN_VALUE (type);
X val = 0;
X break;
X
X case LE_EXPR:
X case GT_EXPR:
X primop1 = TYPE_MAX_VALUE (type);
X val = 0;
X break;
X }
X type = unsigned_type (type);
X }
X
X if (max_lt && !unsignedp0)
X {
X /* This is the case of (char)x >?< 0x80, which people used to use
X expecting old C compilers to change the 0x80 into -0x80. */
X if (val == integer_zero_node)
X warning ("comparison is always 0 due to limited range of data type");
X if (val == integer_one_node)
X warning ("comparison is always 1 due to limited range of data type");
X }
X
X if (val != 0)
X {
X /* Don't forget to evaluate PRIMOP0 if it has side effects. */
X if (TREE_VOLATILE (primop0))
X return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
X return val;
X }
X
X /* Value is not predetermined, but do the comparison
X in the type of the operand that is not constant.
X TYPE is already properly set. */
X }
X else if (real1 && real2
X && TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1)))
X type = TREE_TYPE (primop0);
X
X /* If args' natural types are both narrower than nominal type
X and both extend in the same manner, compare them
X in the type of the wider arg.
X Otherwise must actually extend both to the nominal
X common type lest different ways of extending
X alter the result.
X (eg, (short)-1 == (unsigned short)-1 should be 0.) */
X
X else if (unsignedp0 == unsignedp1 && real1 == real2
X && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
X && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
X {
X type = commontype (TREE_TYPE (primop0), TREE_TYPE (primop1));
X type = signed_or_unsigned_type (unsignedp0
X || TREE_UNSIGNED (*restype_ptr),
X type);
X /* Make sure shorter operand is extended the right way
X to match the longer operand. */
X primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
X primop0);
X primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
X primop1);
X }
X else
X {
X /* Here we must do the comparison on the nominal type
X using the args exactly as we received them. */
X type = *restype_ptr;
X primop0 = op0;
X primop1 = op1;
X }
X
X *op0_ptr = convert (type, primop0);
X *op1_ptr = convert (type, primop1);
X
X *restype_ptr = integer_type_node;
X
X return 0;
X}
X
X/* Handle the case of taking the address of a COMPONENT_REF.
X Called by `build_unary_op' and `build_up_reference'.
X
X ARG is the COMPONENT_REF whose address we want.
X ARGTYPE is the pointer type that this address should have.
X MSG is an error message to print if this COMPONENT_REF is not
X addressable (such as a bitfield). */
X
Xtree
Xbuild_component_addr (arg, argtype, msg)
X tree arg, argtype;
X char *msg;
X{
X tree field = TREE_OPERAND (arg, 1);
X tree basetype = decl_type_context (field);
X tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
X
X if (TREE_PACKED (field))
X {
X error (msg, IDENTIFIER_POINTER (DECL_NAME (field)));
X return error_mark_node;
X }
X
X if (TREE_CODE (field) == FIELD_DECL
X && (TYPE_USES_MULTIPLE_INHERITANCE (basetype)
X || TYPE_USES_VIRTUAL_BASECLASSES (basetype)))
X /* Can't convert directly to ARGTYPE, since that
X may have the same pointer type as one of our
X baseclasses. */
X rval = build1 (NOP_EXPR, argtype,
X convert_pointer_to (basetype, rval));
X else
X /* This conversion is harmless. */
X rval = convert (argtype, rval);
X
X if (DECL_OFFSET (field) != 0)
X {
X tree offset = build_int_2 ((DECL_OFFSET (field) / BITS_PER_UNIT), 0);
X TREE_TYPE (offset) = argtype;
X rval = fold (build (PLUS_EXPR, argtype, rval, offset));
X }
X return rval;
X}
X
X/* Construct and perhaps optimize a tree representation
X for a unary operation. CODE, a tree_code, specifies the operation
X and XARG is the operand. */
X
Xtree
Xbuild_x_unary_op (code, xarg)
X enum tree_code code;
X tree xarg;
X{
X tree rval;
X
X if (rval = build_opfncall (code, LOOKUP_PROTECT, xarg))
X return rval;
X rval = build_unary_op (code, xarg, 0);
X if (rval == error_mark_node)
X build_opfncall (code, LOOKUP_NORMAL, xarg);
X return rval;
X}
X
X/* C++: Must handle pointers to members.
X
X Perhaps type instantiation should be extended to handle conversion
X from aggregates to types we don't yet know we want? (Or are those
X cases typically errors which should be reported?)
X
X NOCONVERT nonzero suppresses the default promotions
X (such as from short to int). */
Xtree
Xbuild_unary_op (code, xarg, noconvert)
X enum tree_code code;
X tree xarg;
X int noconvert;
X{
X /* No default_conversion here. It causes trouble for ADDR_EXPR. */
X register tree arg = xarg;
X register tree argtype = 0;
X register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
X char *errstring = NULL;
X tree val;
X int isaggrtype;
X
X if (typecode == ERROR_MARK)
X return error_mark_node;
X
X if (typecode == REFERENCE_TYPE && code != ADDR_EXPR && ! noconvert)
X {
X arg = convert_from_reference (arg);
X typecode = TREE_CODE (TREE_TYPE (arg));
X }
X
X if (typecode == ENUMERAL_TYPE)
X typecode = INTEGER_TYPE;
X
X isaggrtype = IS_AGGR_TYPE_CODE (typecode);
X
X switch (code)
X {
X case CONVERT_EXPR:
X /* This is used for unary plus, because a CONVERT_EXPR
X is enough to prevent anybody from looking inside for
X associativity, but won't generate any code. */
X if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
X errstring = "wrong type argument to unary plus";
X else if (!noconvert)
X arg = default_conversion (arg);
X break;
X
X case NEGATE_EXPR:
X if (isaggrtype)
X {
X if (!noconvert)
X arg = default_conversion (arg);
X else
X {
X error_with_aggr_type (TREE_TYPE (arg), "type conversion for type `%s' not allowed");
X return error_mark_node;
X }
X typecode = TREE_CODE (TREE_TYPE (arg));
X noconvert = 1;
X }
X
X if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
X errstring = "wrong type argument to unary minus";
X else if (!noconvert)
X arg = default_conversion (arg);
X break;
X
X case BIT_NOT_EXPR:
X if (isaggrtype)
X {
X if (!noconvert)
X arg = default_conversion (arg);
X else
X {
X error_with_aggr_type (TREE_TYPE (arg), "type conversion for type `%s' not allowed");
X return error_mark_node;
X }
X typecode = TREE_CODE (TREE_TYPE (arg));
X noconvert = 1;
X }
X
X if (typecode != INTEGER_TYPE)
X errstring = "wrong type argument to bit-complement";
X else if (!noconvert)
X arg = default_conversion (arg);
X break;
X
X case ABS_EXPR:
X if (isaggrtype)
X {
X if (!noconvert)
X arg = default_conversion (arg);
X else
X {
X error_with_aggr_type (TREE_TYPE (arg), "type conversion for type `%s' not allowed");
X return error_mark_node;
X }
X typecode = TREE_CODE (TREE_TYPE (arg));
X noconvert = 1;
X }
X
X if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
X errstring = "wrong type argument to abs";
X else if (!noconvert)
X arg = default_conversion (arg);
X break;
X
X case TRUTH_NOT_EXPR:
X if (isaggrtype)
X {
X arg = truthvalue_conversion (arg);
X typecode = TREE_CODE (TREE_TYPE (arg));
X }
X
X if (typecode != INTEGER_TYPE
X && typecode != REAL_TYPE && typecode != POINTER_TYPE
X /* These will convert to a pointer. */
X && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
X {
X errstring = "wrong type argument to unary exclamation mark";
X break;
X }
X arg = truthvalue_conversion (arg);
X val = invert_truthvalue (arg);
X if (val) return val;
X break;
X
X case NOP_EXPR:
X break;
X
X case PREINCREMENT_EXPR:
X case POSTINCREMENT_EXPR:
X case PREDECREMENT_EXPR:
X case POSTDECREMENT_EXPR:
X /* Handle complex lvalues (when permitted)
X by reduction to simpler cases. */
X
X val = unary_complex_lvalue (code, arg);
X if (val != 0)
X return val;
X
X /* Report invalid types. */
X
X if (isaggrtype)
X {
X arg = default_conversion (arg);
X typecode = TREE_CODE (TREE_TYPE (arg));
X }
X
X if (typecode != POINTER_TYPE
X && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
X {
X if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
X errstring ="wrong type argument to increment";
X else
X errstring ="wrong type argument to decrement";
X break;
X }
X
X /* Report something read-only. */
X
X if (TREE_READONLY (arg))
X readonly_warning_or_error (arg,
X ((code == PREINCREMENT_EXPR
X || code == POSTINCREMENT_EXPR)
X ? "increment" : "decrement"));
X
X {
X register tree inc;
X tree result_type = TREE_TYPE (arg);
X
X arg = get_unwidened (arg, 0);
X argtype = TREE_TYPE (arg);
X
X /* Compute the increment. */
X
X if (typecode == POINTER_TYPE)
X {
X if (pedantic && (TREE_CODE (argtype) == FUNCTION_TYPE
X || TREE_CODE (argtype) == METHOD_TYPE
X || TREE_CODE (argtype) == VOID_TYPE
X || TREE_CODE (argtype) == OFFSET_TYPE))
X warning ("wrong type argument to %s",
X ((code == PREINCREMENT_EXPR
X || code == POSTINCREMENT_EXPR)
X ? "increment" : "decrement"));
X inc = c_sizeof_nowarn (TREE_TYPE (argtype));
X }
X else
X inc = integer_one_node;
X
X inc = convert (argtype, inc);
X
X /* Handle incrementing a cast-expression. */
X
X switch (TREE_CODE (arg))
X {
X case NOP_EXPR:
X case CONVERT_EXPR:
X case FLOAT_EXPR:
X case FIX_TRUNC_EXPR:
X case FIX_FLOOR_EXPR:
X case FIX_ROUND_EXPR:
X case FIX_CEIL_EXPR:
X {
X tree incremented, modify, value;
X pedantic_lvalue_warning (CONVERT_EXPR);
X arg = stabilize_reference (arg);
X if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
X value = arg;
X else
X value = save_expr (arg);
X incremented = build (((code == PREINCREMENT_EXPR
X || code == POSTINCREMENT_EXPR)
X ? PLUS_EXPR : MINUS_EXPR),
X argtype, value, inc);
X TREE_VOLATILE (incremented) = 1;
X modify = build_modify_expr (arg, NOP_EXPR, incremented);
X return build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
X }
X }
X
X if (TREE_CODE (arg) == OFFSET_REF)
X arg = resolve_offset_ref (arg);
X
X /* Complain about anything else that is not a true lvalue. */
X if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
X || code == POSTINCREMENT_EXPR)
X ? "increment" : "decrement")))
X return error_mark_node;
X
X val = build (code, TREE_TYPE (arg), arg, inc);
X TREE_VOLATILE (val) = 1;
X return convert (result_type, val);
X }
X
X case ADDR_EXPR:
X /* Note that this operation never does default_conversion
X regardless of NOCONVERT. */
X
X if (TREE_CODE (arg) == REFERENCE_EXPR)
X {
X error ("references are not lvalues");
X return error_mark_node;
X }
X else if (typecode == REFERENCE_TYPE)
X return build1 (REFERENCE_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
X
X /* Let &* cancel out to simplify resulting code. */
X if (TREE_CODE (arg) == INDIRECT_REF)
X {
X /* Keep `default_conversion' from converting if
X ARG is of REFERENCE_TYPE. */
X arg = TREE_OPERAND (arg, 0);

X if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
X {
X if (TREE_CODE (arg) == VAR_DECL && DECL_INITIAL (arg)
X && !TREE_VOLATILE (DECL_INITIAL (arg)))
X arg = DECL_INITIAL (arg);
X arg = build1 (REFERENCE_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
X TREE_LITERAL (arg) = TREE_LITERAL (TREE_OPERAND (arg, 0));
X }
X return arg;
X }
X
X /* For &x[y], return x+y */
X if (TREE_CODE (arg) == ARRAY_REF)
X {
X if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
X return error_mark_node;
X return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
X TREE_OPERAND (arg, 1));
X }
X
X /* Uninstantiated types are all functions. Taking the
X address of a function is a no-op, so just return the
X arguemnt. */
X
X if (TREE_CODE (arg) == OP_IDENTIFIER)
X /* We don't know the type yet, so just work around the problem.
X We know that this will resolve to an lvalue. */
X return build1 (ADDR_EXPR, unknown_type_node, arg);
X
X if (TREE_CODE (arg) == TREE_LIST)
X {
X /* Look at methods with only this name. */
X if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL)
X {
X tree targ = TREE_VALUE (arg);
X
X /* If this function is unique, or it is a unique
X constructor, we can takes its address easily. */
X if (TREE_CHAIN (targ) == NULL_TREE
X || (DESTRUCTOR_NAME_P (DECL_NAME (targ))
X && TREE_CHAIN (TREE_CHAIN (targ)) == NULL_TREE))
X {
X if (TREE_CHAIN (targ))
X targ = TREE_CHAIN (targ);
X targ = build (OFFSET_REF, TREE_TYPE (targ), C_C_D, targ);
X
X val = unary_complex_lvalue (ADDR_EXPR, targ);
X if (val)
X return val;
X }
X return build1 (ADDR_EXPR, unknown_type_node, arg);
X }
X if (TREE_CHAIN (arg) == NULL_TREE
X && TREE_CHAIN (TREE_VALUE (TREE_VALUE (arg))) == NULL_TREE)
X {
X /* Unique overloaded member function. */
X return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)), 0);
X }
X return build1 (ADDR_EXPR, unknown_type_node, arg);
X }
X
X /* Handle complex lvalues (when permitted)
X by reduction to simpler cases. */
X val = unary_complex_lvalue (code, arg);
X if (val != 0)
X return val;
X
X /* Address of a cast is just a cast of the address
X of the operand of the cast. */
X switch (TREE_CODE (arg))
X {
X case NOP_EXPR:
X case CONVERT_EXPR:
X case FLOAT_EXPR:
X case FIX_TRUNC_EXPR:
X case FIX_FLOOR_EXPR:
X case FIX_ROUND_EXPR:
X case FIX_CEIL_EXPR:
X if (pedantic)
X warning ("ANSI C forbids the address of a cast expression");
X return convert (build_pointer_type (TREE_TYPE (arg)),
X build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0));
X }
X
X /* Allow the address of a constructor if all the elements
X are constant. */
X if (TREE_CODE (arg) == CONSTRUCTOR && TREE_LITERAL (arg))
X ;
X /* Anything not already handled and not a true memory reference
X is an error. */
X else if (typecode != FUNCTION_TYPE
X && typecode != METHOD_TYPE
X && !lvalue_or_else (arg, "unary `&'"))
X return error_mark_node;
X
X /* Ordinary case; arg is a COMPONENT_REF or a decl. */
X argtype = TREE_TYPE (arg);
X if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
X argtype = build_type_variant (argtype,
X TREE_READONLY (arg),
X TREE_THIS_VOLATILE (arg));
X
X argtype = build_pointer_type (argtype);
X
X if (mark_addressable (arg) == 0)
X return error_mark_node;
X
X {
X tree addr;
X
X if (TREE_CODE (arg) == COMPONENT_REF)
X addr = build_component_addr (arg, argtype,
X "attempt to take address of bit-field structure member `%s'");
X else
X addr = build1 (code, argtype, arg);
X
X /* Address of a static or external variable or
X function counts as a constant */
X TREE_LITERAL (addr) = staticp (arg);
X return addr;
X }
X }
X
X if (!errstring)
X {
X if (argtype == 0)
X argtype = TREE_TYPE (arg);
X return fold (build1 (code, argtype, arg));
X }
X
X error (errstring);
X return error_mark_node;
X}
X
X/* If CONVERSIONS is a conversion expression or a nested sequence of such,
X convert ARG with the same conversions in the same order
X and return the result. */
X
Xstatic tree
Xconvert_sequence (conversions, arg)
X tree conversions;
X tree arg;
X{
X switch (TREE_CODE (conversions))
X {
X case NOP_EXPR:
X case CONVERT_EXPR:
X case FLOAT_EXPR:
X case FIX_TRUNC_EXPR:
X case FIX_FLOOR_EXPR:
X case FIX_ROUND_EXPR:
X case FIX_CEIL_EXPR:
X return convert (TREE_TYPE (conversions),
X convert_sequence (TREE_OPERAND (conversions, 0),
X arg));
X
X default:
X return arg;
X }
X}
X
X/* Apply unary lvalue-demanding operator CODE to the expression ARG
X for certain kinds of expressions which are not really lvalues
X but which we can accept as lvalues.
X
X If ARG is not a kind of expression we can handle, return zero. */
X
Xtree
Xunary_complex_lvalue (code, arg)
X enum tree_code code;
X tree arg;
X{
X /* Handle (a, b) used as an "lvalue". */
X if (TREE_CODE (arg) == COMPOUND_EXPR)
X {
X tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
X pedantic_lvalue_warning (COMPOUND_EXPR);
X return build (COMPOUND_EXPR, TREE_TYPE (real_result),
X TREE_OPERAND (arg, 0), real_result);
X }
X
X /* Handle (a ? b : c) used as an "lvalue". */
X if (TREE_CODE (arg) == COND_EXPR)
X {
X pedantic_lvalue_warning (COND_EXPR);
X return (build_conditional_expr
X (TREE_OPERAND (arg, 0),
X build_unary_op (code, TREE_OPERAND (arg, 1), 0),
X build_unary_op (code, TREE_OPERAND (arg, 2), 0)));
X }
X
X if (code != ADDR_EXPR)
X return 0;
X
X /* Handle (a = b) used as an "lvalue" for `&'. */
X if (TREE_CODE (arg) == MODIFY_EXPR
X || TREE_CODE (arg) == INIT_EXPR)
X {
X tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
X return build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
X }
X
X if (TREE_CODE (arg) == WITH_CLEANUP_EXPR)
X {
X tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
X real_result = build (WITH_CLEANUP_EXPR, TREE_TYPE (real_result),
X real_result, 0, TREE_OPERAND (arg, 2));
X return real_result;
X }
X
X if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
X || TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
X {
X /* The representation of something of type OFFSET_TYPE
X is really the representation of a pointer to it.
X Here give the representation its true type. */
X tree t;
X tree offset;
X
X assert (TREE_CODE (arg) != SCOPE_REF);
X
X if (TREE_CODE (arg) != OFFSET_REF)
X return 0;
X
X t = TREE_OPERAND (arg, 1);
X if (TREE_OPERAND (arg, 0)
X && (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
X || TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
X {
X /* Don't know if this should return address to just
X _DECL, or actual address resolved in this expression. */
X sorry ("address of bound pointer-to-member expression");
X return error_mark_node;
X }
X
X if (TREE_CODE (t) == FUNCTION_DECL)
X {
X tree context = NULL_TREE;
X
X if (DECL_VIRTUAL_P (t)
X#ifdef SOS
X || flag_all_virtual == 2
X#endif
X || (flag_all_virtual == 1
X && ((context = decl_type_context (t))
X && (TYPE_OVERLOADS_METHOD_CALL_EXPR (context)
X || TYPE_NEEDS_WRAPPER (context))
X && ! DECL_CONSTRUCTOR_P (t))))
X {
X offset = copy_node (DECL_VINDEX (t));
X TREE_TYPE (offset) = build_pointer_type (TREE_TYPE (arg));
X }
X else
X offset = build_unary_op (ADDR_EXPR, t, 0);
X
X return offset;
X }
X if (TREE_CODE (t) == VAR_DECL)
X {
X if (TREE_STATIC (t))
X offset = build_unary_op (ADDR_EXPR, t, 0);
X else
X return 0;
X }
X else
X {
X /* Can't build a pointer to member if the member must
X go through virtual base classes. */
X if (virtual_member (DECL_FIELD_CONTEXT (t),
X CLASSTYPE_VBASECLASSES (TREE_TYPE (TREE_OPERAND (arg, 0)))))
X {
X sorry ("pointer to member via virtual baseclass");
X return error_mark_node;
X }
X /* @@ What is the correct machine-independent way to do this? */
X offset = build_int_2 (DECL_OFFSET (t) / DECL_SIZE_UNIT (t), 0);
X TREE_TYPE (offset) = build_pointer_type (TREE_TYPE (arg));
X return offset;
X }
X }
X
X if (TREE_CODE (arg) == OFFSET_REF)
X {
X tree left = TREE_OPERAND (arg, 0), left_addr;
X tree right_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 1), 0);
X
X if (left == 0)
X if (current_class_decl)
X left_addr = current_class_decl;
X else
X {
X error ("no `this' for pointer to member");
X return error_mark_node;
X }
X else
X left_addr = build_unary_op (ADDR_EXPR, left, 0);
X
X return build (PLUS_EXPR, build_pointer_type (TREE_TYPE (arg)),
X build1 (NOP_EXPR, integer_type_node, left_addr),
X build1 (NOP_EXPR, integer_type_node, right_addr));
X }
X
X /* We permit compiler to make function calls returning
X objects of aggregate type look like lvalues. */
X {
X tree targ = arg;
X
X if (TREE_CODE (targ) == SAVE_EXPR)
X targ = TREE_OPERAND (targ, 0);
X
X if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (TREE_TYPE (targ)))
X {
X if (TREE_CODE (arg) == SAVE_EXPR)
X targ = arg;
X else
X targ = build_cplus_new (TREE_TYPE (arg), arg, 1);
X return build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)), targ);
X }
X
X if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == INDIRECT_REF)
X return build (SAVE_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)),
X TREE_OPERAND (targ, 0), NULL);
X
X /* We shouldn't wrap WITH_CLEANUP_EXPRs inside of SAVE_EXPRs, but in case
X we do, here's how to handle it. */
X if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == WITH_CLEANUP_EXPR)
X {
X#if 0
X /* Not really a bug, but something to turn on when testing. */
X compiler_error ("WITH_CLEANUP_EXPR wrapped in SAVE_EXPR");
X#endif
X return unary_complex_lvalue (ADDR_EXPR, targ);
X }
X }
X
X /* Don't let anything else be handled specially. */
X return 0;
X}
X
X/* If pedantic, warn about improper lvalue. CODE is either COND_EXPR
X COMPOUND_EXPR, or CONVERT_EXPR (for casts). */
X
Xstatic void
Xpedantic_lvalue_warning (code)
X enum tree_code code;
X{
X if (pedantic)
X warning ("ANSI C forbids use of %s expressions as lvalues",
X code == COND_EXPR ? "conditional"
X : code == COMPOUND_EXPR ? "compound" : "cast");
X}
X
X/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
X or validate its data type for an `if' or `while' statement or ?..: exp.
X
X This preparation consists of taking the ordinary
X representation of an expression expr and producing a valid tree
X boolean expression describing whether expr is nonzero. We could
X simply always do build_binary_op (NE_EXPR, expr, integer_zero_node),
X but we optimize comparisons, &&, ||, and ! */
X
Xtree
Xtruthvalue_conversion (expr)
X tree expr;
X{
X register enum tree_code form;
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since EXPR is being used in non-lvalue context. */
X if (TREE_CODE (expr) == NOP_EXPR
X && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
X expr = TREE_OPERAND (expr, 0);
X
X form = TREE_CODE (expr);
X
X if (form == EQ_EXPR && integer_zerop (TREE_OPERAND (expr, 1)))
X return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0);
X
X /* A one-bit unsigned bit-field is already acceptable. */
X if (form == COMPONENT_REF
X && 1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
X && 1 == DECL_SIZE_UNIT (TREE_OPERAND (expr, 1))
X && TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
X return expr;
X
X if (form == TRUTH_ANDIF_EXPR || form == TRUTH_ORIF_EXPR
X || form == TRUTH_AND_EXPR || form == TRUTH_OR_EXPR
X || form == TRUTH_NOT_EXPR
X || form == EQ_EXPR || form == NE_EXPR
X || form == LE_EXPR || form == GE_EXPR
X || form == LT_EXPR || form == GT_EXPR
X || form == ERROR_MARK)
X return expr;
X
X /* Unary minus has no effect on whether its argument is nonzero. */
X if (form == NEGATE_EXPR)
X return truthvalue_conversion (TREE_OPERAND (expr, 0));
X
X /* Distribute the conversion into the arms of a COND_EXPR. */
X if (form == COND_EXPR)
X return build (COND_EXPR, TREE_TYPE (expr),
X TREE_OPERAND (expr, 0),
X truthvalue_conversion (TREE_OPERAND (expr, 1)),
X truthvalue_conversion (TREE_OPERAND (expr, 2)));
X
X /* Sign-extension and zero-extension has no effect. */
X if (form == NOP_EXPR
X && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
X && (TYPE_PRECISION (TREE_TYPE (expr))
X > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))))
X return truthvalue_conversion (TREE_OPERAND (expr, 0));
X
X return build_binary_op (NE_EXPR, expr, integer_zero_node);
X}
X
X/* Return a simplified tree node for the truth-negation of ARG
X (perhaps by altering ARG).
X If it can't be simplified, return 0. */
X
Xstatic tree
Xinvert_truthvalue (arg)
X tree arg;
X{
X switch (TREE_CODE (arg))
X {
X case NE_EXPR:
X TREE_SET_CODE (arg, EQ_EXPR);
X return arg;
X
X case EQ_EXPR:
X TREE_SET_CODE (arg, NE_EXPR);
X return arg;
X
X case GE_EXPR:
X TREE_SET_CODE (arg, LT_EXPR);
X return arg;
X
X case GT_EXPR:
X TREE_SET_CODE (arg, LE_EXPR);
X return arg;
X
X case LE_EXPR:
X TREE_SET_CODE (arg, GT_EXPR);
X return arg;
X
X case LT_EXPR:
X TREE_SET_CODE (arg, GE_EXPR);
X return arg;
X
X#if 0
X case TRUTH_AND_EXPR:
X return build (TRUTH_OR_EXPR, TREE_TYPE (arg),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 0), 0),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 1), 0));
X
X case TRUTH_OR_EXPR:
X return build (TRUTH_AND_EXPR, TREE_TYPE (arg),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 0), 0),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 1), 0));
X#endif
X
X case TRUTH_ANDIF_EXPR:
X return build (TRUTH_ORIF_EXPR, TREE_TYPE (arg),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 0), 0),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 1), 0));
X
X case TRUTH_ORIF_EXPR:
X return build (TRUTH_ANDIF_EXPR, TREE_TYPE (arg),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 0), 0),
X build_unary_op (TRUTH_NOT_EXPR,
X TREE_OPERAND (arg, 1), 0));
X
X case TRUTH_NOT_EXPR:
X return TREE_OPERAND (arg, 0);
X }
X return 0;
X}
X
X/* Mark EXP saying that we need to be able to take the
X address of it; it should not be allocated in a register.
X
X Return 1 if taking address of this expression is ok.
X Return 0 otherwise.
X
X C++: we do not allow `current_class_decl' to be addressable. */
X
Xint
Xmark_addressable (exp)
X tree exp;
X{
X register tree x = exp;
X
X if (TREE_ADDRESSABLE (x) == 1)
X return 1;
X
X while (1)
X switch (TREE_CODE (x))
X {
X case ADDR_EXPR:
X case COMPONENT_REF:
X case ARRAY_REF:
X x = TREE_OPERAND (x, 0);
X break;
X
X case PARM_DECL:
X if (x == current_class_decl)
X {
X error ("address of `this' not available");
X TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
X put_var_into_stack (x);
X return 1;
X }
X case VAR_DECL:
X if (TREE_STATIC (x)
X && TREE_READONLY (x)
X && DECL_RTL (x) != 0
X && ! memory_operand (DECL_RTL (x), DECL_MODE (x)))
X {
X /* We thought this would make a good constant variable,
X but we were wrong. */
X int temp = TREE_PERMANENT (x) && allocation_temporary_p ();
X
X if (temp)
X end_temporary_allocation ();
X
X TREE_ASM_WRITTEN (x) = 0;
X DECL_RTL (x) = 0;
X rest_of_decl_compilation (x, 0, IDENTIFIER_LOCAL_VALUE (x) == 0, 0);
X TREE_ADDRESSABLE (x) = 1;
X
X if (temp)
X resume_temporary_allocation ();
X
X return 1;
X }
X /* Caller should not be trying to mark initialized
X constant fields addressable. */
X assert (DECL_LANG_SPECIFIC (x) == 0 || DECL_IN_AGGR_P (x) == 0 || TREE_STATIC (x));
X
X case CONST_DECL:
X if (TREE_REGDECL (x))
X {
X if (TREE_PUBLIC (x))
X {
X error ("address of global register variable `%s' requested",
X IDENTIFIER_POINTER (DECL_NAME (x)));
X return 0;
X }
X warning ("address requested for `%s', which is declared `register'",
X IDENTIFIER_POINTER (DECL_NAME (x)));
X }
X put_var_into_stack (x);
X TREE_ADDRESSABLE (x) = 1;
X return 1;
X
X case RESULT_DECL:
X put_var_into_stack (x);
X TREE_ADDRESSABLE (x) = 1;
X return 1;
X
X case FUNCTION_DECL:
X if (TREE_INLINE (x))
X mark_inline_for_output (x);
X TREE_ADDRESSABLE (x) = 1;
X TREE_USED (x) = 1;
X TREE_ADDRESSABLE (DECL_NAME (x)) = 1;
X return 1;
X
X default:
X return 1;
X }
X}
X
X/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
X
Xtree
Xbuild_x_conditional_expr (ifexp, op1, op2)
X tree ifexp, op1, op2;
X{
X tree rval;
X
X if (op1 != 0 && (rval = build_opfncall (COND_EXPR, LOOKUP_PROTECT, ifexp, op1, op2)))
X return rval;
X rval = build_conditional_expr (ifexp, op1, op2);
X if (op1 != 0 && rval == error_mark_node)
X build_opfncall (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
X return rval;
X}
X
Xtree
Xbuild_conditional_expr (ifexp, op1, op2)
X tree ifexp, op1, op2;
X{
X register tree type1;
X register tree type2;
X register enum tree_code code1;
X register enum tree_code code2;
X register tree result_type = NULL_TREE;
X
X /* If second operand is omitted, it is the same as the first one;
X make sure it is calculated only once. */
X if (op1 == 0)
X {
X if (pedantic)
X warning ("ANSI C forbids omitting the middle term of a ?: expression");
X ifexp = op1 = save_expr (ifexp);
X }
X
X ifexp = truthvalue_conversion (default_conversion (ifexp));
X
X if (TREE_CODE (ifexp) == ERROR_MARK)
X return error_mark_node;
X
X op1 = require_instantiated_type (TREE_TYPE (op2), op1, error_mark_node);
X if (op1 == error_mark_node)
X return error_mark_node;
X op2 = require_instantiated_type (TREE_TYPE (op1), op2, error_mark_node);
X if (op2 == error_mark_node)
X return error_mark_node;
X
X /* C++: REFERENCE_TYPES must be dereferenced. */
X type1 = TREE_TYPE (op1);
X code1 = TREE_CODE (type1);
X type2 = TREE_TYPE (op2);
X code2 = TREE_CODE (type2);
X
X if (code1 == REFERENCE_TYPE)
X {
X op1 = convert_from_reference (op1);
X type1 = TREE_TYPE (op1);
X code1 = TREE_CODE (type1);
X }
X if (code2 == REFERENCE_TYPE)
X {
X op2 = convert_from_reference (op2);
X type2 = TREE_TYPE (op2);
X code2 = TREE_CODE (type2);
X }
X
X /* Don't promote the operands separately if they promote
X the same way. Return the unpromoted type and let the combined
X value get promoted if necessary. */
X
X if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
X && code2 != ARRAY_TYPE
X#if 0
X /* For C++, let the enumeral type come through. */
X && code2 != ENUMERAL_TYPE
X#endif
X && code2 != FUNCTION_TYPE
X && code2 != METHOD_TYPE)
X {
X if (TREE_LITERAL (ifexp)
X && (TREE_CODE (ifexp) == INTEGER_CST
X || TREE_CODE (ifexp) == ADDR_EXPR))
X return (integer_zerop (ifexp) ? op2 : op1);
X
X if (TREE_CODE (op1) == CONST_DECL)
X op1 = DECL_INITIAL (op1);
X else if (TREE_READONLY_DECL_P (op1))
X op1 = decl_constant_value (op1);
X if (TREE_CODE (op2) == CONST_DECL)
X op2 = DECL_INITIAL (op2);
X else if (TREE_READONLY_DECL_P (op2))
X op2 = decl_constant_value (op2);
X if (type1 != type2)
X {
X int constp = TREE_READONLY (type1) || TREE_READONLY (type2);
X int volatilep = TREE_VOLATILE (type1) || TREE_VOLATILE (type2);
X type1 = build_type_variant (type1, constp, volatilep);
X }
X return build (COND_EXPR, type1, ifexp, op1, op2);
X }
X
X /* They don't match; promote them both and then try to reconcile them.
X But don't permit mismatching enum types. */
X if (code1 == ENUMERAL_TYPE)
X {
X if (code2 == ENUMERAL_TYPE)
X {
X message_2_types (error, "enumeral mismatch in conditional expression: `%s' vs `%s'", type1, type2);
X return error_mark_node;
X }
X else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2))
X warning ("enumeral and non-enumeral type in conditional expression");
X }
X else if (extra_warnings
X && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1))
X warning ("enumeral and non-enumeral type in conditional expression");
X
X if (code1 != VOID_TYPE)
X {
X op1 = default_conversion (op1);
X type1 = TREE_TYPE (op1);
X code1 = TREE_CODE (type1);
X }
X if (code2 != VOID_TYPE)
X {
X op2 = default_conversion (op2);
X type2 = TREE_TYPE (op2);
X code2 = TREE_CODE (type2);
X }
X
X /* Quickly detect the usual case where op1 and op2 have the same type
X after promotion. */
X if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
X {
X if (type1 != type2)
X {
X int constp = TREE_READONLY (type1) || TREE_READONLY (type2);
X int volatilep = TREE_VOLATILE (type1) || TREE_VOLATILE (type2);
X type1 = build_type_variant (type1, constp, volatilep);
X }
X result_type = type1;
X }
X else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE)
X && (code2 == INTEGER_TYPE || code2 == REAL_TYPE))
X {
X result_type = commontype (type1, type2);
X }
X else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
X {
X if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
X warning ("ANSI C forbids conditional expr with only one void side");
X result_type = void_type_node;
X }
X else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
X {
X if (comp_target_types (type1, type2, 1))
X result_type = commontype (type1, type2);
X else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
X {
X if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
X warning ("ANSI C forbids conditional expr between `void *' and function pointer");
X result_type = qualify_type (type1, type2);
X }
X else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node)
X {
X if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
X warning ("ANSI C forbids conditional expr between `void *' and function pointer");
X result_type = qualify_type (type2, type1);

X }
X /* C++ */
X else if (comptypes (type2, type1, 0))
X result_type = type2;
X else if (result_type = common_base_type (TREE_TYPE (type1), TREE_TYPE (type2)))
X {
X if (result_type == error_mark_node)
X {
X message_2_types (error, "common base type of types `%s' and `%s' is ambiguous",
X TREE_TYPE (type1), TREE_TYPE (type2));
X result_type = ptr_type_node;
X }
X else result_type = TYPE_POINTER_TO (result_type);
X }
X else
X {
X warning ("pointer type mismatch in conditional expression");
X result_type = ptr_type_node;
X }
X }
X else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
X {
X if (!integer_zerop (op2))
X warning ("pointer/integer type mismatch in conditional expression");
X else
X {
X op2 = null_pointer_node;
X if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
X warning ("ANSI C forbids conditional expr between 0 and function pointer");
X }
X result_type = type1;
X }
X else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
X {
X if (!integer_zerop (op1))
X warning ("pointer/integer type mismatch in conditional expression");
X else
X {
X op1 = null_pointer_node;
X if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
X warning ("ANSI C forbids conditional expr between 0 and function pointer");
X }
X result_type = type2;
X op1 = null_pointer_node;
X }
X
X if (!result_type)
X {
X /* The match does not look good. If either is
X an aggregate value, try converting to a scalar type. */
X if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
X {
X message_2_types (error, "aggregate mismatch in conditional expression: `%s' vs `%s'", type1, type2);
X return error_mark_node;
X }
X if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
X {
X tree tmp = build_type_conversion (CONVERT_EXPR, type2, op1, 0);
X if (tmp == NULL_TREE)
X {
X error_with_aggr_type (type1, "aggregate type `%s' could not convert on lhs of `:'");
X return error_mark_node;
X }
X if (tmp == error_mark_node)
X error ("ambiguous pointer conversion");
X result_type = type2;
X op1 = tmp;
X }
X else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
X {
X tree tmp = build_type_conversion (CONVERT_EXPR, type1, op2, 0);
X if (tmp == NULL_TREE)
X {
X error_with_aggr_type (type2, "aggregate type `%s' could not convert on rhs of `:'");
X return error_mark_node;
X }
X if (tmp == error_mark_node)
X error ("ambiguous pointer conversion");
X result_type = type1;
X op2 = tmp;
X }
X else if (flag_cond_mismatch)
X result_type = void_type_node;
X else
X {
X error ("type mismatch in conditional expression");
X return error_mark_node;
X }
X }
X
X if (result_type != TREE_TYPE (op1))
X op1 = convert (result_type, op1);
X if (result_type != TREE_TYPE (op2))
X op2 = convert (result_type, op2);
X
X#if 0
X if (IS_AGGR_TYPE_CODE (code1))
X {
X result_type = TREE_TYPE (op1);
X if (TREE_LITERAL (ifexp))
X return (integer_zerop (ifexp) ? op2 : op1);
X
X if (TYPE_MODE (result_type) == BLKmode)
X {
X register tree tempvar
X = build_decl (VAR_DECL, NULL_TREE, result_type);
X register tree xop1 = build_modify_expr (tempvar, NOP_EXPR, op1);
X register tree xop2 = build_modify_expr (tempvar, NOP_EXPR, op2);
X register tree result = build (COND_EXPR, result_type,
X ifexp, xop1, xop2);
X
X layout_decl (tempvar);
X /* No way to handle variable-sized objects here.
X I fear that the entire handling of BLKmode conditional exprs
X needs to be redone. */
X assert (TREE_LITERAL (DECL_SIZE (tempvar)));
X DECL_RTL (tempvar)
X = assign_stack_local (DECL_MODE (tempvar),
X (TREE_INT_CST_LOW (DECL_SIZE (tempvar))
X * DECL_SIZE_UNIT (tempvar)
X + BITS_PER_UNIT - 1)
X / BITS_PER_UNIT);
X
X TREE_VOLATILE (result)
X = TREE_VOLATILE (ifexp) | TREE_VOLATILE (op1)
X | TREE_VOLATILE (op2);
X return build (COMPOUND_EXPR, result_type, result, tempvar);
X }
X }
X#endif /* 0 */
X
X if (TREE_LITERAL (ifexp))
X return (integer_zerop (ifexp) ? op2 : op1);
X
X return build (COND_EXPR, result_type, ifexp, op1, op2);
X}
X
X/* Handle overloading of the ',' operator when needed. Otherwise,
X this function just builds an expression list. */
Xtree
Xbuild_x_compound_expr (list)
X tree list;
X{
X tree type, rest = TREE_CHAIN (list);
X tree result;
X
X if (rest == NULL_TREE)
X return build_compound_expr (list);
X
X result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
X TREE_VALUE (list), TREE_VALUE (rest));
X if (result)
X return build_x_compound_expr (tree_cons (NULL_TREE, result, TREE_CHAIN (rest)));
X else
X return build_compound_expr (tree_cons (NULL_TREE, TREE_VALUE (list),
X build_tree_list (NULL_TREE, build_x_compound_expr (rest))));
X}
X
X/* Given a list of expressions, return a compound expression
X that performs them all and returns the value of the last of them. */
X
Xtree
Xbuild_compound_expr (list)
X tree list;
X{
X register tree rest;
X
X if (TREE_CODE (TREE_VALUE (list)) == CALL_EXPR
X && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_VALUE (list))))
X TREE_VALUE (list) = cleanup_after_call (TREE_VALUE (list));
X else if (TREE_READONLY_DECL_P (TREE_VALUE (list)))
X TREE_VALUE (list) = decl_constant_value (TREE_VALUE (list));
X
X if (TREE_CHAIN (list) == 0)
X {
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since LIST is used in non-lvalue context. */
X if (TREE_CODE (list) == NOP_EXPR
X && TREE_TYPE (list) == TREE_TYPE (TREE_OPERAND (list, 0)))
X list = TREE_OPERAND (list, 0);
X
X /* Convert arrays to pointers. */
X if (TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
X return default_conversion (TREE_VALUE (list));
X else
X return TREE_VALUE (list);
X }
X
X rest = build_compound_expr (TREE_CHAIN (list));
X
X if (! TREE_VOLATILE (TREE_VALUE (list)))
X return rest;
X
X return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
X}
X
X/* Build an expression representing a cast to type TYPE of expression EXPR. */
X
Xtree
Xbuild_c_cast (type, expr)
X register tree type;
X tree expr;
X{
X register tree value = expr;
X
X if (type == error_mark_node || expr == error_mark_node)
X return error_mark_node;
X type = TYPE_MAIN_VARIANT (type);
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since VALUE is being used in non-lvalue context. */
X if (TREE_CODE (value) == NOP_EXPR
X && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
X value = TREE_OPERAND (value, 0);
X
X if (TREE_TYPE (expr)
X && TREE_CODE (TREE_TYPE (expr)) == OFFSET_TYPE
X && TREE_CODE (type) != OFFSET_TYPE)
X value = resolve_offset_ref (value);
X
X if (TREE_CODE (type) == ARRAY_TYPE)
X {
X warning ("ANSI C forbids casting to array type");
X }
X
X if (type == TREE_TYPE (value))
X {
X if (pedantic)
X {
X if (TREE_CODE (type) == RECORD_TYPE
X || TREE_CODE (type) == UNION_TYPE)
X warning ("ANSI C forbids casting nonscalar to the same type");
X }
X return value;
X }
X
X /* If there's only one function in the overloaded space,
X just take it. */
X if (TREE_CODE (value) == TREE_LIST
X && TREE_CHAIN (value) == NULL_TREE)
X value = TREE_VALUE (value);
X
X /* Make up for the fact that we do not always perform
X `default_conversion' anymore. */
X if (TREE_READONLY_DECL_P (value))
X value = decl_constant_value (value);
X
X if (TREE_TYPE (value) == NULL_TREE
X || type_unknown_p (value))
X {
X value = instantiate_type (type, value, 1);
X /* Did we lose? */
X if (value == error_mark_node)
X return error_mark_node;
X }
X else if (TREE_CODE (type) == REFERENCE_TYPE
X && TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
X {
X /* Reference-to-reference conversion is special. */
X value = build_unary_op (ADDR_EXPR, value, 0);
X if (value != error_mark_node)
X value = convert_force (build_pointer_type (TREE_TYPE (type)), value);
X if (value == error_mark_node)
X return error_mark_node;
X return build1 (NOP_EXPR, type, value);
X }
X else
X {
X tree otype;
X /* Convert functions and arrays to pointers and
X convert references to their expanded types,
X but don't convert any other types. */
X if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
X || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
X value = default_conversion (value);
X otype = TREE_TYPE (value);
X
X /* Optionally warn about potentially worrysome casts. */
X
X if (warn_cast_qual
X && TREE_CODE (type) == POINTER_TYPE
X && TREE_CODE (otype) == POINTER_TYPE)
X {
X if (TREE_VOLATILE (TREE_TYPE (otype))
X && ! TREE_VOLATILE (TREE_TYPE (type)))
X warning ("cast discards `volatile' from pointer target type");
X if (TREE_READONLY (TREE_TYPE (otype))
X && ! TREE_READONLY (TREE_TYPE (type)))
X warning ("cast discards `const' from pointer target type");
X }
X value = convert_force (type, value);
X }
X if (value == expr)
X /* Always produce some operator for an explicit cast,
X so we can tell (for -pedantic) that the cast is no lvalue. */
X {
X tree nvalue = build1 (NOP_EXPR, type, value);
X TREE_LITERAL (nvalue) = TREE_LITERAL (value);
X return nvalue;
X }
X
X if (TREE_CODE (value) == CALL_EXPR
X && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (value)))
X value = cleanup_after_call (value);
X
X return value;
X}
X
X/* Build an assignment expression of lvalue LHS from value RHS.
X
X In C++, if the left hand side of the assignment is a REFERENCE_TYPE,
X that reference becomes deferenced down to it base type. */
X
X/* Return a reference to the BASE_INDEX part of EXPR. TYPE is
X the type to which BASE_INDEX applies. */
Xstatic tree
Xget_base_ref (type, base_index, expr)
X tree type;
X int base_index;
X tree expr;
X{
X tree basetype = CLASSTYPE_BASECLASS (type, base_index);
X tree ref;
X
X if (TREE_CODE (expr) == ARRAY_REF
X || CLASSTYPE_OFFSET (basetype) != integer_zero_node
X || CLASSTYPE_VIA_VIRTUAL (type, base_index)
X || TYPE_MODE (type) != TYPE_MODE (basetype))
X {
X tree addr = build_unary_op (ADDR_EXPR, expr, 0);
X ref = build_indirect_ref (convert_pointer_to (basetype, addr), 0);
X }
X else
X {
X ref = copy_node (expr);
X TREE_TYPE (ref) = basetype;
X }
X return ref;
X}
X
X/* Build an assignment expression of lvalue LHS from value RHS.
X MODIFYCODE is the code for a binary operator that we use
X to combine the old value of LHS with RHS to get the new value.
X Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
X
X C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
X
X `build_modify_expr_1' implements recursive part of memberwise
X assignment operation. */
Xstatic tree
Xbuild_modify_expr_1 (lhs, modifycode, rhs, basetype_path)
X tree lhs, rhs;
X enum tree_code modifycode;
X tree basetype_path;
X{
X register tree result;
X tree newrhs = rhs;
X tree lhstype = TREE_TYPE (lhs);
X tree olhstype = lhstype;
X
X /* Avoid duplicate error messages from operands that had errors. */
X if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
X return error_mark_node;
X
X /* If a binary op has been requested, combine the old LHS value with the RHS
X producing the value we should actually store into the LHS. */
X
X if (modifycode == INIT_EXPR)
X ;
X else if (modifycode == NOP_EXPR)
X {
X /* must deal with overloading of `operator=' here. */
X if (TREE_CODE (lhstype) == REFERENCE_TYPE)
X lhstype = TREE_TYPE (lhstype);
X lhstype = olhstype;
X }
X else
X {
X lhs = stabilize_reference (lhs);
X newrhs = build_binary_op (modifycode, lhs, rhs);
X modifycode = NOP_EXPR;
X }
X
X /* If storing into a structure or union member,
X it has probably been given type `int'.
X Compute the type that would go with
X the actual amount of storage the member occupies. */
X
X if (TREE_CODE (lhs) == COMPONENT_REF
X && (TREE_CODE (lhstype) == INTEGER_TYPE
X || TREE_CODE (lhstype) == REAL_TYPE
X || TREE_CODE (lhstype) == ENUMERAL_TYPE))
X lhstype = TREE_TYPE (get_unwidened (lhs, 0));
X
X /* C++: The semantics of C++ differ from those of C when an
X assignment of an aggregate is desired. Assignment in C++ is
X now defined as memberwise assignment of non-static members
X and base class objects. This rule applies recursively
X until a member of a built-in type is found.
X
X Also, we cannot do a bit-wise copy of aggregates which
X contain virtual function table pointers. Those
X pointer values must be preserved through the copy.
X However, this is handled in expand_expr, and not here.
X This is because much better code can be generated at
X that stage than this one. */
X if (TREE_CODE (lhstype) == RECORD_TYPE
X && TYPE_LANG_SPECIFIC (lhstype)
X && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
X {
X register tree elt;
X int i;
X
X /* Perform operation on object. */
X if (modifycode == INIT_EXPR && TYPE_HAS_INIT_REF (lhstype))
X {
X result = build_method_call (lhs, DECL_NAME (TYPE_NAME (lhstype)),
X build_tree_list (NULL_TREE, rhs),
X basetype_path, LOOKUP_NORMAL);
X return build_indirect_ref (result, 0);
X }
X else if (modifycode == NOP_EXPR)
X {
X /* `operator=' is not an inheritable operator. */
X if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
X {
X result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, (tree)NOP_EXPR);
X if (result == NULL_TREE)
X return error_mark_node;
X return result;
X }
X }
X
X if (TYPE_USES_VIRTUAL_BASECLASSES (lhstype)
X || (modifycode == NOP_EXPR && TYPE_GETS_ASSIGNMENT (lhstype))
X || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype)))
X {
X result = NULL_TREE;
X
X /* Perform operation on each member, depth-first, left-right. */
X for (i = 1; i <= CLASSTYPE_N_BASECLASSES (lhstype); i++)
X {
X tree base_lhs, base_rhs;
X tree new_result;
X
X /* Assignments from virtual baseclasses handled elsewhere. */
X if (CLASSTYPE_VIA_VIRTUAL (lhstype, i))
X continue;
X
X base_lhs = get_base_ref (lhstype, i, lhs);
X base_rhs = get_base_ref (lhstype, i, newrhs);
X
X new_result
X = build_modify_expr_1 (base_lhs, modifycode, base_rhs,
X tree_cons (NULL_TREE,
X TREE_TYPE (base_lhs),
X basetype_path));
X
X /* We either get back a compound stmt, or a simple one. */
X if (new_result && TREE_CODE (new_result) == TREE_LIST)
X new_result = build_compound_expr (new_result);
X result = tree_cons (NULL_TREE, new_result, result);
X }
X
X for (elt = TYPE_FIELDS (lhstype); elt; elt = TREE_CHAIN (elt))
X {
X tree vbases = NULL_TREE;
X tree elt_lhs, elt_rhs;
X
X if (TREE_CODE (elt) != FIELD_DECL)
X continue;
X if (DECL_NAME (elt)
X && (VFIELD_NAME_P (DECL_NAME (elt))
X || VBASE_NAME_P (DECL_NAME (elt))))
X continue;
X
X if (IS_AGGR_TYPE (TREE_TYPE (elt))
X && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
X vbases = CLASSTYPE_VBASECLASSES (TREE_TYPE (elt));
X
X elt_lhs = build (COMPONENT_REF, TREE_TYPE (elt), lhs, elt);
X elt_rhs = build (COMPONENT_REF, TREE_TYPE (elt), newrhs, elt);
X /* It is not always safe to go through `build_modify_expr_1'
X when performing element-wise copying. This is because
X an element may be of ARRAY_TYPE, which will not
X be properly copied as a naked element. */
X if (TREE_CODE (TREE_TYPE (elt)) == RECORD_TYPE
X && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
X basetype_path = CLASSTYPE_AS_LIST (TREE_TYPE (elt));
X
X while (vbases)
X {
X tree elt_lhs_addr = build_unary_op (ADDR_EXPR, elt_lhs);
X tree elt_rhs_addr = build_unary_op (ADDR_EXPR, elt_rhs);
X
X elt_lhs_addr = convert_pointer_to (TREE_TYPE (vbases), elt_lhs_addr);
X elt_rhs_addr = convert_pointer_to (TREE_TYPE (vbases), elt_rhs_addr);
X result = tree_cons (NULL_TREE, build_modify_expr_1 (build_indirect_ref (elt_lhs_addr, 0), modifycode, build_indirect_ref (elt_rhs_addr, 0), basetype_path), result);
X if (TREE_VALUE (result) == error_mark_node)
X return error_mark_node;
X vbases = TREE_CHAIN (vbases);
X }
X elt_lhs = build_modify_expr_1 (elt_lhs, modifycode, elt_rhs,
X basetype_path);
X result = tree_cons (NULL_TREE, elt_lhs, result);
X }
X
X if (result)
X return build_compound_expr (result);
X /* No fields to move. */
X return integer_zero_node;
X }
X else
X {
X result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
X void_type_node, lhs, rhs);
X TREE_VOLATILE (result) = 1;
X return result;
X }
X }
X
X result = build_modify_expr (lhs, modifycode, newrhs);
X /* ARRAY_TYPEs cannot be converted to anything meaningful,
X and leaving it there screws up `build_compond_exr' when
X it tries to defaultly convert everything. */
X if (TREE_CODE (TREE_TYPE (result)) == ARRAY_TYPE)
X TREE_TYPE (result) = void_type_node;
X return result;
X}
X
Xtree
Xbuild_modify_expr (lhs, modifycode, rhs)
X tree lhs, rhs;
X enum tree_code modifycode;
X{
X register tree result;
X tree newrhs = rhs;
X tree lhstype = TREE_TYPE (lhs);
X tree olhstype = lhstype;
X
X /* Types that aren't fully specified cannot be used in assignments. */
X lhs = require_complete_type (lhs);
X
X /* Avoid duplicate error messages from operands that had errors. */
X if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
X return error_mark_node;
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since RHS is being used in non-lvalue context. */
X if (TREE_CODE (rhs) == NOP_EXPR
X && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
X rhs = TREE_OPERAND (rhs, 0);
X
X newrhs = rhs;
X
X /* Handle control structure constructs used as "lvalues". */
X
X switch (TREE_CODE (lhs))
X {
X /* Handle (a, b) used as an "lvalue". */
X case COMPOUND_EXPR:
X pedantic_lvalue_warning (COMPOUND_EXPR);
X return build (COMPOUND_EXPR, lhstype,
X TREE_OPERAND (lhs, 0),
X build_modify_expr (TREE_OPERAND (lhs, 1),
X modifycode, rhs));
X
X /* Handle (a ? b : c) used as an "lvalue". */
X case COND_EXPR:
X pedantic_lvalue_warning (COND_EXPR);
X rhs = save_expr (rhs);
X {
X /* Produce (a ? (b = rhs) : (c = rhs))
X except that the RHS goes through a save-expr
X so the code to compute it is only emitted once. */
X tree cond
X = build_conditional_expr (TREE_OPERAND (lhs, 0),
X build_modify_expr (TREE_OPERAND (lhs, 1),
X modifycode, rhs),
X build_modify_expr (TREE_OPERAND (lhs, 2),
X modifycode, rhs));
X /* Make sure the code to compute the rhs comes out
X before the split. */
X return build (COMPOUND_EXPR, TREE_TYPE (lhs),
X /* Case to void to suppress warning
X from warn_if_unused_value. */
X convert (void_type_node, rhs), cond);
X }
X }
X
X /* If a binary op has been requested, combine the old LHS value with the RHS
X producing the value we should actually store into the LHS. */
X
X if (modifycode == INIT_EXPR)
X ;
X else if (modifycode == NOP_EXPR)
X {
X /* must deal with overloading of `operator=' here. */
X if (TREE_CODE (lhstype) == REFERENCE_TYPE)
X lhstype = TREE_TYPE (lhstype);
X#if 1
X /* `operator=' is not an inheritable operator. */
X if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
X {
X result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, (tree)NOP_EXPR);
X if (result == NULL_TREE)
X return error_mark_node;
X return result;
X }
X#else
X /* Treat `operator=' as an inheritable operator. */
X if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_GETS_ASSIGNMENT (lhstype))
X {
X tree orig_lhstype = lhstype;
X while (! TYPE_HAS_ASSIGNMENT (lhstype))
X {
X int i;
X tree basetype = NULL_TREE;
X for (i = 1; i <= CLASSTYPE_N_BASECLASSES (lhstype); i++)
X if (TYPE_GETS_ASSIGNMENT (CLASSTYPE_BASECLASS (lhstype, i)))
X {
X if (basetype != NULL_TREE)
X {
X message_2_types (error, "base classes `%s' and `%s' both have operator ='",
X basetype,
X CLASSTYPE_BASECLASS (lhstype, i));
X return error_mark_node;
X }
X basetype = CLASSTYPE_BASECLASS (lhstype, i);
X }
X lhstype = basetype;
X }
X if (orig_lhstype != lhstype)
X {
X lhs = build_indirect_ref (convert_pointer_to (lhstype,
X build_unary_op (ADDR_EXPR, lhs, 0)), 0);
X if (lhs == error_mark_node)
X {
X error_with_aggr_type (lhstype, "conversion to private basetype `%s'");
X return error_mark_node;
X }
X }
X result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, (tree)NOP_EXPR);
X if (result == NULL_TREE)
X return error_mark_node;
X return result;
X }
X#endif
X lhstype = olhstype;
X }
X else if (IS_AGGR_TYPE (lhstype)
X || (TREE_CODE (lhstype) == REFERENCE_TYPE
X && IS_AGGR_TYPE (TREE_TYPE (lhstype))))
X {
X /* This case must convert to some sort of lvalue that
X can participate in a op= operation. */
X tree lhs_tmp = lhs;
X tree rhs_tmp = rhs;
X if (build_default_binary_type_conversion (modifycode, &lhs_tmp, &rhs_tmp))
X {
X lhs = stabilize_reference (lhs_tmp);
X /* Forget is was ever anything else. */
X olhstype = lhstype = TREE_TYPE (lhs);
X newrhs = build_binary_op (modifycode, lhs, rhs_tmp);
X }
X else
X return error_mark_node;
X }
X else
X {
X lhs = stabilize_reference (lhs);
X newrhs = build_binary_op (modifycode, lhs, rhs);
X }
X
X /* Handle a cast used as an "lvalue".
X We have already performed any binary operator using the value as cast.
X Now convert the result to the true type of the lhs and store there;
X then cast the result back to the specified type to be the value
X of the assignment. */
X
X switch (TREE_CODE (lhs))
X {
X case NOP_EXPR:
X case CONVERT_EXPR:
X case FLOAT_EXPR:
X case FIX_TRUNC_EXPR:
X case FIX_FLOOR_EXPR:
X case FIX_ROUND_EXPR:
X case FIX_CEIL_EXPR:
X if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
X || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
X || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
X newrhs = default_conversion (newrhs);
X {
X tree inner_lhs = TREE_OPERAND (lhs, 0);
X tree result = build_modify_expr (inner_lhs, NOP_EXPR,
X convert (TREE_TYPE (inner_lhs),
X newrhs));
X return convert (TREE_TYPE (lhs), result);
X }
X }
X
X if (TREE_CODE (lhs) == OFFSET_REF)
X if (TREE_OPERAND (lhs, 0) == NULL_TREE)
X {
X /* Static class member? */
X tree member = TREE_OPERAND (lhs, 1);
X if (TREE_CODE (member) == VAR_DECL)
X lhs = member;
X else
X {
X compiler_error ("invalid static class member");
X return error_mark_node;
X }
X }
X else
X {
X tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (lhs, 0), 0);
X tree member = build_unary_op (ADDR_EXPR, TREE_OPERAND (lhs, 1), 0);
X
X if (TREE_CODE (base) == ERROR_MARK
X || TREE_CODE (member) == ERROR_MARK)
X return error_mark_node;
X lhs = build_indirect_ref (build (PLUS_EXPR, build_pointer_type (TREE_TYPE (lhs)),
X base, member));
X }
X
X /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
X Reject anything strange now. */
X
X if (!lvalue_or_else (lhs, "assignment"))
X return error_mark_node;
X
X#ifdef FIELD_XREF
X FIELD_xref_assign(lhs);
X#endif
X
X /* Warn about storing in something that is `const'. */
X /* For C++, don't warn if this is initialization. */
X if (modifycode != INIT_EXPR
X && (TREE_READONLY (lhs)
X || ((TREE_CODE (lhstype) == RECORD_TYPE
X || TREE_CODE (lhstype) == UNION_TYPE)
X && C_TYPE_FIELDS_READONLY (lhstype))
X || (TREE_CODE (lhstype) == REFERENCE_TYPE
X && TREE_READONLY (TREE_TYPE (lhstype)))))
X readonly_warning_or_error (lhs, "assignment");
X
X /* If storing into a structure or union member,
X it has probably been given type `int'.
X Compute the type that would go with
X the actual amount of storage the member occupies. */
X
X if (TREE_CODE (lhs) == COMPONENT_REF
X && (TREE_CODE (lhstype) == INTEGER_TYPE
X || TREE_CODE (lhstype) == REAL_TYPE
X || TREE_CODE (lhstype) == ENUMERAL_TYPE))
X lhstype = TREE_TYPE (get_unwidened (lhs, 0));
X
X /* check to see if there is an assignment to `this' */
X if (lhs == current_class_decl)
X {
X if (flag_this_is_variable
X && current_class_name != DECL_ORIGINAL_NAME (current_function_decl))
X warning ("assignment to `this' not in constructor or destructor");
X current_function_just_assigned_this = 1;
X }
X
X /* The TREE_TYPE of RHS may be TYPE_UNKNOWN. This can happen
X when the type of RHS is not yet known, i.e. its type
X is inherited from LHS. */
X rhs = require_instantiated_type (lhstype, newrhs, error_mark_node);
X if (rhs == error_mark_node)
X return error_mark_node;
X newrhs = rhs;
X
X if (modifycode != INIT_EXPR)
X {
X /* Make modifycode now either a NOP_EXPR or an INIT_EXPR. */
X modifycode = NOP_EXPR;
X /* Reference-bashing */
X if (TREE_CODE (lhstype) == REFERENCE_TYPE)
X {
X tree tmp = convert_from_reference (lhs);
X lhstype = TREE_TYPE (tmp);
X if (TYPE_SIZE (lhstype) == 0)
X {
X incomplete_type_error (lhs, lhstype);
X return error_mark_node;
X }
X lhs = tmp;
X olhstype = lhstype;
X }
X if (TREE_CODE (TREE_TYPE (newrhs)) == REFERENCE_TYPE)
X {
X tree tmp = convert_from_reference (newrhs);
X if (TYPE_SIZE (TREE_TYPE (tmp)) == 0)
X {
X incomplete_type_error (newrhs, TREE_TYPE (tmp));
X return error_mark_node;
X }
X newrhs = tmp;
X }
X }
X
X if (TREE_VOLATILE (lhs))
X lhs = stabilize_reference (lhs);
X if (TREE_VOLATILE (newrhs))
X newrhs = stabilize_reference (newrhs);
X
X /* C++: The semantics of C++ differ from those of C when an
X assignment of an aggregate is desired. Assignment in C++ is
X now defined as memberwise assignment of non-static members
X and base class objects. This rule applies recursively
X until a member of a built-in type is found.
X
X Also, we cannot do a bit-wise copy of aggregates which
X contain virtual function table pointers. Those
X pointer values must be preserved through the copy.
X However, this is handled in expand_expr, and not here.
X This is because much better code can be generated at
X that stage than this one. */
X if (TREE_CODE (lhstype) == RECORD_TYPE
X && (TYPE_USES_VIRTUAL_BASECLASSES (lhstype)
X || (modifycode != INIT_EXPR && TYPE_GETS_ASSIGNMENT (lhstype))
X || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype)))
X && (TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))
X || (TREE_CODE (TREE_TYPE (newrhs)) == RECORD_TYPE
X && get_base_type (lhstype, TREE_TYPE (newrhs), 0))))
X {
X tree vbases = CLASSTYPE_VBASECLASSES (lhstype);
X tree lhs_addr = build_unary_op (ADDR_EXPR, lhs);
X tree rhs_addr;
X
X /* Memberwise assignment would cause NEWRHS to be
X evaluated for every member that gets assigned.
X By wrapping side-effecting exprs in a SAVE_EXPR,
X NEWRHS will only be evaluated once. */
X if (IS_AGGR_TYPE (TREE_TYPE (newrhs))
X && TREE_VOLATILE (newrhs)
X /* This are things we don't have to save. */
X && TREE_CODE (newrhs) != NEW_EXPR
X && TREE_CODE (newrhs) != WITH_CLEANUP_EXPR)
X newrhs = save_expr (newrhs);
X
X rhs_addr = build_unary_op (ADDR_EXPR, newrhs);
X result = NULL_TREE;
X
X if (! comptypes (TREE_TYPE (lhs_addr), TREE_TYPE (rhs_addr), 1))
X {
X rhs_addr = convert_pointer_to (TREE_TYPE (TREE_TYPE (lhs_addr)), rhs_addr);
X newrhs = build_indirect_ref (rhs_addr, 0);
X }
X
X while (vbases)
X {
X tree elt_lhs = convert_pointer_to (TREE_TYPE (vbases), lhs_addr);
X tree elt_rhs = convert_pointer_to (TREE_TYPE (vbases), rhs_addr);
X result = tree_cons (NULL_TREE, build_modify_expr_1 (build_indirect_ref (elt_lhs, 0), modifycode, build_indirect_ref (elt_rhs, 0), CLASSTYPE_AS_LIST (lhstype)), result);
X if (TREE_VALUE (result) == error_mark_node)
X return error_mark_node;
X vbases = TREE_CHAIN (vbases);
X }
X result = tree_cons (NULL_TREE,
X build_modify_expr_1 (lhs, modifycode, newrhs, CLASSTYPE_AS_LIST (lhstype)),
X result);
X return build_compound_expr (result);
X }
X
X /* If storing in a field that is in actuality a short or narrower than one,
X we must store in the field in its actual type. */
X
X if (lhstype != TREE_TYPE (lhs))
X {
X lhs = copy_node (lhs);
X TREE_TYPE (lhs) = lhstype;
X }
X
X /* Convert new value to destination type. */
X
X if (modifycode == INIT_EXPR)
X {
X newrhs = convert_for_initialization (lhs, lhstype, newrhs, "assignment", LOOKUP_NORMAL);
X if (lhs == DECL_RESULT (current_function_decl))
X {
X if (DECL_INITIAL (lhs))
X warning ("return value from function receives multiple initializations");
X DECL_INITIAL (lhs) = newrhs;
X }
X }
X else
X {
X if (IS_AGGR_TYPE (lhstype))
X {
X if (TYPE_GETS_ASSIGNMENT (lhstype)
X && ! TYPE_HAS_ASSIGNMENT (lhstype))
X {
X error_with_aggr_type (lhstype, "assignment not defined for type `%s'");
X return error_mark_node;
X }
X if (result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, newrhs, NOP_EXPR))
X return result;
X }
X else if (TREE_CODE (lhstype) == ARRAY_TYPE)
X {
X /* Have to wrap this in RTL_EXPR for two cases:
X in base or member initialization and if we
X are a branch of a ?: operator. Since we
X can't easily know the latter, just do it always. */
X
X extern struct rtx_def *get_insns (), *const0_rtx;
X result = make_node (RTL_EXPR);
X
X TREE_TYPE (result) = void_type_node;
X do_pending_stack_adjust ();
X start_sequence ();
X
X /* As a matter of principle, `start_sequence' should do this. */
X emit_note (0, -1);
X
X expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs, 2);
X
X do_pending_stack_adjust ();
X
X TREE_VOLATILE (result) = 1;
X RTL_EXPR_SEQUENCE (result) = get_insns ();
X RTL_EXPR_RTL (result) = const0_rtx;
X end_sequence ();
X return result;
X }
X newrhs = convert_for_assignment (lhstype, newrhs, "assignment");
X if (flag_elide_constructors == 0
X && TREE_CODE (newrhs) == CALL_EXPR
X && TREE_ADDRESSABLE (lhstype))
X {
X /* Can't initialized directly from a CALL_EXPR, since
X we don't know about what doesn't alias what. */
X
X if (TYPE_NEEDS_DESTRUCTOR (lhstype))
X newrhs = cleanup_after_call (newrhs);
X else
X {
X tree temp = get_temp_name (lhstype, 0);
X newrhs = build (COMPOUND_EXPR, lhstype,
X build_modify_expr (temp, INIT_EXPR, newrhs),
X temp);
X }
X }
X }
X
X if (TREE_CODE (newrhs) == ERROR_MARK)
X return error_mark_node;
X
X result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
X lhstype, lhs, newrhs);
X TREE_VOLATILE (result) = 1;
X
X /* If we got the LHS in a different type for storing in,
X convert the result back to the nominal type of LHS
X so that the value we return always has the same type
X as the LHS argument. */
X
X if (olhstype == TREE_TYPE (result))
X return result;
X return convert_for_assignment (olhstype, result, "assignment");
X}
X
X
X/* Return 0 if EXP is not a valid lvalue in this language
X even though `lvalue_or_else' would accept it. */
X
Xint
Xlanguage_lvalue_valid (exp)
X tree exp;
X{
X return 1;
X}
X
X/* Convert value RHS to type TYPE as preparation for an assignment
X to an lvalue of type TYPE.
X The real work of conversion is done by `convert'.
X The purpose of this function is to generate error messages
X for assignments that are not allowed in C.
X ERRTYPE is a string to use in error messages:
X "assignment", "return", etc.
X
X C++: attempts to allow `convert' to find conversions involving
X implicit type conversion between aggregate and scalar types
X as per 8.5.6 of C++ manual. Does not randomly dereference
X pointers to aggregates! */
X
Xstatic tree
Xconvert_for_assignment (type, rhs, errtype)
X tree type, rhs;
X char *errtype;
X{
X register enum tree_code codel = TREE_CODE (type);
X register tree rhstype;
X register enum tree_code coder = TREE_CODE (TREE_TYPE (rhs));
X
X if (coder == UNKNOWN_TYPE)
X rhs = instantiate_type (type, rhs, 1);
X
X if (coder == ERROR_MARK)
X return error_mark_node;
X
X if (codel == OFFSET_TYPE)
X {
X type = TREE_TYPE (type);
X codel = TREE_CODE (type);
X }
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */
X if (TREE_CODE (rhs) == NOP_EXPR
X && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
X rhs = TREE_OPERAND (rhs, 0);
X
X if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
X {
X rhs = resolve_offset_ref (rhs);
X if (rhs == error_mark_node)
X return error_mark_node;
X rhstype = TREE_TYPE (rhs);
X coder = TREE_CODE (rhstype);
X }
X
X if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
X || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
X rhs = default_conversion (rhs);
X else if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
X rhs = convert_from_reference (rhs);
X
X if (rhs == error_mark_node)
X return error_mark_node;
X
X rhstype = TREE_TYPE (rhs);
X coder = TREE_CODE (rhstype);
X
X /* This should no longer change types on us. */
X if (TREE_CODE (rhs) == CONST_DECL)
X rhs = DECL_INITIAL (rhs);
X else if (TREE_READONLY_DECL_P (rhs))
X rhs = decl_constant_value (rhs);
X
X if (type == rhstype)
X return rhs;
X
X if (coder == VOID_TYPE)
X {
X error ("void value not ignored as it ought to be");
X return error_mark_node;
X }
X /* Arithmetic types all interconvert. */
X if ((codel == INTEGER_TYPE || codel == REAL_TYPE)
X && (coder == INTEGER_TYPE || coder == REAL_TYPE))
X {
X /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
X if (coder == REAL_TYPE && codel == INTEGER_TYPE)
X warning ("float or double assigned to integer data type");
X /* And we should warn if assigning a negative value to
X an unsigned variable. */
X else if (TREE_UNSIGNED (type))
X {
X if (TREE_CODE (rhs) == INTEGER_CST
X && TREE_NEGATED_INT (rhs))
X warning ("negative value assigned to unsigned quantity");
X if (TREE_LITERAL (rhs))
X rhs = fold (rhs);
X }
X
X return convert (type, rhs);
X }
X /* Conversions involving enums. */
X else if ((codel == ENUMERAL_TYPE
X && (coder == ENUMERAL_TYPE || coder == INTEGER_TYPE || coder == REAL_TYPE))
X || (coder == ENUMERAL_TYPE
X && (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE || codel == REAL_TYPE)))
X {
X extern int warn_enum_clash;
X
X if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
X return convert (type, rhs);
X if (warn_enum_clash)
X {
X if (codel == ENUMERAL_TYPE && coder == ENUMERAL_TYPE)
X message_2_types (warning, "conversion between incompatible enumeral types `%s' and `%s'",
X type, rhstype);
X else if (coder == REAL_TYPE)
X warning ("float or double assigned to enumeral data type");
X else if (codel == REAL_TYPE)
X warning ("enumeral value assigned to real data type");
X else if (coder == INTEGER_TYPE)
X warning ("assignment of integer to enumeral data type");
X }
X return convert (type, rhs);
X }
X /* Conversions among pointers */
X else if (codel == POINTER_TYPE && coder == POINTER_TYPE)
X {
X register tree ttl = TREE_TYPE (type);
X register tree ttr = TREE_TYPE (rhstype);
X
X /* If both pointers are of aggregate type, then we
X can give better error messages, and save some work
X as well. */
X if (IS_AGGR_TYPE (ttl) && IS_AGGR_TYPE (ttr))
X {
X tree basetype;
X
X if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr))
X basetype = ttl;
X else
X basetype = get_base_type (ttl, ttr, 1);
X
X if (basetype == error_mark_node)
X return error_mark_node;
X if (basetype == 0)
X {
X error_not_base_type (ttl, ttr);
X return error_mark_node;
X }
X if (! TREE_READONLY (ttl) && TREE_READONLY (ttr))
X warning ("%s of non-const * pointer from const *", errtype);
X if (! TREE_VOLATILE (ttl) && TREE_VOLATILE (ttr))
X warning ("%s of non-volatile * pointer from volatile *", errtype);
X }
X /* Any non-function converts to a [const][volatile] void *
X and vice versa; otherwise, targets must be the same.
X Meanwhile, the lhs target must have all the qualifiers of the rhs. */
X else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
X || TYPE_MAIN_VARIANT (ttr) == void_type_node
X || comp_target_types (type, rhstype, 1))
X {
X if (pedantic
X && ((TYPE_MAIN_VARIANT (ttl) == void_type_node
X && (TREE_CODE (ttr) == FUNCTION_TYPE
X || TREE_CODE (ttr) == METHOD_TYPE))
X ||
X (TYPE_MAIN_VARIANT (ttr) == void_type_node
X && (TREE_CODE (ttl) == FUNCTION_TYPE
X || TREE_CODE (ttl) == METHOD_TYPE))))
X warning ("%s between incompatible pointer types", errtype);
X else
X {
X if (TREE_CODE (ttl) == OFFSET_TYPE
X && virtual_member (TYPE_OFFSET_BASETYPE (ttr),
X CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl))))
X {
X sorry ("%s between pointer to members converting across virtual baseclasses", errtype);
X return error_mark_node;
X }
X if (! TREE_READONLY (ttl) && TREE_READONLY (ttr))
X warning ("%s of non-const * pointer from const *", errtype);
X if (! TREE_VOLATILE (ttl) && TREE_VOLATILE (ttr))
X warning ("%s of non-volatile * pointer from volatile *", errtype);
X }
X }
X else if (TREE_CODE (ttr) == OFFSET_TYPE
X && TREE_CODE (ttl) != OFFSET_TYPE)
X {
X /* Normally, pointers to different type codes (other
X than void) are not compatible, but we perform
X some type instantiation if that resolves the
X ambiguity of (X Y::*) and (X *). */
X
X if (current_class_decl)
X {
X if (TREE_CODE (rhs) == INTEGER_CST)
X {
X rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
X current_class_decl, rhs);
X return convert_for_assignment (type, rhs, errtype);
X }
X }
X if (TREE_CODE (ttl) == METHOD_TYPE)
X error ("%s between pointer-to-method and pointer-to-member types", errtype);
X else
X error ("%s between pointer and pointer-to-member types", errtype);
X return error_mark_node;
X }
X else
X {
X int const_parity = TREE_READONLY (type) ^ TREE_READONLY (rhstype);
X int volatile_parity = TREE_VOLATILE (type) ^ TREE_VOLATILE (rhstype);
X int unsigned_parity;
X int nptrs = 0;
X
X while (TREE_CODE (ttl) == POINTER_TYPE
X && TREE_CODE (ttr) == POINTER_TYPE)
X {
X nptrs -= 1;
X const_parity |= TREE_READONLY (ttl) ^ TREE_READONLY (ttr);
X volatile_parity |= TREE_VOLATILE (ttl) ^ TREE_VOLATILE (ttr);
X ttl = TREE_TYPE (ttl);
X ttr = TREE_TYPE (ttr);
X }
X unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
X if (unsigned_parity)
X if (TREE_UNSIGNED (ttl))
X ttr = unsigned_type (ttr);
X else
X ttl = unsigned_type (ttl);
X
X if (comp_target_types (ttl, ttr, nptrs))
X {
X if (const_parity)
X warning ("%s of non-const * pointer from const *", errtype);
X if (volatile_parity)
X warning ("%s of non-volatile * pointer from volatile *", errtype);
X if (unsigned_parity > 0)
X warning ("%s of unsigned pointer from signed pointer", errtype);
X else if (unsigned_parity < 0)
X warning ("%s of signed pointer from unsigned pointer", errtype);
X
X /* C++ is not so friendly about converting function and
X member function pointers as C. Emit warnings here. */
X if (TREE_CODE (ttl) == FUNCTION_TYPE
X || TREE_CODE (ttl) == METHOD_TYPE)
X if (! comptypes (ttl, ttr, 0))
X {
X char lhsbuf[2048];
X char rhsbuf[2048];
X tree null_name = get_identifier ("");
X tree lhs = build_decl (FUNCTION_DECL, null_name, ttl);
X tree rhs = build_decl (FUNCTION_DECL, null_name, ttr);
X fndecl_as_string (lhsbuf, 0, lhs, 1);
X fndecl_as_string (rhsbuf, 0, rhs, 1);
X warning ("conflicting function types in %s:", errtype);
X warning ("\t`%s' != `%s'", lhsbuf, rhsbuf);
X }
X }
X else if (TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
X {
X /* When does this happen? */
X abort ();
X /* Conversion of a pointer-to-member type to void *. */
X rhs = build_unary_op (ADDR_EXPR, rhs, 0);
X TREE_TYPE (rhs) = type;
X return rhs;
X }
X else if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
X {
X /* When does this happen? */
X abort ();
X /* Conversion of a pointer-to-member type to void *. */
X rhs = build_unary_op (ADDR_EXPR, rhs, 0);
X TREE_TYPE (rhs) = type;
X return rhs;
X }
X else
X {
X error ("%s between incompatible pointer types", errtype);
X return error_mark_node;
X }
X }
X return convert (type, rhs);
X }
X else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
X {
X if (! integer_zerop (rhs))
X {
X warning ("%s of pointer from integer lacks a cast", errtype);
X return convert (type, rhs);
X }
X return null_pointer_node;
X }
X else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
X {
X warning ("%s of integer from pointer lacks a cast", errtype);
X return convert (type, rhs);
X }
X
X /* C++ */
X else if (codel == ERROR_MARK || coder == ERROR_MARK)
X return error_mark_node;
X
X /* This should no longer happen. References are initialzed via
X `convert_for_initialization'. They should otherwise be
X bashed before coming here. */
X else if (codel == REFERENCE_TYPE)
X assert (codel != REFERENCE_TYPE);
X else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
X return build1 (NOP_EXPR, type, rhs);
X else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
X return convert (type, rhs);
X
X error ("incompatible types in %s", errtype);
X return error_mark_node;
X}
X
X/* Convert RHS to be of type TYPE. If EXP is non-zero,
X it is the target of the initialization.
X ERRTYPE is a string to use in error messages.
X
X Two major differences between the behavior of
X `convert_for_assignment' and `convert_for_initialization'
X are that references are bashed in the former, while
X copied in the latter, and aggregates are assigned in
X the former (operator=) while initialized in the
X latter (X(X&)). */
Xtree
Xconvert_for_initialization (exp, type, rhs, errtype, flags)
X tree exp, type, rhs;
X char *errtype;
X int flags;
X{
X register enum tree_code codel = TREE_CODE (type);
X register tree rhstype;
X register enum tree_code coder;
X
X /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
X Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */
X if (TREE_CODE (rhs) == NOP_EXPR
X && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
X rhs = TREE_OPERAND (rhs, 0);
X
X if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
X {
X rhs = resolve_offset_ref (rhs);
X if (rhs == error_mark_node)
X return error_mark_node;
X rhstype = TREE_TYPE (rhs);
X coder = TREE_CODE (rhstype);
X }
X
X if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
X && TREE_CODE (type) != ARRAY_TYPE && TREE_CODE (type) != REFERENCE_TYPE)
X || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
X || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
X rhs = default_conversion (rhs);
X
X rhstype = TREE_TYPE (rhs);
X coder = TREE_CODE (rhstype);
X
X if (coder == UNKNOWN_TYPE)
X {
X rhs = instantiate_type (type, rhs, 1);
X rhstype = TREE_TYPE (rhs);
X coder = TREE_CODE (rhstype);
X }
X
X if (coder == ERROR_MARK)
X return error_mark_node;
X
X#if 0
X /* This is *not* the quick way out! It is the way to disaster. */
X if (type == rhstype)
X goto converted;
X#endif
X
X /* We accept references to incomplete types, so we can
X return here before checking if RHS is of complete type. */
X
X if (codel == REFERENCE_TYPE)
X return convert_to_reference ((exp ? exp : error_mark_node), type, rhs, 0, flags);
X
X rhs = require_complete_type (rhs);
X if (rhs == error_mark_node)
X return error_mark_node;
X
X if (exp != 0) exp = require_complete_type (exp);
X if (exp == error_mark_node)
X return error_mark_node;
X
X if (TREE_CODE (rhstype) == REFERENCE_TYPE)
X rhstype = TREE_TYPE (rhstype);
X
X if (IS_AGGR_TYPE (type) && TYPE_NEEDS_CONSTRUCTOR (type))
X {
X if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
X {
X /* This is sufficient to perform initialization. No need, apparently,
X to go through X(X&) to do first-cut initialization. Return through
X a NEW_EXPR so that we get cleanups if it is used. */
X if (TREE_CODE (rhs) == CALL_EXPR)
X {
X rhs = build_cplus_new (type, rhs, 0);
X return rhs;
X }
X }
X if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)
X || (IS_AGGR_TYPE (rhstype) && get_base_type (type, rhstype, 0)))
X {
X if (TYPE_HAS_INIT_REF (type))
X {
X tree init = build_method_call (exp, DECL_NAME (TYPE_NAME (type)),
X build_tree_list (NULL_TREE, rhs),
X NULL_TREE, LOOKUP_NORMAL);
X
X if (init == error_mark_node)
X return error_mark_node;
X
X if (exp == 0)
X {
X exp = build_cplus_new (type, init, 0);
X return exp;
X }
X
X return build (COMPOUND_EXPR, type, init, exp);
X }
X
X if (TYPE_GETS_ASSIGNMENT (type))
X warning ("bitwise copy: `%s' defines operator=()",
X TYPE_NAME_STRING (type));
X
X if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
X rhs = convert_from_reference (rhs);
X if (type != rhstype)
X return build1 (NOP_EXPR, type, rhs);
X return rhs;
X }
X
X return convert (type, rhs);
X }
X if (TYPE_LANG_SPECIFIC (type) && TYPE_GETS_ASSIGNMENT (type))
X warning ("bitwise copy: `%s' defines operator=()",
X TYPE_NAME_STRING (type));
X
X converted:
X if (type == TREE_TYPE (rhs))
X {
X if (TREE_READONLY_DECL_P (rhs))
X rhs = decl_constant_value (rhs);
X return rhs;
X }
X
X return convert_for_assignment (type, rhs, errtype);
X}
X
X/* Expand an ASM statement with operands, handling output operands
X that are not variables or INDIRECT_REFS by transforming such
X cases into cases that expand_asm_operands can handle.
X
X Arguments are same as for expand_asm_operands. */
X
Xvoid
Xc_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
X tree string, outputs, inputs, clobbers;
X int vol;
X char *filename;
X int line;
X{
X int noutputs = list_length (outputs);
X register int i;
X /* o[I] is the place that output number I should be written. */
X register tree *o = (tree *) alloca (noutputs * sizeof (tree));
X register tree tail;
X
X /* Record the contents of OUTPUTS before it is modifed. */
X for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
X o[i] = TREE_VALUE (tail);
X
X#if 0 /* Don't do this--it screws up operands expected to be in memory. */
X /* Perform default conversions on all inputs. */
X for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++)
X TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
X#endif
X
X /* Generate the ASM_OPERANDS insn;
X store into the TREE_VALUEs of OUTPUTS some trees for
X where the values were actually stored. */
X expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line);
X
X /* Copy all the intermediate outputs into the specified outputs. */
X for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
X {
X extern struct rtx_def *const0_rtx;
X
X if (o[i] != TREE_VALUE (tail))
X expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
X const0_rtx, VOIDmode, 0);
X /* Detect modification of read-only values.
X (Otherwise done by build_modify_expr.) */
X else
X {
X tree type = TREE_TYPE (o[i]);
X if (TREE_READONLY (o[i])
X || ((TREE_CODE (type) == RECORD_TYPE
X || TREE_CODE (type) == UNION_TYPE)
X && C_TYPE_FIELDS_READONLY (type)))
X readonly_warning_or_error (o[i], "modification by `asm'");
X }
X }
X
X /* Those MODIFY_EXPRs could do autoincrements. */
X emit_queue ();
X}
X
X/* Expand a C `return' statement.
X RETVAL is the expression for what to return,
X or a null pointer for `return;' with no value.
X
X C++: upon seeing a `return', we must call destructors on all
X variables in scope which had constructors called on them.
X This means that if in a destructor, the base class destructors
X must be called before returning.
X
X The RETURN statement in C++ has initialization semantics. */
X
Xvoid
Xc_expand_return (retval)
X tree retval;
X{
X extern struct rtx_def *original_result_rtx;
X extern tree dtor_label, ctor_label;
X tree result = DECL_RESULT (current_function_decl);
X tree valtype = TREE_TYPE (result);
X register int use_temp = 0;
X
X if (TREE_THIS_VOLATILE (current_function_decl))
X warning ("function declared `volatile' has a `return' statement");
X
X if (retval == error_mark_node)
X {
X current_function_returns_null = 1;
X return;
X }
X
X if (retval == NULL_TREE)
X {
X /* A non-named return value does not count. */
X extern tree value_identifier;
X
X /* Can't just return from a destructor. */
X if (dtor_label)
X {
X expand_goto (dtor_label);
X return;
X }
X
X if (DECL_CONSTRUCTOR_P (current_function_decl))
X retval = current_class_decl;
X else if (result != NULL_TREE
X && DECL_NAME (result) != value_identifier
X && TREE_CODE (valtype) != VOID_TYPE)
X retval = result;
X else
X {
X current_function_returns_null = 1;
X if (valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
X {
X extern tree value_identifier;
X if (DECL_NAME (DECL_RESULT (current_function_decl)) == value_identifier)
X warning ("`return' with no value, in function returning non-void");
X }
X
X expand_null_return ();
X return;
X }
X }
X else if (DECL_CONSTRUCTOR_P (current_function_decl)
X && retval != current_class_decl)
X {
X error ("return from a constructor: use `this = ...' instead");
X retval = current_class_decl;
X }
X
X if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
X {
X current_function_returns_null = 1;
X if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
X warning ("`return' with a value, in function returning void");
X expand_return (retval);
X }
X /* Add some useful error checking for C++. */
X else if (TREE_CODE (valtype) == REFERENCE_TYPE)
X {
X tree whats_returned;
X tree tmp_result = result;
X
X /* Don't initialize directly into a non-BLKmode retval, since that
X could lose when being inlined by another caller. (GCC can't
X read the function return register in an inline function when
X the return value is being ignored). */
X if (result && TYPE_MODE (TREE_TYPE (tmp_result)) != BLKmode)
X tmp_result = 0;
X
X /* convert to reference now, so we can give error if we
X return an reference to a non-lvalue. */
X retval = convert_for_initialization (tmp_result, valtype, retval,
X LOOKUP_NORMAL, "return",
X NULL_TREE, 0);
X
X /* Sort through common things to see what it is
X we are returning. */
X whats_returned = retval;
X if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
X {
X whats_returned = TREE_OPERAND (whats_returned, 1);
X if (TREE_CODE (whats_returned) == ADDR_EXPR)
X whats_returned = TREE_OPERAND (whats_returned, 0);
X }
X if (TREE_CODE (whats_returned) == ADDR_EXPR)
X {
X whats_returned = TREE_OPERAND (whats_returned, 0);
X while (TREE_CODE (whats_returned) == NEW_EXPR
X || TREE_CODE (whats_returned) == WITH_CLEANUP_EXPR)
X /* Get the target. */
X whats_returned = TREE_OPERAND (whats_returned, 0);
X }
X
X if (TREE_CODE (whats_returned) == VAR_DECL)
X if (DECL_NAME (whats_returned) == NULL_TREE
X || TEMP_NAME_P (DECL_NAME (whats_returned)))
X warning ("reference to non-lvalue returned");
X else if (! TREE_STATIC (whats_returned)
X && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned)))
X warning_with_decl (whats_returned, "reference to local variable `%s' returned");
X }
X
X /* Now deal with possible C++ hair:
X (1) Compute the return value.
X (2) If there are aggregate values with destructors which
X must be cleaned up, clean them (taking care
X not to clobber the return value).
X (3) If an X(X&) constructor is defined, the return
X value must be returned via that. */
X
X if (retval == result
X /* Watch out for constructors, which "return" aggregates
X via initialization, but which otherwise "return" a pointer. */
X || DECL_CONSTRUCTOR_P (current_function_decl))
X {
X if (TYPE_MODE (valtype) != BLKmode
X && any_pending_cleanups (1))
X {
X retval = get_temp_regvar (valtype, retval);
X use_temp = obey_regdecls;
X }
X }
X else if (IS_AGGR_TYPE (valtype) && TYPE_NEEDS_CONSTRUCTOR (valtype))
X {
X /* Throw away the cleanup that `build_functional_cast' gave us. */
X if (TREE_CODE (retval) == WITH_CLEANUP_EXPR)
X retval = TREE_OPERAND (retval, 0);
X expand_aggr_init (result, retval, 0);
X DECL_INITIAL (result) = NULL_TREE;
X retval = 0;
X }
X else
X {
X if (TYPE_MODE (valtype) == VOIDmode)
X {
X if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode
X && warn_return_type)
X warning ("return of void value in function returning non-void");
X expand_expr_stmt (retval);
X retval = 0;
X result = 0;
X }
X else if (TYPE_MODE (valtype) != BLKmode
X && any_pending_cleanups (1))
X {
X retval = get_temp_regvar (valtype, retval);
X use_temp = obey_regdecls;
X result = 0;
X }
X else
X {
X retval = convert_for_initialization (result, valtype, retval,
X "return", LOOKUP_NORMAL);
X DECL_INITIAL (result) = NULL_TREE;
X }
X if (retval == error_mark_node)
X return;
X }
X
X emit_queue ();
X
X if (result)
X {
X /* Everything's great--RETVAL is in RESULT. */
X if (original_result_rtx)
X store_expr (result, original_result_rtx, 0);
X else if (retval && retval != result)
X {
X /* Here is where we finally get RETVAL into RESULT.
X `expand_return' does the magic of protecting
X RESULT from cleanups. */
X retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
X TREE_VOLATILE (retval) = 1;
X expand_return (retval);
X }
X else
X expand_return (result);
X
X use_variable (DECL_RTL (result));
X if (ctor_label)
X expand_goto (ctor_label);
X else
X expand_null_return ();
X }
X else
X {
X /* We may still need to put RETVAL into RESULT. */
X result = DECL_RESULT (current_function_decl);
X if (original_result_rtx)
X {
X /* Here we have a named return value that went
X into memory. We can compute RETVAL into that. */
X if (retval)
X expand_assignment (result, retval, 0, 0);
X else
X store_expr (result, original_result_rtx, 0);
X result = build (SAVE_EXPR, TREE_TYPE (result),
X error_mark_node, original_result_rtx);
X }
X else if (ctor_label)
X {
X /* Here RETVAL is CURRENT_CLASS_DECL, so there's nothing to do. */
X expand_goto (ctor_label);
X }
X else if (retval)
X {
X /* Here is where we finally get RETVAL into RESULT.
X `expand_return' does the magic of protecting
X RESULT from cleanups. */
X result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
X TREE_VOLATILE (result) = 1;
X expand_return (result);
X }
X else if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode)
X expand_return (result);
X }
X
X current_function_returns_value = 1;
X if (original_result_rtx)
X use_variable (original_result_rtx);
X if (use_temp)
X use_variable (DECL_RTL (DECL_RESULT (current_function_decl)));
X
X /* One way to clear out cleanups that EXPR might
X generate. Note that this code will really be
X dead code, but that is ok--cleanups that were
X needed were handled by the magic of `return'. */
X expand_cleanups_to (NULL_TREE);
X}
X
X/* Start a C switch statement, testing expression EXP.
X Return EXP if it is valid, an error node otherwise. */
X
Xtree
Xc_expand_start_case (exp)
X tree exp;
X{
X tree type = TREE_TYPE (exp);
X register enum tree_code code = TREE_CODE (type);
X
X if (IS_AGGR_TYPE_CODE (code))
X exp = build_type_conversion (CONVERT_EXPR, integer_type_node, exp, 1);
X else
X exp = default_conversion (exp);
X type = TREE_TYPE (exp);
X code = TREE_CODE (type);
X
X if (code != INTEGER_TYPE && code != ENUMERAL_TYPE && code != ERROR_MARK)
X {
X error ("switch quantity not an integer");
X exp = error_mark_node;
X }
X else
X {
X tree index;
X
X index = get_unwidened (exp, 0);
X /* We can't strip a conversion from a signed type to an unsigned,
X because if we did, int_fits_type_p would do the wrong thing
X when checking case values for being in range,
X and it's too hard to do the right thing. */
X if (TREE_UNSIGNED (TREE_TYPE (exp))
X == TREE_UNSIGNED (TREE_TYPE (index)))
X exp = index;
X }
X
X expand_start_case (1, exp, type);
X
X return exp;
X}
!EOF
echo "Extracting init_main.h..."
sed 's/^X//' >init_main.h << '!EOF'
X/* Startup code needed by GCC C++ output code. */
X/* Copyright (C) 1991 Free Software Foundation, Inc.
X
XThis file is part of GNU CC.
X
XGNU CC is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 2, or (at your option)
Xany later version.
X
XGNU CC is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU CC; see the file COPYING. If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X/* As a special exception, if you link this file with files
X compiled with GCC to produce an executable, this does not cause
X the resulting executable to be covered by the GNU General Public License.
X This exception does not however invalidate any other reasons why
X the executable file might be covered by the GNU General Public License. */
X
X/* init_main.h: Originally developed by James Kempf for SUN,
X * adapted and commented for FSF by Heinz Seidl ([email protected])
X */
X
X#ifndef _INIT_MAIN_H
X#define _INIT_MAIN_H
X
X/* That's the type of the entry point for initialization and finalization */
X
Xtypedef void entry_pt();
X
X/* Type of __C/DTOR_LIST__[] */
X
Xtypedef entry_pt * ep_fp;
X
X/* The default name of the initialization function(s). */
X
X#define INITIALIZE_MODULE __init /* one less _ due to assembler */
X#define FINALIZE_MODULE __fini
X#define INITIALIZE_MODULE_NAME "___init"
X#define FINALIZE_MODULE_NAME "___finit"
X#define INIT_START __init_start
X#define INIT_END __init_end
X
X#endif /* !_INIT_MAIN_H */
!EOF
echo "Extracting tree.def..."
sed 's/^X//' >tree.def << '!EOF'
X/* This file contains the definitions and documentation for the
X tree codes used in the GNU C compiler.
X Copyright (C) 1987, 1988 Free Software Foundation, Inc.
X
XThis file is part of GNU CC.
X
XGNU CC is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU CC is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU CC; see the file COPYING. If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X
X/* The third argument can be:
X "x" for an exceptional code (fits no category).
X "s" for a statement code.
X "t" for a type object code.
X
X "c" for codes for constants.
X "d" for codes for declarations (also serving as variable refs).
X "r" for codes for references to storage.
X "e" for codes for other kinds of expressions. */
X
X/* For `r', `e' and `x' nodes,
X the 4th element is the number of argument slots to allocate.
X This determines the size of the tree node object. */
X
X/* Any erroneous construct is parsed into a node of this type.
X This type of node is accepted without complaint in all contexts
X by later parsing activities, to avoid multiple error messages
X for one error.
X No fields in these nodes are used except the TREE_CODE. */
XDEFTREECODE (ERROR_MARK, "error_mark", "x", 0)
X
X/* Used to represent a name (such as, in the DECL_NAME of a decl node).
X Internally it looks like a STRING_CST node.
X There is only one IDENTIFIER_NODE ever made for any particular name.
X Use `get_identifier' to get it (or create it, the first time). */
XDEFTREECODE (IDENTIFIER_NODE, "identifier_node", "x", 2)
X
X/* Used to hold information to identify an operator (or combination
X of two operators) considered as a `noun' rather than a `verb'.
X The first operand is encoded in the TREE_TYPE field. */
XDEFTREECODE (OP_IDENTIFIER, "op_identifier", "x", 2)
X
X/* Has the TREE_VALUE and TREE_PURPOSE fields. */
X/* These nodes are made into lists by chaining through the
X TREE_CHAIN field. The elements of the list live in the
X TREE_VALUE fields, while TREE_PURPOSE fields are occasionally
X used as well to get the effect of Lisp association lists. */
XDEFTREECODE (TREE_LIST, "tree_list", "x", 2)
X
X/* These nodes contain an array of tree nodes. */
XDEFTREECODE (TREE_VEC, "tree_vec", "x", 2)
X
X/* Each data type is represented by a tree node whose code is one of
X the following: */
X/* Each node that represents a data type has a component TYPE_SIZE
X containing a tree that is an expression for the size in some units.
X The TYPE_SIZE_UNIT component is the number of bits in a unit.
X The TYPE_MODE contains the machine mode for values of this type.
X The TYPE_POINTER_TO field contains a type for a pointer to this type,
X or zero if no such has been created yet.
X The TYPE_NEXT_VARIANT field is used to chain together types
X that are variants made by type modifiers such as "const" and "volatile".
X The TYPE_MAIN_VARIANT field, in any member of such a chain,
X points to the start of the chain.
X The TYPE_NONCOPIED_PARTS field is a list specifying which parts
X of an object of this type should *not* be copied by assignment.
X The TREE_PURPOSE of each element is the offset of the part
X and the TREE_VALUE is the size in bits of the part.
X The TYPE_NAME field contains info on the name used in the program
X for this type (for GDB symbol table output). It is either a
X TYPE_DECL node, for types that are typedefs, or an IDENTIFIER_NODE
X in the case of structs, unions or enums that are known with a tag,
X or zero for types that have no special name. */
X/* The TREE_CHAIN of a ..._TYPE node is normally used to put
X every type onto permanent_type_chain or temporary_type_chain (see tree.c).
X One exception is for ENUMERAL_TYPE, RECORD_TYPE and UNION_TYPE
X nodes used as forward-references to names; see below. */
X
XDEFTREECODE (VOID_TYPE, "void_type", "t", 0) /* The void type in C */
X
X/* Integer types in all languages, including char in C. */
X/* Has components TYPE_MIN_VALUE, TYPE_MAX_VALUE (expressions, inclusive)
X and TYPE_PRECISION (number of bits used by this type).
X In the case of a subrange type in Pascal, the TREE_TYPE
X of this will point at the supertype (another INTEGER_TYPE).
X Otherwise, the TREE_TYPE is zero. */
XDEFTREECODE (INTEGER_TYPE, "integer_type", "t", 0)
X
X/* C's float and double. Different floating types are distinguished
X by machine mode and by the TYPE_SIZE and the TYPE_PRECISION. */
XDEFTREECODE (REAL_TYPE, "real_type", "t", 0)
X
X/* Complex number types. The TREE_TYPE field is the data type
X of the real and imaginary parts. */
XDEFTREECODE (COMPLEX_TYPE, "complex_type", "t", 0)
X
X/* C enums. The type node looks just like an INTEGER_TYPE node.
X The symbols for the values of the enum type are defined by
X CONST_DECL nodes, but the type does not point to them;
X however, the TREE_VALUES is a list in which each elements' TREE_PURPOSE
X is a name and the TREE_VALUE is the value (an INTEGER_CST node). */
X/* A forward reference `enum foo' when no enum named foo is defined yet
X has zero (a null pointer) in its TYPE_SIZE. The tag name is in
X the TYPE_NAME field. If the type is later defined, the normal
X fields are filled in.
X RECORD_TYPE and UNION_TYPE forward refs are treated similarly. */
XDEFTREECODE (ENUMERAL_TYPE, "enumeral_type", "t", 0)
X
X/* Pascal's boolean type (true or false are the only values);
X no special fields needed. */
XDEFTREECODE (BOOLEAN_TYPE, "boolean_type", "t", 0)
X
X/* CHAR in Pascal; not used in C.
X No special fields needed. */
XDEFTREECODE (CHAR_TYPE, "char_type", "t", 0)
X
X/* All pointer-to-x types have code POINTER_TYPE.
X The TREE_TYPE points to the node for the type pointed to. */
XDEFTREECODE (POINTER_TYPE, "pointer_type", "t", 0)
X
X/* An offset is a pointer relative to an object.
X The TREE_TYPE field is the type of the object at the offset.
X The TYPE_OFFSET_BASETYPE points to the node for the type of object
X that the offset is relative to. */
XDEFTREECODE (OFFSET_TYPE, "offset_type", "t", 0)
X
X/* A reference is like a pointer except that it is coerced
X automatically to the value it points to. Used in C++. */
XDEFTREECODE (REFERENCE_TYPE, "reference_type", "t", 0)
X
X/* METHOD_TYPE is the type of a function which takes an extra first
X argument for "self", which is not present in the declared argument list.
X The TREE_TYPE is the return type of the method. The TYPE_METHOD_BASETYPE
X is the type of "self". TYPE_ARG_TYPES is the real argument list, which
X includes the hidden argument for "self". */
XDEFTREECODE (METHOD_TYPE, "method_type", "t", 0)
X
X/* Used for Pascal; details not determined right now. */
XDEFTREECODE (FILE_TYPE, "file_type", "t", 0)
X
X/* Types of arrays. Special fields:
X TREE_TYPE Type of an array element.
X TYPE_DOMAIN Type to index by.
X Its range of values specifies the array length.
X TYPE_SEP Expression for units from one elt to the next.
X TYPE_SEP_UNIT Number of bits in a unit for previous.
X The field TYPE_POINTER_TO (TREE_TYPE (array_type)) is always nonzero
X and holds the type to coerce a value of that array type to in C. */
X/* Array types in C or Pascal */
XDEFTREECODE (ARRAY_TYPE, "array_type", "t", 0)
X
X/* Types of sets for Pascal. Special fields are the same as
X in an array type. The target type is always a boolean type. */
XDEFTREECODE (SET_TYPE, "set_type", "t", 0)
X
X/* Not known whether Pascal really needs this
X or what it should contain. */
XDEFTREECODE (STRING_TYPE, "string_type", "t", 0)
X
X/* Struct in C, or record in Pascal. */
X/* Special fields:
X TYPE_FIELDS chain of FIELD_DECLs for the fields of the struct.
X A few may need to be added for Pascal. */
X/* See the comment above, before ENUMERAL_TYPE, for how
X forward references to struct tags are handled in C. */
XDEFTREECODE (RECORD_TYPE, "record_type", "t", 0)
X
X/* Union in C. Like a struct, except that the offsets of the fields
X will all be zero. */
X/* See the comment above, before ENUMERAL_TYPE, for how
X forward references to union tags are handled in C. */
XDEFTREECODE (UNION_TYPE, "union_type", "t", 0) /* C union type */
X
X/* Type of functions. Special fields:
X TREE_TYPE type of value returned.
X TYPE_ARG_TYPES list of types of arguments expected.
X this list is made of TREE_LIST nodes.
X Types of "Procedures" in languages where they are different from functions
X have code FUNCTION_TYPE also, but then TREE_TYPE is zero or void type. */
XDEFTREECODE (FUNCTION_TYPE, "function_type", "t", 0)
X
X/* This is a language-specific kind of type.
X Its meaning is defined by the language front end.
X layout_type does not know how to lay this out,
X so the front-end must do so manually. */
XDEFTREECODE (LANG_TYPE, "lang_type", "t", 0)
X
X/* All statement types have fields STMT_SOURCE_FILE and STMT_SOURCE_LINE. */
X/* Consecutive statements within a compound statement are chained together
X through the TREE_CHAIN field. */
X
X/* A label definition, encapsulated as a statement.
X STMT_BODY is the LABEL_DECL node for the label that appears here. */
XDEFTREECODE (LABEL_STMT, "label_stmt", "s", 1)
X
X/* GOTO, in any language. STMT_BODY is a LABEL_DECL node. */
XDEFTREECODE (GOTO_STMT, "goto_stmt", "s", 1)

X
X/* RETURN, in any language.
X Evaluates the expression STMT_BODY, then returns from the current function.
X Presumably STMT_BODY is an assignment that stores into the
X RESULT_DECL that hold the value to be returned.
X STMT_BODY may be zero. */
XDEFTREECODE (RETURN_STMT, "return_stmt", "s", 1)
X
X/* Statement that evaluates an expression. STMT_BODY is the expression. */
XDEFTREECODE (EXPR_STMT, "expr_stmt", "s", 1)
X
X/* Pascal WITH statement.
X Contains a chain of variables (..._DECL nodes) in the STMT_VARS
X and a chain of statements (the STMT_BODY).
X STMT_SUPERCONTEXT points to the containing declaration scope. */
XDEFTREECODE (WITH_STMT, "with_stmt", "s", 5)
X
X/* Declare variables whose scope is less than a function.
X This is used for C brace-pairs that contain declarations.
X Contains a chain of variables (..._DECL nodes) in the STMT_VARS
X and a chain of statements (the STMT_BODY).
X STMT_SUPERCONTEXT points to the containing declaration scope.
X STMT_BIND_SIZE is an expression for the size of local storage here.
X STMT_TYPE_TAGS is a list (chain of TREE_LIST nodes)
X pairing struct, union and enum tag names with the types they mean,
X for tags defined in this context.
X
X A LET_STMT can be used as an expression. Its STMT_BODY is expanded
X in its stead. Its TREE_USED is set if it is expanded.
X
X A LET_STMT whose TREE_USED is not set is ignored when symbols
X are output. If the LET_STMT is passed to expand_expr but it
X should not be ignored, set its TREE_USED by hand. */
XDEFTREECODE (LET_STMT, "let_stmt", "s", 6)
X
X/* if-then-else statements in C and other languages.
X STMT_COND is the condition (an expression).
X STMT_THEN is the then-branch (a statement or chain of statements).
X STMT_ELSE is the else-branch (a statement or chain of statements). */
XDEFTREECODE (IF_STMT, "if_stmt", "s", 3)
X
X/* if-else-exit; used in building parts of iterations.
X STMT_BODY is the condition (an expression).
X Exit if the iteration if the condition is FALSE. */
XDEFTREECODE (EXIT_STMT, "exit_stmt", "s", 1)
X
X/* STMT_CASE_INDEX is an expression for the value to dispatch on.
X STMT_CASE_LIST is a list (a chain of TREE_LIST nodes)
X of the branches of the dispatch.
X Each such TREE_LIST node has the case it is for (a constant expression)
X as the TREE_PURPOSE
X and the label to go to (a LABEL_DECL) as the TREE_VALUE.
X
X Normally, the labels reside inside a COMPOUND_STMT
X which contains ths CASE_STMT as its first statement. */
XDEFTREECODE (CASE_STMT, "case_stmt", "s", 3)
X
X/* STMT_LOOP_VARS are the variables to be used as iterators
X in the loop.
X STMT_LOOP_COND is the condition to test each time through
X the loop. If TREE_READONLY is set, condition is tested
X before entering the loop; otherwise it is tested at the bottom.
X STMT_LOOP_BODY contains a chain of statements to be executed in loop. */
XDEFTREECODE (LOOP_STMT, "loop_stmt", "s", 3)
X
X/* Contains as its STMT_BODY a chain of substatements. */
XDEFTREECODE (COMPOUND_STMT, "compound_stmt", "s", 1)
X
X/* Contains as its STMT_BODY a string of assembly code. */
XDEFTREECODE (ASM_STMT, "asm_stmt", "s", 1)
X
X/* Expressions */
X
X/* First, the constants. */
X
X/* Contents are in TREE_INT_CST_LOW and TREE_INT_CST_HIGH fields,
X 32 bits each, giving us a 64 bit constant capability.
X Note: constants of type char in Pascal are INTEGER_CST,
X and so are pointer constants such as nil in Pascal or NULL in C.
X `(int *) 1' in C also results in an INTEGER_CST. */
XDEFTREECODE (INTEGER_CST, "integer_cst", "c", 2)
X
X/* Contents are in TREE_REAL_CST field. Also there is TREE_CST_RTL. */
XDEFTREECODE (REAL_CST, "real_cst", "c", 3)
X
X/* Contents are in TREE_REALPART and TREE_IMAGPART fields,
X whose contents are other constant nodes.
X Also there is TREE_CST_RTL. */
XDEFTREECODE (COMPLEX_CST, "complex_cst", "c", 3)
X
X/* Contents are TREE_STRING_LENGTH and TREE_STRING_POINTER fields.
X Also there is TREE_CST_RTL. */
XDEFTREECODE (STRING_CST, "string_cst", "c", 3)
X
X/* Declarations. All references to names are represented as ..._DECL nodes.
X The decls in one binding context are chained through the TREE_CHAIN field.
X Each DECL has a DECL_NAME field which contains an IDENTIFIER_NODE.
X (Some decls, most often labels, may have zero as the DECL_NAME).
X DECL_CONTEXT points to the node representing the context in which
X this declaration has its scope. For FIELD_DECLs, this is the
X RECORD_TYPE or UNION_TYPE node that the field belongs to;
X for VAR_DECL, PARM_DECL, FUNCTION_DECL and LABEL_DECL, this
X is the FUNCTION_DECL for the containing function, or 0 if global.
X The TREE_TYPE field holds the data type of the object, when relevant.
X LABEL_DECLs have no data type. For TYPE_DECL, the TREE_TYPE field
X contents are the type whose name is being declared.
X The DECL_ALIGN, DECL_SIZE, DECL_SIZE_UNIT
X and DECL_MODE fields exist in decl nodes just as in type nodes.
X They are unused in LABEL_DECL, TYPE_DECL and CONST_DECL nodes.
X
X DECL_OFFSET holds an integer number of bits offset for the location.
X DECL_VOFFSET holds an expression for a variable offset; it is
X to be multiplied by DECL_VOFFSET_UNIT (an integer).
X These fields are relevant only in FIELD_DECLs and PARM_DECLs.
X
X DECL_INITIAL holds the value to initialize a variable to,
X or the value of a constant. For a function, it holds the body
X (a node of type LET_STMT representing the function's binding contour
X and whose body contains the function's statements.) For a LABEL_DECL
X in C, it is a flag, nonzero if the label's definition has been seen.
X
X PARM_DECLs use a special field:
X DECL_ARG_TYPE is the type in which the argument is actually
X passed, which may be different from its type within the function.
X
X FUNCTION_DECLs use four special fields:
X DECL_ARGUMENTS holds a chain of PARM_DECL nodes for the arguments.
X DECL_RESULT holds a RESULT_DECL node for the value of a function,
X or it is 0 for a function that returns no value.
X (C functions returning void have zero here.)
X DECL_RESULT_TYPE holds the type in which the result is actually
X returned. This is usually the same as the type of DECL_RESULT,
X but (1) it may be a wider integer type and
X (2) it remains valid, for the sake of inlining, even after the
X function's compilation is done.
X DECL_FUNCTION_CODE is a code number that is nonzero for
X built-in functions. Its value is an enum built_in_function
X that says which built-in function it is.
X DECL_BLOCK_SYMTAB_ADDRESS records (after the symtab data for the function's
X body has been output) the address in the symtab file of the
X `struct block' for the function's top-level binding context.
X This must be stored in the symtab structure for the function name.
X Also, TREE_UNSIGNED (function_decl) is nonzero if the ({...})
X construct is used in the function.
X
X DECL_SOURCE_FILE holds a filename string and DECL_SOURCE_LINE
X holds a line number. In some cases these can be the location of
X a reference, if no definition has been seen. */
X
XDEFTREECODE (FUNCTION_DECL, "function_decl", "d", 5)
XDEFTREECODE (LABEL_DECL, "label_decl", "d", 0)
XDEFTREECODE (CONST_DECL, "const_decl", "d", 0)
XDEFTREECODE (TYPE_DECL, "type_decl", "d", 0)
XDEFTREECODE (VAR_DECL, "var_decl", "d", 0)
XDEFTREECODE (PARM_DECL, "parm_decl", "d", -3)
XDEFTREECODE (RESULT_DECL, "result_decl", "d", 0)
XDEFTREECODE (FIELD_DECL, "field_decl", "d", 0)
X
X/* References to storage. */
X
X/* Value is structure or union component.
X Operand 0 is the structure or union (an expression);
X operand 1 is the field (a node of type FIELD_DECL). */
XDEFTREECODE (COMPONENT_REF, "component_ref", "r", 2)
X
X/* C unary `*' or Pascal `^'. One operand, an expression for a pointer. */
XDEFTREECODE (INDIRECT_REF, "indirect_ref", "r", 1)
X
X/* Reference to the contents of an offset
X (a value whose type is an OFFSET_TYPE).
X Operand 0 is the object within which the offset is taken.
X Operand 1 is the offset. */
XDEFTREECODE (OFFSET_REF, "offset_ref", "r", 2)
X
X/* Pascal `^` on a file. One operand, an expression for the file. */
XDEFTREECODE (BUFFER_REF, "buffer_ref", "r", 1)
X
X/* Array indexing in languages other than C.
X Operand 0 is the array; operand 1 is a list of indices
X stored as a chain of TREE_LIST nodes. */
XDEFTREECODE (ARRAY_REF, "array_ref", "r", 2)
X
X/* Constructor: return an aggregate value made from specified components.
X In C, this is used only for structure and array initializers.
X The first "operand" is really a pointer to the RTL,
X for constant constructors only.
X The second operand is a list of component values
X made out of a chain of TREE_LIST nodes. */
XDEFTREECODE (CONSTRUCTOR, "constructor", "e", 2)
X
X/* The expression types are mostly straightforward,
X with the fourth argument of DEFTREECODE saying
X how many operands there are.
X Unless otherwise specified, the operands are expressions. */
X
X/* Contains two expressions to compute, one followed by the other.
X the first value is ignored. The second one's value is used. */
XDEFTREECODE (COMPOUND_EXPR, "compound_expr", "e", 2)
X
X/* Assignment expression. Operand 0 is the what to set; 1, the new value. */
XDEFTREECODE (MODIFY_EXPR, "modify_expr", "e", 2)
X
X/* Initialization expression. Operand 0 is the variable to initialize;
X Operand 1 is the initializer. */
XDEFTREECODE (INIT_EXPR, "init_expr", "e", 2)
X
X/* For NEW_EXPR, operand 0 is function which performs initialization,
X operand 1 is argument list to initialization function,
X and operand 2 is the cleanup for this node, if any. */
XDEFTREECODE (NEW_EXPR, "new_expr", "e", 3)
X
X/* Conditional expression ( ... ? ... : ... in C).
X Operand 0 is the condition.
X Operand 1 is the then-value.
X Operand 2 is the else-value. */
XDEFTREECODE (COND_EXPR, "cond_expr", "e", 3)
X
X/* Function call. Operand 0 is the function.
X Operand 1 is the argument list, a list of expressions
X made out of a chain of TREE_LIST nodes.
X There is no operand 2. That slot is used for the
X CALL_EXPR_RTL macro (see preexpand_calls). */
XDEFTREECODE (CALL_EXPR, "call_expr", "e", 3)
X
X/* Call a method. Operand 0 is the method, whose type is a METHOD_TYPE.
X Operand 1 is the expression for "self".
X Operand 2 is the list of explicit arguments. */
XDEFTREECODE (METHOD_CALL_EXPR, "method_call_expr", "e", 4)
X
X/* Specify a value to compute along with its corresponding cleanup.
X Operand 0 argument is an expression whose value needs a cleanup.
X Operand 1 is an RTL_EXPR which will eventually represent that value.
X Operand 2 is the cleanup expression for the object.
X The RTL_EXPR is used in this expression, which is how the expression
X manages to act on the proper value.
X The cleanup is executed when the value is no longer needed,
X which is not at precisely the same time that this value is computed. */
XDEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", "e", 3)
X
X/* Simple arithmetic. Operands must have the same machine mode
X and the value shares that mode. */
XDEFTREECODE (PLUS_EXPR, "plus_expr", "e", 2)
XDEFTREECODE (MINUS_EXPR, "minus_expr", "e", 2)
XDEFTREECODE (MULT_EXPR, "mult_expr", "e", 2)
X
X/* Division for integer result that rounds the quotient toward zero. */
X/* Operands must have the same machine mode.
X In principle they may be real, but that is not currently supported.
X The result is always fixed point, and it has the same type as the
X operands if they are fixed point. */
XDEFTREECODE (TRUNC_DIV_EXPR, "trunc_div_expr", "e", 2)
X
X/* Division for integer result that rounds the quotient toward infinity. */
XDEFTREECODE (CEIL_DIV_EXPR, "ceil_div_expr", "e", 2)
X
X/* Division for integer result that rounds toward minus infinity. */
XDEFTREECODE (FLOOR_DIV_EXPR, "floor_div_expr", "e", 2)
X
X/* Division for integer result that rounds toward nearest integer. */
XDEFTREECODE (ROUND_DIV_EXPR, "round_div_expr", "e", 2)
X
X/* Four kinds of remainder that go with the four kinds of division. */
XDEFTREECODE (TRUNC_MOD_EXPR, "trunc_mod_expr", "e", 2)
XDEFTREECODE (CEIL_MOD_EXPR, "ceil_mod_expr", "e", 2)
XDEFTREECODE (FLOOR_MOD_EXPR, "floor_mod_expr", "e", 2)
XDEFTREECODE (ROUND_MOD_EXPR, "round_mod_expr", "e", 2)
X
X/* Division for real result. The two operands must have the same type.
X In principle they could be integers, but currently only real
X operands are supported. The result must have the same type
X as the operands. */
XDEFTREECODE (RDIV_EXPR, "rdiv_expr", "e", 2)
X
X/* Division which is not supposed to need rounding.
X Used for pointer subtraction in C. */
XDEFTREECODE (EXACT_DIV_EXPR, "exact_div_expr", "e", 2)
X
X/* Conversion of real to fixed point: four ways to round,
X like the four ways to divide.
X CONVERT_EXPR can also be used to convert a real to an integer,
X and that is what is used in languages that do not have ways of
X specifying which of these is wanted. Maybe these are not needed. */
XDEFTREECODE (FIX_TRUNC_EXPR, "fix_trunc_expr", "e", 1)
XDEFTREECODE (FIX_CEIL_EXPR, "fix_ceil_expr", "e", 1)
XDEFTREECODE (FIX_FLOOR_EXPR, "fix_floor_expr", "e", 1)
XDEFTREECODE (FIX_ROUND_EXPR, "fix_round_expr", "e", 1)
X
X/* Conversion of an integer to a real. */
XDEFTREECODE (FLOAT_EXPR, "float_expr", "e", 1)
X
X/* Exponentiation. Operands may have any types;
X constraints on value type are not known yet. */
XDEFTREECODE (EXPON_EXPR, "expon_expr", "e", 2)
X
X/* Unary negation. Value has same type as operand. */
XDEFTREECODE (NEGATE_EXPR, "negate_expr", "e", 1)
X
XDEFTREECODE (MIN_EXPR, "min_expr", "e", 2)
XDEFTREECODE (MAX_EXPR, "max_expr", "e", 2)
XDEFTREECODE (ABS_EXPR, "abs_expr", "e", 1)
XDEFTREECODE (FFS_EXPR, "ffs_expr", "e", 1)
X
X/* Shift operations for shift and rotate.
X Shift is supposed to mean logical shift if done on an
X unsigned type, arithmetic shift on a signed type.
X The second operand is the number of bits to
X shift by, and must always have mode SImode.
X The result has the same mode as the first operand. */
XDEFTREECODE (LSHIFT_EXPR, "alshift_expr", "e", 2)
XDEFTREECODE (RSHIFT_EXPR, "arshift_expr", "e", 2)
XDEFTREECODE (LROTATE_EXPR, "lrotate_expr", "e", 2)
XDEFTREECODE (RROTATE_EXPR, "rrotate_expr", "e", 2)
X
X/* Bitwise operations. Operands have same mode as result. */
XDEFTREECODE (BIT_IOR_EXPR, "bit_ior_expr", "e", 2)
XDEFTREECODE (BIT_XOR_EXPR, "bit_xor_expr", "e", 2)
XDEFTREECODE (BIT_AND_EXPR, "bit_and_expr", "e", 2)
XDEFTREECODE (BIT_ANDTC_EXPR, "bit_andtc_expr", "e", 2)
XDEFTREECODE (BIT_NOT_EXPR, "bit_not_expr", "e", 1)
X
X/* Combination of boolean values or of integers considered only
X as zero or nonzero. ANDIF and ORIF allow the second operand
X not to be computed if the value of the expression is determined
X from the first operand. AND and OR always compute the second
X operand whether its value is needed or not (for side effects). */
XDEFTREECODE (TRUTH_ANDIF_EXPR, "truth_andif_expr", "e", 2)
XDEFTREECODE (TRUTH_ORIF_EXPR, "truth_orif_expr", "e", 2)
XDEFTREECODE (TRUTH_AND_EXPR, "truth_and_expr", "e", 2)
XDEFTREECODE (TRUTH_OR_EXPR, "truth_or_expr", "e", 2)
XDEFTREECODE (TRUTH_NOT_EXPR, "truth_not_expr", "e", 1)
X
X/* Relational operators.
X `EQ_EXPR' and `NE_EXPR' are allowed for any types.
X The others are allowed only for integer (or pointer or enumeral)
X or real types.
X In all cases the operands will have the same type,
X and the value is always the type used by the language for booleans. */
XDEFTREECODE (LT_EXPR, "lt_expr", "e", 2)
XDEFTREECODE (LE_EXPR, "le_expr", "e", 2)
XDEFTREECODE (GT_EXPR, "gt_expr", "e", 2)
XDEFTREECODE (GE_EXPR, "ge_expr", "e", 2)
XDEFTREECODE (EQ_EXPR, "eq_expr", "e", 2)
XDEFTREECODE (NE_EXPR, "ne_expr", "e", 2)
X
X/* Operations for Pascal sets. Not used now. */
XDEFTREECODE (IN_EXPR, "in_expr", "e", 2)
XDEFTREECODE (SET_LE_EXPR, "set_le_expr", "e", 2)
XDEFTREECODE (CARD_EXPR, "card_expr", "e", 1)
XDEFTREECODE (RANGE_EXPR, "range_expr", "e", 2)
X
X/* Represents a conversion of type of a value.
X All conversions, including implicit ones, must be
X represented by CONVERT_EXPR nodes. */
XDEFTREECODE (CONVERT_EXPR, "convert_expr", "e", 1)
X
X/* Represents a conversion expected to require no code to be generated. */
XDEFTREECODE (NOP_EXPR, "nop_expr", "e", 1)
X
X/* Represents something we computed once and will use multiple times.
X First operand is that expression. Second is the RTL,
X nonzero only after the expression has been computed.
X TREE_UNSIGNED in a SAVE_EXPR is nonzero if that SAVE_EXPR
X has been seen already in assign_vars_1. */
XDEFTREECODE (SAVE_EXPR, "save_expr", "e", 2)
X
X/* Represents something whose RTL has already been expanded
X as a sequence which should be emitted when this expression is expanded.
X The first operand is the RTL to emit. It is the first of a chain of insns.
X The second is the RTL expression for the result. */
XDEFTREECODE (RTL_EXPR, "rtl_expr", "e", 2)
X
X/* & in C. Value is the address at which the operand's value resides.
X Operand may have any mode. Result mode is Pmode. */
XDEFTREECODE (ADDR_EXPR, "addr_expr", "e", 1)
X
X/* Non-lvalue reference or pointer to an object. */
XDEFTREECODE (REFERENCE_EXPR, "reference_expr", "e", 1)
X
X/* A wrapper in C++. Operand 0 is the type that the wrapper
X belongs to (if non-virtual). Operand 1 is the function
X being wrapped. An anti-wrapper means do not wrap the function
X (if it would be wrapped by default). */
XDEFTREECODE (WRAPPER_EXPR, "wrapper_expr", "e", 2)
XDEFTREECODE (ANTI_WRAPPER_EXPR, "anti_wrapper_expr", "e", 2)
X
X/* Operand is a function constant; result is a function variable value
X of typeEPmode. Used only for languages that need static chains. */
XDEFTREECODE (ENTRY_VALUE_EXPR, "entry_value_expr", "e", 1)
X
X/* Given two real or integer operands of the same type,
X returns a complex value of the corresponding complex type. */
XDEFTREECODE (COMPLEX_EXPR, "complex_expr", "e", 2)
X
X/* Complex conjugate of operand. Used only on complex types.
X The value has the same type as the operand. */
XDEFTREECODE (CONJ_EXPR, "conj_expr", "e", 1)
X
X/* Used only on an operand of complex type, these return
X a value of the corresponding component type. */
XDEFTREECODE (REALPART_EXPR, "realpart_expr", "e", 1)
XDEFTREECODE (IMAGPART_EXPR, "imagpart_expr", "e", 1)
X
X/* Nodes for ++ and -- in C.
X The second arg is how much to increment or decrement by.
X For a pointer, it would be the size of the object pointed to. */
XDEFTREECODE (PREDECREMENT_EXPR, "predecrement_expr", "e", 2)
XDEFTREECODE (PREINCREMENT_EXPR, "preincrement_expr", "e", 2)
XDEFTREECODE (POSTDECREMENT_EXPR, "postdecrement_expr", "e", 2)
XDEFTREECODE (POSTINCREMENT_EXPR, "postincrement_expr", "e", 2)
X
X/*
XLocal variables:
Xmode:c
Xversion-control: t
XEnd:
X*/
!EOF
echo "Extracting cplus-decl.c..."
sed 's/^X//' >cplus-decl.c << '!EOF'
X/* Process declarations and variables for C compiler.
X Copyright (C) 1988 Free Software Foundation, Inc.
X Hacked by Michael Tiemann ([email protected])
X
XThis file is part of GNU CC.
X
XGNU CC is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU CC is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU CC; see the file COPYING. If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X
X/* Process declarations and symbol lookup for C front end.
X Also constructs types; the standard scalar types at initialization,
X and structure, union, array and enum types when they are declared. */
X
X/* ??? not all decl nodes are given the most useful possible
X line numbers. For example, the CONST_DECLs for enum values. */
X
X#include "config.h"
X#include "tree.h"
X#include "flags.h"
X#include "cplus-tree.h"
X#include "cplus-parse.h"
X#include
X#include "assert.h"
X#include "obstack.h"
X#include "rtl.h"
X#include "insn-flags.h"
X
X#define obstack_chunk_alloc xmalloc
X#define obstack_chunk_free free
X
Xextern int xmalloc ();
Xextern void free ();
X
X/* Define this if C structs should have gratuitous typedefing
X done just like C++ structs do. */
X#define BREAK_C_TAGS
X
X/* Stack of places to restore the search obstack back to. */
X
X/* Obstack used for remembering local class declarations (like
X enums and static (const) members. */
X#include "stack.h"
Xstatic struct obstack decl_obstack;
Xstatic struct stack_level *decl_stack;
X
X#include "cplus-decl.h"
X
X#define NULL 0
X#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
X#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
X
X#ifndef CHAR_TYPE_SIZE
X#define CHAR_TYPE_SIZE BITS_PER_UNIT
X#endif
X
X#ifndef SHORT_TYPE_SIZE
X#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
X#endif
X
X#ifndef INT_TYPE_SIZE
X#define INT_TYPE_SIZE BITS_PER_WORD
X#endif
X
X#ifndef LONG_TYPE_SIZE
X#define LONG_TYPE_SIZE BITS_PER_WORD
X#endif
X
X#ifndef LONG_LONG_TYPE_SIZE
X#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
X#endif
X
X#ifndef FLOAT_TYPE_SIZE
X#define FLOAT_TYPE_SIZE BITS_PER_WORD
X#endif
X
X#ifndef DOUBLE_TYPE_SIZE
X#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
X#endif
X
X#ifndef LONG_DOUBLE_TYPE_SIZE
X#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
X#endif
X
Xstatic tree grokparms ();
Xtree grokdeclarator ();
Xtree pushdecl ();
Xvoid push_overloaded_decl ();
Xvoid pop_implicit_try_blocks ();
X
X#define builtin_function(NAME, TYPE, CODE) \
X define_function (NAME, TYPE, CODE, (void (*)())&pushdecl)
X#define auto_function(NAME, TYPE, CODE) \
X define_function (NAME, TYPE, CODE, (void (*)())&push_overloaded_decl)
X
X/* static */ void grokclassfn ();
X/* static */ tree grokopexpr (), grokoptypename ();
X
Xstatic tree lookup_tag ();
Xstatic tree lookup_tag_reverse ();
Xstatic tree lookup_name_current_level ();
Xstatic char *redeclaration_error_message ();
Xstatic int parmlist_is_exprlist ();
Xstatic int parmlist_is_random ();
Xstatic void grok_ctor_properties ();
Xstatic void grok_op_properties ();
Xstatic void expand_static_init ();
Xstatic void deactivate_exception_cleanups ();
X
Xtree finish_table ();
X#ifdef FIELD_XREF
Xstatic void FIELD_end_scope();
X#endif
X
X/* a node which has tree code ERROR_MARK, and whose type is itself.
X All erroneous expressions are replaced with this node. All functions
X that accept nodes as arguments should avoid generating error messages
X if this node is one of the arguments, since it is undesirable to get
X multiple error messages from one error in the input. */
X
X#undef error_mark_node
Xtree error_mark_node;
X#define error_mark_node (&ERROR_MARK_NODE)
X
X/* Erroneous argument lists can use this *IFF* they do not modify it. */
Xtree error_mark_list;
X
X/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */
X
Xtree short_integer_type_node;
Xtree integer_type_node;
Xtree long_integer_type_node;
Xtree long_long_integer_type_node;
X
Xtree short_unsigned_type_node;
Xtree unsigned_type_node;
Xtree long_unsigned_type_node;
Xtree long_long_unsigned_type_node;
X
Xtree unsigned_char_type_node;
Xtree signed_char_type_node;
Xtree char_type_node;
X
Xtree float_type_node;
Xtree double_type_node;
Xtree long_double_type_node;
X
X/* a VOID_TYPE node, and the same, packaged in a TREE_LIST. */
X
Xtree void_type_node, void_list_node;
X
X/* A node for type `void *'. */
X
Xtree ptr_type_node;
X
X/* A node for type `char *'. */
X
Xtree string_type_node;
X
X/* Type `char[256]' or something like it.
X Used when an array of char is needed and the size is irrelevant. */
X
Xtree char_array_type_node;
X
X/* Type `int[256]' or something like it.
X Used when an array of int needed and the size is irrelevant. */
X
Xtree int_array_type_node;
X
X/* type `int ()' -- used for implicit declaration of functions. */
X
Xtree default_function_type;
X
X/* function types `double (double)' and `double (double, double)', etc. */
X
Xtree double_ftype_double, double_ftype_double_double;
Xtree int_ftype_int, long_ftype_long;
X
X/* Function type `void (void *, void *, int)' and similar ones. */
X
Xtree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int;
X
X/* C++ extensions */
Xtree vtable_entry_type;
Xtree class_type_node, record_type_node, union_type_node, enum_type_node;
Xtree exception_type_node, unknown_type_node;
X
X/* Function type `void * (long)', 'void (void *)' */
Xtree ptr_ftype_long, void_ftype_ptr;
Xtree ptr_ftype_ptr_int_int_ptr, void_ftype_ptr_int_int_ptr_int_int;
X
X/* Used for virtual function tables. */
Xtree vtbl_mask;
X
X/* Array type `(void *)[]' */
Xtree vtbl_type_node;
X
X#ifdef SOS
X/* SOS extensions. */
Xtree zlink_type, zret_type;
Xtree zlink, zret;
X#endif
X
X/* Static decls which do not have static initializers have no
X initializers as far as GNU C is concerned. EMPTY_INIT_NODE
X is a static initializer which makes varasm code place the decl
X in data rather than in bss space. Such gymnastics are necessary
X to avoid the problem that the linker will not include a library
X file if all the library appears to contribute are bss variables. */
X
Xtree empty_init_node;
X
X/* In a destructor, the point at which all derived class destroying
X has been done, just before any base class destroying will be done. */
X
Xtree dtor_label;
X
X/* In a constructor, the point at which we are ready to return
X the pointer to the initialized object. */
X
Xtree ctor_label;
X
X/* A FUNCTION_DECL which can call `unhandled_exception'.
X Not neccessarily the one that the user will declare,
X but sufficient to be called by routines that want to abort the program. */
X
Xtree unhandled_exception_fndecl;
X
X/* A FUNCTION_DECL which can call `abort'. Not neccessarily the
X one that the user will declare, but sufficient to be called
X by routines that want to abort the program. */
X
Xtree abort_fndecl;
X
X/* -- end of C++ */
X
X/* Two expressions that are constants with value zero.
X The first is of type `int', the second of type `void *'. */
X
Xtree integer_zero_node;
Xtree null_pointer_node;
X
X/* A node for the integer constants 1, 2, and 3. */
X
Xtree integer_one_node, integer_two_node, integer_three_node;
X
X/* An identifier whose name is . This is used as the "name"
X of the RESULT_DECLs for values of functions. */
X

Xtree value_identifier;
X
X/* If original DECL_RESULT of current function was a register,
X but due to being an addressable named return value, would up
X on the stack, this variable holds the named return value's
X original location. */
Xstruct rtx_def *original_result_rtx;
X
X/* Sequence of insns which represents base initialization. */
Xstruct rtx_def *base_init_insns;
X
X/* C++: Keep these around to reduce calls to `get_identifier'.
X Identifiers for `this' in member functions and the auto-delete
X parameter for destructors. */
Xtree this_identifier, in_charge_identifier;
X
X/* While defining an enum type, this is 1 plus the last enumerator
X constant value. */
X
Xstatic tree enum_next_value;
X
X/* Parsing a function declarator leaves a list of parameter names
X or a chain or parameter decls here. */
X
Xtree last_function_parms;
X
X/* Parsing a function declarator leaves here a chain of structure
X and enum types declared in the parmlist. */
X
Xstatic tree last_function_parm_tags;
X
X/* After parsing the declarator that starts a function definition,
X `start_function' puts here the list of parameter names or chain of decls.
X `store_parm_decls' finds it here. */
X
Xstatic tree current_function_parms;
X
X/* Similar, for last_function_parm_tags. */
Xstatic tree current_function_parm_tags;
X
X/* A list (chain of TREE_LIST nodes) of all LABEL_STMTs in the function
X that have names. Here so we can clear out their names' definitions
X at the end of the function. */
X
Xstatic tree named_labels;
X
X/* A list (chain of TREE_LIST nodes) of named label uses.
X The TREE_PURPOSE field is the list of variables defined
X the the label's scope defined at the point of use.
X The TREE_VALUE field is the LABEL_DECL used.
X The TREE_TYPE field holds `current_binding_level' at the
X point of the label's use.
X
X Used only for jumps to as-yet undefined labels, since
X jumps to defined labels can have their validity checked
X by stmt.c. */
X
Xstatic tree named_label_uses;
X
X/* A list of objects which have constructors or destructors
X which reside in the global scope. The decl is stored in
X the TREE_VALUE slot and the initializer is stored
X in the TREE_PURPOSE slot. */
Xtree static_aggregates;
X
X/* A list of functions which were declared inline, but later had their
X address taken. Used only for non-virtual member functions, since we can
X find other functions easily enough. */
Xtree pending_addressable_inlines;
X
X/* A list of overloaded functions which we should forget ever
X existed, such as functions declared in a function's scope,
X once we leave that function's scope. */
Xstatic tree overloads_to_forget;
X
X/* The FUNCTION_DECL for the function currently being compiled,
X or 0 if between functions. */
Xtree current_function_decl;
X
X/* Set to 0 at beginning of a function definition, set to 1 if
X a return statement that specifies a return value is seen. */
X
Xint current_function_returns_value;
X
X/* Set to 0 at beginning of a function definition, set to 1 if
X a return statement with no argument is seen. */
X
Xint current_function_returns_null;
X
X/* Set to nonzero by `grokdeclarator' for a function
X whose return type is defaulted, if warnings for this are desired. */
X
Xstatic int warn_about_return_type;
X
X/* Nonzero when starting a function delcared `extern inline'. */
X
Xstatic int current_extern_inline;
X
Xchar *language_string = "GNU C++";
X
X/* Set to 0 at beginning of a constructor, set to 1
X if that function does an allocation before referencing its
X instance variable. */
Xint current_function_assigns_this;
Xint current_function_just_assigned_this;
X
X/* Set to 0 at beginning of a function. Set non-zero when
X store_parm_decls is called. Don't call store_parm_decls
X if this flag is non-zero! */
Xint current_function_parms_stored;
X
X/* Allocate a level of searching. */
Xstruct stack_level *
Xpush_decl_level (stack, obstack)
X struct stack_level *stack;
X struct obstack *obstack;
X{
X struct stack_level tem;
X tem.prev = stack;
X
X return push_stack_level (obstack, &tem, sizeof (tem));
X}
X
X/* Discard a level of decl allocation. */
X
Xstatic struct stack_level *
Xpop_decl_level (stack)
X struct stack_level *stack;
X{
X tree *bp, *tp;
X struct obstack *obstack = stack->obstack;
X bp = stack->first;
X tp = (tree *)obstack_next_free (obstack);
X while (tp != bp)
X {
X --tp;
X IDENTIFIER_CLASS_VALUE (DECL_NAME (*tp)) = NULL_TREE;
X }
X return pop_stack_level (stack);
X}
X
X/* For each binding contour we allocate a binding_level structure
X * which records the names defined in that contour.
X * Contours include:
X * 0) the global one
X * 1) one for each function definition,
X * where internal declarations of the parameters appear.
X * 2) one for each compound statement,
X * to record its declarations.
X *
X * The current meaning of a name can be found by searching the levels from
X * the current one out to the global one.
X *
X * Off to the side, may be the class_binding_level. This exists
X * only to catch class-local declarations. It is otherwise
X * nonexistent.
X *
X * Also there may be binding levels that catch cleanups that
X * must be run when exceptions occur.
X */
X
X/* Note that the information in the `names' component of the global contour
X is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */
X
Xstruct binding_level
X {
X /* A chain of _DECL nodes for all variables, constants, functions,
X * and typedef types. These are in the reverse of the order supplied.
X */
X tree names;
X
X /* A list of structure, union and enum definitions,
X * for looking up tag names.
X * It is a chain of TREE_LIST nodes, each of whose TREE_PURPOSE is a name,
X * or NULL_TREE; and whose TREE_VALUE is a RECORD_TYPE, UNION_TYPE,
X * or ENUMERAL_TYPE node.
X *
X * C++: the TREE_VALUE nodes can be simple types for component_bindings.
X *
X */
X tree tags;
X
X /* For each level, a list of shadowed outer-level local definitions
X to be restored when this level is popped.
X Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
X whose TREE_VALUE is its old definition (a kind of ..._DECL node). */
X tree shadowed;
X
X /* Same, for IDENTIFIER_CLASS_VALUE. */
X tree class_shadowed;
X
X /* For each level (except not the global one),
X a chain of LET_STMT nodes for all the levels
X that were entered and exited one level down. */
X tree blocks;
X
X /* The binding level which this one is contained in (inherits from). */
X struct binding_level *level_chain;
X
X /* Number of decls in `names' that have incomplete
X structure or union types. */
X unsigned short n_incomplete;
X
X /* 1 for the level that holds the parameters of a function.
X 2 for the level that holds a class declaration.
X 3 for levels that hold parameter declarations. */
X unsigned parm_flag : 4;
X
X /* 1 means make a LET_STMT for this level regardless of all else.
X 2 for temporary binding contours created by the compiler. */
X unsigned keep : 3;
X
X /* Nonzero if this level "doesn't exist" for tags. */
X unsigned tag_transparent : 1;
X
X /* Nonzero if this level can safely have additional
X cleanup-needing variables added to it. */
X unsigned more_cleanups_ok : 1;
X unsigned have_cleanups : 1;
X
X /* Nonzero if this level can safely have additional
X exception-raising statements added to it. */
X unsigned more_exceptions_ok : 1;
X unsigned have_exceptions : 1;
X
X /* Four bits left for this word. */
X };
X
X#define NULL_BINDING_LEVEL (struct binding_level *) NULL
X
X/* The binding level currently in effect. */
X
Xstatic struct binding_level *current_binding_level;
X
X/* The binding level of the current class, if any. */
X
Xstatic struct binding_level *class_binding_level;
X
X/* A chain of binding_level structures awaiting reuse. */
X
Xstatic struct binding_level *free_binding_level;
X
X/* The outermost binding level, for names of file scope.
X This is created when the compiler is started and exists
X through the entire run. */
X
Xstatic struct binding_level *global_binding_level;
X
X/* Binding level structures are initialized by copying this one. */
X
Xstatic struct binding_level clear_binding_level;
X
X/* Nonzero means unconditionally make a LET_STMT for the next level pushed. */
X
Xstatic int keep_next_level_flag;
X
X#define PUSH_BINDING_LEVEL(NEWLEVEL, TAG_TRANSPARENT, KEEP) \
Xdo { \
X /* Add this level to the front of the chain (stack) of levels that \
X are active. */ \
X *NEWLEVEL = clear_binding_level; \
X if (class_binding_level) \
X { \
X NEWLEVEL->level_chain = class_binding_level; \
X class_binding_level = 0; \
X } \
X else \
X { \
X NEWLEVEL->level_chain = current_binding_level; \
X } \
X current_binding_level = NEWLEVEL; \
X NEWLEVEL->tag_transparent = TAG_TRANSPARENT; \
X NEWLEVEL->more_cleanups_ok = 1; \
X NEWLEVEL->more_exceptions_ok = 1; \
X NEWLEVEL->keep = KEEP; \
X} while (0)
X
X#define POP_BINDING_LEVEL \
Xdo { \
X /* Pop the current level, and free the structure for reuse. */ \
X { \
X register struct binding_level *level = current_binding_level; \
X current_binding_level = current_binding_level->level_chain; \
X level->level_chain = free_binding_level; \
X free_binding_level = level; \
X if (current_binding_level->parm_flag == 2) \
X { \
X class_binding_level = current_binding_level; \
X do \
X { \
X current_binding_level = current_binding_level->level_chain; \
X } \
X while (current_binding_level->parm_flag == 2); \
X } \
X } \
X} while (0)
X
X/* Create a new `struct binding_level'. */
X
Xstatic
Xstruct binding_level *
Xmake_binding_level ()
X{
X /* NOSTRICT */
X return (struct binding_level *) xmalloc (sizeof (struct binding_level));
X}
X
X/* Nonzero if we are currently in the global binding level. */
X
Xint
Xglobal_bindings_p ()
X{
X return current_binding_level == global_binding_level;
X}
X
Xvoid
Xkeep_next_level ()
X{
X keep_next_level_flag = 1;
X}
X
X/* Identify this binding level as a level of parameters. */
X
Xvoid
Xdeclare_parm_level ()
X{
X current_binding_level->parm_flag = 1;
X}
X
X/* Identify this binding level as a level of a default exception handler. */
X
Xvoid
Xdeclare_implicit_exception ()
X{
X current_binding_level->parm_flag = 3;
X}
X
X/* Nonzero if current binding contour contains expressions
X that might raise exceptions. */
X
Xint
Xhave_exceptions_p ()
X{
X return current_binding_level->have_exceptions;
X}
X
X/* Enter a new binding level.
X If TAG_TRANSPARENT is nonzero, do so only for the name space of variables,
X not for that of tags. */
X
Xvoid
Xpushlevel (tag_transparent)
X int tag_transparent;
X{
X register struct binding_level *newlevel = NULL_BINDING_LEVEL;
X
X /* If this is the top level of a function,
X just make sure that NAMED_LABELS is 0.
X They should have been set to 0 at the end of the previous function. */
X
X if (current_binding_level == global_binding_level)
X assert (named_labels == NULL_TREE);
X
X /* Reuse or create a struct for this binding level. */
X
X if (free_binding_level)
X {
X newlevel = free_binding_level;
X free_binding_level = free_binding_level->level_chain;
X }
X else
X {
X newlevel = make_binding_level ();
X }
X PUSH_BINDING_LEVEL (newlevel, tag_transparent, keep_next_level_flag);
X#ifdef FIELD_XREF
X FIELD_xref_start_scope(newlevel);
X#endif
X keep_next_level_flag = 0;
X}
X
Xvoid
Xpushlevel_temporary (tag_transparent)
X int tag_transparent;
X{
X pushlevel (tag_transparent);
X current_binding_level->keep = 2;
X clear_last_expr ();
X#if 0
X /* Don't call push_momentary here! It will cause cleanups
X to be allocated on the momentary obstack, and they
X will be overwritten by the next statement. */
X push_momentary ();
X#endif
X expand_start_bindings (0);
X}
X
X/* Exit a binding level.
X Pop the level off, and restore the state of the identifier-decl mappings
X that were in effect when this level was entered.
X
X If KEEP == 1, this level had explicit declarations, so
X and create a "block" (a LET_STMT node) for the level
X to record its declarations and subblocks for symbol table output.
X
X If KEEP == 2, this level's subblocks go to the front,
X not the back of the current binding level. This happens,
X for instance, when code for constructors and destructors
X need to generate code at the end of a function which must
X be moved up to the front of the function.
X
X If FUNCTIONBODY is nonzero, this level is the body of a function,
X so create a block as if KEEP were set and also clear out all
X label names.
X
X If REVERSE is nonzero, reverse the order of decls before putting
X them into the LET_STMT. */
X
Xtree
Xpoplevel (keep, reverse, functionbody)
X int keep;
X int reverse;
X int functionbody;
X{
X register tree link;
X /* The chain of decls was accumulated in reverse order.
X Put it into forward order, just for cleanliness. */
X tree decls;
X int tmp = functionbody;
X int implicit_try_block = current_binding_level->parm_flag == 3;
X int real_functionbody = current_binding_level->keep == 2
X ? ((functionbody = 0), tmp) : functionbody;
X tree tags = functionbody >= 0 ? current_binding_level->tags : 0;
X tree subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
X tree block = 0;
X
X#ifdef FIELD_XREF
X FIELD_xref_end_scope(current_binding_level,
X current_binding_level->level_chain,
X current_binding_level->parm_flag,
X current_binding_level->keep,
X current_binding_level->tag_transparent);
X#endif
X
X if (current_binding_level->keep == 1)
X keep = 1;
X
X /* This warning is turned off because it causes warnings for
X declarations like `extern struct foo *x'. */
X#if 0
X /* Warn about incomplete structure types in this level. */
X for (link = tags; link; link = TREE_CHAIN (link))
X if (TYPE_SIZE (TREE_VALUE (link)) == 0)
X {
X tree type = TREE_VALUE (link);
X char *errmsg;
X switch (TREE_CODE (type))
X {
X case RECORD_TYPE:
X errmsg = "`struct %s' incomplete in scope ending here";
X break;
X case UNION_TYPE:
X errmsg = "`union %s' incomplete in scope ending here";
X break;
X case ENUMERAL_TYPE:
X errmsg = "`enum %s' incomplete in scope ending here";
X break;
X }
X if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
X error (errmsg, IDENTIFIER_POINTER (TYPE_NAME (type)));
X else
X /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */
X error (errmsg, TYPE_NAME_STRING (type));
X }
X#endif /* 0 */
X
X /* Get the decls in the order they were written.
X Usually current_binding_level->names is in reverse order.
X But parameter decls were previously put in forward order. */
X
X if (reverse)
X current_binding_level->names
X = decls = nreverse (current_binding_level->names);
X else
X decls = current_binding_level->names;
X
X /* If there were any declarations or structure tags in that level,
X or if this level is a function body,
X create a LET_STMT to record them for the life of this function. */
X
X if (keep == 1 || functionbody > 0)
X block = build_let (0, 0, keep ? decls : 0,
X subblocks, 0, keep ? tags : 0);
X
X /* In each subblock, record that this is its superior. */
X
X if (keep >= 0)
X for (link = subblocks; link; link = TREE_CHAIN (link))
X STMT_SUPERCONTEXT (link) = block;
X
X /* Clear out the meanings of the local variables of this level;
X also record in each decl which block it belongs to. */
X
X for (link = decls; link; link = TREE_CHAIN (link))
X {
X if (DECL_NAME (link) != 0)
X IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0;
X DECL_CONTEXT (link) = block;
X }
X
X /* Restore all name-meanings of the outer levels
X that were shadowed by this level. */
X
X for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
X IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
X for (link = current_binding_level->class_shadowed;
X link;
X link = TREE_CHAIN (link))
X IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
X
X /* If the level being exited is the top level of a function,
X check over all the labels. */
X
X if (functionbody)
X {
X /* Clear out the definitions of all label names,
X since their scopes end here. */
X
X for (link = named_labels; link; link = TREE_CHAIN (link))
X {
X if (DECL_SOURCE_LINE (TREE_VALUE (link)) == 0)
X {
X error ("label `%s' used somewhere above but not defined",
X IDENTIFIER_POINTER (DECL_NAME (TREE_VALUE (link))));
X /* Avoid crashing later. */
X define_label (input_filename, 1, DECL_NAME (TREE_VALUE (link)));
X }
X else if (warn_unused && !TREE_USED (TREE_VALUE (link)))
X warning_with_decl (TREE_VALUE (link),
X "label `%s' defined but not used");
X SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)), 0);
X }
X
X named_labels = 0;
X }
X
X /* Any uses of undefined labels now operate under constraints
X of next binding contour. */
X {
X struct binding_level *level_chain;
X level_chain = current_binding_level->level_chain;
X if (level_chain)
X {
X tree labels;
X for (labels = named_label_uses; labels; labels = TREE_CHAIN (labels))
X if (TREE_TYPE (labels) == (tree)current_binding_level)
X {
X TREE_TYPE (labels) = (tree)level_chain;
X TREE_PURPOSE (labels) = level_chain->names;
X }
X }
X }
X
X tmp = current_binding_level->keep;
X
X POP_BINDING_LEVEL;
X if (functionbody > 0)
X {
X DECL_INITIAL (current_function_decl) = block;
X /* If this is the top level block of a function,
X the vars are the function's parameters.
X Don't leave them in the LET_STMT because they are
X found in the FUNCTION_DECL instead. */
X STMT_VARS (block) = 0;
X }
X else if (block)
X current_binding_level->blocks
X = chainon (current_binding_level->blocks, block);
X /* If we did not make a block for the level just exited,
X any blocks made for inner levels
X (since they cannot be recorded as subblocks in that level)
X must be carried forward so they will later become subblocks
X of something else. */
X else if (subblocks)
X if (keep == 2)
X current_binding_level->blocks = chainon (subblocks, current_binding_level->blocks);
X else
X current_binding_level->blocks
X = chainon (current_binding_level->blocks, subblocks);
X
X /* Take care of compiler's internal binding structures. */
X if (tmp == 2 && !implicit_try_block)
X {
X#if 0
X /* We did not call push_momentary for this
X binding contour, so there is nothing to pop. */
X pop_momentary ();
X#endif
X expand_end_bindings (getdecls (), keep, 1);
X block = poplevel (keep, reverse, real_functionbody);
X }
X if (block)
X TREE_USED (block) = 1;
X return block;
X}
X
X/* Add BLOCK to the current list of blocks for this binding contour. */
Xvoid
Xadd_block_current_level (block)
X tree block;
X{
X current_binding_level->blocks
X = chainon (current_binding_level->blocks, block);
X}
X
X/* Do a pushlevel for class declarations. */
Xvoid
Xpushlevel_class ()
X{
X pushlevel (0);
X decl_stack = push_decl_level (decl_stack, &decl_obstack);
X class_binding_level = current_binding_level;
X class_binding_level->parm_flag = 2;
X do
X {
X current_binding_level = current_binding_level->level_chain;
X }
X while (current_binding_level->parm_flag == 2);
X}
X
X/* ...and a poplevel for class declarations. */
Xtree
Xpoplevel_class ()
X{
X register struct binding_level *level = class_binding_level;
X tree block = 0;
X tree shadowed;
X
X if (level == 0)
X {
X while (current_binding_level && class_binding_level == 0)
X block = poplevel (0, 0, 0);
X if (current_binding_level == 0)
X fatal ("syntax error too serious");
X level = class_binding_level;
X }
X decl_stack = pop_decl_level (decl_stack);
X for (shadowed = level->class_shadowed; shadowed; shadowed = TREE_CHAIN (shadowed))
X IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed);
X
X#ifdef FIELD_XREF
X FIELD_xref_end_scope(class_binding_level,
X class_binding_level->level_chain,
X class_binding_level->parm_flag,
X class_binding_level->keep,
X class_binding_level->tag_transparent);
X#endif
X
X class_binding_level = level->level_chain;
X
X level->level_chain = free_binding_level;
X free_binding_level = level;
X if (class_binding_level->parm_flag != 2)
X class_binding_level = 0;
X return block;
X}
X
X/* Push a definition of struct, union or enum tag "name".
X "type" should be the type node.
X We assume that the tag "name" is not already defined.
X
X Note that the definition may really be just a forward reference.
X In that case, the TYPE_SIZE will be zero.
X
X C++ gratuitously puts all these tags in the name space. */
X
Xvoid
Xpushtag (name, type)
X tree name, type;
X{
X register struct binding_level *b;
X
X if (class_binding_level)
X b = class_binding_level;
X else
X {
X b = current_binding_level;
X while (b->tag_transparent) b = b->level_chain;
X }
X
X if (name)
X {
X /* Record the identifier as the type's name if it has none. */
X
X if (TYPE_NAME (type) == 0)
X TYPE_NAME (type) = name;
X
X if (b == global_binding_level)
X b->tags = perm_tree_cons (name, type, b->tags);
X else
X b->tags = saveable_tree_cons (name, type, b->tags);
X
X /* Do C++ gratuitous typedefing. Note that we put the
X TYPE_DECL in the TREE_TYPE of the IDENTIFIER_NODE. */
X if (TREE_TYPE (name) != TYPE_NAME (type)
X#ifndef BREAK_C_TAGS
X /* This *should* only happen in C++ language scope.
X But everybody else seems to think otherwise. */
X && current_lang_name == lang_name_cplusplus
X#endif
X && (TREE_CODE (type) != RECORD_TYPE
X || class_binding_level == 0
X || !CLASSTYPE_DECLARED_EXCEPTION (type)))
X {
X register tree t = build_decl (TYPE_DECL, name, type);
X if (!TREE_NONLOCAL (type))
X t = pushdecl (t);
X TYPE_NAME (type) = t;
X TREE_TYPE (name) = t;
X }
X if (b->parm_flag == 2)
X {
X TREE_NONLOCAL (type) = 1;
X IDENTIFIER_CLASS_VALUE (name) = TYPE_NAME (type);
X CLASSTYPE_TAGS (current_class_type) = b->tags;
X }
X }
X}
X
X/* Subroutine of duplicate_decls: return truthvalue of whether
X or not types of these decls match. */
Xstatic int
Xdecls_match (newdecl, olddecl)
X tree newdecl, olddecl;
X{
X int types_match;
X
X if (TREE_CODE (newdecl) == FUNCTION_DECL && TREE_CODE (olddecl) == FUNCTION_DECL)
X {
X tree f1 = TREE_TYPE (newdecl);
X tree f2 = TREE_TYPE (olddecl);
X tree p1 = TYPE_ARG_TYPES (f1);
X tree p2 = TYPE_ARG_TYPES (f2);
X
X /* When we parse a static member function definition,
X we put together a FUNCTION_DECL which thinks its type
X is METHOD_TYPE. Change that to FUNCTION_TYPE, and
X proceed. */
X if (TREE_CODE (f1) == METHOD_TYPE
X && DECL_STATIC_FUNCTION_P (olddecl))
X {
X tree n1;
X p1 = TREE_CHAIN (p1);
X n1 = build_function_type (TREE_TYPE (f1), p1);
X n1 = build_type_variant (n1, TREE_READONLY (f1), TREE_VOLATILE (f1));
X n1 = build_exception_variant (TYPE_METHOD_BASETYPE (f1), n1, TYPE_RAISES_EXCEPTIONS (f1));
X TREE_TYPE (newdecl) = n1;
X f1 = n1;
X DECL_STATIC_FUNCTION_P (newdecl) = 1;
X }
X /* Here we must take care of the case where new default
X parameters are specified. Also, warn if an old
X declaration becomes ambiguous because default
X parameters may cause the two to be ambiguous. */
X if (TREE_CODE (f1) != TREE_CODE (f2))
X {
X if (TREE_CODE (f1) == OFFSET_TYPE)
X compiler_error_with_decl (newdecl, "`%s' redeclared as member function");
X else
X compiler_error_with_decl (newdecl, "`%s' redeclared as non-member function");
X return 0;
X }
X
X if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (f1)),
X TYPE_MAIN_VARIANT (TREE_TYPE (f2)), 1))
X {
X types_match = compparms (p1, p2, 1);
X#ifndef MERGED
X /* C++: copy friendlist *before* we get smooshed. */
X if (DECL_FRIENDLIST (olddecl) && !DECL_FRIENDLIST (newdecl))
X DECL_FRIENDLIST (newdecl) = DECL_FRIENDLIST (olddecl);
X#endif
X }
X else types_match = 0;
X }
X else
X {
X if (TREE_TYPE (newdecl) == error_mark_node)
X types_match = TREE_TYPE (olddecl) == error_mark_node;
X else
X types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 1);
X }
X
X return types_match;
X}
X
X/* Handle when a new declaration NEWDECL has the same name as an old
X one OLDDECL in the same binding contour. Prints an error message
X if appropriate.
X
X If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
X Otherwise, return 0. */
X
Xstatic int
Xduplicate_decls (newdecl, olddecl)
X register tree newdecl, olddecl;
X{
X extern struct obstack permanent_obstack;
X int types_match;
X int new_is_definition;
X
X if (TREE_CODE (olddecl) == TREE_LIST
X && TREE_CODE (newdecl) == FUNCTION_DECL)
X {
X /* If a new decl finds a list of old decls, then
X we assume that the new decl has C linkage, and
X that the old decls have C++ linkage. In this case,
X we must look through the list to see whether
X there is an ambiguity or not. */
X tree olddecls = olddecl;
X
X /* If the overload list is empty, just install the decl. */
X if (TREE_VALUE (olddecls) == NULL_TREE)
X {
X TREE_VALUE (olddecls) = newdecl;
X return 1;
X }
X
X while (olddecls)
X {
X if (decls_match (newdecl, TREE_VALUE (olddecls)))
X {
X if (TREE_CODE (newdecl) == VAR_DECL)
X ;
X else if (DECL_LANGUAGE (newdecl)
X != DECL_LANGUAGE (TREE_VALUE (olddecls)))
X {
X error_with_decl (newdecl, "declaration of `%s' with different language linkage");
X error_with_decl (TREE_VALUE (olddecls), "previous declaration here");
X }
X types_match = 1;
X break;
X }
X olddecls = TREE_CHAIN (olddecls);
X }
X if (olddecls)
X olddecl = TREE_VALUE (olddecl);
X else
X return 1;
X }
X else
X types_match = decls_match (newdecl, olddecl);
X
X if (TREE_CODE (TREE_TYPE (newdecl)) == ERROR_MARK
X || TREE_CODE (TREE_TYPE (olddecl)) == ERROR_MARK)
X types_match = 0;
X
X /* If this decl has linkage, and the old one does too, maybe no error. */
X if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
X {
X error_with_decl (newdecl, "`%s' redeclared as different kind of symbol");
X if (TREE_CODE (olddecl) == TREE_LIST)
X olddecl = TREE_VALUE (olddecl);
X error_with_decl (olddecl, "previous declaration of `%s'");
X
X /* New decl is completely inconsistent with the old one =>
X tell caller to replace the old one. */
X
X return 0;
X }
X
X if (TREE_CODE (newdecl) == FUNCTION_DECL)
X {
X /* Now that functions must hold information normally held
X by field decls, there is extra work to do so that
X declaration information does not get destroyed during
X definition. */
X if (DECL_VINDEX (olddecl) && ! DECL_VINDEX (newdecl))
X DECL_VINDEX (newdecl) = DECL_VINDEX (olddecl);
X if (DECL_VCONTEXT (olddecl) && ! DECL_VCONTEXT (newdecl))
X DECL_VCONTEXT (newdecl) = DECL_VCONTEXT (olddecl);
X if (DECL_FIELD_CONTEXT (olddecl) && ! DECL_FIELD_CONTEXT (newdecl))
X DECL_FIELD_CONTEXT (newdecl) = DECL_FIELD_CONTEXT (olddecl);
X#ifdef SOS
X if (DECL_DINDEX (olddecl) && ! DECL_DINDEX (newdecl))
X DECL_DINDEX (newdecl) = DECL_DINDEX (newdecl);
X#endif
X if (DECL_PENDING_INLINE_INFO (newdecl) == 0)
X DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl);
X }
X
X if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL
X && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (newdecl)) == olddecl)
X /* If -traditional, avoid error for redeclaring fcn
X after implicit decl. */
X ;
X else if (TREE_CODE (olddecl) == FUNCTION_DECL
X && DECL_FUNCTION_CODE (olddecl) != NOT_BUILT_IN)
X {
X if (!types_match)
X error_with_decl (newdecl, "conflicting types for built-in function `%s'");
X else if (extra_warnings)
X warning_with_decl (newdecl, "built-in function `%s' redeclared");
X }
X else if (!types_match)
X {
X tree oldtype = TREE_TYPE (olddecl);
X tree newtype = TREE_TYPE (newdecl);
X int give_error = 0;
X
X /* Already complained about this, so don't do so again. */
X if (current_class_type == NULL_TREE
X || IDENTIFIER_ERROR_LOCUS (DECL_NAME (newdecl)) != current_class_type)
X {
X give_error = 1;
X error_with_decl (newdecl, "conflicting types for `%s'");
X }
X
X /* Check for function type mismatch
X involving an empty arglist vs a nonempty one. */
X if (TREE_CODE (olddecl) == FUNCTION_DECL
X && comptypes (TREE_TYPE (oldtype),
X TREE_TYPE (newtype), 1)
X && ((TYPE_ARG_TYPES (oldtype) == 0
X && DECL_INITIAL (olddecl) == 0)
X || (TYPE_ARG_TYPES (newtype) == 0
X && DECL_INITIAL (newdecl) == 0)))
X {
X /* Classify the problem further. */
X register tree t = TYPE_ARG_TYPES (oldtype);
X if (t == 0)
X t = TYPE_ARG_TYPES (newtype);
X for (; t; t = TREE_CHAIN (t))
X {
X register tree type = TREE_VALUE (t);
X
X if (TREE_CHAIN (t) == 0 && type != void_type_node)
X {
X error ("A parameter list with an ellipsis can't match");
X error ("an empty parameter name list declaration.");
X break;
X }
X
X if (type == float_type_node
X || (TREE_CODE (type) == INTEGER_TYPE
X && (TYPE_PRECISION (type)
X < TYPE_PRECISION (integer_type_node))))
X {
X error ("An argument type that has a default promotion");
X error ("can't match an empty parameter name list declaration.");
X break;
X }
X }
X }
X if (give_error)
X error_with_decl (olddecl, "previous declaration of `%s'");
X
X /* There is one thing GNU C++ cannot tolerate: a constructor
X which takes the type of object being constructed.
X Farm that case out here. */
X if (TREE_CODE (newdecl) == FUNCTION_DECL
X && DECL_CONSTRUCTOR_P (newdecl))
X {
X tree tmp = TREE_CHAIN (TYPE_ARG_TYPES (newtype));
X
X if (tmp != NULL_TREE
X && (TYPE_MAIN_VARIANT (TREE_VALUE (tmp))
X == TYPE_METHOD_BASETYPE (newtype)))
X {
X tree parm = TREE_CHAIN (DECL_ARGUMENTS (newdecl));
X tree argtypes
X = hash_tree_chain (build_reference_type (TREE_VALUE (tmp)),
X TREE_CHAIN (tmp));
X
X DECL_ARG_TYPE (parm)
X = TREE_TYPE (parm)
X = TYPE_REFERENCE_TO (TREE_VALUE (tmp));
X
X TREE_TYPE (newdecl) = newtype
X = build_cplus_method_type (TYPE_METHOD_BASETYPE (newtype),
X TREE_TYPE (newtype), argtypes);
X error ("constructor cannot take as argument the type being constructed");
X SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (newdecl), current_class_type);
X }
X }
X }
X else
X {
X char *errmsg = redeclaration_error_message (newdecl, olddecl);
X if (errmsg)
X {
X error_with_decl (newdecl, errmsg);
X if (DECL_LANG_SPECIFIC (olddecl)
X && DECL_COMPILER_GENERATED_P (olddecl))
X DECL_COMPILER_GENERATED_P (olddecl) = 0;
X else
X error_with_decl (olddecl,
X "here is the previous declaration of `%s'");
X }
X else if (TREE_CODE (olddecl) == FUNCTION_DECL
X && DECL_INITIAL (olddecl) != 0
X && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) == 0
X && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0)
X {
X /* Prototype decl follows defn w/o prototype. */
X warning_with_decl (newdecl, "prototype for `%s'");
X warning_with_decl (olddecl,
X "follows non-prototype definition here");
X }
X
X /* These bits are logically part of the type. */
X if (pedantic
X && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
X || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)))
X error_with_decl (newdecl, "type qualifiers for `%s' conflict with previous decl");
X }
X
X /* Deal with C++: must preserve virtual function table size. */
X if (TREE_CODE (olddecl) == TYPE_DECL)
X {
X if (TYPE_LANG_SPECIFIC (TREE_TYPE (newdecl))
X && TYPE_LANG_SPECIFIC (TREE_TYPE (olddecl)))
X {
X CLASSTYPE_VSIZE (TREE_TYPE (newdecl))
X = CLASSTYPE_VSIZE (TREE_TYPE (olddecl));
X CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (newdecl))
X = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (olddecl));
X }
X }
X
X new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
X && DECL_INITIAL (newdecl) != 0);
X
X /* Copy all the DECL_... slots specified in the new decl
X except for any that we copy here from the old type. */
X
X if (types_match)
X {
X /* Automatically handles default parameters. */
X tree oldtype = TREE_TYPE (olddecl);
X /* Merge the data types specified in the two decls. */
X tree newtype = commontype (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
X
X if (TREE_CODE (newdecl) == VAR_DECL)
X DECL_EXTERNAL (newdecl) |= DECL_EXTERNAL (olddecl);
X /* Do this after calling `commontype' so that default
X parameters don't confuse us. */
X else if (TREE_CODE (newdecl) == FUNCTION_DECL
X && (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl))
X != TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl))))
X {
X tree ctype = NULL_TREE;
X if (TREE_CODE (newtype) == METHOD_TYPE)
X ctype = TYPE_METHOD_BASETYPE (newtype);
X else if (DECL_STATIC_FUNCTION_P (newdecl))
X ctype = DECL_STATIC_CONTEXT (newdecl);
X TREE_TYPE (newdecl) = build_exception_variant (ctype, newtype,
X TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)));
X TREE_TYPE (olddecl) = build_exception_variant (ctype, newtype,
X TYPE_RAISES_EXCEPTIONS (oldtype));
X
X if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
X {
X error_with_decl (newdecl, "declaration of `%s' raises different exceptions...");
X error_with_decl (olddecl, "...from previous declaration here");
X }
X }
X TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
X
X /* Lay the type out, unless already done. */
X if (oldtype != TREE_TYPE (newdecl))
X {
X if (TREE_TYPE (newdecl) != error_mark_node)
X layout_type (TREE_TYPE (newdecl));
X if (TREE_CODE (newdecl) != FUNCTION_DECL
X && TREE_CODE (newdecl) != TYPE_DECL
X && TREE_CODE (newdecl) != CONST_DECL)
X layout_decl (newdecl, 0);
X }
X else
X {
X /* Since the type is OLDDECL's, make OLDDECL's size go with. */
X DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
X DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
X if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
X DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
X }
X
X /* Merge the type qualifiers. */
X if (TREE_READONLY (newdecl))
X TREE_READONLY (olddecl) = 1;
X if (TREE_THIS_VOLATILE (newdecl))
X TREE_THIS_VOLATILE (olddecl) = 1;
X
X /* Merge the initialization information. */
X if (DECL_INITIAL (newdecl) == 0)
X DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
X /* Keep the old rtl since we can safely use it. */
X DECL_RTL (newdecl) = DECL_RTL (olddecl);
X }
X /* If cannot merge, then use the new type and qualifiers,
X and don't preserve the old rtl. */
X else
X {
X /* Clean out any memory we had of the old declaration. */
X tree oldstatic = value_member (olddecl, static_aggregates);
X if (oldstatic)
X TREE_VALUE (oldstatic) = error_mark_node;
X
X TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
X TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
X TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
X TREE_VOLATILE (olddecl) = TREE_VOLATILE (newdecl);
X }
X
X /* Merge the storage class information. */
X if (TREE_EXTERNAL (newdecl))
X {
X TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
X TREE_EXTERNAL (newdecl) = TREE_EXTERNAL (olddecl);
X
X /* For functions, static overrides non-static. */
X if (TREE_CODE (newdecl) == FUNCTION_DECL)
X {
X TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
X /* This is since we don't automatically
X copy the attributes of NEWDECL into OLDDECL. */
X TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
X /* If this clears `static', clear it in the identifier too. */
X if (! TREE_PUBLIC (olddecl))
X TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
X }
X else
X TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
X }
X else
X {
X TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
X TREE_EXTERNAL (olddecl) = 0;
X /* A `const' which was not declared `extern' and is
X in static storage is invisible. */
X if (TREE_CODE (newdecl) == VAR_DECL
X && TREE_READONLY (newdecl) && TREE_STATIC (newdecl)
X && ! DECL_EXTERNAL (newdecl))
X TREE_PUBLIC (newdecl) = 0;
X TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
X }
X /* If either decl says `inline', this fn is inline,
X unless its definition was passed already. */
X TREE_INLINE (olddecl) |= TREE_INLINE (newdecl);
X
X if (TREE_CODE (newdecl) == FUNCTION_DECL)
X {
X if (new_is_definition)
X /* If defining a function declared with other language
X linkage, use the previously declared language linkage. */
X DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl);
X else
X {
X /* If redeclaring a builtin function, and not a definition,
X it stays built in. */
X DECL_SET_FUNCTION_CODE (newdecl, DECL_FUNCTION_CODE (olddecl));
X DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
X if (DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl))
X /* Previously saved insns go together with
X the function's previous definition. */
X DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
X DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
X }
X }
X
X /* Now preserve various other info from the definition. */
X TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl);
X TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl);
X
X /* Don't really know how much of the language-specific
X values we should copy from old to new. */
X#if 1
X if (DECL_LANG_SPECIFIC (olddecl))
X DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
X#endif
X
X if (TREE_CODE (newdecl) == FUNCTION_DECL)
X {
X int function_size;
X struct lang_decl *ol = DECL_LANG_SPECIFIC (olddecl);
X struct lang_decl *nl = DECL_LANG_SPECIFIC (newdecl);
X
X#ifdef MERGED
X function_size = sizeof (struct tree_decl);
X#else
X function_size = sizeof (struct tree_function_decl);
X#endif
X
X /* Don't lose track of having output OLDDECL as GDB symbol. */
X DECL_BLOCK_SYMTAB_ADDRESS (newdecl)
X = DECL_BLOCK_SYMTAB_ADDRESS (olddecl);
X
X bcopy ((char *) newdecl + sizeof (struct tree_common),
X (char *) olddecl + sizeof (struct tree_common),
X function_size - sizeof (struct tree_common));
X
X if ((char *)newdecl == obstack_next_free (&permanent_obstack)
X - (function_size + sizeof (struct lang_decl)))
X {
X DECL_MAIN_VARIANT (newdecl) = olddecl;
X DECL_LANG_SPECIFIC (olddecl) = ol;
X bcopy (nl, ol, sizeof (struct lang_decl));
X
X obstack_free (&permanent_obstack, newdecl);
X }
X#ifdef LANG_DECL_PERMANENT
X else if (LANG_DECL_PERMANENT (ol))
X {
X if (DECL_MAIN_VARIANT (olddecl) == olddecl)
X {
X /* Save these lang_decls that would otherwise be lost. */
X extern tree free_lang_decl_chain;
X tree free_lang_decl = (tree) ol;
X TREE_CHAIN (free_lang_decl) = free_lang_decl_chain;
X free_lang_decl_chain = free_lang_decl;
X }
X else
X {
X /* Storage leak. */
X }
X }
X#else
X /* Storage leak. */
X#endif
X }
X else
X {
X bcopy ((char *) newdecl + sizeof (struct tree_common),
X (char *) olddecl + sizeof (struct tree_common),
X sizeof (struct tree_decl) - sizeof (struct tree_common)
X + tree_code_length [(int)TREE_CODE (newdecl)] * sizeof (char *));
X }
X
X return 1;
X}
X
X/* Record a decl-node X as belonging to the current lexical scope.
X Check for errors (such as an incompatible declaration for the same
X name already seen in the same scope).
X
X Returns either X or an old decl for the same name.
X If an old decl is returned, it may have been smashed
X to agree with what X says. */
X
Xtree
Xpushdecl (x)
X tree x;
X{
X register tree t;
X register tree name = DECL_NAME (x);
X register struct binding_level *b = current_binding_level;
X
X if (name)
X {
X char *file;
X int line;
X
X t = lookup_name_current_level (name);
X if (t != 0 && t == error_mark_node)
X /* error_mark_node is 0 for a while during initialization! */
X {
X t = 0;
X error_with_decl (x, "`%s' used prior to declaration");
X }
X
X if (t != 0)
X {
X tree cntxt = t;
X if (TREE_CODE (t) == PARM_DECL)
X {
X if (DECL_CONTEXT (t) == NULL_TREE)
X fatal ("parse errors have confused me too much");
X cntxt = DECL_CONTEXT (t);
X }
X file = DECL_SOURCE_FILE (t);
X line = DECL_SOURCE_LINE (t);
X }
X
X if (t != 0 && TREE_CODE (t) != TREE_CODE (x))
X {
X if (TREE_CODE (t) == TYPE_DECL)
X {
X#ifdef BREAK_C_TAGS
X ;
X#else
X warning ("type declaration of %s shadowed",
X IDENTIFIER_POINTER (name));
X#endif
X }
X else if (TREE_CODE (x) == TYPE_DECL)
X {
X#ifdef BREAK_C_TAGS
X ;
X#else
X warning ("type declaration of %s shadows previous declaration",
X IDENTIFIER_POINTER (name));
X#endif
X }
X else if (duplicate_decls (x, t))
X return t;
X }
X else if (t != 0 && duplicate_decls (x, t))
X {
X /* If this decl is `static' and an `extern' was seen previously,
X that is erroneous. But don't complain if -traditional,
X since traditional compilers don't complain.
X
X Note that this does not apply to the C++ case of declaring
X a variable `extern const' and then later `const'. */
X if (!flag_traditional && TREE_PUBLIC (name)
X && ! TREE_PUBLIC (x) && ! TREE_EXTERNAL (x) && ! TREE_INLINE (x))
X {
X /* Due to interference in memory reclamation (X may be
X obstack-deallocated at this point, we must guard against
X one really special case). */
X if (current_function_decl == x)
X current_function_decl = t;
X if (IDENTIFIER_IMPLICIT_DECL (name))
X warning ("`%s' was declared implicitly `extern' and later `static'",
X lang_printable_name (t));
X else
X warning ("`%s' was declared `extern' and later `static'",
X lang_printable_name (t));
X warning_with_file_and_line (file, line,
X "previous declaration of `%s'",
X lang_printable_name (t));
X }
X return t;
X }
X
X /* If declaring a type as a typedef, and the type has no known
X typedef name, install this TYPE_DECL as its typedef name.
X
X C++: If it had an anonymous aggregate or enum name,
X give it a `better' one. */
X if (TREE_CODE (x) == TYPE_DECL)
X {
X tree name = TYPE_NAME (TREE_TYPE (x));
X
X if (name == NULL_TREE
X || (TREE_CODE (name) != TYPE_DECL
X#ifndef BREAK_C_TAGS
X && current_lang_name == lang_name_cplusplus
X#endif
X ))
X {
X /* If these are different names, make two equivalent
X definitions. */
X TYPE_NAME (TREE_TYPE (x)) = x;
X }
X else
X {
X if (TREE_CODE (name) == TYPE_DECL)
X name = DECL_NAME (name);
X if (ANON_AGGRNAME_P (name))
X {
X /* do gratuitous C++ typedefing, and make sure that
X we access this type either through TREE_TYPE field
X or via the tags list. */
X TYPE_NAME (TREE_TYPE (x)) = x;
X pushtag (name, TREE_TYPE (x));
X }
X }
X }
X
X /* Multiple external decls of the same identifier ought to match. */
X
X if (TREE_EXTERNAL (x) && IDENTIFIER_GLOBAL_VALUE (name) != 0
X && (TREE_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name))
X || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name))))
X {
X if (! comptypes (TREE_TYPE (x),
X TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)), 1))
X {
X warning_with_decl (x,
X "type mismatch with previous external decl");
X warning_with_decl (IDENTIFIER_GLOBAL_VALUE (name),
X "previous external decl of `%s'");
X }
X }
X
X /* In PCC-compatibility mode, extern decls of vars with no current decl
X take effect at top level no matter where they are. */
X if (flag_traditional && TREE_EXTERNAL (x)
X && lookup_name (name) == 0)
X b = global_binding_level;
X
X /* This name is new in its binding level.
X Install the new declaration and return it. */
X if (b == global_binding_level)
X {
X /* Install a global value. */
X
X /* Rule for VAR_DECLs, but not for other kinds of _DECLs:
X A `const' which was not declared `extern' is invisible. */
X if (TREE_CODE (x) == VAR_DECL
X && TREE_READONLY (x) && ! DECL_EXTERNAL (x))
X TREE_PUBLIC (x) = 0;
X
X /* If the first global decl has external linkage,
X warn if we later see static one. */
X if (IDENTIFIER_GLOBAL_VALUE (name) == 0 && TREE_PUBLIC (x))
X TREE_PUBLIC (name) = 1;
X
X IDENTIFIER_GLOBAL_VALUE (name) = x;
X
X /* Don't forget if the function was used via an implicit decl. */
X if (IDENTIFIER_IMPLICIT_DECL (name)
X && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name)))
X TREE_USED (x) = 1;
X
X /* Don't forget if its address was taken in that way. */
X if (IDENTIFIER_IMPLICIT_DECL (name)
X && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name)))
X TREE_ADDRESSABLE (x) = 1;
X
X /* Warn about mismatches against previous implicit decl. */
X if (IDENTIFIER_IMPLICIT_DECL (name) != 0
X /* If this real decl matches the implicit, don't complain. */
X && ! (TREE_CODE (x) == FUNCTION_DECL
X && TREE_TYPE (TREE_TYPE (x)) == integer_type_node))
X warning ("`%s' was previously implicitly declared to return `int'",
X lang_printable_name (x));
X
X /* If this decl is `static' and an `extern' was seen previously,
X that is erroneous. */
X if (TREE_PUBLIC (name)
X && ! TREE_PUBLIC (x) && ! TREE_EXTERNAL (x))
X {
X if (IDENTIFIER_IMPLICIT_DECL (name))
X warning ("`%s' was declared implicitly `extern' and later `static'",
X lang_printable_name (x));
X else
X warning ("`%s' was declared `extern' and later `static'",
X lang_printable_name (x));
X }
X }
X else
X {
X /* Here to install a non-global value. */
X tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
X tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name);
X IDENTIFIER_LOCAL_VALUE (name) = x;
X
X /* If this is an extern function declaration, see if we
X have a global definition for the function. */
X if (oldlocal == 0
X && oldglobal != 0
X && TREE_CODE (x) == FUNCTION_DECL
X && TREE_CODE (oldglobal) == FUNCTION_DECL)
X {
X /* We have one. Their types must agree. */
X if (! comptypes (TREE_TYPE (x), TREE_TYPE (oldglobal), 1))
X warning_with_decl (x, "local declaration of `%s' doesn't match global one");
X /* If the global one is inline, make the local one inline. */
X else if (TREE_INLINE (oldglobal)
X || DECL_FUNCTION_CODE (oldglobal) != NOT_BUILT_IN
X || (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != 0
X && TYPE_ARG_TYPES (TREE_TYPE (x)) == 0))
X IDENTIFIER_LOCAL_VALUE (name) = oldglobal;
X }
X /* If we have a local external declaration,
X and no file-scope declaration has yet been seen,
X then if we later have a file-scope decl it must not be static. */
X if (oldlocal == 0
X && oldglobal == 0
X && TREE_EXTERNAL (x)
X && TREE_PUBLIC (x))
X {
X TREE_PUBLIC (name) = 1;
X }
X
X if (TREE_INLINE (x))
X /* Inline decls shadow nothing. */;
X
X /* Warn if shadowing an argument at the top level of the body. */
X else if (oldlocal != 0 && !TREE_EXTERNAL (x)
X && TREE_CODE (oldlocal) == PARM_DECL
X && TREE_CODE (x) != PARM_DECL
X /* The parm level is two levels above the first user-visible
X level. One level was created for parm cleanups, the
X other declared by the user. */
X && current_binding_level->level_chain->level_chain->parm_flag == 1)
X warning ("declaration of `%s' shadows a parameter",
X IDENTIFIER_POINTER (name));
X
X /* Maybe warn if shadowing something else. */
X else if (warn_shadow && !TREE_EXTERNAL (x))
X {
X char *warnstring = 0;
X
X if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL)
X warnstring = "declaration of `%s' shadows a parameter";
X else if (IDENTIFIER_CLASS_VALUE (name) != 0)
X warnstring = "declaration of `%s' shadows a member of `this'";
X else if (oldlocal != 0)
X warnstring = "declaration of `%s' shadows previous local";
X else if (oldglobal != 0)
X warnstring = "declaration of `%s' shadows global declaration";
X
X if (warnstring)
X warning (warnstring, IDENTIFIER_POINTER (name));
X }
X
X /* If storing a local value, there may already be one (inherited).
X If so, record it for restoration when this binding level ends. */
X if (oldlocal != 0)
X b->shadowed = tree_cons (name, oldlocal, b->shadowed);
X }
X
X /* Keep count of variables in this level with incomplete type. */
X if (TYPE_SIZE (TREE_TYPE (x)) == 0
X && (IS_AGGR_TYPE (TREE_TYPE (x))
X || (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
X && IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (x))))))
X {
X if (++b->n_incomplete == 0)
X error ("too many incomplete variables at this point");
X }
X }
X
X /* Put decls on list in reverse order.
X We will reverse them later if necessary. */
X TREE_CHAIN (x) = b->names;
X b->names = x;
X
X return x;
X}
X
X/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL,
X if appropriate. */
Xtree
Xpushdecl_top_level (x)
X tree x;
X{
X register tree t;
X register struct binding_level *b = current_binding_level;
X
X current_binding_level = global_binding_level;
X t = pushdecl (x);
X current_binding_level = b;
X return t;
X}
X
X/* Make the declaration of X appear in CLASS scope. */
Xtree
Xpushdecl_class_level (x)
X tree x;
X{
X register tree name = DECL_NAME (x);
X
X if (name)
X {
X tree oldclass = IDENTIFIER_CLASS_VALUE (name);
X if (oldclass)
X class_binding_level->class_shadowed
X = tree_cons (name, oldclass, class_binding_level->class_shadowed);
X IDENTIFIER_CLASS_VALUE (name) = x;
X obstack_ptr_grow (&decl_obstack, x);
X }
X return x;
X}
X
X/* Tell caller how to interpret a TREE_LIST which contains
X chains of FUNCTION_DECLS. */
Xint
Xoverloaded_globals_p (list)
X tree list;
X{
X assert (TREE_CODE (list) == TREE_LIST);
X
X /* Don't commit caller to seeing them as globals. */
X if (TREE_NONLOCAL (list))
X return -1;
X /* Do commit caller to seeing them as globals. */
X if (TREE_CODE (TREE_PURPOSE (list)) == IDENTIFIER_NODE)
X return 1;
X /* Do commit caller to not seeing them as globals. */
X return 0;
X}
X
X/* DECL is a FUNCTION_DECL which may have other definitions already in place.
X We get around this by making IDENTIFIER_GLOBAL_VALUE (DECL_ORIGINAL_NAME (DECL))
X point to a list of all the things that want to be referenced by that name.
X It is then up to the users of that name to decide what to do with that
X list. */
Xvoid
Xpush_overloaded_decl (decl)
X tree decl;
X{
X tree orig_name = DECL_ORIGINAL_NAME (decl);
X tree glob = IDENTIFIER_GLOBAL_VALUE (orig_name);
X
X DECL_OVERLOADED (decl) = 1;
X if (glob && TREE_CODE (glob) != TREE_LIST)
X {
X if (DECL_LANGUAGE (decl) == lang_c)
X {
X if (TREE_CODE (glob) == FUNCTION_DECL)
X {
X if (DECL_LANGUAGE (glob) == lang_c)
X {
X error_with_decl (decl, "C-language function `%s' overloaded here");
X error_with_decl (glob, "Previous C-language version of this function was `%s'");
X }
X }
X else abort ();
X }
X if (! flag_traditional
X && TREE_PERMANENT (glob) == 1
X && current_binding_level != global_binding_level)
X overloads_to_forget = tree_cons (orig_name, glob, overloads_to_forget);
X if (TREE_CODE (glob) == FUNCTION_DECL
X && DECL_LANGUAGE (glob) != DECL_LANGUAGE (decl)
X && comptypes (TREE_TYPE (glob), TREE_TYPE (decl), 1))
X {
X error_with_decl (decl, "conflicting language contexts for declaration of `%s';");
X error_with_decl (glob, "conflicts with previous declaration here");
X }
X glob = tree_cons (DECL_NAME (glob), glob, NULL_TREE);
X glob = tree_cons (TREE_PURPOSE (glob), decl, glob);
X IDENTIFIER_GLOBAL_VALUE (orig_name) = glob;
X TREE_TYPE (glob) = unknown_type_node;
X return;
X }
X if (glob)
X {
X tree tmp, name;
X
X if (TREE_VALUE (glob) == NULL_TREE)
X {
X TREE_VALUE (glob) = decl;
X return;
X }
X name = DECL_NAME (decl);
X for (tmp = glob; tmp; tmp = TREE_CHAIN (tmp))
X {
X if (TREE_CODE (TREE_VALUE (tmp)) == FUNCTION_DECL
X && DECL_LANGUAGE (TREE_VALUE (tmp)) != DECL_LANGUAGE (decl)
X && comptypes (TREE_TYPE (TREE_VALUE (tmp)), TREE_TYPE (decl), 1))
X {
X error_with_decl (decl, "conflicting language contexts for declaration of `%s';");
X error_with_decl (TREE_VALUE (tmp), "conflicts with previous declaration here");
X }
X if (DECL_NAME (TREE_VALUE (tmp)) == name)
X return;
X }
X }
X
X if (DECL_LANGUAGE (decl) == lang_c)
X {
X tree decls = glob;
X while (decls && DECL_LANGUAGE (TREE_VALUE (decls)) == lang_cplusplus)
X decls = TREE_CHAIN (decls);
X if (decls)
X {
X error_with_decl (decl, "C-language function `%s' overloaded here");
X error_with_decl (TREE_VALUE (decls), "Previous C-language version of this function was `%s'");
X }
X }
X
X if (! flag_traditional
X && (glob == 0 || TREE_PERMANENT (glob) == 1)
X && current_binding_level != global_binding_level)
X overloads_to_forget = tree_cons (orig_name, glob, overloads_to_forget);
X glob = tree_cons (orig_name, decl, glob);
X IDENTIFIER_GLOBAL_VALUE (orig_name) = glob;
X TREE_TYPE (glob) = unknown_type_node;
X}
X
X/* Generate an implicit declaration for identifier FUNCTIONID
X as a function of type int (). Print a warning if appropriate. */
X
Xtree
Ximplicitly_declare (functionid)
X tree functionid;
X{
X register tree decl;
X int temp = allocation_temporary_p ();
X
X /* Save the decl permanently so we can warn if definition follows. */
X if (temp && (flag_traditional || !warn_implicit))
X end_temporary_allocation ();
X
X /* We used to reuse an old implicit decl here,
X but this loses with inline functions because it can clobber
X the saved decl chains. */
X/* if (IDENTIFIER_IMPLICIT_DECL (functionid) != 0)
X decl = IDENTIFIER_IMPLICIT_DECL (functionid);
X else */
X decl = build_lang_decl (FUNCTION_DECL, functionid, default_function_type);
X
X TREE_EXTERNAL (decl) = 1;
X TREE_PUBLIC (decl) = 1;
X
X /* ANSI standard says implicit declarations are in the innermost block.
X So we record the decl in the standard fashion.
X If flag_traditional is set, pushdecl does it top-level. */
X pushdecl (decl);
X rest_of_decl_compilation (decl, 0, 0, 0);
X
X if (warn_implicit
X /* Only one warning per identifier. */
X && IDENTIFIER_IMPLICIT_DECL (functionid) == 0)
X warning ("implicit declaration of function `%s'",
X IDENTIFIER_POINTER (functionid));
X
X SET_IDENTIFIER_IMPLICIT_DECL (functionid, decl);
X
X if (temp && (flag_traditional || ! warn_implicit))
X resume_temporary_allocation ();
X
X return decl;
X}
X
X/* Return zero if the declaration NEWDECL is valid
X when the declaration OLDDECL (assumed to be for the same name)
X has already been seen.
X Otherwise return an error message format string with a %s
X where the identifier should go. */
X
Xstatic char *
Xredeclaration_error_message (newdecl, olddecl)
X tree newdecl, olddecl;
X{
X if (TREE_CODE (newdecl) == TYPE_DECL)
X {
X /* Because C++ can put things into name space for free,
X constructs like "typedef struct foo { ... } foo"
X would look like an erroneous redeclaration. */
X if (TREE_TYPE (olddecl) == TREE_TYPE (newdecl))
X return 0;
X else
X return "redefinition of `%s'";
X }
X else if (TREE_CODE (newdecl) == FUNCTION_DECL)
X {
X /* Declarations of functions can insist on internal linkage
X but they can't be inconsistent with internal linkage,
X so there can be no error on that account.
X However defining the same name twice is no good. */
X if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0
X /* However, defining once as extern inline and a second
X time in another way is ok. */
X && !(TREE_INLINE (olddecl) && TREE_EXTERNAL (olddecl)
X && !(TREE_INLINE (newdecl) && TREE_EXTERNAL (newdecl))))
X {
X if (DECL_LANG_SPECIFIC (olddecl)
X && DECL_COMPILER_GENERATED_P (olddecl))
X return "`%s' not declared in class";
X else
X return "redefinition of `%s'";
X }
X return 0;
X }
X else if (current_binding_level == global_binding_level)
X {
X /* Objects declared at top level: */
X /* If at least one is a reference, it's ok. */
X if (TREE_EXTERNAL (newdecl) || TREE_EXTERNAL (olddecl))
X return 0;
X /* Reject two definitions. */
X if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0)
X return "redefinition of `%s'";
X /* Now we have two tentative defs, or one tentative and one real def. */
X /* Insist that the linkage match. */
X if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl))
X return "conflicting declarations of `%s'";
X return 0;
X }
X else
X {
X /* Objects declared with block scope: */
X /* Reject two definitions, and reject a definition
X together with an external reference. */
X if (!(TREE_EXTERNAL (newdecl) && TREE_EXTERNAL (olddecl)))
X return "redeclaration of `%s'";
X return 0;
X }
X}
X
X/* Get the LABEL_DECL corresponding to identifier ID as a label.
X Create one if none exists so far for the current function.
X This function is called for both label definitions and label references. */
X
Xtree
Xlookup_label (id)
X tree id;
X{
X register tree decl = IDENTIFIER_LABEL_VALUE (id);
X
X if ((decl == 0
X || DECL_SOURCE_LINE (decl) == 0)
X && (named_label_uses == 0
X || TREE_PURPOSE (named_label_uses) != current_binding_level->names
X || TREE_VALUE (named_label_uses) != decl))
X {
X named_label_uses
X = tree_cons (current_binding_level->names, decl, named_label_uses);
X TREE_TYPE (named_label_uses) = (tree)current_binding_level;
X }
X
X if (decl != 0)
X return decl;
X
X /* By giving the label type `void *', we can use it as a value. */
X decl = build_decl (LABEL_DECL, id, ptr_type_node);
X DECL_MODE (decl) = VOIDmode;
X /* Mark that the label's definition has not been seen. */
X DECL_SOURCE_LINE (decl) = 0;
X
X SET_IDENTIFIER_LABEL_VALUE (id, decl);
X
X named_labels = tree_cons (NULL_TREE, decl, named_labels);
X TREE_VALUE (named_label_uses) = decl;
X
X return decl;
X}
X
X/* Define a label, specifying the location in the source file.
X Return the LABEL_DECL node for the label, if the definition is valid.
X Otherwise return 0. */
X
Xtree
Xdefine_label (filename, line, name)
X char *filename;
X int line;
X tree name;
X{
X tree decl = lookup_label (name);
X
X /* After labels, make any new cleanups go into their
X own new (temporary) binding contour. */
X current_binding_level->more_cleanups_ok = 0;
X
X if (DECL_SOURCE_LINE (decl) != 0)
X {
X error_with_decl (decl, "duplicate label `%s'");
X return 0;
X }
X else
X {
X tree uses, prev;
X
X /* Mark label as having been defined. */
X DECL_SOURCE_FILE (decl) = filename;
X DECL_SOURCE_LINE (decl) = line;
X
X for (prev = 0, uses = named_label_uses;
X uses;
X prev = uses, uses = TREE_CHAIN (uses))
X if (TREE_VALUE (uses) == decl)
X {
X struct binding_level *b = current_binding_level;
X while (1)
X {
X tree new_decls = b->names;
X tree old_decls = ((tree)b == TREE_TYPE (uses)
X ? TREE_PURPOSE (uses) : NULL_TREE);
X while (new_decls != old_decls)
X {
X if (TREE_CODE (new_decls) == VAR_DECL
X /* Don't complain about crossing initialization
X of temporaries. They can't be accessed,
X and they should be cleaned up
X by the time we get to the label. */
X && ! TEMP_NAME_P (DECL_NAME (new_decls))
X && ((DECL_INITIAL (new_decls) != NULL_TREE
X && DECL_INITIAL (new_decls) != error_mark_node)
X || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
X {
X if (IDENTIFIER_ERROR_LOCUS (decl) == NULL_TREE)
X error_with_decl (decl, "invalid jump to label `%s'");
X SET_IDENTIFIER_ERROR_LOCUS (decl, current_function_decl);
X error_with_decl (new_decls, "crosses initialization of `%s'");
X }
X new_decls = TREE_CHAIN (new_decls);
X }
X if ((tree)b == TREE_TYPE (uses))
X break;
X b = b->level_chain;
X }
X
X if (prev)
X TREE_CHAIN (prev) = TREE_CHAIN (uses);
X else
X named_label_uses = TREE_CHAIN (uses);
X }
X return decl;
X }
X}
X
X/* Same, but for CASE labels. */
Xvoid
Xdefine_case_label (decl)
X tree decl;
X{
X /* After labels, make any new cleanups go into their
X own new (temporary) binding contour. */
X
X current_binding_level->more_cleanups_ok = 0;
X}
X
X/* Return the list of declarations of the current level.
X Note that this list is in reverse order unless/until
X you nreverse it; and when you do nreverse it, you must
X store the result back using `storedecls' or you will lose. */
X
Xtree
Xgetdecls ()
X{
X return current_binding_level->names;
X}
X
X/* Return the list of type-tags (for structs, etc) of the current level. */
X
Xtree
Xgettags ()
X{
X return current_binding_level->tags;
X}
X
X/* Store the list of declarations of the current level.
X This is done for the parameter declarations of a function being defined,
X after they are modified in the light of any missing parameters. */
X
Xstatic void
Xstoredecls (decls)
X tree decls;
X{
X current_binding_level->names = decls;
X}
X
X/* Similarly, store the list of tags of the current level. */
X
Xstatic void
Xstoretags (tags)
X tree tags;
X{
X current_binding_level->tags = tags;
X}
X
X/* Given NAME, an IDENTIFIER_NODE,
X return the structure (or union or enum) definition for that name.
X Searches binding levels from BINDING_LEVEL up to the global level.
X If THISLEVEL_ONLY is nonzero, searches only the specified context
X (but skips any tag-transparent contexts to find one that is
X meaningful for tags).
X FORM says which kind of type the caller wants;
X it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE.
X If the wrong kind of type is found, an error is reported. */
X
Xstatic tree
Xlookup_tag (form, name, binding_level, thislevel_only)
X enum tree_code form;
X struct binding_level *binding_level;
X tree name;
X int thislevel_only;
X{
X register struct binding_level *level;
X
X for (level = binding_level; level; level = level->level_chain)
X {
X register tree tail;
X for (tail = level->tags; tail; tail = TREE_CHAIN (tail))
X {
X if (TREE_PURPOSE (tail) == name)
X {
X if (TREE_CODE (TREE_VALUE (tail)) != form)
X {
X /* Definition isn't the kind we were looking for. */
X error ("`%s' defined as wrong kind of tag",
X IDENTIFIER_POINTER (name));
X }
X return TREE_VALUE (tail);
X }
X }
X if (thislevel_only && ! level->tag_transparent)
X return NULL_TREE;
X if (current_class_type && level->level_chain == global_binding_level)
X {
X /* Try looking in this class's tags before heading into
X global binding level. */
X tree these_tags = CLASSTYPE_TAGS (current_class_type);
X while (these_tags)
X {
X if (TREE_PURPOSE (these_tags) == name)
X {
X if (TREE_CODE (TREE_VALUE (these_tags)) != form)
X {
X error ("`%s' defined as wrong kind of tag in class scope",
X IDENTIFIER_POINTER (name));
X }
X return TREE_VALUE (tail);
X }
X these_tags = TREE_CHAIN (these_tags);
X }
X }
X }
X return NULL_TREE;
X}
X
X/* Given a type, find the tag that was defined for it and return the tag name.
X Otherwise return 0. However, the value can never be 0
X in the cases in which this is used.
X
X C++: If NAME is non-zero, this is the new name to install. This is
X done when replacing anonymous tags with real tag names. */
X
Xstatic tree
Xlookup_tag_reverse (type, name)
X tree type;
X tree name;
X{
X register struct binding_level *level;
X
X for (level = current_binding_level; level; level = level->level_chain)
X {
X register tree tail;
X for (tail = level->tags; tail; tail = TREE_CHAIN (tail))
X {
X if (TREE_VALUE (tail) == type)
X {
X if (name)
X TREE_PURPOSE (tail) = name;
X return TREE_PURPOSE (tail);
X }
X }
X }
X return NULL_TREE;
X}
X
X/* Given type TYPE which was not declared in C++ language context,
X attempt to find a name by which it is refered. */
Xtree
Xtypedecl_for_tag (tag)
X tree tag;
X{
X struct binding_level *b = current_binding_level;
X
X if (TREE_CODE (TYPE_NAME (tag)) == TYPE_DECL)
X return TYPE_NAME (tag);
X
X while (b)
X {
X tree decls = b->names;
X while (decls)
X {
X if (TREE_CODE (decls) == TYPE_DECL && TREE_TYPE (decls) == tag)
X break;
X decls = TREE_CHAIN (decls);
X }
X if (decls)
X return decls;
X b = b->level_chain;
X }
X return NULL_TREE;
X}
X
X/* Look up NAME in the current binding level and its superiors
X in the namespace of variables, functions and typedefs.
X Return a ..._DECL node of some kind representing its definition,
X or return 0 if it is undefined. */
X
Xtree
Xlookup_name (name)
X tree name;
X{
X register tree val;
X if (current_binding_level != global_binding_level
X && IDENTIFIER_LOCAL_VALUE (name))
X val = IDENTIFIER_LOCAL_VALUE (name);
X /* In C++ class fields are between local and global scope,
X just before the global scope. */
X else if (current_class_type)
X {
X if (IDENTIFIER_CLASS_VALUE (name))
X val = IDENTIFIER_CLASS_VALUE (name);
X else if (TYPE_SIZE (current_class_type) == 0
X && CLASSTYPE_LOCAL_TYPEDECLS (current_class_type))
X {
X /* Try to find values from base classes
X if we are presently defining a type.
X We are presently only interested in TYPE_DECLs. */
X val = lookup_field (current_class_type, name, 0);
X if (val == error_mark_node)
X return val;
X if (val && TREE_CODE (val) != TYPE_DECL)
X val = NULL_TREE;
X else if (val == NULL_TREE)
X val = IDENTIFIER_GLOBAL_VALUE (name);
X }
X else
X val = IDENTIFIER_GLOBAL_VALUE (name);
X }
X else
X val = IDENTIFIER_GLOBAL_VALUE (name);
X if (val && TREE_TYPE (val) == error_mark_node)
X return error_mark_node;
X return val;
X}
X
X/* Similar to `lookup_name' but look only at current binding level. */
X
Xstatic tree
Xlookup_name_current_level (name)
X tree name;
X{
X register tree t;
X
X if (current_binding_level == global_binding_level)
X return IDENTIFIER_GLOBAL_VALUE (name);
X
X if (IDENTIFIER_LOCAL_VALUE (name) == 0)
X return 0;
X
X for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
X if (DECL_NAME (t) == name)
X break;
X
X return t;
X}
X
Xstatic int sigsegv ()
X{
X error ("Segmentation violation");
X signal (SIGSEGV, SIG_DFL);
X}
X
X/* Create the predefined scalar types of C,
X and some nodes representing standard constants (0, 1, (void *)0).
X Initialize the global binding level.
X Make definitions for built-in primitive functions. */
X
Xunion tree_node ERROR_MARK_NODE;
X
Xvoid
Xinit_decl_processing ()
X{
X register tree endlink, int_endlink, double_endlink, ptr_endlink;
X
X /* Have to make these distinct before we try using them. */
X lang_name_cplusplus = get_identifier ("C++");
X lang_name_c = get_identifier ("C");
X
X /* Initially, C. */
X current_lang_name = lang_name_c;
X
X current_function_decl = NULL_TREE;
X named_labels = NULL_TREE;
X named_label_uses = NULL_TREE;
X current_binding_level = NULL_BINDING_LEVEL;
X free_binding_level = NULL_BINDING_LEVEL;
X
X if (write_symbols == GDB_DEBUG)
X fatal ("GNU C++ does not support GDB symbol info yet, use -g");
X
X /* Handle signals. */
X signal (SIGSEGV, sigsegv);
X
X obstack_init (&decl_obstack);
X
X /* Must lay these out before anything else gets laid out. */
X#if 0
X error_mark_node = make_node (ERROR_MARK);
X#else
X#undef error_mark_node
X error_mark_node = &ERROR_MARK_NODE;
X#define error_mark_node (&ERROR_MARK_NODE)
X TREE_PERMANENT (error_mark_node) = 1;
X#endif
X TREE_TYPE (error_mark_node) = error_mark_node;
X error_mark_list = build_tree_list (error_mark_node, error_mark_node);
X TREE_TYPE (error_mark_list) = error_mark_node;
X
X pushlevel (0); /* make the binding_level structure for global names. */
X global_binding_level = current_binding_level;
X
X value_identifier = get_identifier ("");
X this_identifier = get_identifier (THIS_NAME);
X in_charge_identifier = get_identifier (IN_CHARGE_NAME);
X
X /* Define `int' and `char' first so that dbx will output them first. */
X
X integer_type_node = make_signed_type (INT_TYPE_SIZE);
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_INT])
X = pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_INT],
X integer_type_node));
X
X /* Define `char', which is like either `signed char' or `unsigned char'
X but not the same as either. */
X
X char_type_node =
X (flag_signed_char
X ? make_signed_type (CHAR_TYPE_SIZE)
X : make_unsigned_type (CHAR_TYPE_SIZE));
X
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_CHAR])
X = pushdecl (build_decl (TYPE_DECL, get_identifier ("char"),
X char_type_node));
X
X long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_LONG])
X = pushdecl (build_decl (TYPE_DECL, get_identifier ("long int"),
X long_integer_type_node));
X
X unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_UNSIGNED])
X = pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"),
X unsigned_type_node));
X
X long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
X pushdecl (build_decl (TYPE_DECL, get_identifier ("long unsigned int"),
X long_unsigned_type_node));
X
X /* `unsigned long' or `unsigned int' is the standard type for sizeof.
X Traditionally, use a signed type. */
X if (INT_TYPE_SIZE != BITS_PER_WORD)
X sizetype = flag_traditional ? long_integer_type_node : long_unsigned_type_node;
X else
X sizetype = flag_traditional ? integer_type_node : unsigned_type_node;
X
X TREE_TYPE (TYPE_SIZE (integer_type_node)) = sizetype;
X TREE_TYPE (TYPE_SIZE (char_type_node)) = sizetype;
X TREE_TYPE (TYPE_SIZE (unsigned_type_node)) = sizetype;
X TREE_TYPE (TYPE_SIZE (long_unsigned_type_node)) = sizetype;
X TREE_TYPE (TYPE_SIZE (long_integer_type_node)) = sizetype;
X
X short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_SHORT])
X = pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
X short_integer_type_node));
X
X long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
X pushdecl (build_decl (TYPE_DECL, get_identifier ("long long int"),
X long_long_integer_type_node));
X short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
X pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned short int"),
X short_unsigned_type_node));
X long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
X pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"),
X long_long_unsigned_type_node));
X
X /* Define both `signed char' and `unsigned char'. */
X signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
X pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"),
X signed_char_type_node));
X unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
X pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned char"),
X unsigned_char_type_node));
X
X float_type_node = make_node (REAL_TYPE);
X TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_FLOAT])
X = pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT],
X float_type_node));
X layout_type (float_type_node);
X
X double_type_node = make_node (REAL_TYPE);
X TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_DOUBLE])
X = pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_DOUBLE],
X double_type_node));
X layout_type (double_type_node);
X
X long_double_type_node = make_node (REAL_TYPE);
X TYPE_PRECISION (long_double_type_node) = DOUBLE_TYPE_SIZE;
X pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"),
X long_double_type_node));
X layout_type (long_double_type_node);
X
X integer_zero_node = build_int_2 (0, 0);
X TREE_TYPE (integer_zero_node) = integer_type_node;
X integer_one_node = build_int_2 (1, 0);
X TREE_TYPE (integer_one_node) = integer_type_node;
X integer_two_node = build_int_2 (2, 0);
X TREE_TYPE (integer_two_node) = integer_type_node;
X integer_three_node = build_int_2 (3, 0);
X TREE_TYPE (integer_three_node) = integer_type_node;
X empty_init_node = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
X
X size_zero_node = build_int_2 (0, 0);
X TREE_TYPE (size_zero_node) = sizetype;
X size_one_node = build_int_2 (1, 0);
X TREE_TYPE (size_one_node) = sizetype;
X
X void_type_node = make_node (VOID_TYPE);
X IDENTIFIER_GLOBAL_VALUE (ridpointers[(int) RID_VOID])
X = pushdecl (build_decl (TYPE_DECL,
X ridpointers[(int) RID_VOID], void_type_node));
X layout_type (void_type_node); /* Uses integer_zero_node. */
X void_list_node = build_tree_list (NULL_TREE, void_type_node);
X TREE_PARMLIST (void_list_node) = 1;
X
X null_pointer_node = build_int_2 (0, 0);
X TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
X layout_type (TREE_TYPE (null_pointer_node));
X
X string_type_node = build_pointer_type (char_type_node);
X
X /* make a type for arrays of 256 characters.
X 256 is picked randomly because we have a type for integers from 0 to 255.
X With luck nothing will ever really depend on the length of this
X array type. */
X char_array_type_node
X = build_array_type (char_type_node, unsigned_char_type_node);
X /* Likewise for arrays of ints. */
X int_array_type_node
X = build_array_type (integer_type_node, unsigned_char_type_node);
X
X default_function_type
X = build_function_type (integer_type_node, NULL_TREE);
X build_pointer_type (default_function_type);
X
X ptr_type_node = build_pointer_type (void_type_node);
X endlink = void_list_node;
X int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
X double_endlink = tree_cons (NULL_TREE, double_type_node, endlink);
X ptr_endlink = tree_cons (NULL_TREE, ptr_type_node, endlink);
X
X double_ftype_double
X = build_function_type (double_type_node, double_endlink);
X
X double_ftype_double_double
X = build_function_type (double_type_node,
X tree_cons (NULL_TREE, double_type_node, double_endlink));
X
X int_ftype_int
X = build_function_type (integer_type_node, int_endlink);
X
X long_ftype_long
X = build_function_type (long_integer_type_node,
X tree_cons (NULL_TREE, long_integer_type_node, endlink));
X
X void_ftype_ptr_ptr_int
X = build_function_type (void_type_node,
X tree_cons (NULL_TREE, ptr_type_node,
X tree_cons (NULL_TREE, ptr_type_node,
X int_endlink)));
X
X int_ftype_ptr_ptr_int
X = build_function_type (integer_type_node, TYPE_ARG_TYPES (void_ftype_ptr_ptr_int));
X
X void_ftype_ptr_int_int
X = build_function_type (void_type_node,
X tree_cons (NULL_TREE, ptr_type_node,
X tree_cons (NULL_TREE, integer_type_node,
X int_endlink)));
X
X ptr_ftype_long
X = build_function_type (ptr_type_node, TYPE_ARG_TYPES (long_ftype_long));
X
X ptr_ftype_ptr_int_int_ptr
X = build_function_type (ptr_type_node,
X tree_cons (NULL_TREE, ptr_type_node,
X tree_cons (NULL_TREE, integer_type_node,
X tree_cons (NULL_TREE, integer_type_node,
X ptr_endlink))));
X
X void_ftype_ptr
X = build_function_type (void_type_node, ptr_endlink);
X
X void_ftype_ptr_int_int_ptr_int_int
X = build_function_type (void_type_node,
X tree_cons (NULL_TREE, ptr_type_node,
X tree_cons (NULL_TREE, integer_type_node,
X tree_cons (NULL_TREE, integer_type_node,
X TYPE_ARG_TYPES (void_ftype_ptr_int_int)))));
X
X#ifdef VTABLE_USES_MASK
X /* This is primarily for virtual function definition. We
X declare an array of `void *', which can later be
X converted to the appropriate function pointer type.
X To do pointers to members, we need a mask which can
X distinguish an index value into a virtual function table
X from an address. */
X vtbl_mask = build_int_2 (~(VINDEX_MAX - 1), -1);
X#endif
X
X vtbl_type_node
X = build_array_type (ptr_type_node, NULL_TREE);
X layout_type (vtbl_type_node);
X vtbl_type_node = build_type_variant (vtbl_type_node, 1, 0);
X
X builtin_function ("__builtin_alloca",
X build_function_type (ptr_type_node, int_endlink),
X BUILT_IN_ALLOCA);
X
X builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS);
X builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS);
X builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS);
X builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS);
X#if 0
X /* Support for these has not been written in either expand_builtin
X or build_function_call. */
X builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV);
X builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV);
X builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR);
X builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL);
X builtin_function ("__builtin_fmod", double_ftype_double_double, BUILT_IN_FMOD);
X builtin_function ("__builtin_frem", double_ftype_double_double, BUILT_IN_FREM);
X builtin_function ("__builtin_memcpy", void_ftype_ptr_ptr_int, BUILT_IN_MEMCPY);
X builtin_function ("__builtin_memcmp", int_ftype_ptr_ptr_int, BUILT_IN_MEMCMP);
X builtin_function ("__builtin_memset", void_ftype_ptr_int_int, BUILT_IN_MEMSET);
X builtin_function ("__builtin_fsqrt", double_ftype_double, BUILT_IN_FSQRT);
X builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP);
X builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN);
X#endif
X
X /* C++ extensions */
X
X unknown_type_node = make_node (UNKNOWN_TYPE);
X pushdecl (build_decl (TYPE_DECL,
X get_identifier ("unknown type"),
X unknown_type_node));
X TYPE_SIZE (unknown_type_node) = TYPE_SIZE (void_type_node);
X TYPE_SIZE_UNIT (unknown_type_node) = TYPE_SIZE_UNIT (void_type_node);
X TYPE_ALIGN (unknown_type_node) = 1;
X TYPE_MODE (unknown_type_node) = TYPE_MODE (void_type_node);
X /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node. */
X TREE_TYPE (unknown_type_node) = unknown_type_node;
X /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same result. */
X TYPE_POINTER_TO (unknown_type_node) = unknown_type_node;
X TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node;
X
X /* Define these now, but use 0 as their DECL_FUNCTION_CODE. This
X will install them in the global binding level, but cause them
X to be expanded normally. */
X if (flag__main)
X {
X builtin_function ("__main", default_function_type, NOT_BUILT_IN);
X pushdecl (lookup_name (get_identifier ("__main")));
X }
X builtin_function ("__builtin_saveregs", default_function_type,
X BUILT_IN_SAVEREGS);
X builtin_function ("__builtin_classify_type", default_function_type,
X BUILT_IN_CLASSIFY_TYPE);
X
X {
X /* Simplify life by making a "vtable_entry_type". Give its
X fields names so that the debugger can use them. */
X tree fields[4];
X int i;
X
X vtable_entry_type = make_lang_type (RECORD_TYPE);
X CLASSTYPE_OFFSET (vtable_entry_type) = integer_zero_node;
X fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier (VTABLE_DELTA_NAME), short_integer_type_node);
X fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier (VTABLE_INDEX_NAME), short_integer_type_node);
X fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier (VTABLE_PFN_NAME), ptr_type_node);
X TYPE_FIELDS (vtable_entry_type) = fields[0];
X for (i = 0; i < 2; i++)
X {
X DECL_FIELD_CONTEXT (fields[i]) = vtable_entry_type;
X TREE_CHAIN (fields[i]) = fields[i+1];
X }
X DECL_FIELD_CONTEXT (fields[i]) = vtable_entry_type;
X TYPE_ALIGN (vtable_entry_type) = TYPE_ALIGN (double_type_node);
X layout_type (vtable_entry_type);
X CLASSTYPE_VBASE_SIZE (vtable_entry_type) = integer_zero_node;
X TYPE_NAME (vtable_entry_type) = build_decl (TYPE_DECL,
X get_identifier (VTBL_PTR_TYPE),
X vtable_entry_type);
X layout_decl (TYPE_NAME (vtable_entry_type));
X
X /* Make this part of an invisible union. */
X fields[3] = copy_node (fields[2]);
X TREE_TYPE (fields[3]) = short_integer_type_node;
X DECL_NAME (fields[3]) = get_identifier (VTABLE_DELTA2_NAME);
X DECL_MODE (fields[3]) = TYPE_MODE (short_integer_type_node);
X DECL_SIZE (fields[3]) = TYPE_SIZE (short_integer_type_node);
X DECL_SIZE_UNIT (fields[3]) = TYPE_SIZE_UNIT (short_integer_type_node);
X TREE_UNSIGNED (fields[3]) = 0;
X TREE_CHAIN (fields[2]) = fields[3];
X
X vtable_entry_type = build_type_variant (vtable_entry_type, 1, 0);
X }
X
X#ifdef SOS
X if (flag_all_virtual == 2)
X {
X tree fields[5];
X tree ptr_ftype_default
X = build_function_type (ptr_type_node, NULL_TREE);
X int i;
X
X builtin_function ("sosFindCode", ptr_ftype_default, NOT_BUILT_IN);
X builtin_function ("sosLookup", ptr_ftype_default, NOT_BUILT_IN);
X builtin_function ("sosImport", ptr_ftype_default, NOT_BUILT_IN);
X builtin_function ("sosDynError", ptr_ftype_default, NOT_BUILT_IN);
X
X zlink_type = make_lang_type (RECORD_TYPE);
X CLASSTYPE_OFFSET (zlink_type) = integer_zero_node;
X fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("n"), string_type_node);
X fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("t"), char_type_node);
X fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("ptr"), TYPE_POINTER_TO (default_function_type));
X
X TYPE_FIELDS (zlink_type) = fields[0];
X for (i = 0; i < 2; i++)
X {
X DECL_FIELD_CONTEXT (fields[i]) = zlink_type;
X TREE_CHAIN (fields[i]) = fields[i+1];
X }
X DECL_FIELD_CONTEXT (fields[i]) = zlink_type;
X TYPE_ALIGN (zlink_type) = 1;
X layout_type (zlink_type);
X CLASSTYPE_VBASE_SIZE (zlink_type) = integer_zero_node;
X
X zret_type = make_lang_type (RECORD_TYPE);
X CLASSTYPE_OFFSET (zret_type) = integer_zero_node;
X fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("cn"), string_type_node);
X fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("ptr"), build_pointer_type (TYPE_POINTER_TO (default_function_type)));
X fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("n"), integer_type_node);
X fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("bcl"), string_type_node);
X fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("f"), char_type_node);
X
X TYPE_FIELDS (zret_type) = fields[0];
X for (i = 0; i < 4; i++)
X {
X TREE_CHAIN (fields[i]) = fields[i+1];
X DECL_FIELD_CONTEXT (fields[i]) = zret_type;
X }
X DECL_FIELD_CONTEXT (fields[i]) = zret_type;
X TYPE_ALIGN (zret_type) = 1;
X layout_type (zret_type);
X CLASSTYPE_VBASE_SIZE (zret_type) = integer_zero_node;
X }
X#endif
X
X /* Now, C++. */
X current_lang_name = lang_name_cplusplus;
X
X auto_function ("__builtin_new", ptr_ftype_long, NOT_BUILT_IN);
X auto_function ("__builtin_vec_new", ptr_ftype_ptr_int_int_ptr, NOT_BUILT_IN);
X auto_function ("__builtin_delete", void_ftype_ptr, NOT_BUILT_IN);
X auto_function ("__builtin_vec_delete", void_ftype_ptr_int_int_ptr_int_int, NOT_BUILT_IN);
X
X abort_fndecl
X = define_function ("abort",
X build_function_type (void_type_node, void_list_node),
X NOT_BUILT_IN, 0);
X
X unhandled_exception_fndecl
X = define_function ("__unhandled_exception",
X build_function_type (void_type_node, NULL_TREE),
X NOT_BUILT_IN, 0);
X
X /* Perform other language dependent initializations. */
X init_class_processing ();
X init_init_processing ();
X init_search_processing ();
X if (flag_handle_exceptions)
X {
X init_exception_processing ();
X if (flag_handle_exceptions == 2)
X /* Too much trouble to inline all the trys needed for this. */
X flag_this_is_variable = 2;
X }
X if (flag_no_inline)
X flag_inline_functions = 0;
X}
X
X/* Make a definition for a builtin function named NAME and whose data type
X is TYPE. TYPE should be a function type with argument types.
X FUNCTION_CODE tells later passes how to compile calls to this function.
X See tree.h for its possible values. */
X
Xtree
Xdefine_function (name, type, function_code, pfn)
X char *name;
X tree type;
X enum built_in_function function_code;
X void (*pfn)();
X{
X tree decl = build_lang_decl (FUNCTION_DECL, get_identifier (name), type);
X TREE_EXTERNAL (decl) = 1;
X TREE_PUBLIC (decl) = 1;
X make_function_rtl (decl);
X if (pfn) pfn (decl);
X DECL_SET_FUNCTION_CODE (decl, function_code);
X return decl;
X}
X
X/* Called when a declaration is seen that contains no names to declare.
X If its type is a reference to a structure, union or enum inherited
X from a containing scope, shadow that tag name for the current scope
X with a forward reference.
X If its type defines a new named structure or union
X or defines an enum, it is valid but we need not do anything here.
X Otherwise, it is an error.
X
X C++: may have to grok the declspecs to learn about static,
X complain for anonymous unions. */
X
Xvoid
Xshadow_tag (declspecs)
X tree declspecs;
X{
X int found_tag = 0;
X int warned = 0;
X register tree link;
X register enum tree_code code, ok_code = ERROR_MARK;
X register tree t = NULL_TREE;
X
X for (link = declspecs; link; link = TREE_CHAIN (link))
X {
X register tree value = TREE_VALUE (link);
X
X code = TREE_CODE (value);
X if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE)
X /* Used to test also that TYPE_SIZE (value) != 0.
X That caused warning for `struct foo;' at top level in the file. */
X {
X register tree name = TYPE_NAME (value);
X
X if (name == NULL_TREE)
X name = lookup_tag_reverse (value, NULL_TREE);
X
X if (name && TREE_CODE (name) == TYPE_DECL)
X name = DECL_NAME (name);
X
X if (class_binding_level)
X t = lookup_tag (code, name, class_binding_level, 1);
X else
X t = lookup_tag (code, name, current_binding_level, 1);
X
X if (t == 0)
X {
X int temp = allocation_temporary_p ();
X if (temp)
X end_temporary_allocation ();
X if (IS_AGGR_TYPE_CODE (code))
X t = make_lang_type (code);
X else
X t = make_node (code);
X pushtag (name, t);
X if (temp)
X resume_temporary_allocation ();
X ok_code = code;
X break;
X }
X else if (name != 0 || code == ENUMERAL_TYPE)
X ok_code = code;
X
X if (ok_code != ERROR_MARK)
X found_tag++;
X else
X {
X if (!warned)
X warning ("useless keyword or type name in declaration");
X warned = 1;
X }
X }
X }
X
X /* This is where the variables in an anonymous union are
X declared. An anonymous union declaration looks like:
X union { ... } ;
X because there is no declarator after the union, the parser
X sends that declaration here. */
X if (ok_code == UNION_TYPE
X && t != NULL_TREE
X && ((TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE
X && ANON_AGGRNAME_P (TYPE_NAME (t)))
X || (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
X && ANON_AGGRNAME_P (DECL_NAME (TYPE_NAME (t)))))
X && TYPE_FIELDS (t))
X {
X tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0, NULL_TREE);
X finish_anon_union (decl);
X }
X else if (ok_code == RECORD_TYPE
X && found_tag == 1
X && TYPE_LANG_SPECIFIC (t)
X && CLASSTYPE_DECLARED_EXCEPTION (t))
X {
X if (TYPE_SIZE (t))
X error_with_aggr_type (t, "redeclaration of exception `%s'");
X else
X {
X tree ename, decl;
X int temp = allocation_temporary_p ();
X int momentary = suspend_momentary ();
X if (temp)
X end_temporary_allocation ();
X
X pushclass (t, 0);
X finish_exception (t, NULL_TREE);
X
X ename = TYPE_NAME (t);
X if (TREE_CODE (ename) == TYPE_DECL)
X ename = DECL_NAME (ename);
X decl = build_lang_field_decl (VAR_DECL, ename, t);
X finish_exception_decl (current_class_name, decl);
X end_exception_decls ();
X
X if (temp)
X resume_temporary_allocation ();
X if (momentary)
X resume_momentary ();
X }
X }
X else if (!warned)
X {
X if (found_tag > 1)
X warning ("multiple types in one declaration");
X if (found_tag == 0)
X warning ("empty declaration");
X }
X}
X
X/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
X
Xtree
Xgroktypename (typename)
X tree typename;
X{
X if (TREE_CODE (typename) != TREE_LIST)
X return typename;
X return grokdeclarator (TREE_VALUE (typename),
X TREE_PURPOSE (typename),
X TYPENAME, 0, NULL_TREE);
X}
X
X/* Decode a declarator in an ordinary declaration or data definition.
X This is called as soon as the type information and variable name
X have been parsed, before parsing the initializer if any.
X Here we create the ..._DECL node, fill in its type,
X and put it on the list of decls for the current context.
X The ..._DECL node is returned as the value.
X
X Exception: for arrays where the length is not specified,
X the type is left null, to be filled in by `finish_decl'.
X
X Function definitions do not come here; they go to start_function
X instead. However, external and forward declarations of functions
X do go through here. Structure field declarations are done by
X grokfield and not through here. */
X
X/* Set this to zero to debug not using the temporary obstack
X to parse initializers. */
Xint debug_temp_inits = 1;
X
Xtree
Xstart_decl (declarator, declspecs, initialized, raises)
X tree declspecs, declarator;
X int initialized;
X tree raises;
X{
X register tree decl = grokdeclarator (declarator, declspecs,
X NORMAL, initialized, raises);
X register tree type, tem;
X int init_written = initialized;
X
X if (decl == NULL_TREE) return decl;
X
X type = TREE_TYPE (decl);
X
X /* Don't lose if destructors must be executed at file-level. */
X if (TREE_STATIC (decl)
X && TYPE_NEEDS_DESTRUCTOR (type)
X && TREE_PERMANENT (decl) == 0)
X {
X end_temporary_allocation ();
X decl = copy_node (decl);
X if (TREE_CODE (type) == ARRAY_TYPE)
X {
X tree itype = TYPE_DOMAIN (type);
X if (itype && ! TREE_PERMANENT (itype))
X {
X itype = build_index_type (copy_to_permanent (TYPE_MAX_VALUE (itype)));
X type = build_cplus_array_type (TREE_TYPE (type), itype);
X TREE_TYPE (decl) = type;
X }
X }
X resume_temporary_allocation ();
X }
X
X /* Interesting work for this is done in `finish_exception_decl'. */
X if (TREE_CODE (type) == RECORD_TYPE
X && CLASSTYPE_DECLARED_EXCEPTION (type))
X return decl;
X
X if (DECL_CONTEXT (decl))
X {
X /* If it was not explicitly declared `extern',
X revoke any previous claims of TREE_EXTERNAL. */
X if (DECL_EXTERNAL (decl) == 0)
X TREE_EXTERNAL (decl) = 0;
X if (DECL_LANG_SPECIFIC (decl))
X DECL_IN_AGGR_P (decl) = 0;
X pushclass (DECL_CONTEXT (decl), 2);
X }
X
X /* If this type of object needs a cleanup, and control may
X jump past it, make a new binding level so that it is cleaned
X up only when it is initialized first. */
X if (TYPE_NEEDS_DESTRUCTOR (type)
X && current_binding_level->more_cleanups_ok == 0)
X pushlevel_temporary (1);
X
X if (initialized)
X /* Is it valid for this decl to have an initializer at all?
X If not, set INITIALIZED to zero, which will indirectly
X tell `finish_decl' to ignore the initializer once it is parsed. */
X switch (TREE_CODE (decl))
X {
X case TYPE_DECL:
X /* typedef foo = bar means give foo the same type as bar.
X We haven't parsed bar yet, so `finish_decl' will fix that up.
X Any other case of an initialization in a TYPE_DECL is an error. */
X if (pedantic || list_length (declspecs) > 1)
X {
X error ("typedef `%s' is initialized",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X initialized = 0;
X }
X break;
X
X case FUNCTION_DECL:
X error ("function `%s' is initialized like a variable",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X initialized = 0;
X break;
X

X default:
X /* Don't allow initializations for incomplete types
X except for arrays which might be completed by the initialization. */
X if (TYPE_SIZE (type) != 0)
X ; /* A complete type is ok. */
X else if (TREE_CODE (type) != ARRAY_TYPE)
X {
X error ("variable `%s' has initializer but incomplete type",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X initialized = 0;
X }
X else if (TYPE_SIZE (TREE_TYPE (type)) == 0)
X {
X error ("elements of array `%s' have incomplete type",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X initialized = 0;
X }
X }
X
X if (!initialized && TREE_CODE (decl) != TYPE_DECL
X && IS_AGGR_TYPE (type) && ! TREE_EXTERNAL (decl))
X {
X if (TYPE_SIZE (type) == 0)
X {
X error ("aggregate `%s' has incomplete type and cannot be initialized",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X /* Change the type so that assemble_variable will give
X DECL an rtl we can live with: (mem (const_int 0)). */
X TREE_TYPE (decl) = error_mark_node;
X type = error_mark_node;
X }
X else
X {
X /* If any base type in the hierarchy of TYPE needs a constructor,
X then we set initialized to 1. This way any nodes which are
X created for the purposes of initializing this aggregate
X will live as long as it does. This is necessary for global
X aggregates which do not have their initializers processed until
X the end of the file. */
X initialized = TYPE_NEEDS_CONSTRUCTING (type);
X }
X }
X
X if (initialized)
X {
X if (current_binding_level != global_binding_level
X && TREE_EXTERNAL (decl))
X warning ("declaration of `%s' has `extern' and is initialized",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X TREE_EXTERNAL (decl) = 0;
X if (current_binding_level == global_binding_level)
X TREE_STATIC (decl) = 1;
X
X /* Tell `pushdecl' this is an initialized decl
X even though we don't yet have the initializer expression.
X Also tell `finish_decl' it may store the real initializer. */
X DECL_INITIAL (decl) = error_mark_node;
X }
X
X /* Add this decl to the current binding level, but not if it
X comes from another scope, e.g. a static member variable.
X TEM may equal DECL or it may be a previous decl of the same name. */
X if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE)
X || TREE_CODE (type) == LANG_TYPE)
X tem = decl;
X else
X {
X tem = pushdecl (decl);
X if (TREE_CODE (tem) == TREE_LIST)
X {
X tree tem2 = value_member (decl, tem);
X if (tem2 != NULL_TREE)
X tem = TREE_VALUE (tem2);
X else
X {
X while (tem && ! decls_match (decl, TREE_VALUE (tem)))
X tem = TREE_CHAIN (tem);
X if (tem == NULL_TREE)
X tem = decl;
X else
X tem = TREE_VALUE (tem);
X }
X }
X }
X
X#if 0
X /* We don't do this yet for GNU C++. */
X /* For a local variable, define the RTL now. */
X if (current_binding_level != global_binding_level
X /* But not if this is a duplicate decl
X and we preserved the rtl from the previous one
X (which may or may not happen). */
X && DECL_RTL (tem) == 0)
X {
X if (TYPE_SIZE (TREE_TYPE (tem)) != 0)
X expand_decl (tem);
X else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
X && DECL_INITIAL (tem) != 0)
X expand_decl (tem);
X }
X#endif
X
X if (TREE_CODE (decl) == FUNCTION_DECL && DECL_OVERLOADED (decl))
X /* @@ Also done in start_function. */
X push_overloaded_decl (tem);
X
X if (init_written
X && ! (TREE_CODE (tem) == PARM_DECL
X || (TREE_READONLY (tem)
X && (TREE_CODE (tem) == VAR_DECL
X || TREE_CODE (tem) == FIELD_DECL))))
X {
X /* When parsing and digesting the initializer,
X use temporary storage. Do this even if we will ignore the value. */
X if (current_binding_level == global_binding_level && debug_temp_inits)
X {
X if (TYPE_NEEDS_CONSTRUCTING (type))
X /* In this case, the initializer must lay down in permanent
X storage, since it will be saved until `finish_file' is run. */
X ;
X else
X temporary_allocation ();
X }
X }
X
X return tem;
X}
X
Xstatic void
Xmake_temporary_for_reference (decl, ctor_call, init, cleanupp)
X tree decl, ctor_call, init;
X tree *cleanupp;
X{
X tree type = TREE_TYPE (decl);
X tree target_type = TREE_TYPE (type);
X tree tmp, tmp_addr;
X
X if (ctor_call)
X {
X tmp_addr = TREE_VALUE (TREE_OPERAND (ctor_call, 1));
X if (TREE_CODE (tmp_addr) == NOP_EXPR)
X tmp_addr = TREE_OPERAND (tmp_addr, 0);
X assert (TREE_CODE (tmp_addr) == ADDR_EXPR);
X tmp = TREE_OPERAND (tmp_addr, 0);
X }
X else
X {
X tmp = get_temp_name (target_type,
X current_binding_level == global_binding_level);
X tmp_addr = build_unary_op (ADDR_EXPR, tmp, 0);
X }
X
X TREE_TYPE (tmp_addr) = build_pointer_type (target_type);
X DECL_INITIAL (decl) = convert_pointer_to (target_type, tmp_addr);
X TREE_TYPE (DECL_INITIAL (decl)) = type;
X if (TYPE_NEEDS_CONSTRUCTING (target_type))
X {
X if (current_binding_level == global_binding_level)
X {
X /* lay this variable out now. Otherwise `output_addressed_constants'
X gets confused by its initializer. */
X make_decl_rtl (tmp, 0, 1);
X static_aggregates = perm_tree_cons (init, tmp, static_aggregates);
X }
X else
X {
X if (ctor_call != NULL_TREE)
X init = ctor_call;
X else
X init = build_method_call (tmp, DECL_NAME (TYPE_NAME (target_type)),
X build_tree_list (NULL_TREE, init),
X NULL_TREE, LOOKUP_NORMAL);
X DECL_INITIAL (decl) = build (COMPOUND_EXPR, type, init,
X DECL_INITIAL (decl));
X *cleanupp = maybe_build_cleanup (tmp);
X }
X }
X else
X {
X DECL_INITIAL (tmp) = init;
X TREE_STATIC (tmp) = current_binding_level == global_binding_level;
X finish_decl (tmp, init, 0);
X }
X if (TREE_STATIC (tmp))
X preserve_initializer ();
X}
X
X/* Handle initialization of references.
X These three arguments from from `finish_decl', and have the
X same meaning here that they do there. */
Xstatic void
Xgrok_reference_init (decl, type, init, cleanupp)
X tree decl, type, init;
X tree *cleanupp;
X{
X char *errstr = 0;
X int is_reference;
X tree tmp;
X tree this_ptr_type, actual_init;
X
X if (init == NULL_TREE)
X {
X if (DECL_LANG_SPECIFIC (decl) == 0 || DECL_IN_AGGR_P (decl) == 0)
X {
X error ("variable declared as reference not initialized");
X if (TREE_CODE (decl) == VAR_DECL)
X SET_DECL_REFERENCE_SLOT (decl, error_mark_node);
X }
X return;
X }
X
X if (TREE_CODE (init) == TREE_LIST)
X init = build_compound_expr (init);
X is_reference = TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE;
X tmp = is_reference ? convert_from_reference (init) : init;
X
X if (is_reference)
X {
X if (! comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
X TYPE_MAIN_VARIANT (TREE_TYPE (tmp)), 0))
X errstr = "initialization of `%s' from dissimilar reference type";
X else if (TREE_READONLY (TREE_TYPE (type))
X >= TREE_READONLY (TREE_TYPE (TREE_TYPE (init))))
X {
X is_reference = 0;
X init = tmp;
X }
X }
X else
X {
X if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE
X && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
X {
X /* Note: default conversion is only called in very
X special cases. */
X init = default_conversion (init);
X }
X if (IS_AGGR_TYPE (TREE_TYPE (type))
X && IS_AGGR_TYPE (TREE_TYPE (init))
X && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
X TYPE_MAIN_VARIANT (TREE_TYPE (init)), 0))
X {
X /* Nothing happens. */
X }
X else if (TREE_CODE (TREE_TYPE (type)) == TREE_CODE (TREE_TYPE (init)))
X {
X init = convert (TREE_TYPE (type), init);
X }
X else if (init != error_mark_node
X && ! comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
X TYPE_MAIN_VARIANT (TREE_TYPE (init)), 0))
X errstr = "invalid type conversion for reference";
X }
X
X if (errstr)
X {
X /* Things did not go smoothly; look for operator& type conversion. */
X if (IS_AGGR_TYPE (TREE_TYPE (tmp)))
X {
X tmp = build_type_conversion (CONVERT_EXPR, type, init, 0);
X if (tmp != NULL_TREE)
X {
X init = tmp;
X if (tmp == error_mark_node)
X errstr = "ambiguous pointer conversion";
X else
X errstr = 0;
X is_reference = 1;
X }
X else
X {
X tmp = build_type_conversion (CONVERT_EXPR, TREE_TYPE (type), init, 0);
X if (tmp != NULL_TREE)
X {
X init = tmp;
X if (tmp == error_mark_node)
X errstr = "ambiguous pointer conversion";
X else
X errstr = 0;
X is_reference = 0;
X }
X }
X }
X /* Look for constructor. */
X else if (IS_AGGR_TYPE (TREE_TYPE (type))
X && TYPE_HAS_CONSTRUCTOR (TREE_TYPE (type)))
X {
X tmp = get_temp_name (TREE_TYPE (type),
X current_binding_level == global_binding_level);
X tmp = build_method_call (tmp, DECL_NAME (TYPE_NAME (TREE_TYPE (type))),
X build_tree_list (NULL_TREE, init),
X NULL_TREE, LOOKUP_NORMAL);
X if (tmp == NULL_TREE || tmp == error_mark_node)
X {
X if (TREE_CODE (decl) == VAR_DECL)
X SET_DECL_REFERENCE_SLOT (decl, error_mark_node);
X error_with_decl (decl, "constructor failed to build reference initializer");
X return;
X }
X make_temporary_for_reference (decl, tmp, init, cleanupp);
X goto done;
X }
X }
X
X if (errstr)
X {
X error_with_decl (decl, errstr);
X if (TREE_CODE (decl) == VAR_DECL)
X SET_DECL_REFERENCE_SLOT (decl, error_mark_node);
X return;
X }
X
X /* In the case of initialization, it is permissable
X to assign one reference to another. */
X this_ptr_type = build_pointer_type (TREE_TYPE (type));
X
X if (is_reference)
X {
X if (TREE_VOLATILE (init))
X DECL_INITIAL (decl) = save_expr (init);
X else
X DECL_INITIAL (decl) = init;
X }
X else if (lvalue_p (init))
X {
X tmp = build_unary_op (ADDR_EXPR, init, 0);
X if (TREE_CODE (tmp) == ADDR_EXPR
X && TREE_CODE (TREE_OPERAND (tmp, 0)) == WITH_CLEANUP_EXPR)
X {
X /* Associate the cleanup with the reference so that we
X don't get burned by "aggressive" cleanup policy. */
X *cleanupp = TREE_OPERAND (TREE_OPERAND (tmp, 0), 2);
X TREE_OPERAND (TREE_OPERAND (tmp, 0), 2) = error_mark_node;
X }
X DECL_INITIAL (decl) = convert_pointer_to (TREE_TYPE (this_ptr_type), tmp);
X DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
X if (DECL_INITIAL (decl) == current_class_decl)
X DECL_INITIAL (decl) = copy_node (current_class_decl);
X TREE_TYPE (DECL_INITIAL (decl)) = type;
X }
X else if ((actual_init = unary_complex_lvalue (ADDR_EXPR, init)))
X {
X /* The initializer for this decl goes into its
X DECL_REFERENCE_SLOT. Make sure that we can handle
X multiple evaluations without ill effect. */
X if (TREE_CODE (actual_init) == ADDR_EXPR
X && TREE_CODE (TREE_OPERAND (actual_init, 0)) == NEW_EXPR)
X actual_init = save_expr (actual_init);
X DECL_INITIAL (decl) = convert_pointer_to (TREE_TYPE (this_ptr_type), actual_init);
X DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
X TREE_TYPE (DECL_INITIAL (decl)) = type;
X }
X else if (TREE_READONLY (TREE_TYPE (type)))
X /* Section 8.4.3 allows us to make a temporary for
X the initialization of const&. */
X make_temporary_for_reference (decl, NULL_TREE, init, cleanupp);
X else
X {
X error_with_decl (decl, "type mismatch in initialization of `%s' (use `const')");
X DECL_INITIAL (decl) = error_mark_node;
X }
X
X done:
X /* ?? Can this be optimized in some cases to
X hand back the DECL_INITIAL slot?? */
X if (TYPE_SIZE (TREE_TYPE (type)))
X SET_DECL_REFERENCE_SLOT (decl, convert_from_reference (decl));
X
X if (TREE_STATIC (decl) && ! TREE_LITERAL (DECL_INITIAL (decl)))
X {
X expand_static_init (decl, DECL_INITIAL (decl));
X DECL_INITIAL (decl) = 0;
X }
X}
X
X/* Finish processing of a declaration;
X install its line number and initial value.
X If the length of an array type is not known before,
X it must be determined now, from the initial value, or it is an error.
X
X For C++, `finish_decl' must be fairly evasive: it must keep initializers
X for aggregates that have constructors alive on the permanent obstack,
X so that the global initializing functions can be written at the end.
X
X INIT0 holds the value of an initializer that should be allowed to escape
X the normal rules.
X
X For functions that take defualt parameters, DECL points to its
X "maximal" instantiation. finish_decl must then also declared its
X subsequently lower and lower forms of instantiation, checking for
X ambiguity as it goes. This can be sped up later. */
X
Xvoid
Xfinish_decl (decl, init, asmspec_tree)
X tree decl, init;
X tree asmspec_tree;
X{
X register tree type;
X tree cleanup = NULL_TREE, ttype;
X int was_incomplete;
X int temporary = allocation_temporary_p ();
X char *asmspec = 0;
X int was_readonly = 0;
X
X /* If this is 0, then we did not change obstacks. */
X if (! decl)
X {
X if (init)
X error ("assignment (not initialization) in declaration");
X return;
X }
X
X if (asmspec_tree)
X {
X asmspec = TREE_STRING_POINTER (asmspec_tree);
X /* Zero out old RTL, since we will rewrite it. */
X DECL_RTL (decl) = 0;
X }
X
X /* If the type of the thing we are declaring either has
X a constructor, or has a virtual function table pointer,
X AND its initialization was accepted by `start_decl',
X then we stayed on the permanent obstack through the
X declaration, otherwise, changed obstacks as GCC would. */
X
X type = TREE_TYPE (decl);
X
X was_incomplete = (DECL_SIZE (decl) == 0);
X
X /* Take care of TYPE_DECLs up front. */
X if (TREE_CODE (decl) == TYPE_DECL)
X {
X if (init && DECL_INITIAL (decl))
X {
X /* typedef foo = bar; store the type of bar as the type of foo. */
X TREE_TYPE (decl) = type = TREE_TYPE (init);
X DECL_INITIAL (decl) = init = 0;
X }
X if (IS_AGGR_TYPE (type))
X {
X#ifndef BREAK_C_TAGS
X if (current_lang_name == lang_name_cplusplus)
X#endif
X {
X if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type)
X warning ("shadowing previous type declaration of `%s'",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X TREE_TYPE (DECL_NAME (decl)) = decl;
X }
X CLASSTYPE_GOT_SEMICOLON (type) = 1;
X }
X
X#ifdef FIELD_XREF
X FIELD_xref_decl(current_function_decl,decl);
X#endif
X
X rest_of_decl_compilation (decl, 0,
X current_binding_level == global_binding_level, 0);
X goto finish_end;
X }
X if (IS_AGGR_TYPE (type) && CLASSTYPE_DECLARED_EXCEPTION (type))
X {
X finish_exception_decl (NULL_TREE, decl);
X CLASSTYPE_GOT_SEMICOLON (type) = 1;
X goto finish_end;
X }
X if (TREE_CODE (decl) != FUNCTION_DECL)
X {
X ttype = target_type (type);
X if (TYPE_NAME (ttype)
X && TREE_CODE (TYPE_NAME (ttype)) == TYPE_DECL
X && ANON_AGGRNAME_P (DECL_NAME (TYPE_NAME (ttype))))
X {
X tree old_id = DECL_NAME (TYPE_NAME (ttype));
X char *newname = (char *)alloca (IDENTIFIER_LENGTH (old_id) + 2);
X newname[0] = '_';
X bcopy (IDENTIFIER_POINTER (old_id), newname + 1,
X IDENTIFIER_LENGTH (old_id) + 1);
X old_id = get_identifier (newname);
X lookup_tag_reverse (ttype, old_id);
X DECL_NAME (TYPE_NAME (ttype)) = old_id;
X }
X }
X
X if (! TREE_EXTERNAL (decl) && TREE_READONLY (decl)
X && TYPE_NEEDS_CONSTRUCTING (type))
X {
X
X /* Currently, GNU C++ puts constants in text space, making them
X impossible to initialize. In the future, one would hope for
X an operating system which understood the difference between
X initialization and the running of a program. */
X was_readonly = 1;
X TREE_READONLY (decl) = 0;
X }
X
X if (TREE_CODE (decl) == FIELD_DECL)
X {
X if (init && init != error_mark_node)
X assert (TREE_PERMANENT (init));
X
X if (asmspec)
X {
X /* This must override the asm specifier which was placed
X by grokclassfn. Lay this out fresh.
X
X @@ Should emit an error if this redefines an asm-specified
X @@ name, or if we have already used the function's name. */
X DECL_RTL (TREE_TYPE (decl)) = 0;
X DECL_ASSEMBLER_NAME (decl) = asmspec;
X make_decl_rtl (decl, asmspec, 0);
X }
X }
X /* If `start_decl' didn't like having an initialization, ignore it now. */
X else if (init != 0 && DECL_INITIAL (decl) == 0)
X init = 0;
X else if (TREE_EXTERNAL (decl))
X ;
X else if (TREE_CODE (type) == REFERENCE_TYPE)
X {
X grok_reference_init (decl, type, init, &cleanup);
X init = 0;
X }
X
X#ifdef FIELD_XREF
X FIELD_xref_decl(current_function_decl,decl);
X#endif
X
X if (TREE_CODE (decl) == FIELD_DECL || TREE_EXTERNAL (decl))
X ;
X else if (TREE_CODE (decl) == CONST_DECL)
X {
X assert (TREE_CODE (decl) != REFERENCE_TYPE);
X
X DECL_INITIAL (decl) = init;
X
X /* This will keep us from needing to worry about our obstacks. */
X assert (init != 0);
X init = 0;
X }
X else if (init)
X {
X if (TYPE_NEEDS_CONSTRUCTING (type))
X {
X if (TREE_CODE (type) == ARRAY_TYPE)
X init = digest_init (type, init, 0);
X else if (TREE_CODE (init) == CONSTRUCTOR
X && CONSTRUCTOR_ELTS (init) != NULL_TREE)
X {
X error_with_decl (decl, "`%s' must be initialized by constructor, not by `{...}'");
X init = error_mark_node;
X }
X#if 0
X /* fix this in `build_functional_cast' instead.
X Here's the trigger code:
X
X struct ostream
X {
X ostream ();
X ostream (int, char *);
X ostream (char *);
X operator char *();
X ostream (void *);
X operator void *();
X operator << (int);
X };
X int buf_size = 1024;
X static char buf[buf_size];
X const char *debug(int i) {
X char *b = &buf[0];
X ostream o = ostream(buf_size, b);
X o << i;
X return buf;
X }
X */
X
X else if (TREE_CODE (init) == NEW_EXPR
X && TREE_CODE (TREE_OPERAND (init, 1) == CPLUS_NEW_EXPR))
X {
X /* User wrote something like `foo x = foo (args)' */
X assert (TREE_CODE (TREE_OPERAND (init, 0)) == VAR_DECL);
X assert (DECL_NAME (TREE_OPERAND (init, 0)) == NULL_TREE);
X
X /* User wrote exactly `foo x = foo (args)' */
X if (TYPE_MAIN_VARIANT (type) == TREE_TYPE (init))
X {
X init = build (CALL_EXPR, TREE_TYPE (init),
X TREE_OPERAND (TREE_OPERAND (init, 1), 0),
X TREE_OPERAND (TREE_OPERAND (init, 1), 1), 0);
X TREE_VOLATILE (init) = 1;
X }
X }
X#endif
X
X /* We must hide the initializer so that expand_decl
X won't try to do something it does not understand. */
X if (current_binding_level == global_binding_level)
X {
X tree value = digest_init (type, empty_init_node, 0);
X DECL_INITIAL (decl) = value;
X }
X else
X DECL_INITIAL (decl) = error_mark_node;
X }
X else
X {
X if (TREE_CODE (init) != TREE_VEC)
X init = store_init_value (decl, init);
X
X if (init)
X /* Don't let anyone try to initialize this variable
X until we are ready to do so. */
X DECL_INITIAL (decl) = error_mark_node;
X }
X }
X else if (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type))
X {
X tree ctype = type;
X while (TREE_CODE (ctype) == ARRAY_TYPE)
X ctype = TREE_TYPE (ctype);
X if (! TYPE_NEEDS_CONSTRUCTOR (ctype))
X {
X if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (ctype))
X error_with_decl (decl, "structure `%s' with uninitialized const members");
X if (CLASSTYPE_REF_FIELDS_NEED_INIT (ctype))
X error_with_decl (decl, "structure `%s' with uninitialized reference members");
X }
X
X if (TREE_CODE (decl) == VAR_DECL
X && !TYPE_NEEDS_CONSTRUCTING (type)
X && (TREE_READONLY (type) || TREE_READONLY (decl)))
X error_with_decl (decl, "uninitialized const `%s'");
X
X /* Initialize variables in need of static initialization
X with `empty_init_node' to keep assemble_variable from putting them
X in the wrong program space. */
X if (TREE_STATIC (decl)
X && TREE_CODE (decl) == VAR_DECL
X && TYPE_NEEDS_CONSTRUCTING (type)
X && (DECL_INITIAL (decl) == 0
X || DECL_INITIAL (decl) == error_mark_node))
X {
X tree value = digest_init (type, empty_init_node, 0);
X DECL_INITIAL (decl) = value;
X }
X }
X else if (TREE_CODE (decl) == VAR_DECL
X && TREE_CODE (type) != REFERENCE_TYPE
X && (TREE_READONLY (type) || TREE_READONLY (decl)))
X {
X if (! TREE_STATIC (decl))
X error_with_decl (decl, "uninitialized const `%s'");
X }
X
X /* For top-level declaration, the initial value was read in
X the temporary obstack. MAXINDEX, rtl, etc. to be made below
X must go in the permanent obstack; but don't discard the
X temporary data yet. */
X
X if (current_binding_level == global_binding_level && temporary)
X end_temporary_allocation ();
X
X /* Deduce size of array from initialization, if not already known. */
X
X if (TREE_CODE (type) == ARRAY_TYPE
X && TYPE_DOMAIN (type) == 0
X && TREE_CODE (decl) != TYPE_DECL)
X {
X int do_default = ! ((!pedantic && TREE_STATIC (decl))
X || TREE_EXTERNAL (decl));
X tree initializer = init ? init : DECL_INITIAL (decl);
X int failure = complete_array_type (type, initializer, do_default);
X
X if (failure == 1)
X error_with_decl (decl, "initializer fails to determine size of `%s'");
X
X if (failure == 2)
X {
X if (do_default)
X error_with_decl (decl, "array size missing in `%s'");
X else if (!pedantic && TREE_STATIC (decl))
X TREE_EXTERNAL (decl) = 1;
X }
X
X if (pedantic && TYPE_DOMAIN (type) != 0
X && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
X integer_zero_node))
X error_with_decl (decl, "zero-size array `%s'");
X
X layout_decl (decl, 0);
X }
X
X if (TREE_CODE (decl) == VAR_DECL)
X {
X if (TREE_STATIC (decl) && DECL_SIZE (decl) == 0)
X {
X /* A static variable with an incomplete type:
X that is an error if it is initialized or `static'.
X Otherwise, let it through, but if it is not `extern'
X then it may cause an error message later. */
X if (! (TREE_PUBLIC (decl) && DECL_INITIAL (decl) == 0))
X error_with_decl (decl, "storage size of `%s' isn't known");
X init = 0;
X }
X else if (!TREE_EXTERNAL (decl) && DECL_SIZE (decl) == 0)
X {
X /* An automatic variable with an incomplete type:
X that is an error. */
X error_with_decl (decl, "storage size of `%s' isn't known");
X TREE_TYPE (decl) = error_mark_node;
X }
X else if (!TREE_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
X /* Let debugger know it should output info for this type. */
X CLASSTYPE_ASM_WRITTEN (ttype) = 1;
X
X if ((TREE_EXTERNAL (decl) || TREE_STATIC (decl))
X && DECL_SIZE (decl) != 0 && ! TREE_LITERAL (DECL_SIZE (decl)))
X error_with_decl (decl, "storage size of `%s' isn't constant");
X
X if (!TREE_EXTERNAL (decl) && TYPE_NEEDS_DESTRUCTOR (type))
X {
X int yes = suspend_momentary ();
X
X /* If INIT comes from a functional cast, use the cleanup
X we built for that. Otherwise, make our own cleanup. */
X if (init && TREE_CODE (init) == WITH_CLEANUP_EXPR
X && comptypes (TREE_TYPE (decl), TREE_TYPE (init), 1))
X {
X cleanup = TREE_OPERAND (init, 2);
X init = TREE_OPERAND (init, 0);
X }
X else
X cleanup = maybe_build_cleanup (decl);
X resume_momentary (yes);
X }
X }
X /* PARM_DECLs get cleanups, too. */
X else if (TREE_CODE (decl) == PARM_DECL && TYPE_NEEDS_DESTRUCTOR (type))
X {
X if (temporary)
X end_temporary_allocation ();
X cleanup = maybe_build_cleanup (decl);
X if (temporary)
X resume_temporary_allocation ();
X }
X
X /* Output the assembler code and/or RTL code for variables and functions,
X unless the type is an undefined structure or union.
X If not, it will get done when the type is completed. */
X
X if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
X || TREE_CODE (decl) == RESULT_DECL)
X {
X int toplev = current_binding_level == global_binding_level;
X int was_temp
X = ((flag_traditional
X || (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)))
X && allocation_temporary_p ());
X
X if (was_temp)
X end_temporary_allocation ();
X
X /* If we are in need of a cleanup, get out of any implicit
X handlers that have been established so far. */
X if (cleanup && current_binding_level->parm_flag == 3)
X {
X pop_implicit_try_blocks (decl);
X current_binding_level->more_exceptions_ok = 0;
X }
X
X if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
X make_decl_rtl (decl, 0, toplev);
X else if (TREE_CODE (decl) == VAR_DECL
X && TREE_READONLY (decl)
X && DECL_INITIAL (decl) != 0
X && DECL_INITIAL (decl) != error_mark_node
X && DECL_INITIAL (decl) != empty_init_node)
X {
X DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
X
X if (asmspec)
X DECL_ASSEMBLER_NAME (decl) = asmspec;
X
X if (! toplev
X && TREE_STATIC (decl)
X && ! TREE_VOLATILE (decl)
X && ! TREE_PUBLIC (decl)
X && ! TREE_EXTERNAL (decl)
X && ! TYPE_NEEDS_DESTRUCTOR (type)
X && DECL_MODE (decl) != BLKmode)
X {
X /* If this variable is really a constant, then fill its DECL_RTL
X slot with something which won't take up storage.
X If something later should take its address, we can always give
X it legitimate RTL at that time. */
X DECL_RTL (decl) = (struct rtx_def *)gen_reg_rtx (DECL_MODE (decl));
X store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
X TREE_ASM_WRITTEN (decl) = 1;
X }
X else if (toplev)
X {
X /* Keep GCC from complaining that this variable
X is defined but never used. */
X TREE_INLINE (decl) = 1;
X /* If this is a static const, change its apparent linkage
X if it belongs to a #pragma interface. */
X if (TREE_STATIC (decl) && interface_unknown == 0)
X {
X if (interface_only)
X {
X TREE_STATIC (decl) = 0;
X TREE_EXTERNAL (decl) = 1;
X }
X else
X {
X TREE_PUBLIC (decl) = 1;
X /* Marking it used will cause it to be written. */
X TREE_USED (decl) = 1;
X }
X }
X make_decl_rtl (decl, asmspec, toplev);
X }
X else
X rest_of_decl_compilation (decl, asmspec, toplev, 0);
X }
X else if (TREE_CODE (decl) == VAR_DECL
X && DECL_LANG_SPECIFIC (decl)
X && DECL_IN_AGGR_P (decl))
X {
X if (TREE_STATIC (decl))
X if (init == 0 && TYPE_NEEDS_CONSTRUCTING (type))
X {
X TREE_EXTERNAL (decl) = 1;
X make_decl_rtl (decl, asmspec, 1);
X }
X else
X rest_of_decl_compilation (decl, asmspec, toplev, 0);
X else
X /* Just a constant field. Should not need any rtl. */
X goto finish_end0;
X }
X else
X rest_of_decl_compilation (decl, asmspec, toplev, 0);
X
X if (was_temp)
X resume_temporary_allocation ();
X
X if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_ABSTRACT_VIRTUALS (type))
X abstract_virtuals_error (decl, type);
X else if (TREE_CODE (type) == FUNCTION_TYPE
X && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
X && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (type)))
X abstract_virtuals_error (decl, TREE_TYPE (type));
X
X if (TREE_CODE (decl) == FUNCTION_DECL)
X {
X /* C++: Handle overloaded functions with default parameters. */
X if (DECL_OVERLOADED (decl))
X {
X tree parmtypes = TYPE_ARG_TYPES (type);
X tree prev = NULL_TREE;
X char *original_name = IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (decl));
X struct lang_decl *tmp_lang_decl = DECL_LANG_SPECIFIC (decl);
X /* All variants will share an uncollectable lang_decl. */
X copy_decl_lang_specific (decl);
X
X while (parmtypes && parmtypes != void_list_node)
X {
X if (TREE_PURPOSE (parmtypes))
X {
X tree fnname, fndecl;
X tree *argp = prev
X ? & TREE_CHAIN (prev)
X : & TYPE_ARG_TYPES (type);
X
X *argp = NULL_TREE;
X fnname = build_decl_overload (original_name, TYPE_ARG_TYPES (type), 0);
X *argp = parmtypes;
X fndecl = build_decl (FUNCTION_DECL, fnname, type);
X TREE_EXTERNAL (fndecl) = TREE_EXTERNAL (decl);
X TREE_PUBLIC (fndecl) = TREE_PUBLIC (decl);
X TREE_INLINE (fndecl) = TREE_INLINE (decl);
X /* Keep G++ from thinking this function is unused.
X It is only used to speed up search in name space. */
X TREE_USED (fndecl) = 1;
X TREE_ASM_WRITTEN (fndecl) = 1;
X DECL_INITIAL (fndecl) = NULL_TREE;
X DECL_LANG_SPECIFIC (fndecl) = DECL_LANG_SPECIFIC (decl);
X fndecl = pushdecl (fndecl);
X DECL_INITIAL (fndecl) = error_mark_node;
X DECL_RTL (fndecl) = DECL_RTL (decl);
X }
X prev = parmtypes;
X parmtypes = TREE_CHAIN (parmtypes);
X }
X DECL_LANG_SPECIFIC (decl) = tmp_lang_decl;
X }
X }
X else if (TREE_EXTERNAL (decl))
X ;
X else if (TREE_STATIC (decl))
X {
X /* Cleanups for static variables are handled by `finish_file'. */
X if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE)
X expand_static_init (decl, init);
X }
X else if (current_binding_level != global_binding_level)
X {
X /* This is a declared decl which must live until the
X end of the binding contour. It may need a cleanup. */
X
X /* Recompute the RTL of a local array now
X if it used to be an incomplete type. */
X if (was_incomplete && ! TREE_STATIC (decl))
X {
X /* If we used it already as memory, it must stay in memory. */
X TREE_ADDRESSABLE (decl) = TREE_USED (decl);
X /* If it's still incomplete now, no init will save it. */
X if (DECL_SIZE (decl) == 0)
X DECL_INITIAL (decl) = 0;
X expand_decl (decl);
X }
X else if (! TREE_ASM_WRITTEN (decl)
X && (TYPE_SIZE (type) != 0 || TREE_CODE (type) == ARRAY_TYPE))
X {
X /* Do this here, because we did not expand this decl's
X rtl in start_decl. */
X if (DECL_RTL (decl) == 0)
X expand_decl (decl);
X else if (cleanup)
X {
X expand_decl_cleanup (NULL_TREE, cleanup);
X /* Cleanup used up here. */
X cleanup = 0;
X }
X }
X
X if (DECL_SIZE (decl) && type != error_mark_node)
X {
X /* Compute and store the initial value. */
X expand_decl_init (decl);
X
X if (init || TYPE_NEEDS_CONSTRUCTING (type))
X {
X emit_line_note (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
X expand_aggr_init (decl, init, 0);
X }
X
X /* Set this to 0 so we can tell whether an aggregate
X which was initialized was ever used. */
X if (TYPE_NEEDS_CONSTRUCTING (type))
X TREE_USED (decl) = 0;
X
X /* Store the cleanup, if there was one. */
X if (cleanup)
X {
X if (! expand_decl_cleanup (decl, cleanup))
X error_with_decl (decl, "parser lost in parsing declaration of `%s'");
X }
X }
X }
X finish_end0:
X
X /* Undo call to `pushclass' that was done in `start_decl'
X due to initialization of qualified member variable.
X I.e., Foo::x = 10; */
X if (TREE_CODE (decl) == VAR_DECL && DECL_CONTEXT (decl))
X popclass (1);
X }
X
X finish_end:
X
X /* Resume permanent allocation, if not within a function. */
X if (temporary && current_binding_level == global_binding_level)
X {
X permanent_allocation ();
X#if 0
X /* @@ I don't know whether this is true for GNU C++. */
X /* We need to remember that this array HAD an initialization,
X but discard the actual nodes, since they are temporary anyway. */
X if (DECL_INITIAL (decl) != 0)
X DECL_INITIAL (decl) = error_mark_node;
X#endif
X }
X if (was_readonly)
X TREE_READONLY (decl) = 1;
X}
X
Xstatic void
Xexpand_static_init (decl, init)
X tree decl;
X tree init;
X{
X tree oldstatic = value_member (decl, static_aggregates);
X if (oldstatic)
X {
X if (TREE_PURPOSE (oldstatic))
X error_with_decl (decl, "multiple initializations given for `%s'");
X }
X else if (current_binding_level != global_binding_level)
X {
X /* Emit code to perform this initialization but once. */
X tree temp = get_temp_name (integer_type_node, 1);
X rest_of_decl_compilation (temp, NULL_TREE, 0, 0);
X expand_start_cond (build_binary_op (EQ_EXPR, temp, integer_zero_node), 0);
X expand_assignment (temp, integer_one_node, 0, 0);
X if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
X {
X expand_aggr_init (decl, init, 0);
X do_pending_stack_adjust ();
X }
X else
X expand_assignment (decl, init, 0, 0);
X expand_end_cond ();
X if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
X {
X static_aggregates = perm_tree_cons (temp, decl, static_aggregates);
X TREE_STATIC (static_aggregates) = 1;
X }
X }
X else
X {
X /* This code takes into account memory allocation
X policy of `start_decl'. Namely, if TYPE_NEEDS_CONSTRUCTING
X does not hold for this object, then we must make permanent
X the storage currently in the temporary obstack. */
X if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
X preserve_initializer ();
X static_aggregates = perm_tree_cons (init, decl, static_aggregates);
X }
X}
X
X/* Make TYPE a complete type based on INITIAL_VALUE.
X Return 0 if successful, 1 if INITIAL_VALUE can't be decyphered,
X 2 if there was no information (in which case assume 1 if DO_DEFAULT). */
X
Xint
Xcomplete_array_type (type, initial_value, do_default)
X tree type;
X tree initial_value;
X int do_default;
X{
X register tree maxindex = NULL_TREE;
X int value = 0;
X int temporary = (TREE_PERMANENT (type) && allocation_temporary_p ());
X
X /* Don't put temporary nodes in permanent type. */
X if (temporary)
X end_temporary_allocation ();
X
X if (initial_value)
X {
X /* Note MAXINDEX is really the maximum index,
X one less than the size. */
X if (TREE_CODE (initial_value) == STRING_CST)
X maxindex = build_int_2 (TREE_STRING_LENGTH (initial_value) - 1, 0);
X else if (TREE_CODE (initial_value) == CONSTRUCTOR)
X {
X register int nelts
X = list_length (CONSTRUCTOR_ELTS (initial_value));
X maxindex = build_int_2 (nelts - 1, 0);
X }
X else
X {
X /* Make an error message unless that happened already. */
X if (initial_value != error_mark_node)
X value = 1;
X
X /* Prevent further error messages. */
X maxindex = build_int_2 (1, 0);
X }
X }
X
X if (!maxindex)
X {
X if (do_default)
X maxindex = build_int_2 (1, 0);
X value = 2;
X }
X
X if (maxindex)
X {
X TYPE_DOMAIN (type) = build_index_type (maxindex);
X if (!TREE_TYPE (maxindex))
X TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
X }
X
X /* Lay out the type now that we can get the real answer. */
X
X layout_type (type);
X
X if (temporary)
X resume_temporary_allocation ();
X
X return value;
X}
X
X/* Return zero if something is declared to be a member of type
X CTYPE when in the context of CUR_TYPE. STRING is the error
X message to print in that case. Otherwise, quietly return 1. */
Xstatic int
Xmember_function_or_else (ctype, cur_type, string)
X tree ctype, cur_type;
X char *string;
X{
X if (ctype && ctype != cur_type)
X {
X error (string, TYPE_NAME_STRING (ctype));
X return 0;
X }
X return 1;
X}
X
X/* Subroutine of `grokdeclarator'. */
X
X/* CTYPE is class type, or null if non-class.
X TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
X or METHOD_TYPE.
X DECLARATOR is the function's name.
X VIRTUALP is truthvalue of whether the function is virtual or not.
X FLAGS are to be passed through to `grokclassfn'.
X QUALS are qualifiers indicating whether the function is `const'
X or `volatile'.
X RAISES is a list of exceptions that this function can raise.
X CHECK is 1 if we must find this method in CTYPE, 0 if we should
X not look, and -1 if we should not call `grokclassfn' at all. */
Xstatic tree
Xgrokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check)
X tree ctype, type;
X tree declarator;
X int virtualp;
X enum overload_flags flags;
X tree quals, raises;
X int check;
X{
X tree cname, decl;
X int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
X
X if (ctype)
X cname = TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL
X ? DECL_NAME (TYPE_NAME (ctype)) : TYPE_NAME (ctype);
X else
X cname = NULL_TREE;
X
X if (raises)
X {
X type = build_exception_variant (ctype, type, raises);
X raises = TYPE_RAISES_EXCEPTIONS (type);
X }
X decl = build_lang_decl (FUNCTION_DECL, declarator, type);
X if (staticp)
X {
X DECL_STATIC_FUNCTION_P (decl) = 1;
X DECL_STATIC_CONTEXT (decl) = ctype;
X }
X TREE_EXTERNAL (decl) = 1;
X if (quals != NULL_TREE && TREE_CODE (type) == FUNCTION_TYPE)
X {
X /* Dont have DECL_ORIGINAL_NAME yet, so we cannot pretty print it. */
X error ("functions cannot have method qualifiers");
X quals = NULL_TREE;
X }
X
X /* Caller will do the rest of this. */
X if (check < 0)
X return decl;
X
X if (flags == NO_SPECIAL && ctype && declarator == cname)
X {
X tree tmp;
X /* Just handle constructors here. We could do this
X inside the following if stmt, but I think
X that the code is more legible by breaking this
X case out. See comments below for what each of
X the following calls is supposed to do. */
X DECL_CONSTRUCTOR_P (decl) = 1;
X
X grokclassfn (ctype, declarator, decl, flags, check, quals);
X grok_ctor_properties (ctype, decl);
X if (check == 0)
X {
X tmp = lookup_name (DECL_NAME (decl));
X if (tmp == 0)
X IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl)) = decl;
X else if (TREE_CODE (tmp) != TREE_CODE (decl))
X error_with_decl (decl, "inconsistant declarations for `%s'");
X else
X {
X duplicate_decls (decl, tmp);
X decl = tmp;
X }
X make_decl_rtl (decl, NULL_TREE, 1);
X }
X }
X else
X {
X tree tmp;
X int i;
X
X /* Function gets the ugly name, field gets the nice one.
X This call may change the type of the function (because
X of default parameters)!
X
X Wrappers get field names which will not conflict
X with constructors and destructors. */
X if (ctype != NULL_TREE)
X grokclassfn (ctype, cname, decl, flags, check, quals);
X
X if (OPERATOR_NAME_P (DECL_NAME (decl)))
X {
X TREE_OPERATOR (decl) = 1;
X grok_op_properties (decl);
X }
X
X if (ctype == NULL_TREE || check)
X return decl;
X
X /* Now install the declaration of this function so that
X others may find it (esp. its DECL_FRIENDLIST).
X Pretend we are at top level, we will get true
X reference later, perhaps. */
X tmp = lookup_name (DECL_NAME (decl));
X if (tmp == 0)
X IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl)) = decl;
X else if (TREE_CODE (tmp) != TREE_CODE (decl))
X error_with_decl (decl, "inconsistant declarations for `%s'");
X else
X {
X duplicate_decls (decl, tmp);
X decl = tmp;
X }
X make_decl_rtl (decl, NULL_TREE, 1);
X
X /* If this declaration supersedes the declaration of
X a method declared virtual in the base class, then
X mark this field as being virtual as well. */
X for (i = 1; i <= CLASSTYPE_N_BASECLASSES (ctype); i++)
X {
X tree basetype = CLASSTYPE_BASECLASS (ctype, i);
X if (TYPE_VIRTUAL_P (basetype) || flag_all_virtual == 1)
X {
X tmp = get_first_matching_virtual (basetype, decl,
X flags == DTOR_FLAG);
X if (tmp)
X {
X /* The TMP we really want is the one from the deepest
X baseclass on this path, taking care not to
X duplicate if we have already found it (via another
X path to its virtual baseclass. */
X if (staticp)
X {
X error_with_decl (decl, "method `%s' may not be declared static");
X error_with_decl (tmp, "(since `%s' declared virtual in base class.)");
X break;
X }
X virtualp = 1;
X
X if ((TYPE_USES_VIRTUAL_BASECLASSES (basetype)
X || TYPE_USES_MULTIPLE_INHERITANCE (ctype))
X && TYPE_MAIN_VARIANT (basetype) != DECL_VCONTEXT (tmp))
X tmp = get_first_matching_virtual (DECL_VCONTEXT (tmp),
X decl, flags == DTOR_FLAG);
X if (value_member (tmp, DECL_VINDEX (decl)) == NULL_TREE)
X {
X /* The argument types may have changed... */
X tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
X tree base_variant = TREE_TYPE (TREE_VALUE (argtypes));
X
X argtypes = commonparms (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (tmp))),
X TREE_CHAIN (argtypes));
X /* But the return type has not. */
X type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes);
X if (raises)
X {
X type = build_exception_variant (ctype, type, raises);
X raises == TYPE_RAISES_EXCEPTIONS (type);
X }
X TREE_TYPE (decl) = type;
X SET_DECL_VINDEX (decl, tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl)));
X }
X }
X }
X }
X if (virtualp)
X {
X DECL_VIRTUAL_P (decl) = 1;
X DECL_VIRTUAL_P (declarator) = 1;
X if (ctype && CLASSTYPE_VTABLE_NEEDS_WRITING (ctype)
X && (write_virtuals == 2
X || (write_virtuals == 3
X && ! CLASSTYPE_INTERFACE_UNKNOWN (ctype))))
X TREE_PUBLIC (decl) = 1;
X }
X }
X return decl;
X}
X
Xstatic tree
Xgrokvardecl (ctype, type, declarator, specbits, initialized)
X tree ctype, type;
X tree declarator;
X int specbits;
X{
X tree decl;
X
X if (TREE_CODE (type) == OFFSET_TYPE)
X {
X /* If you declare a static member so that it
X can be initialized, the code will reach here. */
X tree field = lookup_field (TYPE_OFFSET_BASETYPE (type),
X declarator, 0);
X if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL)
X {
X tree basetype = TYPE_OFFSET_BASETYPE (type);
X error ("`%s' is not a static member of class `%s'",
X IDENTIFIER_POINTER (declarator),
X TYPE_NAME_STRING (basetype));
X type = TREE_TYPE (type);
X decl = build_decl (VAR_DECL, declarator, type);
X DECL_CONTEXT (decl) = basetype;
X }
X else
X {
X decl = field;
X if (initialized && DECL_INITIAL (decl)
X /* Complain about multiply-initialized
X member variables, but don't be faked
X out if initializer is faked up from `empty_init_node'. */
X && (TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR
X || CONSTRUCTOR_ELTS (DECL_INITIAL (decl)) != NULL_TREE))
X error_with_aggr_type (DECL_CONTEXT (decl),
X "multiple initializations of static member `%s::%s'",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X }
X }
X else decl = build_decl (VAR_DECL, declarator, type);
X
X if (specbits & (1 << (int) RID_EXTERN))
X {
X DECL_EXTERNAL (decl) = 1;
X TREE_EXTERNAL (decl) = !initialized;
X }
X
X /* In class context, static means one per class,
X public visibility, and static storage. */
X if (DECL_FIELD_CONTEXT (decl) != 0
X && IS_AGGR_TYPE (DECL_FIELD_CONTEXT (decl)))
X {
X TREE_PUBLIC (decl) = 1;
X TREE_STATIC (decl) = 1;
X }
X /* At top level, either `static' or no s.c. makes a definition
X (perhaps tentative), and absence of `static' makes it public. */
X else if (current_binding_level == global_binding_level)
X {
X TREE_PUBLIC (decl) = !(specbits & (1 << (int) RID_STATIC));
X TREE_STATIC (decl) = ! TREE_EXTERNAL (decl);
X }
X /* Not at top level, only `static' makes a static definition. */
X else
X {
X TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
X TREE_PUBLIC (decl) = TREE_EXTERNAL (decl);
X /* `extern' with initialization is invalid if not at top level. */
X if ((specbits & (1 << (int) RID_EXTERN)) && initialized)
X error_with_decl (decl, "`%s' has both `extern' and initializer");
X }
X return decl;
X}
X
X/* Given declspecs and a declarator,
X determine the name and type of the object declared
X and construct a ..._DECL node for it.
X (In one case we can return a ..._TYPE node instead.
X For invalid input we sometimes return 0.)
X
X DECLSPECS is a chain of tree_list nodes whose value fields
X are the storage classes and type specifiers.
X
X DECL_CONTEXT says which syntactic context this declaration is in:
X NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL.
X FUNCDEF for a function definition. Like NORMAL but a few different
X error messages in each case. Return value may be zero meaning
X this definition is too screwy to try to parse.
X MEMFUNCDEF for a function definition. Like FUNCDEF but prepares to
X handle member functions (which have FIELD context).
X Return value may be zero meaning this definition is too screwy to
X try to parse.
X PARM for a parameter declaration (either within a function prototype
X or before a function body). Make a PARM_DECL, or return void_type_node.
X TYPENAME if for a typename (in a cast or sizeof).
X Don't make a DECL node; just return the ..._TYPE node.
X FIELD for a struct or union field; make a FIELD_DECL.
X INITIALIZED is 1 if the decl has an initializer.
X
X In the TYPENAME case, DECLARATOR is really an absolute declarator.
X It may also be so in the PARM case, for a prototype where the
X argument type is specified but not the name.
X
X This function is where the complicated C meanings of `static'
X and `extern' are intrepreted.
X
X For C++, if there is any monkey business to do, the function which
X calls this one must do it, i.e., prepending instance variables,
X renaming overloaded function names, etc.
X
X Note that for this C++, it is an error to define a method within a class
X which does not belong to that class.
X
X Execpt in the case where SCOPE_REFs are implicitly known (such as
X methods within a class being redundantly qualified),
X declarations which involve SCOPE_REFs are returned as SCOPE_REFs
X (class_name::decl_name). The caller must also deal with this.
X
X If a constructor or destructor is seen, and the context is FIELD,
X then the type gains the attribtue TREE_HAS_x. If such a declaration
X is erroneous, NULL_TREE is returned.
X
X QUALS is used only for FUNCDEF and MEMFUNCDEF cases. For a member
X function, these are the qualifiers to give to the `this' pointer.
X
X May return void_type_node if the declarator turned out to be a friend.
X See grokfield for details. */
X
Xenum return_types { return_normal, return_ctor, return_dtor, return_conversion, };
X
Xtree
Xgrokdeclarator (declarator, declspecs, decl_context, initialized, raises)
X tree declspecs;
X tree declarator;
X enum decl_context decl_context;
X int initialized;
X tree raises;
X{
X int specbits = 0;
X int nclasses = 0;
X tree spec;
X tree type = NULL_TREE;
X int longlong = 0;
X int constp;
X int volatilep;
X int virtualp, friendp, inlinep, staticp;
X int explicit_int = 0;
X int explicit_char = 0;
X int explicit_type = 0;
X char *name;
X tree typedef_type = 0;
X int funcdef_flag = 0;
X int resume_temporary = 0;
X enum tree_code innermost_code = ERROR_MARK;
X /* Set this to error_mark_node for FIELD_DECLs we could not handle properly.
X All FIELD_DECLs we build here have `init' put into their DECL_INITIAL. */
X tree init = 0;
X
X /* Keep track of what sort of function is being processed
X so that we can warn about default return values, or explicit
X return values which do not match prescribed defaults. */
X enum return_types return_type = return_normal;
X
X tree dname = NULL_TREE;
X tree ctype = current_class_type;
X tree ctor_return_type = NULL_TREE;
X enum overload_flags flags = NO_SPECIAL;
X int seen_scope_ref = 0;
X tree quals = 0;
X
X if (decl_context == FUNCDEF)
X funcdef_flag = 1, decl_context = NORMAL;
X else if (decl_context == MEMFUNCDEF)
X funcdef_flag = -1, decl_context = FIELD;
X
X if (flag_traditional && allocation_temporary_p ())
X {
X resume_temporary = 1;
X end_temporary_allocation ();
X }
X
X /* Look inside a declarator for the name being declared
X and get it as a string, for an error message. */
X {
X tree type, last = 0;
X register tree decl = declarator;
X name = 0;
X
X /* If we see something of the form `aggr_type xyzzy (a, b, c)'
X it is either an old-style function declaration or a call to
X a constructor. The following conditional makes recognizes this
X case as being a call to a constructor. Too bad if it is not. */
X
X /* For Doug Lea, also grok `aggr_type xyzzy (a, b, c)[10][10][10]'. */
X while (decl && TREE_CODE (decl) == ARRAY_REF)
X {
X last = decl;
X decl = TREE_OPERAND (decl, 0);
X }
X
X if (current_lang_name == lang_name_cplusplus
X && decl && declspecs
X && TREE_CODE (decl) == CALL_EXPR
X && TREE_OPERAND (decl, 0)
X && (TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
X || TREE_CODE (TREE_OPERAND (decl, 0)) == SCOPE_REF))
X {
X type = TREE_CODE (TREE_VALUE (declspecs)) == IDENTIFIER_NODE
X ? lookup_name (TREE_VALUE (declspecs)) :
X (IS_AGGR_TYPE (TREE_VALUE (declspecs))
X ? TYPE_NAME (TREE_VALUE (declspecs)) : NULL_TREE);
X
X if (type && TREE_CODE (type) == TYPE_DECL
X && IS_AGGR_TYPE (TREE_TYPE (type))
X && parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
X {
X if (decl_context == FIELD
X && TREE_CHAIN (TREE_OPERAND (decl, 1)))
X {
X /* That was an initializer list. */
X sorry ("initializer lists for field declarations");
X decl = TREE_OPERAND (decl, 0);
X if (last)
X {
X TREE_OPERAND (last, 0) = decl;
X decl = declarator;
X }
X declarator = decl;
X init = error_mark_node;
X goto bot;
X }
X else
X {
X tree init = TREE_OPERAND (decl, 1);
X if (last)
X {
X TREE_OPERAND (last, 0) = TREE_OPERAND (decl, 0);
X if (pedantic && init)
X error ("arrays cannot take initializers");
X }
X else
X declarator = TREE_OPERAND (declarator, 0);
X decl = start_decl (declarator, declspecs, 1, NULL_TREE);
X finish_decl (decl, init, NULL_TREE);
X return 0;
X }
X }
X
X if (parmlist_is_random (TREE_OPERAND (decl, 1)))
X {
X decl = TREE_OPERAND (decl, 0);
X if (TREE_CODE (decl) == SCOPE_REF)
X decl = TREE_OPERAND (decl, 1);
X if (TREE_CODE (decl) == IDENTIFIER_NODE)
X name = IDENTIFIER_POINTER (decl);
X if (name)
X error ("bad parameter list specification for function `%s'",
X name);
X else
X error ("bad parameter list specification for function");
X return 0;
X }
X bot:
X ;
X }
X else
X /* It didn't look like we thought it would, leave the ARRAY_REFs on. */
X decl = declarator;
X
X while (decl)
X switch (TREE_CODE (decl))
X {
X case WRAPPER_EXPR: /* for C++ wrappers. */
X if (current_lang_name != lang_name_cplusplus)
X error ("wrapper declared in \"%s\" language context",
X IDENTIFIER_POINTER (current_lang_name));
X
X ctype = NULL_TREE;
X assert (flags == NO_SPECIAL);
X flags = WRAPPER_FLAG;
X decl = TREE_OPERAND (decl, 0);
X break;
X
X case ANTI_WRAPPER_EXPR: /* for C++ wrappers. */
X if (current_lang_name != lang_name_cplusplus)
X error ("anti-wrapper declared in \"%s\" language context",
X IDENTIFIER_POINTER (current_lang_name));
X
X ctype = NULL_TREE;
X assert (flags == NO_SPECIAL);
X flags = ANTI_WRAPPER_FLAG;
X decl = TREE_OPERAND (decl, 0);
X break;
X
X case COND_EXPR:
X if (current_lang_name != lang_name_cplusplus)
X error ("wrapper predicate declared in \"%s\" language context",
X IDENTIFIER_POINTER (current_lang_name));
X
X ctype = NULL_TREE;
X assert (flags == WRAPPER_FLAG);
X flags = WRAPPER_PRED_FLAG;
X decl = TREE_OPERAND (decl, 0);
X break;
X
X case BIT_NOT_EXPR: /* for C++ destructors! */
X {
X tree name = TREE_OPERAND (decl, 0);
X tree rename = NULL_TREE;
X
X if (current_lang_name != lang_name_cplusplus)
X error ("destructor declared in \"%s\" language context",
X IDENTIFIER_POINTER (current_lang_name));
X
X assert (flags == NO_SPECIAL);
X flags = DTOR_FLAG;
X return_type = return_dtor;
X assert (TREE_CODE (name) == IDENTIFIER_NODE);
X if (ctype == NULL_TREE)
X {
X if (current_class_type == NULL_TREE)
X {
X error ("destructors must be member functions");
X flags = NO_SPECIAL;
X }
X else if (current_class_name != name)
X rename = current_class_name;
X }
X else if (DECL_NAME (TYPE_NAME (ctype)) != name)
X rename = DECL_NAME (TYPE_NAME (ctype));
X
X if (rename)
X {
X error ("destructor `%s' must match class name `%s'",
X IDENTIFIER_POINTER (name),
X IDENTIFIER_POINTER (rename));
X TREE_OPERAND (decl, 0) = rename;
X }
X decl = name;
X }
X break;
X
X case ADDR_EXPR: /* C++ reference declaration */
X /* fall through */
X case ARRAY_REF:
X case INDIRECT_REF:
X ctype = NULL_TREE;
X innermost_code = TREE_CODE (decl);
X decl = TREE_OPERAND (decl, 0);
X break;
X
X case CALL_EXPR:
X innermost_code = TREE_CODE (decl);
X decl = TREE_OPERAND (decl, 0);
X if (decl_context == FIELD && ctype == NULL_TREE)
X ctype = current_class_type;
X if (ctype != NULL_TREE
X && decl != NULL_TREE && flags != DTOR_FLAG
X && TREE_TYPE (decl) && TREE_TYPE (TREE_TYPE (decl)) == ctype)
X {
X return_type = return_ctor;
X ctor_return_type = ctype;
X }
X ctype = NULL_TREE;
X break;
X
X case IDENTIFIER_NODE:
X dname = decl;
X name = IDENTIFIER_POINTER (decl);
X decl = 0;
X break;
X
X case RECORD_TYPE:
X case UNION_TYPE:
X case ENUMERAL_TYPE:
X /* Parse error puts this typespec where
X a declarator should go. */
X error ("declarator name missing");
X dname = TYPE_NAME (decl);
X if (dname && TREE_CODE (dname) == TYPE_DECL)
X dname = DECL_NAME (dname);
X name = dname ? IDENTIFIER_POINTER (dname) : "";
X declspecs = temp_tree_cons (NULL_TREE, decl, declspecs);
X decl = 0;
X break;
X
X case OP_IDENTIFIER:
X if (current_lang_name != lang_name_cplusplus)
X error ("operator declared in \"%s\" language context",
X IDENTIFIER_POINTER (current_lang_name));
X
X /* C++ operators: if these are member functions, then
X they overload the same way normal methods do. However,
X if they are declared outside of a classes scope, then
X they are implicitly treated like `friends', i.e.,
X they do not take any unseen arguments. */
X assert (flags == NO_SPECIAL);
X flags = OP_FLAG;
X name = "operator name";
X decl = 0;
X break;
X
X case TYPE_EXPR:
X if (current_lang_name != lang_name_cplusplus)
X error ("type conversion operator declared in \"%s\" language context",
X IDENTIFIER_POINTER (current_lang_name));
X
X ctype = NULL_TREE;
X assert (flags == NO_SPECIAL);
X flags = TYPENAME_FLAG;
X name = "operator ";
X /* Go to the absdcl. */
X decl = TREE_OPERAND (decl, 0);
X return_type = return_conversion;
X break;
X
X /* C++ extension */
X case SCOPE_REF:
X if (current_lang_name != lang_name_cplusplus)
X error ("member function declared in \"%s\" language context",
X IDENTIFIER_POINTER (current_lang_name));
X if (seen_scope_ref == 1)
X error ("multiple `::' terms in declarator invalid");
X seen_scope_ref += 1;
X {
X /* Perform error checking, and convert class names to types.
X We may call grokdeclarator multiple times for the same
X tree structure, so only do the conversion once. In this
X case, we have exactly what we want for `ctype'. */
X tree cname = TREE_OPERAND (decl, 0);
X if (cname == NULL_TREE)
X ctype = NULL_TREE;
X else if (IS_AGGR_TYPE (cname))
X ctype = cname;
X else if (! is_aggr_typedef (cname, 1))
X {
X TREE_OPERAND (decl, 0) = 0;
X }
X /* Must test TREE_OPERAND (decl, 1), in case user gives
X us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */
X else if (TREE_OPERAND (decl, 1)
X && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
X {
X TREE_OPERAND (decl, 0) = TREE_TYPE (TREE_TYPE (cname));
X }
X else if (ctype == NULL_TREE)
X {
X ctype = TREE_TYPE (TREE_TYPE (cname));
X TREE_OPERAND (decl, 0) = ctype;
X }
X else
X {
X tree new_type = get_base_type (TREE_TYPE (TREE_TYPE (cname)), ctype, 0);
X if (new_type == NULL_TREE)
X {
X error ("type `%s' is not derived from type `%s'",
X IDENTIFIER_POINTER (cname),
X TYPE_NAME_STRING (ctype));
X TREE_OPERAND (decl, 0) = 0;
X }
X else
X {
X ctype = new_type;
X TREE_OPERAND (decl, 0) = ctype;
X }
X }
X decl = TREE_OPERAND (decl, 1);
X if (ctype != NULL_TREE && DECL_NAME (TYPE_NAME (ctype)) == decl)
X {
X return_type = return_ctor;
X ctor_return_type = ctype;
X }
X }
X break;
X

X case ERROR_MARK:
X decl = NULL_TREE;
X break;
X
X default:
X assert (0);
X }
X if (name == 0)
X name = "type name";
X }
X
X /* A function definition's declarator must have the form of
X a function declarator. */
X
X if (funcdef_flag && innermost_code != CALL_EXPR)
X return 0;
X
X /* Anything declared one level down from the top level
X must be one of the parameters of a function
X (because the body is at least two levels down). */
X
X /* This heuristic cannot be applied to C++ nodes! Fixed, however,
X by not allowing C++ class definitions to specify their parameters
X with xdecls (must be spec.d in the parmlist).
X
X Since we now wait to push a class scope until we are sure that
X we are in a legitimate method context, we must set oldcname
X explicitly (since current_class_name is not yet alive). */
X
X if (decl_context == NORMAL
X && current_binding_level->level_chain == global_binding_level)
X decl_context = PARM;
X
X /* Look through the decl specs and record which ones appear.
X Some typespecs are defined as built-in typenames.
X Others, the ones that are modifiers of other types,
X are represented by bits in SPECBITS: set the bits for
X the modifiers that appear. Storage class keywords are also in SPECBITS.
X
X If there is a typedef name or a type, store the type in TYPE.
X This includes builtin typedefs such as `int'.
X
X Set EXPLICIT_INT if the type is `int' or `char' and did not
X come from a user typedef.
X
X Set LONGLONG if `long' is mentioned twice.
X
X For C++, constructors and destructors have their own fast treatment. */
X
X for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
X {
X register int i;
X register tree id = TREE_VALUE (spec);
X
X /* Certain parse errors slip through. For example,
X `int class;' is not caught by the parser. Try
X weakly to recover here. */
X if (TREE_CODE (spec) != TREE_LIST)
X return 0;
X
X if (TREE_CODE (id) == IDENTIFIER_NODE)
X {
X if (id == ridpointers[(int) RID_INT])
X {
X if (type)
X error ("extraneous `int' ignored");
X else
X {
X explicit_int = 1;
X type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id));
X }
X goto found;
X }
X if (id == ridpointers[(int) RID_CHAR])
X {
X if (type)
X error ("extraneous `char' ignored");
X else
X {
X explicit_char = 1;
X type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id));
X }
X goto found;
X }
X /* C++ aggregate types. */
X if (TREE_TYPE (id))
X {
X if (type)
X error ("multiple declarations `%s' and `%s'",
X IDENTIFIER_POINTER (type),
X IDENTIFIER_POINTER (id));
X else
X type = TREE_TYPE (TREE_TYPE (id));
X goto found;
X }
X
X for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++)
X {
X if (ridpointers[i] == id)
X {
X if (i == (int) RID_LONG && specbits & (1< X {
X if (pedantic)
X warning ("duplicate `%s'", IDENTIFIER_POINTER (id));
X else if (longlong)
X warning ("`long long long' is too long for GCC");
X else
X longlong = 1;
X }
X else if (specbits & (1 << i))
X warning ("duplicate `%s'", IDENTIFIER_POINTER (id));
X specbits |= 1 << i;
X goto found;
X }
X }
X }
X if (type)
X error ("two or more data types in declaration of `%s'", name);
X else if (TREE_CODE (id) == IDENTIFIER_NODE)
X {
X register tree t = lookup_name (id);
X if (!t || TREE_CODE (t) != TYPE_DECL)
X error ("`%s' fails to be a typedef or built in type",
X IDENTIFIER_POINTER (id));
X else type = TREE_TYPE (t);
X }
X else if (TREE_CODE (id) != ERROR_MARK)
X /* Can't change CLASS nodes into RECORD nodes here! */
X type = id;
X
X found: {}
X }
X
X typedef_type = type;
X
X /* No type at all: default to `int', and set EXPLICIT_INT
X because it was not a user-defined typedef. */
X explicit_type = type != 0;
X
X if (type == 0)
X {
X explicit_int = -1;
X if (return_type == return_dtor)
X type = void_type_node;
X else if (return_type == return_ctor)
X type = TYPE_POINTER_TO (ctor_return_type);
X else
X {
X if (funcdef_flag && warn_return_type
X && return_type == return_normal
X && ! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
X | (1 << (int) RID_SIGNED) | (1 << (int) RID_UNSIGNED))))
X warn_about_return_type = 1;
X /* Save warning until we know what is really going on. */
X type = integer_type_node;
X }
X }
X else if (return_type == return_dtor)
X {
X error ("return type specification for destructor invalid");
X type = void_type_node;
X }
X else if (return_type == return_ctor)
X {
X warning ("return type specification for constructor invalid");
X type = TYPE_POINTER_TO (ctor_return_type);
X }
X
X ctype = NULL_TREE;
X
X /* Now process the modifiers that were specified
X and check for invalid combinations. */
X
X /* Long double is a special combination. */
X
X if ((specbits & 1 << (int) RID_LONG) && type == double_type_node)
X {
X specbits &= ~ (1 << (int) RID_LONG);
X type = long_double_type_node;
X }
X
X /* Check all other uses of type modifiers. */
X
X if (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
X | (1 << (int) RID_UNSIGNED) | (1 << (int) RID_SIGNED)))
X {
X explicit_type = 1;
X if (!explicit_int && !explicit_char && !pedantic)
X error ("long, short, signed or unsigned used invalidly for `%s'", name);
X else if ((specbits & 1 << (int) RID_LONG) && (specbits & 1 << (int) RID_SHORT))
X error ("long and short specified together for `%s'", name);
X else if (((specbits & 1 << (int) RID_LONG) || (specbits & 1 << (int) RID_SHORT))
X && explicit_char)
X error ("long or short specified with char for `%s'", name);
X else if ((specbits & 1 << (int) RID_SIGNED) && (specbits & 1 << (int) RID_UNSIGNED))
X error ("signed and unsigned given together for `%s'", name);
X else
X {
X if (specbits & 1 << (int) RID_UNSIGNED)
X {
X if (longlong)
X type = long_long_unsigned_type_node;
X else if (specbits & 1 << (int) RID_LONG)
X type = long_unsigned_type_node;
X else if (specbits & 1 << (int) RID_SHORT)
X type = short_unsigned_type_node;
X else if (type == char_type_node)
X type = unsigned_char_type_node;
X else
X type = unsigned_type_node;
X }
X else if ((specbits & 1 << (int) RID_SIGNED)
X && type == char_type_node)
X type = signed_char_type_node;
X else if (longlong)
X type = long_long_integer_type_node;
X else if (specbits & 1 << (int) RID_LONG)
X type = long_integer_type_node;
X else if (specbits & 1 << (int) RID_SHORT)
X type = short_integer_type_node;
X }
X }
X
X /* Set CONSTP if this declaration is `const', whether by
X explicit specification or via a typedef.
X Likewise for VOLATILEP. */
X
X constp = !! (specbits & 1 << (int) RID_CONST) + TREE_READONLY (type);
X volatilep = !! (specbits & 1 << (int) RID_VOLATILE) + TREE_VOLATILE (type);
X staticp = 0;
X inlinep = !! (specbits & (1 << (int) RID_INLINE));
X if (constp > 1)
X warning ("duplicate `const'");
X if (volatilep > 1)
X warning ("duplicate `volatile'");
X virtualp = specbits & (1 << (int) RID_VIRTUAL);
X if (specbits & (1 << (int) RID_STATIC))
X staticp = 1 + (decl_context == FIELD);
X
X if (virtualp && staticp == 2)
X {
X error ("member `%s' cannot be declared both virtual and static", name);
X staticp = 0;
X }
X friendp = specbits & (1 << (int) RID_FRIEND);
X specbits &= ~ ((1 << (int) RID_VIRTUAL) | (1 << (int) RID_FRIEND));
X
X /* Warn if two storage classes are given. Default to `auto'. */
X
X if (specbits)
X {
X explicit_type = 1;
X if (specbits & 1 << (int) RID_STATIC) nclasses++;
X if (specbits & 1 << (int) RID_EXTERN) nclasses++;
X if (decl_context == PARM && nclasses > 0)
X error ("storage class specifiers invalid in parameter declarations");
X if (specbits & 1 << (int) RID_TYPEDEF)
X {
X if (decl_context == PARM)
X error ("typedef declaration invalid in parameter declaration");
X nclasses++;
X }
X if (specbits & 1 << (int) RID_AUTO) nclasses++;
X if (specbits & 1 << (int) RID_REGISTER) nclasses++;
X }
X
X /* Give error if `virtual' is used outside of class declaration. */
X if (virtualp && current_class_name == NULL_TREE)
X {
X error ("virtual outside class declaration");
X virtualp = 0;
X }
X
X /* Warn about storage classes that are invalid for certain
X kinds of declarations (parameters, typenames, etc.). */
X
X if (nclasses > 1)
X error ("multiple storage classes in declaration of `%s'", name);
X else if (decl_context != NORMAL && nclasses > 0)
X {
X if (decl_context == PARM && (specbits & ((1 << (int) RID_REGISTER)|(1 << (int) RID_AUTO))))
X ;
X else if (decl_context == FIELD
X && (specbits
X & (/* C++ allows static class elements */
X (1 << (int) RID_STATIC)
X /* ...and inlines */
X | (1 << (int) RID_INLINE)
X /* ...and signed and unsigned elements. */
X | (1 << (int) RID_SIGNED)
X | (1 << (int) RID_UNSIGNED))))
X ;
X else if (decl_context == FIELD && (specbits & (1 << (int) RID_TYPEDEF)))
X {
X /* A typedef which was made in a class's scope. */
X tree loc_typedecl;
X register int i = sizeof (struct lang_decl_flags) / sizeof (int);
X register int *pi;
X
X /* keep `grokdeclarator' from thinking we are in PARM context. */
X pushlevel (0);
X loc_typedecl = start_decl (declarator, declspecs, initialized, NULL_TREE);
X
X pi = (int *) permalloc (sizeof (struct lang_decl_flags));
X while (i > 0)
X pi[--i] = 0;
X DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi;
X poplevel (0, 0, 0);
X
X if (TREE_CODE (TREE_TYPE (loc_typedecl)) == ENUMERAL_TYPE)
X {
X tree ref = lookup_tag (ENUMERAL_TYPE, DECL_NAME (loc_typedecl), current_binding_level, 0);
X if (! ref)
X pushtag (DECL_NAME (loc_typedecl), TREE_TYPE (loc_typedecl));
X }
X if (IDENTIFIER_CLASS_VALUE (DECL_NAME (loc_typedecl)))
X error_with_decl (loc_typedecl,
X "typedef of `%s' in class scope hides previous declaration");
X#if 0
X /* Must push this into scope via `pushdecl_class_level'. */
X IDENTIFIER_CLASS_VALUE (DECL_NAME (loc_typedecl)) = loc_typedecl;
X#endif
X return loc_typedecl;
X }
X else
X {
X error ((decl_context == FIELD
X ? "storage class specified for structure field `%s'"
X : (decl_context == PARM
X ? "storage class specified for parameter `%s'"
X : "storage class specified for typename")),
X name);
X specbits &= ~ ((1 << (int) RID_REGISTER) | (1 << (int) RID_AUTO)
X | (1 << (int) RID_EXTERN));
X }
X }
X else if (current_binding_level == global_binding_level)
X {
X if (specbits & (1 << (int) RID_AUTO))
X error ("top-level declaration of `%s' specifies `auto'", name);
X#if 0
X if (specbits & (1 << (int) RID_REGISTER))
X error ("top-level declaration of `%s' specifies `register'", name);
X#endif
X#if 0
X /* I'm not sure under what circumstances we should turn
X on the extern bit, and under what circumstances we should
X warn if other bits are turned on. */
X if (decl_context == NORMAL
X && (specbits & (1 << (int) RID_EXTERN)) == 0
X && ! root_lang_context_p ())
X {
X specbits |= (1 << (int) RID_EXTERN);
X }
X#endif
X }
X
X /* Now figure out the structure of the declarator proper.
X Descend through it, creating more complex types, until we reach
X the declared identifier (or NULL_TREE, in an absolute declarator). */
X
X while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE)
X {
X /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]),
X an INDIRECT_REF (for *...),
X a CALL_EXPR (for ...(...)),
X an identifier (for the name being declared)
X or a null pointer (for the place in an absolute declarator
X where the name was omitted).
X For the last two cases, we have just exited the loop.
X
X For C++ it could also be
X a SCOPE_REF (for class :: ...). In this case, we have converted
X sensible names to types, and those are the values we use to
X qualify the member name.
X an ADDR_EXPR (for &...),
X a BIT_NOT_EXPR (for destructors)
X a TYPE_EXPR (for operator typenames)
X a WRAPPER_EXPR (for wrappers)
X an ANTI_WRAPPER_EXPR (for averting wrappers)
X
X At this point, TYPE is the type of elements of an array,
X or for a function to return, or for a pointer to point to.
X After this sequence of ifs, TYPE is the type of the
X array or function or pointer, and DECLARATOR has had its
X outermost layer removed. */
X
X if (TREE_CODE (type) == ERROR_MARK
X && TREE_CODE (declarator) != OP_IDENTIFIER)
X {
X if (TREE_CODE (declarator) == SCOPE_REF)
X declarator = TREE_OPERAND (declarator, 1);
X else
X declarator = TREE_OPERAND (declarator, 0);
X continue;
X }
X if (quals != NULL_TREE
X && (declarator == NULL_TREE
X || TREE_CODE (declarator) != SCOPE_REF))
X {
X if (ctype == NULL_TREE && TREE_CODE (type) == METHOD_TYPE)
X ctype = TYPE_METHOD_BASETYPE (type);
X if (ctype != NULL_TREE)
X {
X tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
X ctype = grok_method_quals (ctype, dummy, quals);
X type = TREE_TYPE (dummy);
X quals = NULL_TREE;
X }
X }
X switch (TREE_CODE (declarator))
X {
X case ARRAY_REF:
X {
X register tree itype = NULL_TREE;
X register tree size = TREE_OPERAND (declarator, 1);
X
X declarator = TREE_OPERAND (declarator, 0);
X
X /* Check for some types that there cannot be arrays of. */
X
X if (type == void_type_node)
X {
X error ("declaration of `%s' as array of voids", name);
X type = error_mark_node;
X }
X
X if (TREE_CODE (type) == FUNCTION_TYPE)
X {
X error ("declaration of `%s' as array of functions", name);
X type = error_mark_node;
X }
X
X if (size == error_mark_node)
X type = error_mark_node;
X
X if (type == error_mark_node)
X continue;
X
X if (size)
X {
X /* Must suspend_momentary here because the index
X type may need to live until the end of the function.
X For example, it is used in the declaration of a
X variable which requires destructing at the end of
X the function; then build_vec_delete will need this
X value. */
X int yes = suspend_momentary ();
X /* might be a cast */
X if (TREE_CODE (size) == NOP_EXPR
X && TREE_TYPE (size) == TREE_TYPE (TREE_OPERAND (size, 0)))
X size = TREE_OPERAND (size, 0);
X
X if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
X && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE)
X {
X error ("size of array `%s' has non-integer type", name);
X size = integer_one_node;
X }
X if (TREE_READONLY_DECL_P (size))
X size = decl_constant_value (size);
X if (pedantic && integer_zerop (size))
X warning ("ANSI C forbids zero-size array `%s'", name);
X if (TREE_LITERAL (size))
X {
X if (INT_CST_LT (size, integer_zero_node))
X {
X error ("size of array `%s' is negative", name);
X size = integer_one_node;
X }
X itype = build_index_type (build_int_2 (TREE_INT_CST_LOW (size) - 1, 0));
X }
X else
X {
X if (pedantic)
X warning ("ANSI C forbids variable-size array `%s'", name);
X itype = build_binary_op (MINUS_EXPR, size, integer_one_node);
X itype = build_index_type (itype);
X }
X resume_momentary (yes);
X }
X
X /* Build the array type itself.
X Merge any constancy or volatility into the target type. */
X
X if (constp || volatilep)
X type = build_type_variant (type, constp, volatilep);
X
X#if 0 /* don't clear these; leave them set so that the array type
X or the variable is itself const or volatile. */
X constp = 0;
X volatilep = 0;
X#endif
X
X type = build_cplus_array_type (type, itype);
X ctype = NULL_TREE;
X }
X break;
X
X case CALL_EXPR:
X {
X tree arg_types;
X
X /* Declaring a function type.
X Make sure we have a valid type for the function to return. */
X /* Is this an error? Should they be merged into TYPE here? */
X if (pedantic && (constp || volatilep))
X warning ("function declared to return const or volatile result");
X
X /* Warn about some types functions can't return. */
X
X if (TREE_CODE (type) == FUNCTION_TYPE)
X {
X error ("`%s' declared as function returning a function", name);
X type = integer_type_node;
X }
X if (TREE_CODE (type) == ARRAY_TYPE)
X {
X error ("`%s' declared as function returning an array", name);
X type = integer_type_node;
X }
X
X if (ctype == NULL_TREE
X && decl_context == FIELD
X && (friendp == 0 || dname == current_class_name))
X ctype = current_class_type;
X
X if (ctype && flags == TYPENAME_FLAG)
X TYPE_HAS_CONVERSION (ctype) = 1;
X if (ctype && DECL_NAME (TYPE_NAME (ctype)) == dname)
X {
X /* We are within a class's scope. If our declarator name
X is the same as the class name, and we are defining
X a function, then it is a constructor/destructor, and
X therefore returns a void type. */
X
X if (flags == DTOR_FLAG)
X {
X if (staticp == 2)
X error ("destructor cannot be static member function");
X if (decl_context == FIELD)
X {
X if (! member_function_or_else (ctype, current_class_type,
X "destructor for alien class `%s' cannot be a member"))
X return NULL_TREE;
X if (TYPE_HAS_DESTRUCTOR (ctype))
X error_with_aggr_type (ctype, "class `%s' already has destructor defined");
X }
X }
X else if (flags == WRAPPER_FLAG || flags == ANTI_WRAPPER_FLAG)
X {
X if (staticp == 2)
X error ("wrapper cannot be static member function");
X if (decl_context == FIELD)
X {
X if (! member_function_or_else (ctype, current_class_type,
X "wrapper for alien class `%s' cannot be member"))
X return NULL_TREE;
X TYPE_WRAP_TYPE (ctype) = TYPE_MAIN_VARIANT (ctype);
X }
X }
X else if (flags == WRAPPER_PRED_FLAG)
X {
X if (staticp == 2)
X error ("wrapper predicate cannot be static member function");
X if (TREE_CODE (type) != INTEGER_TYPE)
X {
X error ("wrapper predicated must return an integer type");
X type = integer_type_node;
X }
X if (decl_context == FIELD)
X {
X if (! member_function_or_else (ctype, current_class_type,
X "wrapper predicate for alien class `%s' cannot be member"))
X return NULL_TREE;
X TYPE_HAS_WRAPPER_PRED (ctype) = 1;
X }
X }
X else /* its a constructor. */
X {
X if (staticp == 2)
X error ("constructor cannot be static member function");
X if (virtualp || friendp)
X {
X error ("constructors cannot be declared virtual or friend");
X virtualp = 0;
X friendp = 0;
X }
X if (specbits & ~((1 << (int) RID_INLINE)|(1 << (int) RID_STATIC)))
X error ("return value type specifier for `%s' ignored",
X flags == DTOR_FLAG ? "destructor" : "constructor");
X type = TYPE_POINTER_TO (ctype);
X if (decl_context == FIELD)
X {
X if (! member_function_or_else (ctype, current_class_type,
X "constructor for alien class `%s' cannot be member"))
X return NULL_TREE;
X TYPE_HAS_CONSTRUCTOR (ctype) = 1;
X assert (return_type == return_ctor);
X }
X }
X if (decl_context == FIELD)
X staticp = 0;
X }
X else if (friendp && virtualp)
X {
X /* Cannot be both friend and virtual. */
X error ("virtual functions cannot be friends");
X specbits ^= (1 << (int) RID_FRIEND);
X }
X
X if (decl_context == NORMAL && friendp)
X error ("friend declaration not in class definition");
X
X /* Picky up type qualifiers which should be applied to `this'. */
X quals = TREE_OPERAND (declarator, 2);
X
X /* Traditionally, declaring return type float means double. */
X
X if (flag_traditional && type == float_type_node)
X type = double_type_node;
X
X /* Construct the function type and go to the next
X inner layer of declarator. */
X
X {
X int funcdef_p;
X tree inner_parms = TREE_OPERAND (declarator, 1);
X tree inner_decl = TREE_OPERAND (declarator, 0);
X
X declarator = TREE_OPERAND (declarator, 0);
X
X if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF)
X inner_decl = TREE_OPERAND (inner_decl, 1);
X
X /* Say it's a definition only for the CALL_EXPR
X closest to the identifier. */
X funcdef_p =
X (inner_decl &&
X (TREE_CODE (inner_decl) == IDENTIFIER_NODE
X || TREE_CODE (inner_decl) == OP_IDENTIFIER
X || TREE_CODE (inner_decl) == TYPE_EXPR)) ? funcdef_flag : 0;
X
X arg_types = grokparms (inner_parms, funcdef_p);
X }
X
X if (declarator)
X {
X /* Get past destructors, wrappers, etc.
X We know we have one because FLAGS will be non-zero.
X
X Complain about improper parameter lists here. */
X if (TREE_CODE (declarator) == BIT_NOT_EXPR)
X {
X declarator = TREE_OPERAND (declarator, 0);
X
X if (strict_prototype == 0 && arg_types == NULL_TREE)
X arg_types = void_list_node;
X else if (arg_types == NULL_TREE
X || arg_types != void_list_node)
X {
X error ("destructors cannot be specified with parameters");
X arg_types = void_list_node;
X }
X }
X else if (TREE_CODE (declarator) == WRAPPER_EXPR)
X {
X /* Report misuse of wrappers and their associates.
X Note that because wrappers may be invoked
X quite a bit implicitly, if we give an error
X message, we make an effort to fix that error
X so that spurious errors do not show up. */
X if (TREE_CODE (TREE_OPERAND (declarator, 0)) == COND_EXPR)
X {
X /* First parameter must be a pointer to a member function.
X Rest of parameters must all be default parameters. */
X if (arg_types == NULL_TREE
X || arg_types == void_list_node
X || TREE_CODE (TREE_VALUE (arg_types)) != POINTER_TYPE
X || TREE_CODE (TREE_TYPE (TREE_VALUE (arg_types))) != METHOD_TYPE)
X {
X error ("wrapper predicate takes a pointer-to-member-function as first argument");
X arg_types = NULL_TREE;
X }
X else if (TREE_CHAIN (arg_types)
X && TREE_CHAIN (arg_types) != void_list_node
X && TREE_PURPOSE (TREE_CHAIN (arg_types)) == NULL_TREE)
X {
X error ("all arguments past first must be default for wrapper predicate");
X TREE_CHAIN (arg_types) = NULL_TREE;
X }
X declarator = wrapper_pred_name;
X }
X else
X {
X /* First parameter must be an int.
X Second parameter must be a pointer to a member function. */
X if (arg_types == NULL_TREE || TREE_CHAIN (arg_types) == NULL_TREE)
X {
X error ("wrappers must have at least two arguments (int, pointer-to-member-function)");
X arg_types = NULL_TREE;
X }
X else
X {
X if (TREE_CODE (TREE_VALUE (arg_types)) != INTEGER_TYPE)
X {
X error ("first argument to wrapper must be an integer");
X TREE_VALUE (arg_types) = integer_type_node;
X }
X if (TREE_CODE (TREE_VALUE (TREE_CHAIN (arg_types))) != POINTER_TYPE
X || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arg_types)))) != METHOD_TYPE)
X {
X error ("second argument to wrapper must be a pointer-to-member-function type");
X TREE_CHAIN (arg_types) = NULL_TREE;
X }
X }
X declarator = wrapper_name;
X }
X }
X else if (TREE_CODE (declarator) == ANTI_WRAPPER_EXPR)
X declarator = anti_wrapper_name;
X }
X
X type = build_function_type (type, flag_traditional ? 0 : arg_types);
X }
X break;
X
X case ADDR_EXPR:
X case INDIRECT_REF:
X /* Filter out pointers-to-references and references-to-references.
X We can get these if a TYPE_DECL is used. */
X
X if (TREE_CODE (type) == REFERENCE_TYPE)
X {
X error ("cannot declare %s to references",
X TREE_CODE (declarator) == ADDR_EXPR
X ? "references" : "pointers");
X declarator = TREE_OPERAND (declarator, 0);
X continue;
X }
X
X /* Merge any constancy or volatility into the target type
X for the pointer. */
X
X if (constp || volatilep)
X {
X type = build_type_variant (type, constp, volatilep);
X if (IS_AGGR_TYPE (type))
X build_pointer_type (type);
X }
X constp = 0;
X volatilep = 0;
X
X if (TREE_CODE (declarator) == ADDR_EXPR)
X if (TREE_CODE (type) == FUNCTION_TYPE)
X {
X error ("cannot declare references to functions; use pointer to function instead");
X type = build_pointer_type (type);
X }
X else
X {
X if (TYPE_MAIN_VARIANT (type) == void_type_node)
X error ("invalid type: `void &'");
X else
X type = build_reference_type (type);
X }
X else
X type = build_pointer_type (type);
X
X /* Process a list of type modifier keywords (such as
X const or volatile) that were given inside the `*' or `&'. */
X
X if (TREE_TYPE (declarator))
X {
X register tree typemodlist;
X int erred = 0;
X for (typemodlist = TREE_TYPE (declarator); typemodlist;
X typemodlist = TREE_CHAIN (typemodlist))
X {
X if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST])
X constp++;
X else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE])
X volatilep++;
X else if (!erred)
X {
X erred = 1;
X error ("invalid type modifier within %s declarator",
X TREE_CODE (declarator) == ADDR_EXPR
X ? "reference" : "pointer");
X }
X }
X if (constp > 1)
X warning ("duplicate `const'");
X if (volatilep > 1)
X warning ("duplicate `volatile'");
X }
X declarator = TREE_OPERAND (declarator, 0);
X ctype = NULL_TREE;
X break;
X
X case SCOPE_REF:
X {
X /* We have converted type names to NULL_TREE if the
X name was bogus, or to a _TYPE node, if not.
X
X The variable CTYPE holds the type we will ultimately
X resolve to. The code here just needs to build
X up appropriate member types. */
X tree sname = TREE_OPERAND (declarator, 1);
X
X if (TREE_OPERAND (declarator, 0) == NULL_TREE)
X {
X /* We had a reference to a global decl, or
X perhaps we were given a non-aggregate typedef,
X in which case we cleared this out, and should just
X keep going as though it wasn't there. */
X declarator = sname;
X continue;
X }
X ctype = TREE_OPERAND (declarator, 0);
X
X if (sname == NULL_TREE)
X goto done_scoping;
X
X /* Destructors can have their visibilities changed as well. */
X if (TREE_CODE (sname) == BIT_NOT_EXPR)
X sname = TREE_OPERAND (sname, 0);
X
X if (TREE_CODE (sname) == IDENTIFIER_NODE)
X {
X /* This is the `standard' use of the scoping operator:
X basetype :: member . */
X
X if (ctype == current_class_type || friendp)
X if (TREE_CODE (type) == FUNCTION_TYPE)
X type = build_cplus_method_type (ctype, TREE_TYPE (type), TYPE_ARG_TYPES (type));
X else
X type = build_member_type (ctype, type);
X else if (TYPE_SIZE (ctype) != 0
X || (specbits & (1<<(int)RID_TYPEDEF)))
X {
X tree t;
X /* have to move this code elsewhere in this function.
X this code is used for i.e., typedef int A::M; M *pm; */
X
X if (decl_context == FIELD)
X {
X t = lookup_field (ctype, sname, 0);
X if (t)
X {

X t = build_lang_field_decl (FIELD_DECL, build_nt (SCOPE_REF, ctype, t), type);
X DECL_INITIAL (t) = init;
X return t;
X }
X /* No such field, try member functions. */
X t = lookup_fnfields (CLASSTYPE_AS_LIST (ctype), sname, 0);
X if (t)
X {
X if (flags == DTOR_FLAG)
X t = TREE_VALUE (t);
X else if (CLASSTYPE_METHOD_VEC (ctype)
X && TREE_VALUE (t) == TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (ctype), 0))
X {
X /* Don't include destructor with constructors. */
X t = TREE_CHAIN (TREE_VALUE (t));
X if (t == NULL_TREE)
X error ("class `%s' does not have any constructors", IDENTIFIER_POINTER (sname));
X t = build_tree_list (NULL_TREE, t);
X }
X t = build_lang_field_decl (FIELD_DECL, build_nt (SCOPE_REF, ctype, t), type);
X DECL_INITIAL (t) = init;
X return t;
X }
X
X if (flags == TYPENAME_FLAG)
X error_with_aggr_type (ctype, "type conversion is not a member of structure `%s'");
X else
X error ("field `%s' is not a member of structure `%s'",
X IDENTIFIER_POINTER (sname),
X TYPE_NAME_STRING (ctype));
X }
X if (TREE_CODE (type) == FUNCTION_TYPE)
X type = build_cplus_method_type (ctype, TREE_TYPE (type), TYPE_ARG_TYPES (type));
X else
X type = build_member_type (ctype, type);
X }
X else
X sorry ("structure `%s' not yet defined",
X TYPE_NAME_STRING (ctype));
X declarator = sname;
X }
X else if (TREE_CODE (sname) == TYPE_EXPR)
X {
X /* A TYPE_EXPR will change types out from under us.
X So do the TYPE_EXPR now, and make this SCOPE_REF
X inner to the TYPE_EXPR's CALL_EXPR.
X
X This does not work if we don't get a CALL_EXPR back.
X I did not think about error recovery, hence the
X assert (0). */
X
X /* Get the CALL_EXPR. */
X sname = grokoptypename (sname, 0);
X assert (TREE_CODE (sname) == CALL_EXPR);
X type = TREE_TYPE (TREE_OPERAND (sname, 0));
X /* Scope the CALL_EXPR's name. */
X TREE_OPERAND (declarator, 1) = TREE_OPERAND (sname, 0);
X /* Put the SCOPE_EXPR in the CALL_EXPR's innermost position. */
X TREE_OPERAND (sname, 0) = declarator;
X /* Now work from the CALL_EXPR. */
X declarator = sname;
X continue;
X }
X else if (TREE_CODE (sname) == SCOPE_REF)
X abort ();
X else
X {
X done_scoping:
X declarator = TREE_OPERAND (declarator, 1);
X if (declarator && TREE_CODE (declarator) == CALL_EXPR)
X /* In this case, we will deal with it later. */
X ;
X else
X {
X if (TREE_CODE (type) == FUNCTION_TYPE)
X type = build_cplus_method_type (ctype, TREE_TYPE (type), TYPE_ARG_TYPES (type));
X else
X type = build_member_type (ctype, type);
X }
X }
X }
X break;
X
X case OP_IDENTIFIER:
X /* This is exceptional, in that we must finalize a
X member type before calling grokopexpr, if we want
X to use the declared type information to resolve
X ambiguities. Do not get fooled by friends,
X which do not have a member type built for them
X unless they were explicitly scoped (in which case that
X will have been taken care of in the SCOPE_REF case. */
X if (TREE_CODE (type) != FUNCTION_TYPE
X && TREE_CODE (type) != METHOD_TYPE)
X {
X error ("operator name missing at this point in file");
X if (ctype)
X type = build_cplus_method_type (ctype, type, NULL_TREE);
X else
X type = build_function_type (type, NULL_TREE);
X }
X if (TREE_CODE (TREE_OPERAND (declarator, 0)) == NEW_EXPR)
X {
X int was_method = ctype || TREE_CODE (type) == METHOD_TYPE;
X type = coerce_new_type (ctype, type);
X if (was_method)
X staticp = 2;
X }
X else if (TREE_CODE (TREE_OPERAND (declarator, 0)) == DELETE_EXPR)
X {
X int was_method = ctype || TREE_CODE (type) == METHOD_TYPE;
X type = coerce_delete_type (ctype, type);
X if (was_method)
X staticp = 2;
X }
X else if (TREE_CODE (type) == FUNCTION_TYPE
X && ctype != 0
X && (friendp == 0 || staticp < 2))
X type = build_cplus_method_type (ctype, TREE_TYPE (type), TYPE_ARG_TYPES (type));
X {
X tree tmp = declarator;
X declarator = grokopexpr (&tmp, ctype, type, 0,
X staticp == 2 ? 2 : 1);
X }
X if (declarator == NULL_TREE)
X return NULL_TREE;
X name = IDENTIFIER_POINTER (declarator);
X break;
X
X case BIT_NOT_EXPR:
X declarator = TREE_OPERAND (declarator, 0);
X break;
X
X case TYPE_EXPR:
X declarator = grokoptypename (declarator, 0);
X if (explicit_int != -1)
X if (comp_target_types (type, TREE_TYPE (TREE_OPERAND (declarator, 0)), 1) == 0)
X error ("type conversion function declared to return incongruent type");
X else
X warning ("return type specified for type conversion function");
X type = TREE_TYPE (TREE_OPERAND (declarator, 0));
X break;
X
X case WRAPPER_EXPR:
X if (TREE_CODE (TREE_OPERAND (declarator, 0)) == COND_EXPR)
X declarator = wrapper_pred_name;
X else
X declarator = wrapper_name;
X break;
X
X case ANTI_WRAPPER_EXPR:
X declarator = anti_wrapper_name;
X break;
X
X case RECORD_TYPE:
X case UNION_TYPE:
X case ENUMERAL_TYPE:
X declarator = 0;
X break;
X
X case ERROR_MARK:
X declarator = 0;
X break;
X
X default:
X assert (0);
X }
X
X /* layout_type (type); */
X#if 0
X /* @@ Should perhaps replace the following code by changes in
X * @@ stor_layout.c. */
X if (TREE_CODE (type) == FUNCTION_DECL)
X {
X /* A function variable in C should be Pmode rather than EPmode
X because it has just the address of a function, no static chain.*/
X TYPE_MODE (type) = Pmode;
X }
X#endif
X }
X
X /* Now TYPE has the actual type. */
X
X /* If this is declaring a typedef name, return a TYPE_DECL. */
X
X if (specbits & (1 << (int) RID_TYPEDEF))
X {
X tree decl;
X
X /* Note that the grammar rejects storage classes
X in typenames, fields or parameters. */
X if (constp || volatilep)
X type = build_type_variant (type, constp, volatilep);
X
X /* If the user declares "struct {...} foo" then `foo' will have
X an anonymous name. Fill that name in now. Nothing can
X refer to it, so nothing needs know about the name change.
X The TYPE_NAME field was filled in by build_struct_xref. */
X if (TYPE_NAME (type)
X#ifndef BREAK_C_TAGS
X && current_lang_name == lang_name_cplusplus
X#endif
X && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
X && ANON_AGGRNAME_P (DECL_NAME (TYPE_NAME (type))))
X {
X /* replace the anonymous name with the real name everywhere. */
X lookup_tag_reverse (type, declarator);
X DECL_NAME (TYPE_NAME (type)) = declarator;
X
X /* Replace names of default constructors and/or destructors. */
X if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_METHOD_VEC (type))
X {
X tree method_vec = CLASSTYPE_METHOD_VEC (type);
X tree fnptr = TREE_VEC_ELT (method_vec, 0);
X while (fnptr)
X {
X DECL_ORIGINAL_NAME (fnptr) = declarator;
X fnptr = TREE_CHAIN (fnptr);
X }
X }
X }
X
X decl = build_decl (TYPE_DECL, declarator, type);
X if (quals)
X {
X if (ctype == NULL_TREE)
X {
X assert (TREE_CODE (type) == METHOD_TYPE);
X ctype = TYPE_METHOD_BASETYPE (type);
X }
X grok_method_quals (ctype, decl, quals);
X }
X
X if (resume_temporary)
X resume_temporary_allocation ();
X return decl;
X }
X
X /* Detect the case of an array type of unspecified size
X which came, as such, direct from a typedef name.
X We must copy the type, so that each identifier gets
X a distinct type, so that each identifier's size can be
X controlled separately by its own initializer. */
X
X if (type == typedef_type && TREE_CODE (type) == ARRAY_TYPE
X && TYPE_DOMAIN (type) == 0)
X {
X type = build_cplus_array_type (TREE_TYPE (type), TYPE_DOMAIN (type));
X }
X
X /* If this is a type name (such as, in a cast or sizeof),
X compute the type and return it now. */
X
X if (decl_context == TYPENAME)
X {
X /* Note that the grammar rejects storage classes
X in typenames, fields or parameters. */
X if (constp || volatilep)
X type = build_type_variant (type, constp, volatilep);
X
X /* Special case: "friend class foo" looks like a TYPENAME context. */
X if (friendp)
X {
X /* A friendly class? */
X make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type));
X type = void_type_node;
X }
X else if (quals)
X {
X tree dummy = build_decl (TYPE_DECL, declarator, type);
X if (ctype == NULL_TREE)
X {
X assert (TREE_CODE (type) == METHOD_TYPE);
X ctype = TYPE_METHOD_BASETYPE (type);
X }
X grok_method_quals (ctype, dummy, quals);
X type = TREE_TYPE (dummy);
X }
X
X if (resume_temporary)
X resume_temporary_allocation ();
X return type;
X }
X
X /* `void' at top level (not within pointer)
X is allowed only in typedefs or type names.
X We don't complain about parms either, but that is because
X a better error message can be made later. */
X
X if (type == void_type_node && decl_context != PARM)
X {
X if (declarator != NULL_TREE
X && TREE_CODE (declarator) == IDENTIFIER_NODE)
X error ("variable or field `%s' declared void", name);
X else
X error ("variable or field declared void");
X type = integer_type_node;
X }
X
X /* Now create the decl, which may be a VAR_DECL, a PARM_DECL
X or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */
X
X {
X register tree decl;
X
X if (decl_context == PARM)
X {
X if (ctype)
X error ("cannot use `::' in parameter declaration");
X if (virtualp)
X error ("parameter declared `virtual'");
X if (quals)
X error ("`const' and `volatile' function specifiers invalid in parameter declaration");
X if (friendp)
X error ("invalid friend declaration");
X if (raises)
X error ("invalid raises declaration");
X
X /* A parameter declared as an array of T is really a pointer to T.
X One declared as a function is really a pointer to a function.
X One declared as a member is really a pointer to member. */
X
X if (TREE_CODE (type) == ARRAY_TYPE)
X {
X /* Transfer const-ness of array into that of type pointed to. */
X type = build_pointer_type
X (build_type_variant (TREE_TYPE (type), constp, volatilep));
X volatilep = constp = 0;
X }
X else if (TREE_CODE (type) == FUNCTION_TYPE)
X type = build_pointer_type (type);
X else if (TREE_CODE (type) == OFFSET_TYPE)
X type = build_pointer_type (type);
X
X decl = build_decl (PARM_DECL, declarator, type);
X
X /* Compute the type actually passed in the parmlist,
X for the case where there is no prototype.
X (For example, shorts and chars are passed as ints.)
X When there is a prototype, this is overridden later. */
X
X DECL_ARG_TYPE (decl) = type;
X if (type == float_type_node)
X DECL_ARG_TYPE (decl) = double_type_node;
X else if (TREE_CODE (type) == INTEGER_TYPE
X && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
X DECL_ARG_TYPE (decl) = integer_type_node;
X }
X else if (decl_context == FIELD)
X {
X if (type == error_mark_node)
X {
X /* Happens when declaring arrays of sizes which
X are error_mark_node, for example. */
X decl = NULL_TREE;
X }
X else if (TREE_CODE (type) == FUNCTION_TYPE)
X {
X if (current_lang_name == lang_name_c)
X {
X error ("field `%s' declared as a function in %s language context",
X name, IDENTIFIER_POINTER (current_lang_name));
X type = build_pointer_type (type);
X }
X else
X {
X if (friendp == 0)
X {
X if (ctype == NULL_TREE)
X ctype = current_class_type;
X if (staticp < 2)
X type = build_cplus_method_type (ctype, TREE_TYPE (type), TYPE_ARG_TYPES (type));
X }
X decl = grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, friendp ? -1 : 0);
X TREE_INLINE (decl) = inlinep;
X if (specbits & (1 << (int) RID_EXTERN))
X TREE_PUBLIC (decl) = 1;
X }
X }
X else if (TREE_CODE (type) == METHOD_TYPE)
X {
X decl = grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, friendp ? -1 : 0);
X TREE_INLINE (decl) = inlinep;
X if (specbits & (1 << (int) RID_EXTERN))
X TREE_PUBLIC (decl) = 1;
X }
X else if (TREE_CODE (type) == RECORD_TYPE
X && CLASSTYPE_DECLARED_EXCEPTION (type))
X {
X /* Handle a class-local exception declaration. */
X decl = build_lang_field_decl (VAR_DECL, declarator, type);
X if (ctype == NULL_TREE)
X ctype = current_class_type;
X finish_exception_decl (TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL
X ? DECL_NAME (TYPE_NAME (ctype)) : TYPE_NAME (ctype), decl);
X return void_type_node;
X }
X else if (TYPE_SIZE (type) == 0 && !staticp
X && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0))
X {
X if (declarator)
X error ("field `%s' has incomplete type",
X IDENTIFIER_POINTER (declarator));
X else
X error ("field has incomplete type");
X type = error_mark_node;
X decl = NULL_TREE;
X }
X else
X {
X if (friendp)
X {
X if (declarator)
X error ("`%s' is neither function nor method; cannot be declared friend",
X IDENTIFIER_POINTER (declarator));
X else
X {
X error ("invalid friend declaration");
X return void_type_node;
X }
X friendp = 0;
X }
X decl = NULL_TREE;
X }
X
X if (friendp)
X {
X /* Friends are treated specially. */
X if (ctype == current_class_type)
X warning ("member functions are implicitly friends of their class");
X else if (DECL_NAME (decl))
X return do_friend (ctype, declarator, decl, last_function_parms, flags, quals);
X else return void_type_node;
X }
X
X /* Structure field. It may not be a function, except for C++ */
X
X if (decl == 0)
X {
X if (virtualp)
X error ("field declared `virtual'");
X if (quals)
X error ("`const' and `volatile' function specifiers invalid in field declaration");
X if (friendp)
X error ("invalid friend declaration");
X if (raises)
X error ("invalid raises declaration");
X
X if (staticp || (constp && initialized))
X {
X /* C++ allows static class members.
X All other work for this is done by grokfield.
X This VAR_DECL is built by build_lang_field_decl.
X All other VAR_DECLs are built by build_decl. */
X if (current_lang_name == lang_name_c)
X {
X if (staticp)
X error ("field `%s' declared static in %s language context",
X name, IDENTIFIER_POINTER (current_lang_name));
X else
X error ("field `%s' declared with initializer in %s language context",
X name, IDENTIFIER_POINTER (current_lang_name));
X }
X decl = build_lang_field_decl (VAR_DECL, declarator, type);
X if (staticp)
X TREE_STATIC (decl) = 1;
X /* In class context, static means public visibility. */
X TREE_PUBLIC (decl) = 1;
X }
X else
X decl = build_lang_field_decl (FIELD_DECL, declarator, type);
X }
X }
X else if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
X {
X int was_overloaded = 0;
X tree original_name = declarator;
X
X if (! declarator) return NULL_TREE;
X
X if (specbits & ((1 << (int) RID_AUTO) | (1 << (int) RID_REGISTER)))
X error ("invalid storage class for function `%s'", name);
X /* Function declaration not at top level.
X Storage classes other than `extern' are not allowed
X and `extern' makes no difference. */
X if (current_binding_level != global_binding_level
X && (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE)))
X && pedantic)
X warning ("invalid storage class for function `%s'", name);
X
X if (ctype == NULL_TREE)
X {
X if (virtualp)
X {
X error ("virtual non-class function `%s'", name);
X virtualp = 0;
X }
X#ifdef NO_AUTO_OVERLOAD
X if (is_overloaded (declarator))
X {
X /* Plain overloading: will not be grok'd by grokclassfn. */
X if (current_lang_name == lang_name_cplusplus)
X declarator = build_decl_overload (name, TYPE_ARG_TYPES (type), 0);
X was_overloaded = 1;
X }
X#else
X if (current_lang_name == lang_name_cplusplus
X && ! (IDENTIFIER_LENGTH (original_name) == 4
X && IDENTIFIER_POINTER (original_name)[0] == 'm'
X && strcmp (IDENTIFIER_POINTER (original_name), "main") == 0)
X && ! (IDENTIFIER_LENGTH (original_name) > 10
X && IDENTIFIER_POINTER (original_name)[0] == '_'
X && IDENTIFIER_POINTER (original_name)[1] == '_'
X && strncmp (IDENTIFIER_POINTER (original_name)+2, "builtin_", 8) == 0))
X {
X /* Plain overloading: will not be grok'd by grokclassfn. */
X declarator = build_decl_overload (name, TYPE_ARG_TYPES (type), 0);
X was_overloaded = 1;
X }
X#endif
X }
X else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2)
X type = build_cplus_method_type (ctype, TREE_TYPE (type), TYPE_ARG_TYPES (type));
X
X decl = grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, friendp ? 2 : 1);
X /* Record presence of `static'. In C++, `inline' is like `static'. */
X TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE)));
X /* Record presence of `inline', if it is reasonable. */
X if (inlinep)
X {
X tree last = tree_last (TYPE_ARG_TYPES (type));
X
X if (! was_overloaded
X && ! ctype
X && ! strcmp (IDENTIFIER_POINTER (original_name), "main"))
X warning ("cannot inline function `main'");
X else if (last && last != void_list_node)
X warning ("inline declaration ignored for function with `...'");
X else
X /* Assume that otherwise the function can be inlined. */
X TREE_INLINE (decl) = 1;
X
X if (specbits & (1 << (int) RID_EXTERN))
X current_extern_inline = 1;
X }
X if (was_overloaded)
X {
X DECL_OVERLOADED (decl) = 1;
X DECL_ORIGINAL_NAME (decl) = original_name;
X }
X }
X else
X {
X /* It's a variable. */
X
X if (virtualp)
X error ("variable declared `virtual'");
X if (inlinep)
X warning ("variable declared `inline'");
X if (quals)
X error ("`const' and `volatile' function specifiers invalid in field declaration");
X if (friendp)
X error ("invalid friend declaration");
X if (raises)
X error ("invalid raises declaration");
X
X /* An uninitialized decl with `extern' is a reference. */
X decl = grokvardecl (ctype, type, declarator, specbits, initialized);
X }
X
X /* Record `register' declaration for warnings on &
X and in case doing stupid register allocation. */
X
X if (specbits & (1 << (int) RID_REGISTER))
X TREE_REGDECL (decl) = 1;
X
X /* Record constancy and volatility. */
X
X if (constp)
X TREE_READONLY (decl) = TREE_CODE (type) != REFERENCE_TYPE;
X if (volatilep)
X {
X TREE_VOLATILE (decl) = 1;
X TREE_THIS_VOLATILE (decl) = 1;
X }
X
X if (TREE_CODE (decl) != FUNCTION_DECL
X && DECL_NAME (decl)
X && explicit_type == 0)
X warning ("type specifier for member `%s' omitted",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X
X if (resume_temporary)
X resume_temporary_allocation ();
X
X return decl;
X }
X}
X
X/* Tell if a parmlist/exprlist looks like an exprlist or a parmlist.
X An empty exprlist is a parmlist. An exprlist which
X contains only identifiers at the global level
X is a parmlist. Otherwise, it is an exprlist. */
Xstatic int
Xparmlist_is_exprlist (exprs)
X tree exprs;
X{
X if (exprs == NULL_TREE || TREE_PARMLIST (exprs))
X return 0;
X
X if (current_binding_level == global_binding_level)
X {
X /* At the global level, if these are all identifiers,
X then it is a parmlist. */
X while (exprs)
X {
X if (TREE_CODE (TREE_VALUE (exprs)) != IDENTIFIER_NODE)
X return 1;
X exprs = TREE_CHAIN (exprs);
X }
X return 0;
X }
X return 1;
X}
X
X/* Make sure that the this list of PARMS has a chance of being
X grokked by `grokparms'.
X
X @@ This is really weak, but the grammar does not allow us
X @@ to easily reject things that this has to catch as syntax errors. */
Xstatic int
Xparmlist_is_random (parms)
X tree parms;
X{
X if (parms == NULL_TREE)
X return 0;
X
X if (TREE_CODE (parms) != TREE_LIST)
X return 1;
X
X while (parms)
X {
X if (parms == void_list_node)
X return 0;
X
X if (TREE_CODE (TREE_VALUE (parms)) != TREE_LIST)
X return 1;
X /* Don't get faked out by overloaded functions, which
X masquerade as TREE_LISTs! */
X if (TREE_TYPE (TREE_VALUE (parms)) == unknown_type_node)
X return 1;
X parms = TREE_CHAIN (parms);
X }
X return 0;
X}
X
X/* Subroutine of `grokparms'. In a fcn definition, arg types must
X be complete.

X
X C++: also subroutine of `start_function'. */
Xstatic void
Xrequire_complete_types_for_parms (parms)
X tree parms;
X{
X while (parms)
X {
X tree type = TREE_TYPE (parms);
X if (TYPE_SIZE (type) == 0)
X {
X if (DECL_NAME (parms))
X error ("parameter `%s' has incomplete type",
X IDENTIFIER_POINTER (DECL_NAME (parms)));
X else
X error ("parameter has incomplete type");
X TREE_TYPE (parms) = error_mark_node;
X }
X#if 0
X /* If the arg types are incomplete in a declaration,
X they must include undefined tags.
X These tags can never be defined in the scope of the declaration,
X so the types can never be completed,
X and no call can be compiled successfully. */
X /* This is not the right behavior for C++, but not having
X it is also probably wrong. */
X else
X {
X /* Now warn if is a pointer to an incomplete type. */
X while (TREE_CODE (type) == POINTER_TYPE
X || TREE_CODE (type) == REFERENCE_TYPE)
X type = TREE_TYPE (type);
X type = TYPE_MAIN_VARIANT (type);
X if (TYPE_SIZE (type) == 0)
X {
X if (DECL_NAME (parm) != 0)
X warning ("parameter `%s' points to incomplete type",
X IDENTIFIER_POINTER (DECL_NAME (parm)));
X else
X warning ("parameter points to incomplete type");
X }
X }
X#endif
X parms = TREE_CHAIN (parms);
X }
X}
X
X/* Decode the list of parameter types for a function type.
X Given the list of things declared inside the parens,
X return a list of types.
X
X The list we receive can have three kinds of elements:
X an IDENTIFIER_NODE for names given without types,
X a TREE_LIST node for arguments given as typespecs or names with typespecs,
X or void_type_node, to mark the end of an argument list
X when additional arguments are not permitted (... was not used).
X
X FUNCDEF_FLAG is nonzero for a function definition, 0 for
X a mere declaration. A nonempty identifier-list gets an error message
X when FUNCDEF_FLAG is zero.
X If FUNCDEF_FLAG is 1, then parameter types must be complete.
X If FUNCDEF_FLAG is -1, then parameter types may be incomplete.
X
X If all elements of the input list contain types,
X we return a list of the types.
X If all elements contain no type (except perhaps a void_type_node
X at the end), we return a null list.
X If some have types and some do not, it is an error, and we
X return a null list.
X
X Also set last_function_parms to either
X a list of names (IDENTIFIER_NODEs) or a chain of PARM_DECLs.
X A list of names is converted to a chain of PARM_DECLs
X by store_parm_decls so that ultimately it is always a chain of decls.
X
X Note that in C++, paramters can take default values. These default
X values are in the TREE_PURPOSE field of the TREE_LIST. It is
X an error to specify default values which are followed by parameters
X that have no defualt values, or an ELLIPSES. For simplicities sake,
X only parameters which are specified with their types can take on
X default values. */
X
Xstatic tree
Xgrokparms (first_parm, funcdef_flag)
X tree first_parm;
X int funcdef_flag;
X{
X tree result = NULL_TREE;
X tree decls = NULL_TREE;
X
X if (first_parm != 0
X && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE)
X {
X if (! funcdef_flag)
X warning ("parameter names (without types) in function declaration");
X last_function_parms = first_parm;
X return 0;
X }
X else
X {
X /* Types were specified. This is a list of declarators
X each represented as a TREE_LIST node. */
X register tree parm, chain;
X int any_init = 0, any_error = 0, saw_void = 0;
X
X if (first_parm != NULL_TREE)
X {
X tree last_result = NULL_TREE;
X tree last_decl = NULL_TREE;
X
X for (parm = first_parm; parm != NULL_TREE; parm = chain)
X {
X tree type, list_node = parm;
X register tree decl = TREE_VALUE (parm);
X tree init = TREE_PURPOSE (parm);
X
X chain = TREE_CHAIN (parm);
X /* @@ weak defense against parse errors. */
X if (decl != void_type_node && TREE_CODE (decl) != TREE_LIST)
X {
X /* Give various messages as the need arises. */
X if (TREE_CODE (decl) == STRING_CST)
X error ("invalid string constant `%s'",
X TREE_STRING_POINTER (decl));
X else if (TREE_CODE (decl) == INTEGER_CST)
X error ("invalid integer constant in parameter list, did you forget to give parameter name?");
X continue;
X }
X
X if (decl != void_type_node)
X {
X /* @@ May need to fetch out a `raises' here. */
X decl = grokdeclarator (TREE_VALUE (decl),
X TREE_PURPOSE (decl),
X PARM, 0, NULL_TREE);
X if (! decl) continue;
X type = TREE_TYPE (decl);
X if (type == void_type_node)
X decl = void_type_node;
X else if (TREE_CODE (type) == METHOD_TYPE)
X {
X if (DECL_NAME (decl))
X /* Cannot use `error_with_decl' here because
X we don't have DECL_CONTEXT set up yet. */
X error ("parameter `%s' invalidly declared method type",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X else
X error ("parameter invalidly declared method type");
X type = build_pointer_type (type);
X TREE_TYPE (decl) = type;
X }
X else if (TREE_CODE (type) == OFFSET_TYPE)
X {
X if (DECL_NAME (decl))
X error ("parameter `%s' invalidly declared offset type",
X IDENTIFIER_POINTER (DECL_NAME (decl)));
X else
X error ("parameter invalidly declared offset type");
X type = build_pointer_type (type);
X TREE_TYPE (decl) = type;
X }
X }
X
X if (decl == void_type_node)
X {
X if (result == NULL_TREE)
X {
X result = void_list_node;
X last_result = result;
X }
X else
X {
X TREE_CHAIN (last_result) = void_list_node;
X last_result = void_list_node;
X }
X saw_void = 1;
X if (chain
X && (chain != void_list_node || TREE_CHAIN (chain)))
X error ("`void' in parameter list must be entire list");
X break;
X }
X
X /* Since there is a prototype, args are passed in their own types. */
X DECL_ARG_TYPE (decl) = TREE_TYPE (decl);
X#ifdef PROMOTE_PROTOTYPES
X if (TREE_CODE (type) == INTEGER_TYPE
X && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
X DECL_ARG_TYPE (decl) = integer_type_node;
X#endif
X if (!any_error)
X {
X if (init)
X {
X any_init++;
X if (TREE_CODE (init) == SAVE_EXPR)
X PARM_DECL_EXPR (init) = 1;
X else
X init = require_instantiated_type (type, init, integer_zero_node);
X }
X else if (any_init)
X {
X error ("all trailing parameters must have default arguments");
X any_error = 1;
X }
X }
X else
X init = NULL_TREE;
X
X if (decls == NULL_TREE)
X {
X decls = decl;
X last_decl = decls;
X }
X else
X {
X TREE_CHAIN (last_decl) = decl;
X last_decl = decl;
X }
X if (TREE_PERMANENT (list_node))
X {
X TREE_PURPOSE (list_node) = init;
X TREE_VALUE (list_node) = type;
X TREE_CHAIN (list_node) = 0;
X }
X else
X list_node = saveable_tree_cons (init, type, NULL_TREE);
X if (result == NULL_TREE)
X {
X result = list_node;
X last_result = result;
X }
X else
X {
X TREE_CHAIN (last_result) = list_node;
X last_result = list_node;
X }
X }
X if (last_result)
X TREE_CHAIN (last_result) = NULL_TREE;
X /* If there are no parameters, and the function does not end
X with `...', then last_decl will be NULL_TREE. */
X if (last_decl != NULL_TREE)
X TREE_CHAIN (last_decl) = NULL_TREE;
X }
X }
X
X last_function_parms = decls;
X
X /* In a fcn definition, arg types must be complete. */
X if (funcdef_flag > 0)
X require_complete_types_for_parms (last_function_parms);
X
X return result;
X}
X
X/* These memoizing functions keep track of special properties which
X a class may have. `grok_ctor_properties' notices whether a class
X has a constructor of the for X(X&), and also complains
X if the class has a constructor of the form X(X).
X `grok_op_properties' takes notice of the various forms of
X operator= which are defined, as well as what sorts of type conversion
X may apply. Both functions take a FUNCTION_DECL as an argument. */
Xstatic void
Xgrok_ctor_properties (ctype, decl)
X tree ctype, decl;
X{
X tree parmtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl)));
X tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
X
X if (TREE_CODE (parmtype) == REFERENCE_TYPE
X && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype)
X {
X if (TREE_CHAIN (parmtypes) == NULL_TREE
X || TREE_CHAIN (parmtypes) == void_list_node
X || TREE_PURPOSE (TREE_CHAIN (parmtypes)))
X {
X TYPE_HAS_INIT_REF (ctype) = 1;
X TYPE_GETS_INIT_REF (ctype) = 1;
X if (TREE_READONLY (TREE_TYPE (parmtype)))
X TYPE_GETS_CONST_INIT_REF (ctype) = 1;
X }
X else
X TYPE_GETS_INIT_AGGR (ctype) = 1;
X }
X else if (TYPE_MAIN_VARIANT (parmtype) == ctype)
X {
X if (TREE_CHAIN (parmtypes) != NULL_TREE
X && TREE_CHAIN (parmtypes) == void_list_node)
X error ("invalid constructor; you probably meant `%s (%s&)'",
X TYPE_NAME_STRING (ctype),
X TYPE_NAME_STRING (ctype));
X SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
X TYPE_GETS_INIT_AGGR (ctype) = 1;
X }
X else if (TREE_CODE (parmtype) == VOID_TYPE
X || TREE_PURPOSE (parmtypes) != NULL_TREE)
X TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1;
X}
X
Xstatic void
Xgrok_op_properties (decl)
X tree decl;
X{
X char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
X tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
X
X if (DECL_STATIC_FUNCTION_P (decl))
X {
X if (! strncmp (name, OPERATOR_NEW_FORMAT, OPERATOR_NEW_LENGTH))
X {
X /* Take care of function decl if we had syntax errors. */
X if (argtypes == NULL_TREE)
X TREE_TYPE (decl) = build_function_type (ptr_type_node,
X hash_tree_chain (integer_type_node, void_list_node));
X }
X else if (! strncmp (name, OPERATOR_DELETE_FORMAT, OPERATOR_DELETE_LENGTH))
X {
X if (argtypes == NULL_TREE)
X TREE_TYPE (decl) = build_function_type (void_type_node,
X hash_tree_chain (ptr_type_node, void_list_node));
X }
X else
X error_with_decl (decl, "`%s' cannot be a static member function");
X }
X else if (! strncmp (name, OPERATOR_MODIFY_FORMAT, OPERATOR_MODIFY_LENGTH))
X {
X tree parmtypes = TREE_CHAIN (argtypes);
X tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
X
X if (TREE_CODE (parmtype) == REFERENCE_TYPE
X && TREE_TYPE (parmtype) == current_class_type)
X {
X TYPE_HAS_ASSIGN_REF (current_class_type) = 1;
X TYPE_GETS_ASSIGN_REF (current_class_type) = 1;
X if (TREE_READONLY (TREE_TYPE (parmtype)))
X TYPE_GETS_CONST_INIT_REF (current_class_type) = 1;

X }
X }
X}
X
X/* Get the struct, enum or union (CODE says which) with tag NAME.
X Define the tag as a forward-reference if it is not defined.
X
X C++: If a class derivation is given, process it here, and report
X an error if multiple derivation declarations are not identical.
X
X If we are compiling for SOS, then
X if CODE_TYPE_NODE is a TREE_LIST, then we have a dynamic class
X declaration. The name associated with the class is the tree
X purpose, and the real CODE is in the tree value slot. */
Xtree
Xxref_tag (code_type_node, name, binfo)
X tree code_type_node;
X tree name, binfo;
X{
X enum tag_types tag_code;
X enum tree_code code;
X int temp = 0;
X int i, len;
X register tree ref;
X struct binding_level *b
X = (class_binding_level ? class_binding_level : current_binding_level);
X#ifdef SOS
X tree dynamic_name = error_mark_node;
X if (TREE_CODE (code_type_node) == TREE_LIST)
X {
X dynamic_name = TREE_PURPOSE (code_type_node);
X code_type_node = TREE_VALUE (code_type_node);
X }
X#endif
X
X tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node);
X switch (tag_code)
X {
X case record_type:
X case class_type:
X case exception_type:
X code = RECORD_TYPE;
X len = list_length (binfo) + 1;
X break;
X case union_type:
X code = UNION_TYPE;
X if (binfo)
X {
X error ("derived union `%s' invalid", IDENTIFIER_POINTER (name));
X binfo = NULL_TREE;
X }
X len = 1;
X break;
X case enum_type:
X code = ENUMERAL_TYPE;
X break;
X default:
X abort ();
X }
X
X /* If a cross reference is requested, look up the type
X already defined for this tag and return it. */
X ref = lookup_tag (code, name, b, 0);
X
X if (! ref)
X {
X /* Try finding it as a type declaration. If that wins, use it. */
X ref = lookup_name (name);
X if (ref && TREE_CODE (ref) == TYPE_DECL
X && TREE_CODE (TREE_TYPE (ref)) == code)
X ref = TREE_TYPE (ref);
X else
X ref = NULL_TREE;
X }
X
X if (! ref)
X {
X /* If no such tag is yet defined, create a forward-reference node
X and record it as the "definition".
X When a real declaration of this type is found,
X the forward-reference will be altered into a real type. */
X
X /* In C++, since these migrate into the global scope, we must
X build them on the permanent obstack. */
X if (temp == 0)
X temp = allocation_temporary_p ();
X if (temp)
X end_temporary_allocation ();
X
X if (code == ENUMERAL_TYPE)
X {
X ref = make_node (ENUMERAL_TYPE);
X
X /* Give the type a default layout like unsigned int
X to avoid crashing if it does not get defined. */
X TYPE_MODE (ref) = SImode;
X TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node);
X TREE_UNSIGNED (ref) = 1;
X TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node);
X TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node);
X TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
X
X /* Enable us to recognize when a type is created in class context.
X To do nested classes correctly, this should probably be cleared
X out when we leave this classes scope. Currently this in only
X done in `start_enum'. */
X
X pushtag (name, ref);
X }
X else if (tag_code == exception_type)
X {
X ref = make_lang_type (code);
X CLASSTYPE_OFFSET (ref) = integer_zero_node;
X /* Enable us to recognize when an exception type is created in
X class context. To do nested classes correctly, this should
X probably be cleared out when we leave this class's scope. */
X CLASSTYPE_DECLARED_EXCEPTION (ref) = 1;
X pushtag (name, ref);
X }
X else
X {
X extern tree pending_vtables;
X struct binding_level *old_b = class_binding_level;
X int needs_writing;
X
X ref = make_lang_type (code);
X
X CLASSTYPE_BASECLASSES (ref) = (tree *) malloc (len * sizeof (tree));
X CLASSTYPE_N_BASECLASSES (ref) = len - 1;
X CLASSTYPE_OFFSET (ref) = integer_zero_node;
X CLASSTYPE_VIAS (ref) = (unsigned char *) malloc (len);
X
X /* Record how to set the visibility of this class's
X virtual functions. If write_virtuals == 2 or 3, then
X inline virtuals are ``extern inline''. */
X switch (write_virtuals)
X {
X case 0:
X case 1:
X needs_writing = 1;
X break;
X case 2:
X needs_writing = !! value_member (name, pending_vtables);
X break;
X case 3:
X needs_writing
X = ! (CLASSTYPE_INTERFACE_ONLY (ref) || CLASSTYPE_INTERFACE_UNKNOWN (ref));
X break;
X default:
X needs_writing = 0;
X }
X
X CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = needs_writing;
X
X /* Class types don't nest the way enums do. */
X class_binding_level = 0;
X pushtag (name, ref);
X class_binding_level = old_b;
X }
X }
X else
X {
X if (IS_AGGR_TYPE_CODE (code))
X {
X#if 0
X if (TREE_CODE (TYPE_NAME (ref)) == IDENTIFIER_NODE
X#ifndef BREAK_C_TAGS
X && current_lang_name == lang_name_cplusplus
X#endif
X && ! CLASSTYPE_DECLARED_EXCEPTION (ref))
X {
X /* Silently typedef a tag which came from C. */
X register tree t = pushdecl (build_decl (TYPE_DECL, name, ref));
X TYPE_NAME (ref) = t;
X TREE_TYPE (name) = t;
X }
X#endif
X if (IS_AGGR_TYPE (ref)
X && ((tag_code == exception_type)
X != (CLASSTYPE_DECLARED_EXCEPTION (ref) == 1)))
X {
X error ("type `%s' is both exception and aggregate type",
X IDENTIFIER_POINTER (name));
X CLASSTYPE_DECLARED_EXCEPTION (ref) = (tag_code == exception_type);
X }
X }
X if (binfo)
X {
X tree tt1 = binfo;
X tree *tt2 = CLASSTYPE_BASECLASSES (ref);
X
X if (CLASSTYPE_N_BASECLASSES (ref))
X for (i = 1; tt1; i++, tt1 = TREE_CHAIN (tt1))
X if (TREE_VALUE (tt1) != DECL_NAME (TYPE_NAME (tt2[i])))
X {
X error ("redeclaration of derivation chain of type `%s'",
X IDENTIFIER_POINTER (name));
X break;
X }
X
X if (tt1 != NULL_TREE)
X {
X if (CLASSTYPE_BASECLASSES (ref))
X free (CLASSTYPE_BASECLASSES (ref));
X if (CLASSTYPE_VIAS (ref))
X free (CLASSTYPE_VIAS (ref));
X CLASSTYPE_BASECLASSES (ref) = (tree *) malloc (len * sizeof (tree));
X CLASSTYPE_N_BASECLASSES (ref) = len - 1;
X CLASSTYPE_OFFSET (ref) = integer_zero_node;
X CLASSTYPE_ASSOC (ref) = NULL_TREE;
X CLASSTYPE_VIAS (ref) = (unsigned char *) malloc (len);
X }
X else
X {
X /* The user told us something we already knew. */
X goto just_return;
X }
X }
X#ifdef SOS
X else if (TREE_CODE (ref) != ENUMERAL_TYPE
X && (dynamic_name != error_mark_node) != TYPE_DYNAMIC (ref))
X error ("type `%s' declared both dynamic and non-dynamic",
X IDENTIFIER_POINTER (name));
X#endif
X }
X
X if (binfo)
X {
X CLASSTYPE_MARKED (ref) = 1;
X for (i = 1; binfo; binfo = TREE_CHAIN (binfo))
X {
X /* The base of a derived struct is public. */
X int via_public = (tag_code != class_type
X || TREE_PURPOSE (binfo) == (tree)visibility_public
X || TREE_PURPOSE (binfo) == (tree)visibility_public_virtual);
X int via_virtual = (TREE_PURPOSE (binfo) == (tree)visibility_private_virtual
X || TREE_PURPOSE (binfo) == (tree)visibility_public_virtual
X || TREE_PURPOSE (binfo) == (tree)visibility_default_virtual);
X tree basetype = TREE_TYPE (TREE_VALUE (binfo));
X
X#ifdef FIELD_XREF
X FIELD_xref_hier(IDENTIFIER_POINTER(name),
X IDENTIFIER_POINTER(TREE_VALUE(binfo)),
X via_public,via_virtual,0);
X#endif
X
X if (basetype && TREE_CODE (basetype) == TYPE_DECL)
X basetype = TREE_TYPE (basetype);
X if (!basetype || TREE_CODE (basetype) != RECORD_TYPE)
X {
X error ("base type `%s' fails to be a struct or class type",
X IDENTIFIER_POINTER (TREE_VALUE (binfo)));
X continue;
X }
X#if 0
X else if (TYPE_SIZE (basetype) == 0)
X {
X error_with_aggr_type (basetype, "base class `%s' has incomplete type");
X continue;
X }
X#endif
X else
X {
X#ifdef SOS
X if (dynamic_name == error_mark_node && TYPE_DYNAMIC (basetype))
X error_with_aggr_type (ref, "non-dynamic type `%s' cannot derive from dynamic type `%s'", TYPE_NAME_STRING (basetype));
X#endif
X if (CLASSTYPE_MARKED (basetype))
X {
X if (basetype == ref)
X error_with_aggr_type (basetype, "recursive type `%s' undefined");
X else
X error_with_aggr_type (basetype, "duplicate base type `%s' invalid");
X continue;
X }
X CLASSTYPE_BASECLASS (ref, i) = basetype;
X CLASSTYPE_MARKED (basetype) = 1;
X#if 0
X/* XYZZY TEST VIRTUAL BASECLASSES */
Xif (CLASSTYPE_N_BASECLASSES (basetype) == 0
X && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
X && via_virtual == 0)
X {
X warning ("making type `%s' a virtual baseclass",
X TYPE_NAME_STRING (basetype));
X via_virtual = 1;
X }
X#endif
X SET_CLASSTYPE_VIAS (ref, i, via_public, via_virtual);
X if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype))
X TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1;
X
X TYPE_GETS_ASSIGNMENT (ref) |= TYPE_GETS_ASSIGNMENT (basetype);
X TYPE_OVERLOADS_METHOD_CALL_EXPR (ref) |= TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype);
X TYPE_HAS_WRAPPER_PRED (ref) |= TYPE_HAS_WRAPPER_PRED (basetype);
X TREE_GETS_NEW (ref) |= TREE_GETS_NEW (basetype);
X TREE_GETS_DELETE (ref) |= TREE_GETS_DELETE (basetype);
X CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype);
X i += 1;
X }
X }
X /* Set the true number of baseclasses this type really has. */
X CLASSTYPE_N_BASECLASSES (ref) = --i;
X
X if (i > 1)
X TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1;
X else if (i == 1)
X TYPE_USES_MULTIPLE_INHERITANCE (ref)
X = TYPE_USES_MULTIPLE_INHERITANCE (CLASSTYPE_BASECLASS (ref, 1));
X
X while (i > 0)
X {
X CLASSTYPE_MARKED (CLASSTYPE_BASECLASS (ref, i)) = 0;
X i -= 1;
X }
X CLASSTYPE_MARKED (ref) = 0;
X }
X
X just_return:
X
X#ifdef SOS
X if (dynamic_name != error_mark_node)
X {
X if (temp == 0)
X temp = allocation_temporary_p ();
X if (temp)
X end_temporary_allocation ();
X
X if (dynamic_name)
X CLASSTYPE_DYNAMIC_FILENAME (ref) = combine_strings (dynamic_name);
X else
X CLASSTYPE_DYNAMIC_FILENAME (ref) = NULL_TREE;
X TYPE_DYNAMIC (ref) = 1;
X CLASSTYPE_TYPENAME_AS_STRING (ref) = combine_strings (build_string (IDENTIFIER_LENGTH (name), IDENTIFIER_POINTER (name)));
X
X }
X#endif
X
X /* Until the type is defined, tentatively accept whatever
X structure tag the user hands us. */
X if (TYPE_SIZE (ref) == NULL_TREE
X && ref != current_class_type
X && IS_AGGR_TYPE (ref))
X {
X if (tag_code == class_type)
X CLASSTYPE_DECLARED_CLASS (ref) = 1;
X else if (tag_code == record_type)
X CLASSTYPE_DECLARED_CLASS (ref) = 0;
X }
X

X if (temp)
X resume_temporary_allocation ();
X
X return ref;
X}
X
X/* Begin compiling the definition of an enumeration type.
X NAME is its name (or null if anonymous).
X Returns the type object, as yet incomplete.
X Also records info about it so that build_enumerator
X may be used to declare the individual values as they are read. */
X
Xtree
Xstart_enum (name)
X tree name;
X{
X register tree enumtype = 0;
X struct binding_level *b
X = (class_binding_level ? class_binding_level : current_binding_level);
X
X /* If this is the real definition for a previous forward reference,
X fill in the contents in the same object that used to be the
X forward reference. */
X
X if (name != 0)
X enumtype = lookup_tag (ENUMERAL_TYPE, name, b, 1);
X
X if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
X {
X enumtype = make_node (ENUMERAL_TYPE);
X pushtag (name, enumtype);
X }
X
X if (TYPE_VALUES (enumtype) != 0)
X {
X /* This enum is a named one that has been declared already. */
X error ("redeclaration of `enum %s'", IDENTIFIER_POINTER (name));
X
X /* Completely replace its old definition.
X The old enumerators remain defined, however. */
X TYPE_VALUES (enumtype) = 0;
X }
X
X /* Initially, set up this enum as like `int'
X so that we can create the enumerators' declarations and values.
X Later on, the precision of the type may be changed and
X it may be laid out again. */
X
X TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
X TYPE_SIZE (enumtype) = 0;
X fixup_unsigned_type (enumtype);
X
X /* We copy this value because enumerated type constants
X are really of the type of the enumerator, not integer_type_node. */
X enum_next_value = copy_node (integer_zero_node);
X
X#ifdef FIELD_XREF
X FIELD_xref_decl(current_function_decl,enumtype);
X#endif
X
X return enumtype;
X}
X
X/* After processing and defining all the values of an enumeration type,
X install their decls in the enumeration type and finish it off.
X ENUMTYPE is the type object and VALUES a list of name-value pairs.
X Returns ENUMTYPE. */
X
Xtree
Xfinish_enum (enumtype, values)
X register tree enumtype, values;
X{
X register tree pair;
X register long maxvalue = 0;
X register long minvalue = 0;
X register int i;
X
X TYPE_VALUES (enumtype) = values;
X
X /* Calculate the maximum value of any enumerator in this type. */
X
X if (values)
X {
X /* Speed up the main loop by performing some precalculations */
X
X int value = TREE_INT_CST_LOW (TREE_VALUE (values));
X TREE_TYPE (TREE_VALUE (values)) = enumtype;
X minvalue = maxvalue = value;
X
X for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
X {
X value = TREE_INT_CST_LOW (TREE_VALUE (pair));
X if (value > maxvalue)
X maxvalue = value;
X else if (value < minvalue)
X minvalue = value;
X TREE_TYPE (TREE_VALUE (pair)) = enumtype;
X }
X }
X
X if (flag_short_enums)
X {
X /* Determine the precision this type needs, lay it out, and define it. */
X
X for (i = maxvalue; i; i >>= 1)
X TYPE_PRECISION (enumtype)++;
X
X if (!TYPE_PRECISION (enumtype))
X TYPE_PRECISION (enumtype) = 1;
X
X /* Cancel the laying out previously done for the enum type,
X so that fixup_unsigned_type will do it over. */
X TYPE_SIZE (enumtype) = 0;
X
X fixup_unsigned_type (enumtype);
X }
X
X TREE_INT_CST_LOW (TYPE_MAX_VALUE (enumtype)) = maxvalue;
X
X /* An enum can have some negative values; then it is signed. */
X if (minvalue < 0)
X {
X TREE_INT_CST_LOW (TYPE_MIN_VALUE (enumtype)) = minvalue;
X TREE_INT_CST_HIGH (TYPE_MIN_VALUE (enumtype)) = -1;
X TREE_UNSIGNED (enumtype) = 0;
X }
X return enumtype;
X}
X
X/* Build and install a CONST_DECL for one value of the
X current enumeration type (one that was begun with start_enum).
X Return a tree-list containing the name and its value.
X Assignment of sequential values by default is handled here. */
X
Xtree
Xbuild_enumerator (name, value)
X tree name, value;
X{
X tree decl, result;
X
X /* Validate and default VALUE. */
X if (value != 0)
X {
X if (TREE_READONLY_DECL_P (value))
X value = decl_constant_value (value);
X
X if (TREE_CODE (value) != INTEGER_CST)
X {
X error ("enumerator value for `%s' not integer constant",
X IDENTIFIER_POINTER (name));
X value = 0;
X }
X }
X /* The order of things is reversed here so that we
X can check for possible sharing of enum values,
X to keep that from happening. */
X /* Default based on previous value. */
X if (value == 0)
X value = enum_next_value;
X
X /* Remove no-op casts from the value. */
X while (value != 0 && TREE_CODE (value) == NOP_EXPR)
X value = TREE_OPERAND (value, 0);
X
X /* Make up for hacks in cplus-lex.c. */
X if (value == integer_zero_node)
X value = build_int_2 (0, 0);
X else if (value == integer_one_node)
X value = build_int_2 (1, 0);
X else if (TREE_CODE (value) == INTEGER_CST
X && TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE)
X {
X value = copy_node (value);
X TREE_TYPE (value) = integer_type_node;
X }
X
X result = saveable_tree_cons (name, value, NULL_TREE);
X
X /* C++ associates enums with global, function, or class declarations. */
X if (current_class_type == NULL_TREE || current_function_decl != NULL_TREE)
X {
X /* Create a declaration for the enum value name. */
X
X decl = build_decl (CONST_DECL, name, integer_type_node);
X DECL_INITIAL (decl) = value;
X
X pushdecl (decl);
X }
X
X /* Set basis for default for next value. */
X enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
X integer_one_node, PLUS_EXPR);
X if (TREE_UID (enum_next_value) < TREE_UID (result))
X enum_next_value = copy_node (enum_next_value);
X
X return result;
X}
X
Xtree
Xgrok_enum_decls (type, decl)
X tree type, decl;
X{
X struct binding_level *b = class_binding_level;
X tree tag = NULL_TREE;
X tree values;
X
X while (b)
X {
X tag = value_member (type, b->tags);
X if (tag)
X break;
X b = b->level_chain;
X }
X
X if (b == 0)
X {
X tree name = TYPE_NAME (type);
X if (TREE_CODE (name) == TYPE_DECL)
X name = DECL_NAME (name);
X error ("class-local enum declaration `%s' is not in scope here",
X IDENTIFIER_POINTER (name));
X }
X else if (b != class_binding_level)
X {
X warning ("class-local declaration for enumeral type `%s' found",
X IDENTIFIER_POINTER (TREE_PURPOSE (tag)));
X warning ("(probably missing '}' before that enum declaration)");
X return decl;
X }
X else if (TREE_ADDRESSABLE (tag))
X return decl;
X else
X TREE_ADDRESSABLE (tag) = 1;
X
X values = TYPE_VALUES (type);
X while (values)
X {
X /* Create a declaration for the enum value name. */
X tree next = build_lang_field_decl (CONST_DECL, TREE_PURPOSE (values), type);
X DECL_INITIAL (next) = TREE_VALUE (values);
X TREE_CHAIN (next) = decl;
X decl = next;
X pushdecl_class_level (decl);
X values = TREE_CHAIN (values);
X }
X return decl;
X}
X
X/* Create the FUNCTION_DECL for a function definition.
X DECLSPECS and DECLARATOR are the parts of the declaration;
X they describe the function's name and the type it returns,
X but twisted together in a fashion that parallels the syntax of C.
X
X This function creates a binding context for the function body
X as well as setting up the FUNCTION_DECL in current_function_decl.
X
X Returns 1 on success. If the DECLARATOR is not suitable for a function
X (it defines a datum instead), we return 0, which tells
X yyparse to report a parse error.
X
X For C++, we must first check whether that datum makes any sense.
X For example, "class A local_a(1,2);" means that variable local
X a is an aggregate of type A, which should have a constructor
X applied to it with the argument list [1, 2].
X
X @@ There is currently no way to retrieve the storage
X @@ allocated to FUNCTION (or all of its parms) if we return
X @@ something we had previously. */
X
Xint
Xstart_function (declspecs, declarator, raises, pre_parsed_p)
X tree declarator, declspecs, raises;
X int pre_parsed_p;
X{
X extern tree EHS_decl;
X tree decl1, olddecl;
X tree ctype = NULL_TREE;
X tree fntype;
X tree restype;
X
X if (flag_handle_exceptions && EHS_decl == NULL_TREE)
X init_exception_processing_1 ();
X
X /* Sanity check. */
X assert (TREE_VALUE (void_list_node) == void_type_node);
X assert (TREE_CHAIN (void_list_node) == NULL_TREE);
X
X /* Assume, until we see it does. */
X current_function_returns_value = 0;
X current_function_returns_null = 0;
X warn_about_return_type = 0;
X current_extern_inline = 0;
X current_function_assigns_this = 0;
X current_function_just_assigned_this = 0;
X current_function_parms_stored = 0;
X original_result_rtx = 0;
X
X clear_temp_name ();
X
X if (pre_parsed_p)
X {
X decl1 = declarator;
X last_function_parms = DECL_ARGUMENTS (decl1);
X last_function_parm_tags = 0;
X fntype = TREE_TYPE (decl1);
X if (TREE_CODE (fntype) == METHOD_TYPE)
X ctype = TYPE_METHOD_BASETYPE (fntype);
X
X if ( !(DECL_VIRTUAL_P (decl1)
X && write_virtuals >= 2
X && CLASSTYPE_VTABLE_NEEDS_WRITING (ctype)))
X current_extern_inline = TREE_PUBLIC (decl1);
X
X raises = TYPE_RAISES_EXCEPTIONS (fntype);
X
X /* In a fcn definition, arg types must be complete. */
X require_complete_types_for_parms (last_function_parms);
X }
X else
X {
X decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, raises);
X /* If the declarator is not suitable for a function definition,
X cause a syntax error. */
X if (decl1 == 0 || TREE_CODE (decl1) != FUNCTION_DECL) return 0;
X
X fntype = TREE_TYPE (decl1);
X
X restype = TREE_TYPE (fntype);
X if (IS_AGGR_TYPE (restype)
X && ! CLASSTYPE_GOT_SEMICOLON (restype))
X {
X error_with_aggr_type (restype, "semicolon missing after declaration of `%s'");
X shadow_tag (build_tree_list (NULL_TREE, restype));
X CLASSTYPE_GOT_SEMICOLON (restype) = 1;
X if (TREE_CODE (fntype) == FUNCTION_TYPE)
X fntype = build_function_type (integer_type_node,
X TYPE_ARG_TYPES (fntype));
X else
X fntype = build_cplus_method_type (TYPE_METHOD_BASETYPE (fntype),
X integer_type_node,
X TYPE_ARG_TYPES (fntype));
X TREE_TYPE (decl1) = fntype;
X }
X
X if (TREE_CODE (fntype) == METHOD_TYPE)
X ctype = TYPE_METHOD_BASETYPE (fntype);
X else if (IDENTIFIER_LENGTH (DECL_NAME (decl1)) == 4
X && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (decl1)), "main"))
X {
X /* If this doesn't return an integer type, complain. */
X if (TREE_CODE (TREE_TYPE (fntype)) != INTEGER_TYPE)
X {

X#if 0
X error ("return type for `main' must be integer type");
X#else
X warning ("return type for `main' changed to integer type");
X#endif
X TREE_TYPE (decl1) = fntype = default_function_type;
X }
X warn_about_return_type = 0;
X }
X }
X
X /* Warn if function was previously implicitly declared
X (but not if we warned then). */
X if (! warn_implicit && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != 0)
X warning_with_decl (IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)),
X "`%s' implicitly declared before its definition");
X
X current_function_decl = decl1;
X
X announce_function (decl1);
X
X if (TYPE_SIZE (TREE_TYPE (fntype)) == 0)
X {
X if (IS_AGGR_TYPE (TREE_TYPE (fntype)))
X error_with_aggr_type (TREE_TYPE (fntype),
X "return-type `%s' is an incomplete type");
X else
X error ("return-type is an incomplete type");
X
X /* Make it return void instead. */
X if (ctype)
X TREE_TYPE (decl1)
X = build_cplus_method_type (ctype,
X void_type_node,
X TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl1))));
X else
X TREE_TYPE (decl1)
X = build_function_type (void_type_node,
X TYPE_ARG_TYPES (TREE_TYPE (decl1)));
X }
X
X if (warn_about_return_type)
X warning ("return-type defaults to `int'");
X
X /* Make the init_value nonzero so pushdecl knows this is not tentative.
X error_mark_node is replaced below (in poplevel) with the LET_STMT. */
X DECL_INITIAL (decl1) = error_mark_node;
X
X /* Didn't get anything from C. */
X olddecl = 0;
X
X /* This is a definition, not a reference.
X So normally clear TREE_EXTERNAL.
X However, `extern inline' acts like a declaration
X except for defining how to inline. So set TREE_EXTERNAL in that case. */
X TREE_EXTERNAL (decl1) = current_extern_inline;
X
X /* This function exists in static storage.
X (This does not mean `static' in the C sense!) */
X TREE_STATIC (decl1) = 1;
X
X /* If this function belongs to the implementation, make it public.
X It doesn't matter whether it's inline or not. */
X if (!TREE_PRIVATE (decl1) && interface_unknown == 0)
X {
X TREE_PUBLIC (decl1) = ! interface_only;
X TREE_EXTERNAL (decl1) = interface_only;
X }
X
X /* Now see if this is the implementation of a function
X declared with "C" linkage. */
X if (ctype == NULL_TREE && current_lang_name == lang_name_cplusplus)
X {
X olddecl = lookup_name_current_level (DECL_ORIGINAL_NAME (decl1));
X if (olddecl && TREE_CODE (olddecl) != FUNCTION_DECL)
X olddecl = NULL_TREE;
X if (olddecl
X && DECL_ORIGINAL_NAME (decl1) != DECL_ORIGINAL_NAME (olddecl))
X {
X /* Collision between user and internal naming scheme. */
X olddecl = lookup_name_current_level (DECL_NAME (decl1));
X if (olddecl == NULL_TREE)
X olddecl = decl1;
X }
X if (olddecl && olddecl != decl1
X && DECL_ORIGINAL_NAME (decl1) == DECL_ORIGINAL_NAME (olddecl))
X {
X if (TREE_CODE (olddecl) == FUNCTION_DECL
X && (decls_match (decl1, olddecl)
X || comp_target_parms (TYPE_ARG_TYPES (TREE_TYPE (decl1)),
X TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 1)))
X {
X olddecl = DECL_MAIN_VARIANT (olddecl);
X DECL_NAME (decl1) = DECL_NAME (olddecl);
X DECL_PRINT_NAME (decl1) = DECL_PRINT_NAME (olddecl);
X DECL_OVERLOADED (decl1) = DECL_OVERLOADED (olddecl);
X if (DECL_INITIAL (olddecl))
X redeclaration_error_message (decl1, olddecl);
X if (! duplicate_decls (decl1, olddecl))
X abort ();
X decl1 = olddecl;
X }
X else
X olddecl = NULL_TREE;
X }
X }
X
X /* Record the decl so that the function name is defined.
X If we already have a decl for this name, and it is a FUNCTION_DECL,
X use the old decl. */
X
X if (olddecl)
X current_function_decl = olddecl;
X else if (pre_parsed_p == 0)
X {
X current_function_decl = pushdecl (decl1);
X if (TREE_CODE (current_function_decl) == TREE_LIST)
X {
X /* @@ revert to modified original declaration. */
X decl1 = DECL_MAIN_VARIANT (decl1);
X current_function_decl = decl1;
X }
X else
X {
X decl1 = current_function_decl;
X DECL_MAIN_VARIANT (decl1) = decl1;
X }
X fntype = TREE_TYPE (decl1);
X }
X else
X current_function_decl = decl1;
X
X if (DECL_OVERLOADED (decl1))
X push_overloaded_decl (decl1);
X
X if (ctype != 0 && DECL_STATIC_FUNCTION_P (decl1))
X {
X if (TREE_CODE (fntype) == METHOD_TYPE)
X TREE_TYPE (decl1) = fntype
X = build_function_type (TREE_TYPE (fntype),
X TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
X last_function_parms = TREE_CHAIN (last_function_parms);
X DECL_ARGUMENTS (decl1) = last_function_parms;
X ctype = 0;
X }
X restype = TREE_TYPE (fntype);
X
X pushlevel (0);
X current_binding_level->parm_flag = 1;
X
X /* Save the parm names or decls from this function's declarator
X where store_parm_decls will find them. */
X current_function_parms = last_function_parms;
X current_function_parm_tags = last_function_parm_tags;
X
X#ifdef FIELD_XREF
X FIELD_xref_function(decl1,current_function_parms);
X#endif
X
X make_function_rtl (decl1);
X
X if (ctype)
X {
X pushclass (ctype, 1);
X /* We know that this was set up by `grokclassfn'.
X We do not wait until `store_parm_decls', since evil
X parse errors may never get us to that point. Here
X we keep the consistency between `current_class_type'
X and `current_class_decl'. */
X current_class_decl = last_function_parms;
X assert (TREE_CODE (current_class_decl) == PARM_DECL);
X if (TREE_CODE (TREE_TYPE (current_class_decl)) == POINTER_TYPE)
X {
X tree variant = TREE_TYPE (TREE_TYPE (current_class_decl));
X if (CLASSTYPE_INST_VAR (ctype) == NULL_TREE)
X {
X /* Can't call build_indirect_ref here, because it has special
X logic to return C_C_D given this argument. */
X C_C_D = build1 (INDIRECT_REF, current_class_type, current_class_decl);
X CLASSTYPE_INST_VAR (ctype) = C_C_D;
X }
X else
X {
X C_C_D = CLASSTYPE_INST_VAR (ctype);
X /* `current_class_decl' is different for every
X function we compile. */
X TREE_OPERAND (C_C_D, 0) = current_class_decl;
X }
X TREE_READONLY (C_C_D) = TREE_READONLY (variant);
X TREE_VOLATILE (C_C_D) = TREE_VOLATILE (variant);
X }
X else
X C_C_D = current_class_decl;
X }
X else
X {
X if (DECL_STATIC_FUNCTION_P (decl1))
X pushclass (DECL_STATIC_CONTEXT (decl1), 2);
X else
X push_memoized_context (0, 1);
X }
X
X /* Allocate further tree nodes temporarily during compilation
X of this function only. */
X temporary_allocation ();
X
X /* Promote the value to int before returning it. */
X if (TREE_CODE (restype) == INTEGER_TYPE
X && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node))
X restype = integer_type_node;
X DECL_RESULT (decl1) = build_decl (RESULT_DECL, value_identifier, restype);
X
X if (DESTRUCTOR_NAME_P (DECL_NAME (decl1)))
X {
X dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
X ctor_label = NULL_TREE;
X }
X else
X {
X dtor_label = NULL_TREE;
X if (DECL_CONSTRUCTOR_P (decl1))
X ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
X }
X
X /* If this fcn was already referenced via a block-scope `extern' decl
X (or an implicit decl), propagate certain information about the usage. */
X if (TREE_ADDRESSABLE (DECL_NAME (decl1)))
X TREE_ADDRESSABLE (decl1) = 1;
X
X return 1;
X}
X
X/* Store the parameter declarations into the current function declaration.
X This is called after parsing the parameter declarations, before
X digesting the body of the function.
X
X Also install to binding contour return value identifier, if any. */
X
Xvoid
Xstore_parm_decls ()
X{
X register tree fndecl = current_function_decl;
X register tree parm;
X int parms_have_cleanups = 0;
X tree eh_decl;
X
X /* This is either a chain of PARM_DECLs (when a prototype is used). */
X tree specparms = current_function_parms;
X
X /* This is a list of types declared among parms in a prototype. */
X tree parmtags = current_function_parm_tags;
X
X /* This is a chain of any other decls that came in among the parm
X declarations. If a parm is declared with enum {foo, bar} x;
X then CONST_DECLs for foo and bar are put here. */
X tree nonparms = 0;
X
X if (current_binding_level == global_binding_level)
X fatal ("parse errors have confused me too much");
X
X /* Initialize RTL machinery. */
X init_function_start (fndecl);
X
X /* Create a binding level for the parms. */
X expand_start_bindings (0);
X
X /* Prepare to catch raises, if appropriate. */
X if (flag_handle_exceptions)
X {
X /* Get this cleanup to be run last, since it
X is a call to `longjmp'. */
X setup_exception_throw_decl ();
X eh_decl = current_binding_level->names;
X current_binding_level->names = TREE_CHAIN (current_binding_level->names);
X }
X if (flag_handle_exceptions)
X expand_start_try (integer_one_node, 0, 1);
X
X if (specparms != 0)
X {
X /* This case is when the function was defined with an ANSI prototype.
X The parms already have decls, so we need not do anything here
X except record them as in effect
X and complain if any redundant old-style parm decls were written. */
X
X register tree next;
X
X for (parm = nreverse (specparms); parm; parm = next)
X {
X tree cleanup = maybe_build_cleanup (parm);
X next = TREE_CHAIN (parm);
X if (DECL_NAME (parm) == 0)
X {
X#if 0
X error_with_decl (parm, "parameter name omitted");
X#else
X /* for C++, this is not an error. */
X pushdecl (parm);
X#endif
X }
X else if (TREE_TYPE (parm) == void_type_node)
X error_with_decl (parm, "parameter `%s' declared void");
X else
X {
X /* Now fill in DECL_REFERENCE_SLOT for any of the parm decls.
X A parameter is assumed not to have any side effects.
X If this should change for any reason, then this
X will have to wrap the bashed reference type in a save_expr.
X
X Also, if the parameter type is declared to be an X
X and there is an X(X&) constructor, we cannot lay it
X into the stack (any more), so we make this parameter
X look like it is really of reference type. Functions
X which pass parameters to this function will know to
X create a temporary in their frame, and pass a reference
X to that. */
X
X if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
X && TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))))
X SET_DECL_REFERENCE_SLOT (parm, convert_from_reference (parm));
X
X pushdecl (parm);
X }
X
X if (cleanup)
X {
X expand_decl (parm);
X expand_decl_cleanup (parm, cleanup);
X parms_have_cleanups = 1;
X }
X }
X
X /* Get the decls in their original chain order
X and record in the function. */
X DECL_ARGUMENTS (fndecl) = getdecls ();
X
X storetags (chainon (parmtags, gettags ()));
X }
X else
X DECL_ARGUMENTS (fndecl) = 0;
X
X /* Now store the final chain of decls for the arguments
X as the decl-chain of the current lexical scope.
X Put the enumerators in as well, at the front so that
X DECL_ARGUMENTS is not modified. */
X
X storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
X
X /* Initialize the RTL code for the function. */
X DECL_SAVED_INSNS (fndecl) = 0;
X expand_function_start (fndecl, parms_have_cleanups);
X
X if (flag_handle_exceptions)
X {
X /* Make the throw decl visibile at this level, just
X not in the way of the parameters. */
X pushdecl (eh_decl);
X expand_decl_init (eh_decl);
X }
X
X /* Create a binding contour which can be used to catch
X cleanup-generated temporaries. Also, if the return value needs or
X has initialization, deal with that now. */
X if (parms_have_cleanups)
X {
X pushlevel (0);
X expand_start_bindings (0);
X }
X
X current_function_parms_stored = 1;
X
X /* If this function is `main', emit a call to `__main'
X to run global initializers, etc. */
X if (flag__main)
X if (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 4
X && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0)
X expand_expr (build_function_call (lookup_name (get_identifier ("__main")),
X NULL_TREE),
X 0, VOIDmode, 0);
X}
X
X/* Bind a name and initialization to the return value of
X the current function. */
Xvoid
Xstore_return_init (init)
X tree init;
X{
X tree decl = DECL_RESULT (current_function_decl);
X
X /* Can't let this happen for constructors. */
X if (DECL_CONSTRUCTOR_P (current_function_decl))
X {
X error ("can't redefine default return value for constructors");
X return;
X }
X
X /* If we have a named return value, put that in our scope as well. */
X if (DECL_NAME (decl) != value_identifier)
X {
X /* If this named return value comes in a register,
X put it in a pseudo-register. */
X if (TREE_REGDECL (decl))
X {
X original_result_rtx = DECL_RTL (decl);
X DECL_RTL (decl) = (struct rtx_def *)gen_reg_rtx (DECL_MODE (decl));
X }
X
X /* Let `finish_decl' know that this initializer is ok. */
X DECL_INITIAL (decl) = init;
X pushdecl (decl);
X finish_decl (decl, init, 0);
X }
X}
X
X/* Generate code for default X(X&) constructor. */
Xstatic void
Xbuild_default_constructor (fndecl)
X tree fndecl;
X{
X int i = CLASSTYPE_N_BASECLASSES (current_class_type);
X tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
X tree fields = TYPE_FIELDS (current_class_type);
X if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
X parm = TREE_CHAIN (parm);
X parm = DECL_REFERENCE_SLOT (parm);
X
X while (i > 0)
X {
X tree basetype = CLASSTYPE_BASECLASS (current_class_type, i);
X if (TYPE_GETS_INIT_REF (basetype))
X {
X tree name = TYPE_NAME (basetype);
X if (TREE_CODE (name) == TYPE_DECL)
X name = DECL_NAME (name);
X current_base_init_list = tree_cons (name, parm, current_base_init_list);
X }
X i -= 1;
X }
X for (fields = TYPE_FIELDS (current_class_type); fields;
X fields = TREE_CHAIN (fields))
X {
X tree name, init;
X if (TREE_STATIC (fields))
X continue;
X if (TREE_CODE (fields) != FIELD_DECL)
X continue;
X if (DECL_NAME (fields))
X {
X if (VFIELD_NAME_P (DECL_NAME (fields)))
X continue;
X if (VBASE_NAME_P (DECL_NAME (fields)))
X continue;
X
X /* True for duplicate members. */
X if (IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) != fields)
X continue;
X }
X
X init = build (COMPONENT_REF, TREE_TYPE (fields), parm, fields);
X
X if (TREE_ANON_UNION_ELEM (fields))
X name = build (COMPONENT_REF, TREE_TYPE (fields), C_C_D, fields);
X else
X {
X name = DECL_NAME (fields);
X init = build_tree_list (NULL_TREE, init);
X }
X
X current_member_init_list
X = tree_cons (name, init, current_member_init_list);
X }
X}
X
X
X/* Finish up a function declaration and compile that function
X all the way to assembler language output. The free the storage
X for the function definition.
X
X This is called after parsing the body of the function definition.
X LINENO is the current line number.
X
X C++: CALL_POPLEVEL is non-zero if an extra call to poplevel
X (and expand_end_bindings) must be made to take care of the binding
X contour for the base initializers. This is only relevant for
X constructors. */
X
Xvoid
Xfinish_function (lineno, call_poplevel)
X int lineno;
X int call_poplevel;
X{
X register tree fndecl = current_function_decl;
X tree fntype = TREE_TYPE (fndecl), ctype = NULL_TREE;
X struct rtx_def *head, *last_parm_insn, *mark;
X extern struct rtx_def *get_last_insn ();
X extern struct rtx_def *cleanup_label, *return_label;
X extern int sets_exception_throw_decl;
X /* Label to use if this function is supposed to return a value. */
X tree no_return_label = 0;
X
X/* TREE_READONLY (fndecl) = 1;
X This caused &foo to be of type ptr-to-const-function
X which then got a warning when stored in a ptr-to-function variable. */
X
X /* This happens on strange parse errors. */
X if (! current_function_parms_stored)
X {
X call_poplevel = 0;
X store_parm_decls ();
X }
X
X if (flag_minimal_debug
X && write_symbols == DBX_DEBUG
X && (TREE_CODE (fntype) != METHOD_TYPE
X || ! CLASSTYPE_ASM_WRITTEN (TYPE_METHOD_BASETYPE (fntype))))
X {
X tree ttype = target_type (fntype);
X tree parmdecl;
X
X if (IS_AGGR_TYPE (ttype))
X /* Let debugger know it should output info for this type. */
X CLASSTYPE_ASM_WRITTEN (ttype) = 1;
X
X for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl))
X {
X ttype = target_type (TREE_TYPE (parmdecl));
X if (IS_AGGR_TYPE (ttype))
X /* Let debugger know it should output info for this type. */
X CLASSTYPE_ASM_WRITTEN (ttype) = 1;
X }
X }
X
X /* Clean house because we will need to reorder insns here. */
X do_pending_stack_adjust ();
X
X if (dtor_label)
X {
X tree cond = integer_one_node;
X tree exprstmt, vfields;
X tree in_charge_node = lookup_name (in_charge_identifier);
X int ok_to_optimize_dtor = 0;
X
X if (current_function_assigns_this)
X cond = build (NE_EXPR, integer_type_node,
X current_class_decl, integer_zero_node);
X else
X {
X int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
X
X /* If this destructor is empty, then we don't need to check
X whether `this' is NULL in some cases. */
X mark = get_last_insn ();
X last_parm_insn = (struct rtx_def *)get_first_nonparm_insn ();
X
X if ((flag_this_is_variable & 1) == 0)
X ok_to_optimize_dtor = 1;
X else if (mark == last_parm_insn)
X ok_to_optimize_dtor
X = (n_baseclasses == 0
X || (n_baseclasses == 1
X && TYPE_HAS_DESTRUCTOR (CLASSTYPE_BASECLASS (current_class_type, 1))));
X }
X
X /* These initializations might go inline. Protect
X the binding level of the parms. */
X pushlevel (0);
X
X if (current_function_assigns_this)
X {
X TYPE_ANY_ASSIGNS_THIS (current_class_type) = 1;
X current_function_assigns_this = 0;
X current_function_just_assigned_this = 0;
X }
X
X /* Generate the code to call destructor on base class.
X If this destructor belongs to a class with virtual
X functions, then set the virtual function table
X pointer to represent the type of our base class. */
X
X /* This side-effect makes call to `build_delete' generate the
X code we have to have at the end of this destructor. */
X TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
X
X /* These are two cases where we cannot delegate deletion. */
X if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
X || TREE_GETS_DELETE (current_class_type))
X exprstmt = build_delete (current_class_type, C_C_D, integer_zero_node,
X LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
X else
X exprstmt = build_delete (current_class_type, C_C_D, in_charge_node,
X LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
X
X /* If we did not assign to this, then `this' is non-zero at
X the end of a destructor. As a special optimization, don't
X emit test if this is an empty destructor. If it does nothing,
X it does nothing. If it calls a base destructor, the base
X destructor will perform the test. */
X
X if (exprstmt != error_mark_node
X && (TREE_CODE (exprstmt) != NOP_EXPR
X || TREE_OPERAND (exprstmt, 0) != integer_zero_node
X || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
X {
X expand_label (dtor_label);
X if (cond != integer_one_node)
X expand_start_cond (cond, 0);
X expand_expr_stmt (exprstmt);
X
X /* Run destructor on all virtual baseclasses. */
X if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
X {
X tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
X expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
X in_charge_node, integer_two_node), 0);
X while (vbases)
X {
X if (TYPE_NEEDS_DESTRUCTOR (TREE_VALUE (vbases)))
X {
X tree ptr = convert_pointer_to_vbase (TREE_TYPE (vbases), current_class_decl);
X expand_expr_stmt (build_delete (TYPE_POINTER_TO (TREE_VALUE (vbases)),
X ptr, integer_zero_node,
X LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_HAS_IN_CHARGE, 0));
X }
X vbases = TREE_CHAIN (vbases);
X }
X expand_end_cond ();
X }
X
X do_pending_stack_adjust ();
X if (cond != integer_one_node)
X expand_end_cond ();
X }
X
X TYPE_HAS_DESTRUCTOR (current_class_type) = 1;
X
X /* At the end, call delete if that's what's requested. */
X if (TREE_GETS_DELETE (current_class_type))
X /* This NOP_EXPR means we are in a static call context. */
X exprstmt = build_method_call (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), error_mark_node),
X get_identifier (OPERATOR_DELETE_FORMAT),
X build_tree_list (NULL_TREE, current_class_decl),
X NULL_TREE, LOOKUP_NORMAL);
X else if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
X exprstmt = build_x_delete (ptr_type_node, current_class_decl, 0);
X else
X exprstmt = 0;
X
X if (exprstmt)
X {
X cond = build (BIT_AND_EXPR, integer_type_node,
X in_charge_node, integer_one_node);
X expand_start_cond (cond, 0);
X expand_expr_stmt (exprstmt);
X expand_end_cond ();
X }
X
X /* End of destructor. */
X poplevel (2, 0, 0);
X
X /* Back to the top of destructor. */
X /* Dont execute destructor code if `this' is NULL. */
X mark = get_last_insn ();
X last_parm_insn = (struct rtx_def *)get_first_nonparm_insn ();
X if (last_parm_insn == 0) last_parm_insn = mark;
X else last_parm_insn = (struct rtx_def *) previous_insn (last_parm_insn);
X
X /* Make all virtual function table pointers point to CURRENT_CLASS_TYPE's
X virtual function tables. */
X if (CLASSTYPE_VFIELDS (current_class_type))
X {
X for (vfields = CLASSTYPE_VFIELDS (current_class_type);
X TREE_CHAIN (vfields);
X vfields = TREE_CHAIN (vfields))
X expand_expr_stmt (build_virtual_init (current_class_type,
X TREE_VALUE (vfields),
X current_class_decl));
X expand_expr_stmt (build_virtual_init (current_class_type,
X current_class_type,
X current_class_decl));
X }
X if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
X expand_expr_stmt (build_vbase_vtables_init (current_class_type,
X current_class_type,
X C_C_D, current_class_decl, 0));
X if (! ok_to_optimize_dtor)
X {
X cond = build_binary_op (NE_EXPR, current_class_decl, integer_zero_node);
X expand_start_cond (cond, 0);
X }
X if (mark != get_last_insn ())
X reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
X if (! ok_to_optimize_dtor)
X expand_end_cond ();
X }
X else if (current_function_assigns_this)
X {
X /* Does not need to call emit_base_init, because
X that is done (if needed) just after assignment to this
X is seen. */
X
X TYPE_ANY_ASSIGNS_THIS (current_class_type) = 1;
X
X if (DECL_CONSTRUCTOR_P (current_function_decl))
X {
X expand_label (ctor_label);
X ctor_label = NULL_TREE;
X
X if (call_poplevel)
X {
X tree decls = getdecls ();
X if (flag_handle_exceptions == 2)
X deactivate_exception_cleanups ();
X expand_end_bindings (decls, decls != 0, 0);
X poplevel (decls != 0, 0, 0);
X }
X c_expand_return (current_class_decl);
X }
X else if (DECL_RESULT (current_function_decl))
X no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
X
X current_function_assigns_this = 0;
X current_function_just_assigned_this = 0;
X base_init_insns = 0;
X }
X else if (DECL_CONSTRUCTOR_P (fndecl))
X {
X tree allocated_this;
X tree cond, thenclause;
X /* Allow constructor for a type to get a new instance of the object
X using `build_new'. */
X tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
X CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
X
X DECL_RETURNS_FIRST_ARG (fndecl) = 1;
X
X if (flag_this_is_variable)
X {
X cond = build_binary_op (EQ_EXPR, current_class_decl, integer_zero_node);
X thenclause = build_modify_expr (current_class_decl, NOP_EXPR,
X build_new (NULL_TREE, current_class_type, void_type_node, 0));
X if (flag_handle_exceptions == 2)
X {
X tree cleanup, cleanup_deallocate;
X
X allocated_this = build_decl (VAR_DECL, NULL_TREE, ptr_type_node);
X TREE_REGDECL (allocated_this) = 1;
X DECL_INITIAL (allocated_this) = error_mark_node;
X expand_decl (allocated_this);
X expand_decl_init (allocated_this);
X /* How we cleanup `this' if an exception was raised before
X we are ready to bail out. */
X cleanup = TREE_GETS_DELETE (current_class_type)
X ? build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, allocated_this)
X : build_delete (TREE_TYPE (allocated_this), allocated_this, integer_three_node, LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE, 1);
X cleanup_deallocate
X = build_modify_expr (current_class_decl, NOP_EXPR, integer_zero_node);
X cleanup = tree_cons (NULL_TREE, cleanup,
X build_tree_list (NULL_TREE, cleanup_deallocate));
X
X expand_decl_cleanup (allocated_this,
X build (COND_EXPR, integer_type_node,
X build (NE_EXPR, integer_type_node,
X allocated_this, integer_zero_node),
X build_compound_expr (cleanup),
X integer_zero_node));
X }
X }
X else if (TREE_GETS_NEW (current_class_type))
X /* Just check visibility here. */
X build_method_call (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), error_mark_node),
X get_identifier (OPERATOR_NEW_FORMAT),
X build_tree_list (NULL_TREE, integer_zero_node),
X NULL_TREE, LOOKUP_NORMAL);
X
X CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
X
X /* must keep the first insn safe. */
X head = (struct rtx_def *)get_insns ();
X
X /* this note will come up to the top with us. */
X mark = get_last_insn ();
X
X if (flag_this_is_variable)
X {
X expand_start_cond (cond, 0);
X expand_expr_stmt (thenclause);
X if (flag_handle_exceptions == 2)
X expand_assignment (allocated_this, current_class_decl, 0, 0);
X expand_end_cond ();
X }
X
X if (DECL_COMPILER_GENERATED_P (fndecl)
X && TREE_CHAIN (DECL_ARGUMENTS (fndecl)) != NULL_TREE)
X build_default_constructor (fndecl);
X
X /* Emit insns from `emit_base_init' which sets up virtual
X function table pointer(s). */
X emit_insns (base_init_insns);
X base_init_insns = 0;
X
X /* This is where the body of the constructor begins.
X If there were no insns in this function body, then the
X last_parm_insn is also the last insn.
X
X If optimization is enabled, last_parm_insn may move, so
X we don't hold on to it (across emit_base_init). */
X last_parm_insn = (struct rtx_def *)get_first_nonparm_insn ();
X if (last_parm_insn == 0) last_parm_insn = mark;
X else last_parm_insn = (struct rtx_def *) previous_insn (last_parm_insn);
X
X if (mark != get_last_insn ())
X reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
X
X /* This is where the body of the constructor ends. */
X expand_label (ctor_label);
X ctor_label = NULL_TREE;
X if (flag_handle_exceptions == 2)
X {
X expand_assignment (allocated_this, integer_zero_node, 0, 0);
X deactivate_exception_cleanups ();
X }
X
X pop_implicit_try_blocks (NULL_TREE);
X
X if (call_poplevel)
X {
X expand_end_bindings (getdecls (), 1, 0);
X poplevel (1, 1, 0);
X }
X
X c_expand_return (current_class_decl);
X
X current_function_assigns_this = 0;
X current_function_just_assigned_this = 0;
X }
X else if (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 4
X && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main"))
X {
X /* Make it so that `main' always returns 0 by default. */
X#ifdef VMS
X c_expand_return (integer_one_node);
X#else
X c_expand_return (integer_zero_node);
X#endif
X }
X else if (DECL_RESULT (current_function_decl))
X no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
X
X /* That's the end of the vtable decl's life. Need to mark it such
X if doing stupid register allocation.
X
X Note that current_vtable_decl is really an INDIRECT_REF
X on top of a VAR_DECL here. */
X if (obey_regdecls && current_vtable_decl)
X use_variable (DECL_RTL (TREE_OPERAND (current_vtable_decl, 0)));
X
X /* If this function is supposed to return a value, ensure that
X we do not fall into the cleanups by mistake. The end of our
X function will look like this:
X
X user code (may have return stmt somewhere)
X goto no_return_label
X cleanup_label:
X cleanups
X goto return_label
X no_return_label:
X NOTE_INSN_FUNCTION_END
X return_label:
X things for return
X
X If the user omits a return stmt in the USER CODE section, we
X will have a control path which reaches NOTE_INSN_FUNCTION_END.
X Otherwise, we won't. */
X if (no_return_label)
X {
X DECL_CONTEXT (no_return_label) = fndecl;
X DECL_INITIAL (no_return_label) = error_mark_node;
X DECL_SOURCE_FILE (no_return_label) = input_filename;
X DECL_SOURCE_LINE (no_return_label) = lineno;
X expand_goto (no_return_label);
X }
X
X if (cleanup_label)
X {
X /* remove the binding contour which is used
X to catch cleanup-generated temporaries. */
X expand_end_bindings (0, 0, 0);
X poplevel (0, 0, 0);
X }
X
X /* Must mark the RESULT_DECL as being in this function. */
X
X DECL_CONTEXT (DECL_RESULT (fndecl)) = DECL_INITIAL (fndecl);
X
X /* Obey `register' declarations if `setjmp' is called in this fn. */
X if (flag_traditional && current_function_calls_setjmp)
X setjmp_protect (DECL_INITIAL (fndecl));
X
X if (cleanup_label)
X {
X /* Emit label at beginning of cleanup code for parmeters. */
X emit_label (cleanup_label);
X /* After this point we zero out CLEANUP_LABEL so that all
X other `returns' go to RETURN_LABEL. */
X cleanup_label = 0;
X }
X
X#if 1
X /* Cheap hack to get better code from GNU C++. Remove when cse is fixed. */
X if (exception_throw_decl && sets_exception_throw_decl == 0)
X expand_assignment (exception_throw_decl, integer_zero_node, 0, 0);
X#endif
X
X if (flag_handle_exceptions)
X {
X expand_end_try ();
X expand_start_except (0, 0);
X expand_end_except ();
X }
X expand_end_bindings (0, 0, 0);
X
X /* Get return value into reigster if that's where it's supposed to be. */
X if (original_result_rtx)
X fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
X
X /* Finish building code that will trigger warnings if users forget
X to make their functions return values. */
X if (no_return_label)
X {
X expand_null_return ();
X expand_label (no_return_label);
X }
X
X /* reset scope for C++: if we were in the scope of a class,
X then when we finish this function, we are not longer so.
X This cannot be done until we know for sure that no more
X class members will ever be referenced in this function
X (i.e., calls to destructors). */
X if (current_class_name)
X {
X ctype = current_class_type;
X popclass (1);
X }
X else
X pop_memoized_context (1);
X
X /* Forget about all overloaded functions defined in
X this scope which go away. */
X while (overloads_to_forget)
X {
X IDENTIFIER_GLOBAL_VALUE (TREE_PURPOSE (overloads_to_forget))
X = TREE_VALUE (overloads_to_forget);
X overloads_to_forget = TREE_CHAIN (overloads_to_forget);
X }
X
X /* Generate rtl for function exit. */
X expand_function_end (input_filename, lineno);
X
X /* This must come after expand_function_end because cleanups might
X have declarations (from inline functions) that need to go into
X this function's blocks. */
X assert (current_binding_level->parm_flag == 1);
X poplevel (1, 0, 1);
X
X /* So we can tell if jump_optimize sets it to 1. */
X current_function_returns_null = 0;
X
X if (TREE_EXTERNAL (fndecl) && ! TREE_PUBLIC (fndecl)
X /* This function is just along for the ride. If we can make
X it inline, that's great. Otherwise, just punt it. */
X && (TREE_INLINE (fndecl) == 0
X || flag_no_inline
X || function_cannot_inline_p (fndecl)))
X {
X extern int rtl_dump_and_exit;
X int old_rtl_dump_and_exit = rtl_dump_and_exit;
X int inline_spec = TREE_INLINE (fndecl);
X
X /* This throws away the code for FNDECL. */
X rtl_dump_and_exit = 1;
X /* This throws away the memory of the code for FNDECL. */
X if (flag_no_inline)
X TREE_INLINE (fndecl) = 0;
X rest_of_compilation (fndecl);
X rtl_dump_and_exit = old_rtl_dump_and_exit;
X TREE_INLINE (fndecl) = inline_spec;
X }
X else
X /* Run the optimizers and output the assembler code for this function. */
X rest_of_compilation (fndecl);
X
X if (ctype && TREE_ASM_WRITTEN (fndecl))
X CLASSTYPE_ASM_WRITTEN (ctype) = 1;
X
X /* Since we don't normally go through c_expand_return for constructors,
X this normally gets the wrong value.
X Also, named return values have their return codes emitted after
X NOTE_INSN_FUNCTION_END, confusing jump.c. */
X if (DECL_CONSTRUCTOR_P (fndecl)
X || DECL_NAME (DECL_RESULT (fndecl)) != value_identifier)
X current_function_returns_null = 0;
X
X if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
X warning ("`volatile' function does return");
X else if (warn_return_type && current_function_returns_null
X && TREE_TYPE (fntype) != void_type_node)
X /* If this function returns non-void and control can drop through,
X complain. */
X warning ("control reaches end of non-void function");
X /* With just -W, complain only if function returns both with
X and without a value. */
X else if (extra_warnings
X && current_function_returns_value && current_function_returns_null)
X warning ("this function may return with or without a value");
X
X /* Free all the tree nodes making up this function. */
X /* Switch back to allocating nodes permanently
X until we start another function. */
X permanent_allocation ();
X
X if (DECL_SAVED_INSNS (fndecl) == 0)
X {
X /* Stop pointing to the local nodes about to be freed. */
X /* But DECL_INITIAL must remain nonzero so we know this
X was an actual function definition. */
X DECL_INITIAL (fndecl) = error_mark_node;
X if (! DECL_CONSTRUCTOR_P (fndecl)
X || !TYPE_USES_VIRTUAL_BASECLASSES (TYPE_METHOD_BASETYPE (fntype)))
X DECL_ARGUMENTS (fndecl) = 0;
X }
X
X /* Let the error reporting routines know that we're outside a function. */
X current_function_decl = NULL_TREE;
X named_label_uses = NULL_TREE;
X clear_anon_parm_name ();
X}
X
X/* Create the FUNCTION_DECL for a function definition.
X LINE1 is the line number that the definition absolutely begins on.
X LINE2 is the line number that the name of the function appears on.
X DECLSPECS and DECLARATOR are the parts of the declaration;
X they describe the function's name and the type it returns,
X but twisted together in a fashion that parallels the syntax of C.
X
X This function creates a binding context for the function body
X as well as setting up the FUNCTION_DECL in current_function_decl.
X
X Returns a FUNCTION_DECL on success.
X
X If the DECLARATOR is not suitable for a function (it defines a datum
X instead), we return 0, which tells yyparse to report a parse error.
X
X May return void_type_node indicating that this method is actually
X a friend. See grokfield for more details.
X
X Came here with a `.pushlevel' .
X
X DO NOT MAKE ANY CHANGES TO THIS CODE WITHOUT MAKING CORRESPONDING
X CHANGES TO CODE IN `grokfield'. */
Xtree
Xstart_method (declspecs, declarator, raises)
X tree declarator, declspecs, raises;
X{
X tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, raises);
X
X /* Something too ugly to handle. */
X if (fndecl == 0)
X return 0;
X
X /* Pass friends other than inline friend functions back. */
X if (fndecl == void_type_node)
X return void_type_node;
X
X if (TREE_CODE (fndecl) != FUNCTION_DECL)
X /* Not a function, tell parser to report parse error. */
X return 0;
X
X if (DECL_IN_AGGR_P (fndecl))
X {
X if (IDENTIFIER_ERROR_LOCUS (DECL_NAME (fndecl)) != current_class_type)
X error_with_decl (fndecl, "`%s' is already defined in aggregate scope");
X return void_type_node;
X }
X
X if (flag_default_inline)
X TREE_INLINE (fndecl) = 1;
X
X /* We read in the parameters on the maybepermanent_obstack,
X but we won't be getting back to them until after we
X may have clobbered them. So the call to preserve_data
X will keep them safe. */
X preserve_data ();
X
X if (! DECL_FRIEND_P (fndecl))
X {
X if (TREE_CHAIN (fndecl) != NULL_TREE)
X /* Need a fresh node here so that we don't get circularity
X when we link these together. If FNDECL was a friend, then
X `pushdecl' does the right thing, which is nothing wrt its
X current value of TREE_CHAIN. */
X fndecl = copy_node (fndecl);
X
X if (DECL_CONSTRUCTOR_P (fndecl))
X grok_ctor_properties (current_class_type, fndecl);
X else if (OPERATOR_NAME_P (DECL_NAME (fndecl)))
X {
X TREE_OPERATOR (fndecl) = 1;
X grok_op_properties (fndecl);
X }
X }
X
X finish_decl (fndecl, NULL, NULL);
X
X /* Make a place for the parms */
X pushlevel (0);
X current_binding_level->parm_flag = 1;
X
X DECL_IN_AGGR_P (fndecl) = 1;
X return fndecl;
X}
X
X/* Go through the motions of finishing a function definition.
X We don't compile this method until after the whole class has
X been processed.
X
X FINISH_METHOD must return something that looks as though it
X came from GROKFIELD (since we are defining a method, after all).
X
X This is called after parsing the body of the function definition.
X STMTS is the chain of statements that makes up the function body.
X
X DECL is the ..._DECL that `start_method' provided. */
X
Xtree
Xfinish_method (decl)
X tree decl;
X{
X register tree fndecl = decl;
X tree old_initial;
X
X register tree link;
X
X if (decl == void_type_node)
X return decl;
X
X old_initial = DECL_INITIAL (fndecl);
X
X /* Undo the level for the parms (from start_method).
X This is like poplevel, but it causes nothing to be
X saved. Saving information here confuses symbol-table
X output routines. Besides, this information will
X be correctly output when this method is actually
X compiled. */
X
X /* Clear out the meanings of the local variables of this level;
X also record in each decl which block it belongs to. */
X
X for (link = current_binding_level->names; link; link = TREE_CHAIN (link))
X {
X if (DECL_NAME (link) != 0)
X IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0;
X DECL_CONTEXT (link) = 0;
X }
X
X /* Restore all name-meanings of the outer levels
X that were shadowed by this level. */
X
X for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
X IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
X for (link = current_binding_level->class_shadowed;
X link;
X link = TREE_CHAIN (link))
X IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
X
X#ifdef FIELD_XREF
X FIELD_xref_end_scope(current_binding_level,
X current_binding_level->level_chain,
X current_binding_level->parm_flag,
X current_binding_level->keep,
X current_binding_level->tag_transparent);
X#endif
X
X POP_BINDING_LEVEL;
X
X DECL_INITIAL (fndecl) = old_initial;
X if (DECL_FRIEND_P (fndecl))
X {
X if (current_lang_name == lang_name_cplusplus)
X CLASSTYPE_INLINE_FRIENDS (current_class_type)
X = tree_cons (NULL_TREE, fndecl, CLASSTYPE_INLINE_FRIENDS (current_class_type));
X return void_type_node;
X }
X return decl;
X}
X
X/* Called when a new struct TYPE is defined.
X If this structure or union completes the type of any previous
X variable declaration, lay it out and output its rtl. */
X
Xvoid
Xhack_incomplete_structures (type)
X tree type;
X{
X tree decl;
X
X if (current_binding_level->n_incomplete == 0)
X return;
X
X for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl))
X if (TREE_TYPE (decl) == type
X || (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
X && TREE_TYPE (TREE_TYPE (decl)) == type))
X {
X if (TREE_CODE (decl) == TYPE_DECL)
X layout_type (TREE_TYPE (decl));
X else
X {
X int toplevel = global_binding_level == current_binding_level;
X layout_decl (decl, 0);
X rest_of_decl_compilation (decl, 0, toplevel, 0);
X if (! toplevel)
X {
X expand_decl (decl);
X expand_decl_cleanup (decl, maybe_build_cleanup (decl));
X expand_decl_init (decl);
X }
X }
X --current_binding_level->n_incomplete;
X assert (current_binding_level->n_incomplete >= 0);
X }
X}
X
X/* Nonzero if presently building a cleanup. Needed because
X SAVE_EXPRs are not the right things to use inside of cleanups.
X They are only ever evaluated once, where the cleanup
X might be evaluated several times. In this case, a later evaluation
X of the cleanup might fill in the SAVE_EXPR_RTL, and it will
X not be valid for an earlier cleanup. */
X
Xint building_cleanup;
X
X/* If DECL is of a type which needs a cleanup, build that cleanup here.
X We don't build cleanups if just going for syntax checking, since
X fixup_cleanups does not know how to not handle them.
X
X Don't build these on the momentary obstack; they must live
X the life of the binding contour. */
Xtree
Xmaybe_build_cleanup (decl)
X tree decl;
X{
X tree type = TREE_TYPE (decl);
X if (TYPE_NEEDS_DESTRUCTOR (type))
X {
X int temp;
X tree rval;
X int old_building_cleanup = building_cleanup;
X building_cleanup = 1;
X if (TREE_CODE (decl) == PARM_DECL)
X {
X temp = allocation_temporary_p ();
X end_temporary_allocation ();
X }
X else
X temp = suspend_momentary ();
X
X if (TREE_CODE (type) == ARRAY_TYPE)
X rval = decl;
X else
X {
X mark_addressable (decl);
X rval = build1 (ADDR_EXPR, TYPE_POINTER_TO (type), decl);
X }
X rval = build_delete (TREE_TYPE (rval), rval, integer_two_node,
X LOOKUP_NORMAL, 0);
X
X if (TYPE_LANG_SPECIFIC (type)
X && ! TYPE_HAS_DESTRUCTOR (type)
X && TYPE_USES_VIRTUAL_BASECLASSES (type))
X rval = build_compound_expr (tree_cons (NULL_TREE, rval,
X build_tree_list (NULL_TREE, build_vbase_delete (type, decl))));
X
X current_binding_level->have_cleanups = 1;
X current_binding_level->more_exceptions_ok = 0;
X
X if (TREE_CODE (decl) == PARM_DECL)
X {
X if (temp)
X resume_temporary_allocation ();
X }
X else
X resume_momentary (temp);
X
X building_cleanup = old_building_cleanup;
X
X return rval;
X }
X return 0;
X}
X
Xtree
Xcleanup_after_call (expr)
X tree expr;
X{
X tree type = TREE_TYPE (expr);
X tree decl = get_temp_name (type, 0);
X tree rval = build (WITH_CLEANUP_EXPR, type,
X build (INIT_EXPR, type, decl, expr), 0,
X maybe_build_cleanup (decl));
X return rval;
X}
X
X/* Expand a C++ expression at the statement level.
X This is needed to ferret out nodes which have UNKNOWN_TYPE.
X The C++ type checker should get all of these out when
X expressions are combined with other, type-providing, expressions,
X leaving only orphan expressions, such as:
X
X &class::bar; / / takes its address, but do nothing with it.
X
X */
Xvoid
Xcplus_expand_expr_stmt (exp)
X tree exp;
X{
X if (TREE_TYPE (exp) == unknown_type_node)
X {
X if (TREE_CODE (exp) == ADDR_EXPR)
X {
X if (TREE_CODE (TREE_OPERAND (exp, 0)) == OP_IDENTIFIER)
X error ("unresolved reference to user-defined operator");
X else
X error ("address of overloaded function with no contextual type information");
X }
X else if (TREE_CODE (exp) == TREE_LIST)
X error ("address of overloaded function with no contextual type information");
X else if (TREE_CODE (exp) == OP_IDENTIFIER)
X error ("unresolved reference to user-defined operator");
X else if (TREE_CODE (exp) == COMPONENT_REF)
X warning ("useless reference to a member function name, did you forget the ()?");
X }
X else
X {
X int remove_implicit_immediately = 0;
X
X if (TREE_CODE (exp) == CALL_EXPR
X && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (exp)))
X exp = cleanup_after_call (exp);
X else if (TREE_CODE (exp) == FUNCTION_DECL)
X warning_with_decl (exp, "reference, not call, to function `%s'");
X if (TREE_RAISES (exp))
X {
X assert (flag_handle_exceptions);
X if (flag_handle_exceptions == 2)
X {
X if (! current_binding_level->more_exceptions_ok)
X {
X extern struct nesting *nesting_stack, *block_stack;
X
X remove_implicit_immediately
X = (nesting_stack != block_stack);
X cplus_expand_start_try (1);
X }
X current_binding_level->have_exceptions = 1;
X }
X }
X expand_expr_stmt (exp);
X if (remove_implicit_immediately)
X pop_implicit_try_blocks (NULL_TREE);
X }
X
X /* Clean up any pending cleanups. This happens when a function call
X returns a cleanup-needing value that nobody uses. */
X expand_cleanups_to (NULL_TREE);
X}
X
X/* When a stmt has been parsed, this function is called.
X
X Currently, this function only does something within a
X constructor's scope: if a stmt has just assigned to this,
X and we are in a derived class, we call `emit_base_init'. */
X
Xvoid
Xfinish_stmt ()
X{
X extern struct nesting *cond_stack, *loop_stack, *case_stack;
X
X
X if (current_function_assigns_this
X || ! current_function_just_assigned_this)
X return;
X if (DECL_CONSTRUCTOR_P (current_function_decl))
X {
X /* Constructors must wait until we are out of control
X zones before calling base constructors. */
X if (cond_stack || loop_stack || case_stack)
X return;
X emit_insns (base_init_insns);
X check_base_init (current_class_type);
X }
X current_function_assigns_this = 1;
X}
X
Xvoid
Xpop_implicit_try_blocks (decl)
X tree decl;
X{
X if (decl)
X {
X assert (current_binding_level->parm_flag == 3);
X current_binding_level->names = TREE_CHAIN (decl);
X }
X
X while (current_binding_level->parm_flag == 3)
X {
X tree name = get_identifier ("(compiler error)");
X tree orig_ex_type = current_exception_type;
X tree orig_ex_decl = current_exception_decl;
X tree orig_ex_obj = current_exception_object;
X tree decl = cplus_expand_end_try (2), decls;
X tree current_exception_ptr;
X
X /* @@ It would be nice to make all these point
X to exactly the same handler. */
X /* Start hidden EXCEPT. */
X cplus_expand_start_except (name, decl);
X /* reraise ALL. */
X cplus_expand_reraise (NULL_TREE);
X current_exception_type = orig_ex_type;
X current_exception_decl = orig_ex_decl;
X current_exception_object = orig_ex_obj;
X /* This will reraise for us. */
X cplus_expand_end_except (error_mark_node);
X }
X
X if (decl)
X {
X TREE_CHAIN (decl) = current_binding_level->names;
X current_binding_level->names = decl;
X }
X}
X
X#ifdef FIELD_XREF
Xstatic void
XFIELD_end_scope(lvl)
X struct binding_level * lvl;
X{
X FIELD_xref_end_scope(lvl,
X lvl->level_chain,
X lvl->parm_flag,
X lvl->keep,
X lvl->tag_transparent);
X};
X
X#endif
X
X/* Push a cleanup onto the current binding contour that will cause
X ADDR to be cleaned up, in the case that an exception propagates
X through its binding contour. */
X
Xvoid
Xpush_exception_cleanup (addr)
X tree addr;
X{
X tree decl = build_decl (VAR_DECL, get_identifier (EXCEPTION_CLEANUP_NAME), ptr_type_node);
X tree cleanup;
X
X decl = pushdecl (decl);
X TREE_REGDECL (decl) = 1;
X store_init_value (decl, addr);
X expand_decl (decl);
X expand_decl_init (decl);
X
X cleanup = build (COND_EXPR, integer_type_node,
X build (NE_EXPR, integer_type_node,
X decl, integer_zero_node),
X build_delete (TREE_TYPE (addr), decl,
X lookup_name (in_charge_identifier),
X LOOKUP_NORMAL, 0),
X integer_zero_node);
X expand_decl_cleanup (decl, cleanup);
X}
X
X/* For each binding contour, emit code that deactivates the
X exception cleanups. All other cleanups are left as they were. */
X
Xstatic void
Xdeactivate_exception_cleanups ()
X{
X struct binding_level *b = current_binding_level;
X tree xyzzy = get_identifier (EXCEPTION_CLEANUP_NAME);
X while (b != class_binding_level)
X {
X if (b->parm_flag == 3)
X {
X tree decls = b->names;
X while (decls)
X {
X if (DECL_NAME (decls) == xyzzy)
X expand_assignment (decls, integer_zero_node, 0, 0);
X decls = TREE_CHAIN (decls);
X }
X }
X b = b->level_chain;
X }
X}
!EOF
exit 0