home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
gcc-2.3.3-src.lha
/
GNU
/
src
/
amiga
/
gcc-2.3.3
/
cp-except.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
37KB
|
1,210 lines
/* Handle exceptional things in C++.
Copyright (C) 1989, 1992 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* High-level class interface. */
#define NULL 0
/* This should be part of `ansi_opname', or at least be defined by the std. */
#define EXCEPTION_NAME_PREFIX "__ex"
#define EXCEPTION_NAME_LENGTH 4
#include "config.h"
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
#include "flags.h"
/* On Suns this can get you to the right definition if you
set the right value for TARGET. */
#include <setjmp.h>
#ifdef sequent
/* Can you believe they forgot this? */
#define _JBLEN 11
#endif
#ifndef _JBLEN
#define _JBLEN (sizeof(jmp_buf)/sizeof(int))
#endif
void init_exception_processing ();
void init_exception_processing_1 ();
/* If non-zero, a VAR_DECL whose cleanup will cause a throw to the
next exception handler. Its value says whether to throw or not.
In the case of functions which do not issue a RAISE, it should be
possible to optimize away this VAR_DECL (and overhead associated
with it). */
tree exception_throw_decl;
/* Use this to know that we did not set `exception_throw_decl',
until GCC optimizer is smart enough to figure it out for itself. */
int sets_exception_throw_decl;
/* The exception `type' currently in scope, or NULL_TREE if none. */
tree current_exception_type;
/* The exception handler object for the given scope. */
tree current_exception_decl;
rtx current_exception_name_as_rtx;
rtx current_exception_parms_as_rtx;
/* The ``object'' view of the current exception parameters.
We cast up from the `parms' field to `current_exception_type'. */
tree current_exception_object;
/* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception'
after default conversion. Maybe later they will get built-in. */
static tree BISJ, BILJ, BIR, BIUE;
/* Local variables which give the appearance that exception
handling is part of the language and the execution model. */
/* The type of the exception handler stack. */
static tree EHS_type;
/* The global handler stack. */
tree EHS_decl;
/* Cached component refs to fields of `EHS_decl'. */
static tree EHS_prev, EHS_handler, EHS_parms, EHS_name;
static rtx EHS_parms_as_rtx, EHS_name_as_rtx;
/* The parameter names of this exception type. */
static tree last_exception_fields;
static tree last_exception_field_types;
/* When ID is VOID_TYPE_NODE, it means ``raise all''.
Cannot be inline, since it uses `alloca', and that
breaks code which pushes the result of this function
on the stack. */
static tree
exception_object_name (prefix, id)
tree prefix;
tree id;
{
/* First, cons up the `name' of this exception. */
char *name;
int length = (id == void_type_node ? 3 : IDENTIFIER_LENGTH (id)) + EXCEPTION_NAME_LENGTH;
if (prefix)
length += IDENTIFIER_LENGTH (prefix) + 2;
name = (char *)alloca (length);
strcpy (name, EXCEPTION_NAME_PREFIX);
length = EXCEPTION_NAME_LENGTH;
if (prefix)
{
strcpy (name + length, IDENTIFIER_POINTER (prefix));
name[length + IDENTIFIER_LENGTH (prefix)] = JOINER;
length += IDENTIFIER_LENGTH (prefix) + 1;
}
if (id == void_type_node)
strcpy (name + length, "all");
else
strcpy (name + length, IDENTIFIER_POINTER (id));
return get_identifier (name);
}
tree
lookup_exception_cname (ctype, cname, raise_id)
tree ctype, cname;
tree raise_id;
{
tree this_cname = TREE_PURPOSE (raise_id);
if (this_cname == NULL_TREE)
{
if (cname)
{
tree name = TREE_VALUE (raise_id);
if (purpose_member (name, CLASSTYPE_TAGS (ctype)))
this_cname = cname;
}
}
else if (this_cname == void_type_node)
this_cname = NULL_TREE;
else if (TREE_CODE (this_cname) != IDENTIFIER_NODE)
{
sorry ("multiple scope refs in `cplus_expand_raise_stmt'");
this_cname = error_mark_node;
}
return this_cname;
}
tree
lookup_exception_tname (oname)
tree oname;
{
return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH);
}
tree
lookup_exception_object (cname, name, complain)
tree cname, name;
int complain;
{
tree oname;
tree decl;
if (cname == void_type_node)
cname = NULL_TREE;
else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE)
{
sorry ("multiple scope refs in `lookup_exception_object'");
cname = NULL_TREE;
}
oname = exception_object_name (cname, name);
decl = IDENTIFIER_GLOBAL_VALUE (oname);
if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
{
if (complain)
{
push_obstacks_nochange ();
if (cname)
error ("no exception name object for name `%s::%s'",
IDENTIFIER_POINTER (cname),
IDENTIFIER_POINTER (name));
else
error ("no exception name object for name `%s'",
IDENTIFIER_POINTER (name));
end_temporary_allocation ();
/* Avoid further error messages. */
pushdecl_top_level (build_lang_field_decl (VAR_DECL,
exception_object_name (cname, name),
error_mark_node));
pop_obstacks ();
}
return NULL_TREE;
}
return decl;
}
tree
lookup_exception_type (ctype, cname, raise_id)
tree ctype, cname;
tree raise_id;
{
tree name = TREE_VALUE (raise_id);
tree purpose = TREE_PURPOSE (raise_id);
if (cname && purpose == NULL_TREE)
purpose = cname;
if (purpose && purpose != void_type_node)
{
tree link = NULL_TREE;
if (TREE_CODE (purpose) != IDENTIFIER_NODE)
{
sorry ("multiple scope refs in `lookup_exception_type'");
TREE_PURPOSE (raise_id) = NULL_TREE;
return NULL_TREE;
}
if (! is_aggr_typedef (purpose, 1))
return NULL_TREE;
ctype = IDENTIFIER_TYPE_VALUE (purpose);
link = purpose_member (name, CLASSTYPE_TAGS (ctype));
if (link)
return TREE_VALUE (link);
}
ctype = lookup_name (name, 1);
if (ctype && TREE_CODE (ctype) == TYPE_DECL)
ctype = TREE_TYPE (ctype);
if (ctype && TREE_CODE (ctype) == RECORD_TYPE
&& CLASSTYPE_DECLARED_EXCEPTION (ctype))
return ctype;
return NULL_TREE;
}
tree
finish_exception (e, list_of_fieldlists)
tree e;
tree list_of_fieldlists;
{
tree parmtypes = NULL_TREE, name_field;
tree cname = TYPE_NAME (e);
if (TREE_CODE (cname) == TYPE_DECL)
cname = DECL_NAME (cname);
if (last_exception_fields)
error ("cannot declare exceptions within exceptions");
if (list_of_fieldlists && ! ANON_AGGRNAME_P (cname))
error_with_aggr_type (e, "exception name `%s' must follow body declaration");
if (list_of_fieldlists)
{
tree prev, field;
/* Note: no public, private, or protected allowed. */
if (TREE_CHAIN (list_of_fieldlists))
error ("visibility declarations invalid in exception declaration");
else if (TREE_PURPOSE (list_of_fieldlists) != (tree)visibility_default)
error ("visibility declarations invalid in exception declaration");
TREE_PURPOSE (list_of_fieldlists) = (tree)visibility_default;
/* Note also: no member function declarations allowed. */
for (prev = 0, field = TREE_VALUE (list_of_fieldlists);
field; prev = field, field = TREE_CHAIN (field))
{
switch (TREE_CODE (field))
{
case FIELD_DECL:
/* ok. */
parmtypes = tree_cons (NULL_TREE, TREE_TYPE (field), parmtypes);
continue;
case FUNCTION_DECL:
error_with_decl (field, "declaration of function `%s' in exception invalid");
break;
case VAR_DECL:
if (TREE_STATIC (