+Fri May 6 01:25:38 1994 Mike Stump (mrs@cygnus.com)
+
+ Add alpha exception handling support to the compiler.
+ Quick and dirty backend in except.c.
+
+ * cp/*: Remove most remnants of old exception handling support.
+ * decl.c (finish_function): Call expand_exception_blocks to put
+ the exception hanlding blocks at the end of the function.
+ * dec.c (hack_incomplete_structures): Make sure expand_decl_cleanup
+ comes after expand_decl_init.
+ * except.c: Reimplementation.
+ * expr.c (cplus_expand_expr): Handle THROW_EXPRs.
+ * lex.c (init_lex): Always have catch, try and throw be reserved
+ words, so that we may always parse exception handling.
+ * parse.y: Cleanup to support new interface into exception handling.
+ * tree.def (THROW_EXPR): Add.
+
+Thu May 5 17:35:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+
+ * parse.y (simple_stmt, for loops): Use implicitly_scoped_stmt.
+ (various): Lose .kindof_pushlevel and partially_scoped_stmt.
+
+Thu May 5 16:17:27 1994 Kung Hsu (kung@mexican.cygnus.com)
+
+ * parse.y (already_scoped_stmt): move expand_end_binding() to
+ fix the unmatched LBB/LBE in stabs.
+
+Thu May 5 14:36:17 1994 Jason Merrill (jason@deneb.cygnus.com)
+
+ * decl.c (set_nested_typename): Set TREE_MANGLED on the new
+ identifiers.
+ (pushdecl): Check TREE_MANGLED.
+ (xref_tag): Ditto.
+ * cp-tree.h (TREE_MANGLED): This identifier is a
+ DECL_NESTED_TYPENAME (named to allow for future use to denote
+ mangled function names as well).
+
+ Implement inconsistency checking specified in [class.scope0].
+ * decl.c (lookup_name_real): Don't set ICV here after all.
+ (finish_enum): Also set the type of the enumerators themselves.
+ (build_enumerator): Put the CONST_DECL in the list instead of its
+ initial value.
+ (pushdecl_class_level): Check inconsistent use of a name in the
+ class body.
+ * class.c (finish_struct): Check inconsistent use of a name in the
+ class body. Don't set DECL_CONTEXT on types here anymore.
+ * parse.y (qualified_type_name): Note that the identifier has now
+ been used (as a type) in the class body.
+ * lex.c (do_identifier): Note that the identifier has now been used
+ (as a constant) in the class body.
+ * error.c (dump_decl): Print type and enum decls better.
+
Thu May 5 09:35:35 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
* typeck.c (build_modify_expr): Warn about assignment to `this'.
need_vtbl = maybe_needed;
instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (basetype), instance);
}
- else if (instance == current_exception_object)
- {
- instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (current_exception_type),
- TREE_OPERAND (current_exception_object, 0));
- mark_addressable (TREE_OPERAND (current_exception_object, 0));
- result = build_field_call (TYPE_BINFO (current_exception_type),
- instance_ptr, name, parms);
- if (result)
- return result;
- cp_error ("exception member `%D' cannot be invoked", name);
- return error_mark_node;
- }
else
{
/* The MAIN_VARIANT of the type that `instance_ptr' winds up being. */
int warn_anon;
{
extern int interface_only, interface_unknown;
- extern tree EHS_type;
int old;
int round_up_size = 1;
if (! fields)
fields = x;
last_x = x;
- DECL_CONTEXT (x) = t;
continue;
}
+ /* Check for inconsistent use of this name in the class body.
+ Enums, types and static vars have already been checked. */
+ if (TREE_CODE (x) != CONST_DECL && TREE_CODE (x) != VAR_DECL)
+ {
+ tree name = DECL_NAME (x);
+ tree icv = name ? IDENTIFIER_CLASS_VALUE (name) : NULL_TREE;
+
+ /* Don't complain about constructors. */
+ if (icv && name != constructor_name (current_class_type))
+ {
+ cp_error_at ("declaration of identifier `%D' as `%+#D'",
+ name, x);
+ cp_error_at ("conflicts with other use in class as `%#D'",
+ icv);
+ }
+ }
if (TREE_CODE (x) == FUNCTION_DECL)
{
fn_fields = default_fn;
}
- /* Create default copy constructor, if needed. Don't do it for
- the exception handler. */
- if (! TYPE_HAS_INIT_REF (t) && ! cant_synth_copy_ctor && t != EHS_type)
+ /* Create default copy constructor, if needed. */
+ if (! TYPE_HAS_INIT_REF (t) && ! cant_synth_copy_ctor)
{
/* ARM 12.18: You get either X(X&) or X(const X&), but
not both. --Chip */
DEFTREECODE (NEW_EXPR, "nw_expr", "e", 3)
DEFTREECODE (VEC_NEW_EXPR, "vec_nw_expr", "e", 3)
-/* Distinguish variables that are only used to identify exceptions
- that were caught. Only the DECL_NAME (and TREE_CHAIN)
- is really used. */
-DEFTREECODE (CPLUS_CATCH_DECL, "catch_decl", "d", 0)
+/* A throw expression. operand 0 is the expression, if there was one,
+ else it is NULL_TREE. */
+DEFTREECODE (THROW_EXPR, "throw_expr", "e", 1)
/* Template definition. The following fields have the specified uses,
although there are other macros in cp-tree.h that should be used for
extern int flag_elide_constructors;
-/* Nonzero means recognize and handle exception handling constructs. */
-
-extern int flag_handle_exceptions;
-
/* Nonzero means handle things in ANSI, instead of GNU fashion. */
extern int flag_ansi;
/* Nonzero means recognize and handle ansi-style exception handling
constructs. */
-extern int flag_ansi_exceptions;
+extern int flag_handle_exceptions;
/* Nonzero means do argument matching for overloading according to the
ANSI rules, rather than what g++ used to believe to be correct. */
or virtual baseclasses. */
#define TYPE_USES_COMPLEX_INHERITANCE(NODE) (TREE_LANG_FLAG_1 (NODE))
+/* Nonzero in IDENTIFIER_NODE means that this name is not the name the user
+ gave; it's a DECL_NESTED_TYPENAME. Someone may want to set this on
+ mangled function names, too, but it isn't currently. */
+#define TREE_MANGLED(NODE) (TREE_LANG_FLAG_0 (NODE))
+
#if 0 /* UNUSED */
/* Nonzero in IDENTIFIER_NODE means that this name is overloaded, and
should be looked up in a non-standard way. */
-#define TREE_OVERLOADED(NODE) (TREE_LANG_FLAG_0 (NODE))
#define DECL_OVERLOADED(NODE) (DECL_LANG_FLAG_4 (NODE))
#endif
/* in edsel.c */
/* in except.c */
-extern tree lookup_exception_cname PROTO((tree, tree, tree));
-extern tree lookup_exception_tname PROTO((tree));
-extern tree lookup_exception_object PROTO((tree, tree, int));
-extern tree lookup_exception_type PROTO((tree, tree, tree));
-extern tree finish_exception PROTO((tree, tree));
-extern void finish_exception_decl PROTO((tree, tree));
-extern void end_exception_decls PROTO((void));
-extern void cplus_expand_start_try PROTO((int));
-extern tree cplus_expand_end_try PROTO((int));
-extern void cplus_expand_start_except PROTO((tree, tree));
-extern void cplus_expand_end_except PROTO((tree));
-extern void cplus_expand_raise PROTO((tree, tree, tree, int));
-extern tree ansi_exception_object_lookup PROTO((tree));
-extern void cplus_expand_throw PROTO((tree));
-extern tree cplus_expand_start_catch PROTO((tree));
-extern tree ansi_expand_start_catch PROTO((tree));
-extern void cplus_expand_end_catch PROTO((int));
-extern void cplus_expand_reraise PROTO((tree));
-extern void setup_exception_throw_decl PROTO((void));
+
+extern void start_protect PROTO((void));
+extern void end_protect PROTO((tree));
+extern void expand_exception_blocks PROTO((void));
+extern void expand_start_try_stmts PROTO((void));
+extern void expand_end_try_stmts PROTO((void));
+extern void expand_start_all_catch PROTO((void));
+extern void expand_end_all_catch PROTO((void));
+extern void start_catch_block PROTO((tree, tree));
+extern void end_catch_block PROTO((void));
+extern void expand_throw PROTO((tree));
+extern void build_exception_table PROTO((void));
+extern tree build_throw PROTO((tree));
extern void init_exception_processing PROTO((void));
-extern void init_exception_processing_1 PROTO((void));
/* in expr.c */
/* skip cplus_expand_expr */
extern void GNU_xref_hier PROTO((char *, char *, int, int, int));
extern void GNU_xref_member PROTO((tree, tree));
-#define in_try_block(X) (0)
-#define in_exception_handler(X) (0)
-#define expand_raise(X) (0)
-#define expand_start_try(A,B,C) ((void)0)
-#define expand_end_try() ((void)0)
-#define expand_start_except(A,B) ((void)0)
-#define expand_escape_except() (0)
-#define expand_end_except() (NULL_TREE)
-#define expand_catch(X) (0)
-#define expand_catch_default() (0)
-#define expand_end_catch() (0)
-
/* -- end of C++ */
#endif /* not _CP_TREE_H */
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
+extern tree builtin_return_address_fndecl;
+
extern struct obstack permanent_obstack;
extern int current_class_depth;
static tree lookup_nested_type PROTO((tree, tree));
static char *redeclaration_error_message PROTO((tree, tree));
static void grok_op_properties PROTO((tree, int, int));
-static void deactivate_exception_cleanups PROTO((void));
tree define_function
PROTO((char *, tree, enum built_in_function, void (*)(), char *));
tree ctor_label;
-/* A FUNCTION_DECL which can call `unhandled_exception'.
- Not necessarily the one that the user will declare,
- but sufficient to be called by routines that want to abort the program. */
-
-tree unhandled_exception_fndecl;
-
/* A FUNCTION_DECL which can call `abort'. Not necessarily the
one that the user will declare, but sufficient to be called
by routines that want to abort the program. */
unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1;
- /* Nonzero if this level can safely have additional
- exception-raising statements added to it. */
- unsigned more_exceptions_ok : 1;
- unsigned have_exceptions : 1;
-
/* Nonzero if we should accept any name as an identifier in
this scope. This happens in some template definitions. */
unsigned accept_any : 1;
current_binding_level = newlevel;
newlevel->tag_transparent = tag_transparent;
newlevel->more_cleanups_ok = 1;
- newlevel->more_exceptions_ok = 1;
newlevel->keep = keep;
#if defined(DEBUG_CP_BINDING_LEVELS)
newlevel->binding_depth = binding_depth;
current_binding_level->parm_flag = 1;
}
-/* Identify this binding level as a level of a default exception handler. */
-
-void
-declare_implicit_exception ()
-{
- current_binding_level->parm_flag = 3;
-}
-
-/* Nonzero if current binding contour contains expressions
- that might raise exceptions. */
-
-int
-have_exceptions_p ()
-{
- return current_binding_level->have_exceptions;
-}
-
void
declare_uninstantiated_type_level ()
{
}
/* Take care of compiler's internal binding structures. */
- if (tmp == 2 && !implicit_try_block)
+ if (tmp == 2 && class_binding_level)
{
#if 0
/* We did not call push_momentary for this
fprintf (stderr, " more-cleanups-ok");
if (lvl->have_cleanups)
fprintf (stderr, " have-cleanups");
- if (lvl->more_exceptions_ok)
- fprintf (stderr, " more-exceptions-ok");
- if (lvl->have_exceptions)
- fprintf (stderr, " have-exceptions");
fprintf (stderr, "\n");
if (lvl->names)
{
sprintf (buf, "%s::%s", IDENTIFIER_POINTER (classname),
IDENTIFIER_POINTER (name));
DECL_NESTED_TYPENAME (decl) = get_identifier (buf);
+ TREE_MANGLED (DECL_NESTED_TYPENAME (decl)) = 1;
/* This is a special usage of IDENTIFIER_TYPE_VALUE which have no
correspondence in any binding_level. This is ok since the
/* Keep count of variables in this level with incomplete type. */
if (TREE_CODE (x) != TEMPLATE_DECL
- && TREE_CODE (x) != CPLUS_CATCH_DECL
&& TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
&& PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE))
{
{
if (current_class_name)
{
- if (!DECL_NESTED_TYPENAME (TYPE_NAME (TREE_TYPE (x))))
+ if (! TREE_MANGLED (name))
set_nested_typename (x, current_class_name, DECL_NAME (x),
TREE_TYPE (x));
}
if (name)
{
+ if (TYPE_BEING_DEFINED (current_class_type))
+ {
+ /* Check for inconsistent use of this name in the class body.
+ Types, enums, and static vars are checked here; other
+ members are checked in finish_struct. */
+ tree icv = IDENTIFIER_CLASS_VALUE (name);
+
+ if (icv)
+ {
+ cp_error ("declaration of identifier `%D' as `%#D'", name, x);
+ cp_error_at ("conflicts with previous use in class as `%#D'",
+ icv);
+ }
+ }
+
push_class_level_binding (name, x);
if (TREE_CODE (x) == TYPE_DECL)
{
/* Try to find values from base classes if we are presently
defining a type. We are presently only interested in
TYPE_DECLs. */
- {
- val = lookup_field (current_class_type, name, 0, 1);
- if (val)
- pushdecl_class_level (val);
- }
+ val = lookup_field (current_class_type, name, 0, 1);
/* yylex() calls this with -2, since we should never start digging for
the nested name at the point where we haven't even, for example,
builtin_function ("__builtin_constant_p", int_ftype_int,
BUILT_IN_CONSTANT_P, NULL_PTR);
+ builtin_return_address_fndecl =
builtin_function ("__builtin_return_address",
build_function_type (ptr_type_node,
tree_cons (NULL_TREE,
build_function_type (void_type_node, void_list_node),
NOT_BUILT_IN, 0, 0);
- unhandled_exception_fndecl
- = define_function ("__unhandled_exception",
- build_function_type (void_type_node, NULL_TREE),
- NOT_BUILT_IN, 0, 0);
-
/* Perform other language dependent initializations. */
init_class_processing ();
init_init_processing ();
init_search_processing ();
if (flag_handle_exceptions)
- {
- if (flag_handle_exceptions == 2)
- /* Too much trouble to inline all the trys needed for this. */
- flag_this_is_variable = 2;
- init_exception_processing ();
- }
+ init_exception_processing ();
if (flag_gc)
init_gc_processing ();
if (flag_no_inline)
push_obstacks (&permanent_obstack, &permanent_obstack);
pushclass (t, 0);
- finish_exception (t, NULL_TREE);
ename = TYPE_NAME (t);
if (TREE_CODE (ename) == TYPE_DECL)
ename = DECL_NAME (ename);
decl = build_lang_field_decl (VAR_DECL, ename, t);
- finish_exception_decl (current_class_name, decl);
- end_exception_decls ();
pop_obstacks ();
}
if (type != error_mark_node && IS_AGGR_TYPE (type)
&& CLASSTYPE_DECLARED_EXCEPTION (type))
{
- finish_exception_decl (NULL_TREE, decl);
CLASSTYPE_GOT_SEMICOLON (type) = 1;
goto finish_end;
}
cleanup = TREE_OPERAND (init, 2);
init = TREE_OPERAND (init, 0);
current_binding_level->have_cleanups = 1;
- current_binding_level->more_exceptions_ok = 0;
}
else
cleanup = maybe_build_cleanup (decl);
if (was_temp)
end_temporary_allocation ();
- /* If we are in need of a cleanup, get out of any implicit
- handlers that have been established so far. */
- if (cleanup && current_binding_level->parm_flag == 3)
- {
- pop_implicit_try_blocks (decl);
- current_binding_level->more_exceptions_ok = 0;
- }
-
if (TREE_CODE (decl) == VAR_DECL
&& current_binding_level != global_binding_level
&& ! TREE_STATIC (decl)
expand_decl (decl);
else if (cleanup)
{
- expand_decl_cleanup (NULL_TREE, cleanup);
+ /* XXX: Why don't we use decl here? */
+ /* Ans: Because it was already expanded? */
+ if (! expand_decl_cleanup (NULL_TREE, cleanup))
+ cp_error ("parser lost in parsing declaration of `%D'",
+ decl);
/* Cleanup used up here. */
cleanup = NULL_TREE;
}
decl = build_lang_field_decl (VAR_DECL, declarator, type);
if (ctype == NULL_TREE)
ctype = current_class_type;
- finish_exception_decl (TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL
- ? TYPE_IDENTIFIER (ctype) : TYPE_NAME (ctype), decl);
return void_type_node;
}
else if (TYPE_SIZE (type) == NULL_TREE && !staticp
* and don't try to find it as a type. */
xref_next_defn = 0;
if (t && TYPE_CONTEXT(t))
- {
- extern char *index();
- char *p;
- if ((p = index(IDENTIFIER_POINTER(name), ':')) && *(p+1) == ':')
+ {
+ if (TREE_MANGLED (name))
ref = t;
else
ref = lookup_tag (code, name, b, 1);
HOST_WIDE_INT value = TREE_INT_CST_LOW (TREE_VALUE (values));
TREE_TYPE (TREE_VALUE (values)) = enumtype;
+ TREE_TYPE (DECL_INITIAL (TREE_VALUE (values))) = enumtype;
minvalue = maxvalue = value;
for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
}
else
{
- error ("enumerator value for `%s' not integer constant",
- IDENTIFIER_POINTER (name));
+ cp_error ("enumerator value for `%D' not integer constant", name);
value = NULL_TREE;
}
}
TREE_TYPE (value) = integer_type_node;
}
- result = saveable_tree_cons (name, value, NULL_TREE);
-
/* C++ associates enums with global, function, or class declarations. */
decl = current_scope ();
if (enum_next_value == integer_one_node)
enum_next_value = copy_node (enum_next_value);
+ result = saveable_tree_cons (name, decl, NULL_TREE);
return result;
}
tree declarator, declspecs, raises;
int pre_parsed_p;
{
- extern tree EHS_decl;
tree decl1, olddecl;
tree ctype = NULL_TREE;
tree fntype;
extern int used_extern_spec;
int doing_friend = 0;
- if (flag_handle_exceptions && EHS_decl == NULL_TREE)
- init_exception_processing_1 ();
-
/* Sanity check. */
my_friendly_assert (TREE_VALUE (void_list_node) == void_type_node, 160);
my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161);
register tree fndecl = current_function_decl;
register tree parm;
int parms_have_cleanups = 0;
- tree eh_decl;
/* This is either a chain of PARM_DECLs (when a prototype is used). */
tree specparms = current_function_parms;
/* Create a binding level for the parms. */
expand_start_bindings (0);
- /* Prepare to catch raises, if appropriate. */
- if (flag_handle_exceptions)
- {
- /* Get this cleanup to be run last, since it
- is a call to `longjmp'. */
- setup_exception_throw_decl ();
- eh_decl = current_binding_level->names;
- current_binding_level->names = TREE_CHAIN (current_binding_level->names);
- }
- if (flag_handle_exceptions)
- expand_start_try (integer_one_node, 0, 1);
-
if (specparms != NULL_TREE)
{
/* This case is when the function was defined with an ANSI prototype.
if (cleanup)
{
expand_decl (parm);
- expand_decl_cleanup (parm, cleanup);
+ if (! expand_decl_cleanup (parm, cleanup))
+ cp_error ("parser lost in parsing declaration of `%D'",
+ parm);
parms_have_cleanups = 1;
}
}
DECL_SAVED_INSNS (fndecl) = NULL_RTX;
expand_function_start (fndecl, parms_have_cleanups);
- if (flag_handle_exceptions)
- {
- /* Make the throw decl visible at this level, just
- not in the way of the parameters. */
- pushdecl (eh_decl);
- expand_decl_init (eh_decl);
- }
-
/* Create a binding contour which can be used to catch
cleanup-generated temporaries. Also, if the return value needs or
has initialization, deal with that now. */
if (flag_gc)
{
maybe_gc_cleanup = build_tree_list (NULL_TREE, error_mark_node);
- expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup);
+ if (! expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup))
+ cp_error ("parser lost in parsing declaration of `%D'", fndecl);
}
/* If this function is `main', emit a call to `__main'
register tree fndecl = current_function_decl;
tree fntype, ctype = NULL_TREE;
rtx head, last_parm_insn, mark;
- extern int sets_exception_throw_decl;
/* Label to use if this function is supposed to return a value. */
tree no_return_label = NULL_TREE;
tree decls = NULL_TREE;
if (call_poplevel)
{
decls = getdecls ();
- if (flag_handle_exceptions == 2)
- deactivate_exception_cleanups ();
expand_end_bindings (decls, decls != NULL_TREE, 0);
poplevel (decls != NULL_TREE, 0, 0);
}
current_class_decl, integer_zero_node, 1);
thenclause = build_modify_expr (current_class_decl, NOP_EXPR,
build_new (NULL_TREE, current_class_type, void_type_node, 0));
- if (flag_handle_exceptions == 2)
- {
- tree cleanup, cleanup_deallocate;
- tree virtual_size;
-
- /* This is the size of the virtual object pointed to by
- allocated_this. In this case, it is simple. */
- virtual_size = c_sizeof (current_class_type);
-
- allocated_this = build_decl (VAR_DECL, NULL_TREE, ptr_type_node);
- DECL_REGISTER (allocated_this) = 1;
- DECL_INITIAL (allocated_this) = error_mark_node;
- expand_decl (allocated_this);
- expand_decl_init (allocated_this);
- /* How we cleanup `this' if an exception was raised before
- we are ready to bail out. */
- cleanup = TYPE_GETS_REG_DELETE (current_class_type)
- ? build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, allocated_this, virtual_size, NULL_TREE)
- /* The size of allocated_this is wrong, and hence the
- second argument to operator delete will be wrong. */
- : build_delete (TREE_TYPE (allocated_this), allocated_this,
- integer_three_node,
- LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE, 1);
- cleanup_deallocate
- = build_modify_expr (current_class_decl, NOP_EXPR, integer_zero_node);
- cleanup = tree_cons (NULL_TREE, cleanup,
- build_tree_list (NULL_TREE, cleanup_deallocate));
-
- expand_decl_cleanup (allocated_this,
- build (COND_EXPR, integer_type_node,
- build (NE_EXPR, integer_type_node,
- allocated_this, integer_zero_node),
- build_compound_expr (cleanup),
- integer_zero_node));
- }
}
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
{
expand_start_cond (cond, 0);
expand_expr_stmt (thenclause);
- if (flag_handle_exceptions == 2)
- expand_assignment (allocated_this, current_class_decl, 0, 0);
expand_end_cond ();
}
/* This is where the body of the constructor ends. */
expand_label (ctor_label);
ctor_label = NULL_TREE;
- if (flag_handle_exceptions == 2)
- {
- expand_assignment (allocated_this, integer_zero_node, 0, 0);
- if (call_poplevel)
- deactivate_exception_cleanups ();
- }
-
- pop_implicit_try_blocks (NULL_TREE);
if (call_poplevel)
{
/* Emit label at beginning of cleanup code for parameters. */
emit_label (cleanup_label);
-#if 1
- /* Cheap hack to get better code from GNU C++. Remove when cse is fixed. */
- if (exception_throw_decl && sets_exception_throw_decl == 0)
- expand_assignment (exception_throw_decl, integer_zero_node, 0, 0);
-#endif
-
- if (flag_handle_exceptions)
- {
- expand_end_try ();
- expand_start_except (0, 0);
- expand_end_except ();
- }
-
/* Get return value into register if that's where it's supposed to be. */
if (original_result_rtx)
fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
/* Generate rtl for function exit. */
expand_function_end (input_filename, lineno, 1);
+ if (flag_handle_exceptions)
+ expand_exception_blocks();
+
/* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into
this function's blocks. */
rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
if (! toplevel)
{
+ tree cleanup;
expand_decl (decl);
- expand_decl_cleanup (decl, maybe_build_cleanup (decl));
+ cleanup = maybe_build_cleanup (decl);
expand_decl_init (decl);
+ if (! expand_decl_cleanup (decl, cleanup))
+ cp_error ("parser lost in parsing declaration of `%D'",
+ decl);
}
}
my_friendly_assert (current_binding_level->n_incomplete > 0, 164);
rval = build_compound_expr (tree_cons (NULL_TREE, rval,
build_tree_list (NULL_TREE, build_vbase_delete (type, decl))));
- current_binding_level->have_cleanups = 1;
- current_binding_level->more_exceptions_ok = 0;
-
if (TREE_CODE (decl) != PARM_DECL)
resume_momentary (temp);
cp_warning ("reference, not call, to function `%D'", exp);
warning ("at this point in file");
}
- if (TREE_RAISES (exp))
- {
- my_friendly_assert (flag_handle_exceptions, 165);
- if (flag_handle_exceptions == 2)
- {
- if (! current_binding_level->more_exceptions_ok)
- {
- extern struct nesting *nesting_stack, *block_stack;
-
- remove_implicit_immediately
- = (nesting_stack != block_stack);
- cplus_expand_start_try (1);
- }
- current_binding_level->have_exceptions = 1;
- }
- }
expand_expr_stmt (break_out_cleanups (exp));
-
- if (remove_implicit_immediately)
- pop_implicit_try_blocks (NULL_TREE);
}
/* Clean up any pending cleanups. This happens when a function call
cadillac_finish_stmt ();
}
-void
-pop_implicit_try_blocks (decl)
- tree decl;
-{
- if (decl)
- {
- my_friendly_assert (current_binding_level->parm_flag == 3, 166);
- current_binding_level->names = TREE_CHAIN (decl);
- }
-
- while (current_binding_level->parm_flag == 3)
- {
- tree name = get_identifier ("(compiler error)");
- tree orig_ex_type = current_exception_type;
- tree orig_ex_decl = current_exception_decl;
- tree orig_ex_obj = current_exception_object;
- tree decl = cplus_expand_end_try (2);
-
- /* @@ It would be nice to make all these point
- to exactly the same handler. */
- /* Start hidden EXCEPT. */
- cplus_expand_start_except (name, decl);
- /* reraise ALL. */
- cplus_expand_reraise (NULL_TREE);
- current_exception_type = orig_ex_type;
- current_exception_decl = orig_ex_decl;
- current_exception_object = orig_ex_obj;
- /* This will reraise for us. */
- cplus_expand_end_except (error_mark_node);
- }
-
- if (decl)
- {
- TREE_CHAIN (decl) = current_binding_level->names;
- current_binding_level->names = decl;
- }
-}
-
-/* Push a cleanup onto the current binding contour that will cause
- ADDR to be cleaned up, in the case that an exception propagates
- through its binding contour. */
-
-void
-push_exception_cleanup (addr)
- tree addr;
-{
- tree decl = build_decl (VAR_DECL, get_identifier (EXCEPTION_CLEANUP_NAME), ptr_type_node);
- tree cleanup;
-
- decl = pushdecl (decl);
- DECL_REGISTER (decl) = 1;
- store_init_value (decl, addr);
- expand_decl (decl);
- expand_decl_init (decl);
-
- cleanup = build (COND_EXPR, integer_type_node,
- build (NE_EXPR, integer_type_node,
- decl, integer_zero_node),
- build_delete (TREE_TYPE (addr), decl,
- lookup_name (in_charge_identifier, 0),
- LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
- integer_zero_node);
- expand_decl_cleanup (decl, cleanup);
-}
-
-/* For each binding contour, emit code that deactivates the
- exception cleanups. All other cleanups are left as they were. */
-
-static void
-deactivate_exception_cleanups ()
-{
- struct binding_level *b = current_binding_level;
- tree xyzzy = get_identifier (EXCEPTION_CLEANUP_NAME);
- while (b != class_binding_level)
- {
- if (b->parm_flag == 3)
- {
- tree decls = b->names;
- while (decls)
- {
- if (DECL_NAME (decls) == xyzzy)
- expand_assignment (decls, integer_zero_node, 0, 0);
- decls = TREE_CHAIN (decls);
- }
- }
- b = b->level_chain;
- }
-}
-
/* Change a static member function definition into a FUNCTION_TYPE, instead
of the METHOD_TYPE that we create when it's originally parsed.
int flag_elide_constructors;
/* Nonzero means recognize and handle exception handling constructs.
- 2 means handle exceptions the way Spring wants them handled. */
+ Use ansi syntax and semantics. WORK IN PROGRESS! */
int flag_handle_exceptions;
-/* Nonzero means recognize and handle exception handling constructs.
- Use ansi syntax and semantics. WORK IN PROGRESS!
- 2 means handle exceptions the way Spring wants them handled. */
-
-int flag_ansi_exceptions;
-
/* Nonzero means recognize and handle signature language constructs. */
int flag_handle_signatures;
{"memoize-lookups", &flag_memoize_lookups, 1},
{"elide-constructors", &flag_elide_constructors, 1},
{"handle-exceptions", &flag_handle_exceptions, 1},
- {"ansi-exceptions", &flag_ansi_exceptions, 1},
{"handle-signatures", &flag_handle_signatures, 1},
- {"spring-exceptions", &flag_handle_exceptions, 2},
{"default-inline", &flag_default_inline, 1},
{"dollars-in-identifiers", &dollars_in_ident, 1},
{"enum-int-equiv", &flag_int_enum_equivalence, 1},
tree vars = static_aggregates;
int needs_cleaning = 0, needs_messing_up = 0;
+ build_exception_table ();
+
if (flag_detailed_statistics)
dump_tree_statistics ();
break;
case TYPE_DECL:
- if (TYPE_NAME (TREE_TYPE (t)) != t)
- {
- if (v > 0)
- OB_PUTS ("typedef ");
- goto general;
- }
-
- dump_type (TREE_TYPE (t), v);
+ {
+ /* Don't say 'typedef class A' */
+ tree type = TREE_TYPE (t);
+ if (IS_AGGR_TYPE (type) && ! TYPE_PTRMEMFUNC_P (type)
+ && type == TYPE_MAIN_VARIANT (type))
+ {
+ dump_type (type, v);
+ break;
+ }
+ }
+ if (v > 0)
+ OB_PUTS ("typedef ");
+ goto general;
break;
case VAR_DECL:
OB_PUTC (' ');
}
/* DECL_CLASS_CONTEXT isn't being set in some cases. Hmm... */
- if (TREE_CODE (t) == FIELD_DECL
- || (TREE_CODE (t) == VAR_DECL && DECL_CONTEXT (t)
- && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't'))
+ if (DECL_CONTEXT (t)
+ && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't')
{
dump_type (DECL_CONTEXT (t), 0);
OB_PUTC2 (':', ':');
case CONST_DECL:
if (NEXT_CODE (t) == ENUMERAL_TYPE)
- {
- if (DECL_CONTEXT (t))
- {
- dump_decl (DECL_CONTEXT (t), 0);
- OB_PUTC2 (':', ':');
- }
- OB_PUTID (DECL_NAME (t));
- }
+ goto general;
else
dump_expr (DECL_INITIAL (t), 0);
break;
/* Handle exceptional things in C++.
- Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc.
- Contributed by Michael Tiemann (tiemann@cygnus.com)
+ Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann <tiemann@cygnus.com>
+ Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
+ initial re-implementation courtesy Tad Hunt.
This file is part of GNU CC.
#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
+#include "obstack.h"
+#include "expr.h"
-#undef NULL
-#define NULL (char *)0
+/* holds the fndecl for __builtin_return_address () */
+tree builtin_return_address_fndecl;
-/* 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
+/* Define at your own risk! */
+#ifdef sun
+#ifdef sparc
+#define TRY_NEW_EH
+#endif
+#endif
-void init_exception_processing ();
-void init_exception_processing_1 ();
+#ifndef TRY_NEW_EH
-/* 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;
+static void
+sorry_no_eh ()
+{
+ static int warned = 0;
+ if (! warned)
+ {
+ sorry ("exception handling not supported");
+ warned = 1;
+ }
+}
-/* The exception `type' currently in scope, or NULL_TREE if none. */
-tree current_exception_type;
+void
+build_exception_table ()
+{
+}
-/* The exception handler object for the given scope. */
-tree current_exception_decl;
-rtx current_exception_name_as_rtx;
-rtx current_exception_parms_as_rtx;
+void
+expand_exception_blocks ()
+{
+}
-/* The ``object'' view of the current exception parameters.
- We cast up from the `parms' field to `current_exception_type'. */
-tree current_exception_object;
+void
+start_protect ()
+{
+}
-/* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception'
- after default conversion. Maybe later they will get built-in. */
-static tree BISJ, BILJ, BIR, BIUE;
+void
+end_protect (finalization)
+ tree finalization;
+{
+}
-/* Local variables which give the appearance that exception
- handling is part of the language and the execution model. */
+void
+expand_start_try_stmts ()
+{
+ sorry_no_eh ();
+}
-/* The type of the exception handler stack. */
-tree EHS_type;
+void
+expand_end_try_stmts ()
+{
+}
-/* The global handler stack. */
-tree EHS_decl;
+void
+expand_start_all_catch ()
+{
+}
-/* 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;
+void
+expand_end_all_catch ()
+{
+}
-/* The parameter names of this exception type. */
+void
+expand_start_catch_block (typename, identifier)
+ tree typename, identifier;
+{
+}
-static tree last_exception_fields;
-static tree last_exception_field_types;
+void
+expand_end_catch_block ()
+{
+}
-/* 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;
+void
+init_exception_processing ()
{
- /* 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;
+void
+expand_throw (exp)
+ tree exp;
+{
+ sorry_no_eh ();
+}
- name = (char *)alloca (length);
- strcpy (name, EXCEPTION_NAME_PREFIX);
- length = EXCEPTION_NAME_LENGTH;
- if (prefix)
- {
- strcpy (name + length, IDENTIFIER_POINTER (prefix));
-#ifdef JOINER
- name[length + IDENTIFIER_LENGTH (prefix)] = JOINER;
#else
- name[length + IDENTIFIER_LENGTH (prefix)] = '_';
-#endif
- 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;
+static int
+doing_eh (do_warn)
+ int do_warn;
{
- tree this_cname = TREE_PURPOSE (raise_id);
- if (this_cname == NULL_TREE)
+ if (! flag_handle_exceptions)
{
- if (cname)
+ static int warned = 0;
+ if (! warned && do_warn)
{
- tree name = TREE_VALUE (raise_id);
- if (purpose_member (name, CLASSTYPE_TAGS (ctype)))
- this_cname = cname;
+ error ("exception handling disabled, use -fhandle-exceptions to enable.");
+ warned = 1;
}
+ return 0;
}
- 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;
+ return 1;
}
-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;
+/*
+NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
+to supporting exception handling as per Stroustrup's 2nd edition.
+It is a complete rewrite of all the EH stuff that was here before
+ Shortcomings:
+ 1. The type of the throw and catch must still match
+ exactly (no support yet for matching base classes)
+ 2. Throw specifications of functions still doesnt't work.
+ Cool Things:
+ 1. Destructors are called properly :-)
+ 2. No overhead for the non-exception thrown case.
+ 3. Fixing shortcomings 1 and 2 is simple.
+ -Tad Hunt (tad@mail.csh.rit.edu)
+
+*/
+
+/* A couple of backend routines from m88k.c */
+
+/* used to cache a call to __builtin_return_address () */
+static tree BuiltinReturnAddress;
+
+
+
+
+
+#include <stdio.h>
+
+/* XXX - Tad: for EH */
+/* output an exception table entry */
+
+static void
+output_exception_table_entry (file, start_label, end_label, eh_label)
+ FILE *file;
+ rtx start_label, end_label, eh_label;
{
- tree oname;
- tree decl;
+ char label[100];
- if (cname == void_type_node)
- cname = NULL_TREE;
- else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE)
+ fprintf (file, "\t%s\t ", ASM_LONG);
+ if (GET_CODE (start_label) == CODE_LABEL)
{
- sorry ("multiple scope refs in `lookup_exception_object'");
- cname = NULL_TREE;
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (start_label));
+ assemble_name (file, label);
}
- oname = exception_object_name (cname, name);
- decl = IDENTIFIER_GLOBAL_VALUE (oname);
- if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
+ else if (GET_CODE (start_label) == SYMBOL_REF)
{
- 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;
+ fprintf (stderr, "YYYYYYYYYEEEEEEEESSSSSSSSSSSS!!!!!!!!!!\n");
+ assemble_name (file, XSTR (start_label, 0));
}
- return decl;
+ putc ('\n', file);
+
+ fprintf (file, "\t%s\t ", ASM_LONG);
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (end_label));
+ assemble_name (file, label);
+ putc ('\n', file);
+
+ fprintf (file, "\t%s\t ", ASM_LONG);
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (eh_label));
+ assemble_name (file, label);
+ putc ('\n', file);
+
+ putc ('\n', file); /* blank line */
+}
+
+static void
+easy_expand_asm (str)
+ char *str;
+{
+ expand_asm (build_string (strlen (str)+1, str));
}
-tree
-lookup_exception_type (ctype, cname, raise_id)
- tree ctype, cname;
- tree raise_id;
+/* unwind the stack. */
+static void
+do_unwind (throw_label)
+ rtx throw_label;
{
- tree name = TREE_VALUE (raise_id);
- tree purpose = TREE_PURPOSE (raise_id);
+#ifdef sparc
+ extern FILE *asm_out_file;
+ tree fcall;
+ tree params;
+ rtx return_val_rtx;
+
+ /* call to __builtin_return_address () */
+ params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+ fcall = build_function_call (BuiltinReturnAddress, params);
+ return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
+ /* In the return, the new pc is pc+8, as the value comming in is
+ really the address of the call insn, not the next insn. */
+ emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
+ Pmode,
+ throw_label), -8));
+ easy_expand_asm ("st %l0,[%fp]");
+ easy_expand_asm ("st %l1,[%fp+4]");
+ easy_expand_asm ("ret");
+ easy_expand_asm ("restore");
+ emit_barrier ();
+#endif
+#if m88k
+ rtx temp_frame = frame_pointer_rtx;
- if (cname && purpose == NULL_TREE)
- purpose = cname;
+ temp_frame = memory_address (Pmode, temp_frame);
+ temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
- if (purpose && purpose != void_type_node)
- {
- tree link = NULL_TREE;
+ /* hopefully this will successfully pop the frame! */
+ emit_move_insn (frame_pointer_rtx, temp_frame);
+ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+ emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
+ emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+ (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
- 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);
- }
+#if 0
+ emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+ -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
+
+ emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
- 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;
+ emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+ (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
+#endif
+#endif
}
-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))
- cp_error ("exception name `%T' must follow body declaration", e);
- if (list_of_fieldlists)
- {
- tree prev, field;
-
- /* Note: no public, private, or protected allowed. */
- if (TREE_CHAIN (list_of_fieldlists))
- error ("access declarations invalid in exception declaration");
- else if (TREE_PURPOSE (list_of_fieldlists) != (tree)access_default)
- error ("access declarations invalid in exception declaration");
- TREE_PURPOSE (list_of_fieldlists) = (tree)access_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:
- cp_error ("declaration of function `%D' in exception invalid",
- field);
- break;
- case VAR_DECL:
- if (TREE_STATIC (field))
- cp_error ("declaration of static variable `%D' in exception invalid", field);
- else
- cp_error ("declaration of constant field `%D' in exception invalid", field);
- break;
- case CONST_DECL:
- cp_error ("declaration of enum value `%D' in exception invalid", field);
- break;
- case SCOPE_REF:
- error ("use of `::' in exception context invalid");
- break;
- }
- if (prev)
- TREE_CHAIN (prev) = TREE_CHAIN (field);
- else
- TREE_VALUE (list_of_fieldlists) = TREE_CHAIN (field);
- }
- }
+#if 0
+/* This is the startup, and finish stuff per exception table. */
- /* Now that we've cleaned up the fields, add a name identifier at front. */
- name_field = build_lang_field_decl (FIELD_DECL, get_identifier ("__name"),
- ptr_type_node);
- if (list_of_fieldlists)
- {
- TREE_CHAIN (name_field) = TREE_VALUE (list_of_fieldlists);
- TREE_VALUE (list_of_fieldlists) = name_field;
- }
- else
- list_of_fieldlists = build_tree_list (NULL_TREE, name_field);
+/* XXX - Tad: exception handling section */
+#ifndef EXCEPT_SECTION_ASM_OP
+#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
+#endif
- last_exception_fields = TREE_VALUE (list_of_fieldlists);
- if (parmtypes)
- {
- last_exception_field_types = nreverse (parmtypes);
- /* Set the TREE_CHAIN of what is now at the end of the
- list to `void_list_node'. */
- TREE_CHAIN (parmtypes) = void_list_node;
- }
- else
- last_exception_field_types = void_list_node;
+#ifdef EXCEPT_SECTION_ASM_OP
+typedef struct {
+ void *start_protect;
+ void *end_protect;
+ void *exception_handler;
+ } exception_table;
+#endif /* EXCEPT_SECTION_ASM_OP */
- popclass (0);
+#ifdef EXCEPT_SECTION_ASM_OP
-#if 0
- /* Remove aggregate types from the list of tags,
- since these appear at global scope. */
- while (x && IS_AGGR_TYPE (TREE_VALUE (x)))
- x = TREE_CHAIN (x);
- CLASSTYPE_TAGS (t) = x;
- y = x;
- while (x)
- {
- if (IS_AGGR_TYPE (TREE_VALUE (x)))
- TREE_CHAIN (y) = TREE_CHAIN (x);
- x = TREE_CHAIN (x);
- }
-#endif
+ /* on machines which support it, the exception table lives in another section,
+ but it needs a label so we can reference it... This sets up that
+ label! */
+asm (EXCEPT_SECTION_ASM_OP);
+exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
+asm (TEXT_SECTION_ASM_OP);
- if (flag_cadillac)
- cadillac_finish_exception (e);
+#endif /* EXCEPT_SECTION_ASM_OP */
- return e;
-}
+#ifdef EXCEPT_SECTION_ASM_OP
+
+ /* we need to know where the end of the exception table is... so this
+ is how we do it! */
+
+asm (EXCEPT_SECTION_ASM_OP);
+exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
+asm (TEXT_SECTION_ASM_OP);
+
+#endif /* EXCEPT_SECTION_ASM_OP */
+
+#endif
void
-finish_exception_decl (cname, decl)
- tree cname, decl;
+exception_section ()
{
- /* In decl.h. */
- extern tree last_function_parms;
-
- /* An exception declaration. */
- tree t, ctor;
- tree parmdecls = NULL_TREE, fields;
- tree list_of_fieldlists = temp_tree_cons (NULL_TREE,
- copy_list (last_exception_fields),
- NULL_TREE);
- tree edecl = build_lang_field_decl (VAR_DECL,
- exception_object_name (cname, DECL_NAME (decl)),
- ptr_type_node);
-
- DECL_LANGUAGE (edecl) = lang_c;
- TREE_STATIC (edecl) = 1;
- TREE_PUBLIC (edecl) = 1;
- finish_decl (pushdecl (edecl), NULL_TREE, NULL_TREE, 0);
-
- /* Now instantiate the exception decl. */
- t = xref_tag (exception_type_node, DECL_NAME (decl), NULL_TREE, 0);
-
- /* finish_struct will pop this. */
- pushclass (t, 0);
-
- /* Now add a constructor which takes as parameters all the types we
- just defined. */
- ctor = build_lang_decl (FUNCTION_DECL, DECL_NAME (decl),
- build_cplus_method_type (t, TYPE_POINTER_TO (t),
- last_exception_field_types));
- /* Don't take `name'. The constructor handles that. */
- fields = TREE_CHAIN (TREE_VALUE (list_of_fieldlists));
- while (fields)
- {
- tree parm = build_decl (PARM_DECL, DECL_NAME (fields), TREE_TYPE (fields));
- /* Since there is a prototype, args are passed in their own types. */
- DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
-#ifdef PROMOTE_PROTOTYPES
- if ((TREE_CODE (TREE_TYPE (fields)) == INTEGER_TYPE
- || TREE_CODE (TREE_TYPE (fields)) == ENUMERAL_TYPE)
- && TYPE_PRECISION (TREE_TYPE (fields)) < TYPE_PRECISION (integer_type_node))
- DECL_ARG_TYPE (parm) = integer_type_node;
+#ifdef ASM_OUTPUT_SECTION_NAME
+ named_section (".gcc_except_table");
+#else
+ text_section ();
#endif
- TREE_CHAIN (parm) = parmdecls;
- parmdecls = parm;
- fields = TREE_CHAIN (fields);
- }
- fields = TREE_VALUE (list_of_fieldlists);
- last_function_parms = nreverse (parmdecls);
-
- DECL_CONSTRUCTOR_P (ctor) = 1;
- TYPE_HAS_CONSTRUCTOR (t) = 1;
- grokclassfn (t, DECL_NAME (decl), ctor, NO_SPECIAL, NULL_TREE);
- DECL_EXTERNAL (ctor) = 1;
- TREE_STATIC (ctor) = 1;
- TREE_PUBLIC (ctor) = 0;
- DECL_INLINE (ctor) = 1;
- make_decl_rtl (ctor, NULL_PTR, 1);
- finish_decl (ctor, NULL_TREE, NULL_TREE, 0);
- TREE_CHAIN (ctor) = TREE_VALUE (list_of_fieldlists);
- TREE_VALUE (list_of_fieldlists) = ctor;
-
- finish_struct (t, list_of_fieldlists, 0);
-
- if (current_function_decl)
- error ("cannot define exception inside function scope");
- else
- {
- enum debug_info_type old_write_symbols = write_symbols;
- write_symbols = NO_DEBUG;
-
- /* Now build the constructor for this exception. */
- parmdecls = DECL_ARGUMENTS (ctor);
- start_function (NULL_TREE, ctor, 0, 1);
- store_parm_decls ();
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- /* Move all the parameters to the fields, skipping `this'. */
- parmdecls = TREE_CHAIN (parmdecls);
- /* Install `name' of this exception handler. */
- DECL_INITIAL (fields) = build_unary_op (ADDR_EXPR, edecl, 0);
- fields = TREE_CHAIN (fields);
- /* Install all the values. */
- while (fields)
- {
- /* Set up the initialization for this field. */
- DECL_INITIAL (fields) = parmdecls;
- fields = TREE_CHAIN (fields);
- parmdecls = TREE_CHAIN (parmdecls);
- }
- emit_base_init (t, 0);
-
- finish_function (DECL_SOURCE_LINE (ctor), 1);
- write_symbols = old_write_symbols;
- }
}
-void
-end_exception_decls ()
+
+
+
+/* from: my-cp-except.c */
+
+/* VI: ":set ts=4" */
+#if 0
+#include <stdio.h> */
+#include "config.h"
+#include "tree.h"
+#include "rtl.h"
+#include "cp-tree.h"
+#endif
+#include "decl.h"
+#if 0
+#include "flags.h"
+#endif
+#include "insn-flags.h"
+#include "obstack.h"
+#if 0
+#include "expr.h"
+#endif
+
+/* ======================================================================
+ Briefly the algorithm works like this:
+
+ When a constructor or start of a try block is encountered,
+ push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
+ new entry in the unwind protection stack and returns a label to
+ output to start the protection for that block.
+
+ When a destructor or end try block is encountered, pop_eh_entry
+ (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
+ created when push_eh_entry () was called. The ehEntry structure
+ contains three things at this point. The start protect label,
+ the end protect label, and the exception handler label. The end
+ protect label should be output before the call to the destructor
+ (if any). If it was a destructor, then its parse tree is stored
+ in the finalization variable in the ehEntry structure. Otherwise
+ the finalization variable is set to NULL to reflect the fact that
+ is the the end of a try block. Next, this modified ehEntry node
+ is enqueued in the finalizations queue by calling
+ enqueue_eh_entry (&queue,entry).
+
+ +---------------------------------------------------------------+
+ |XXX: Will need modification to deal with partially |
+ | constructed arrays of objects |
+ | |
+ | Basically, this consists of keeping track of how many |
+ | of the objects have been constructed already (this |
+ | should be in a register though, so that shouldn't be a |
+ | problem. |
+ +---------------------------------------------------------------+
+
+ When a catch block is encountered, there is a lot of work to be
+ done.
+
+ Since we don't want to generate the catch block inline with the
+ regular flow of the function, we need to have some way of doing
+ so. Luckily, we have a couple of routines "get_last_insn ()" and
+ "set_last_insn ()" provided. When the start of a catch block is
+ encountered, we save a pointer to the last insn generated. After
+ the catch block is generated, we save a pointer to the first
+ catch block insn and the last catch block insn with the routines
+ "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
+ to be the last insn generated before the catch block, and set the
+ NEXT_INSN (last_insn) to zero.
+
+ Since catch blocks might be nested inside other catch blocks, and
+ we munge the chain of generated insns after the catch block is
+ generated, we need to store the pointers to the last insn
+ generated in a stack, so that when the end of a catch block is
+ encountered, the last insn before the current catch block can be
+ popped and set to be the last insn, and the first and last insns
+ of the catch block just generated can be enqueue'd for output at
+ a later time.
+
+ Next we must insure that when the catch block is executed, all
+ finalizations for the matching try block have been completed. If
+ any of those finalizations throw an exception, we must call
+ terminate according to the ARM (section r.15.6.1). What this
+ means is that we need to dequeue and emit finalizations for each
+ entry in the ehQueue until we get to an entry with a NULL
+ finalization field. For any of the finalization entries, if it
+ is not a call to terminate (), we must protect it by giving it
+ another start label, end label, and exception handler label,
+ setting its finalization tree to be a call to terminate (), and
+ enqueue'ing this new ehEntry to be output at an outer level.
+ Finally, after all that is done, we can get around to outputting
+ the catch block which basically wraps all the "catch (...) {...}"
+ statements in a big if/then/else construct that matches the
+ correct block to call.
+
+ ===================================================================== */
+
+extern rtx emit_insn PROTO((rtx));
+extern rtx gen_nop PROTO(());
+extern void do_unwind PROTO((rtx));
+
+/* local globals for function calls
+ ====================================================================== */
+
+/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
+ "set_unexpected ()" after default_conversion. (lib-except.c) */
+static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
+
+/* used to cache __find_first_exception_table_match ()
+ for throw (lib-except.c) */
+static tree FirstExceptionMatch;
+
+/* used to cache a call to __unwind_function () (lib-except.c) */
+static tree Unwind;
+
+/* holds a ready to emit call to "terminate ()". */
+static tree TerminateFunctionCall;
+
+/* ====================================================================== */
+
+
+
+/* data structures for my various quick and dirty stacks and queues
+ Eventually, most of this should go away, because I think it can be
+ integrated with stuff already built into the compiler. */
+
+/* =================================================================== */
+
+struct labelNode {
+ rtx label;
+ struct labelNode *chain;
+ };
+
+
+/* this is the most important structure here. Basically this is how I store
+ an exception table entry internally. */
+struct ehEntry {
+ rtx start_label;
+ rtx end_label;
+ rtx exception_handler_label;
+
+ tree finalization;
+ };
+
+struct ehNode {
+ struct ehEntry *entry;
+ struct ehNode *chain;
+ };
+
+struct ehStack {
+ struct ehNode *top;
+ };
+
+struct ehQueue {
+ struct ehNode *head;
+ struct ehNode *tail;
+ };
+
+struct exceptNode {
+ rtx catchstart;
+ rtx catchend;
+
+ struct exceptNode *chain;
+ };
+
+struct exceptStack {
+ struct exceptNode *top;
+ };
+/* ========================================================================= */
+
+
+
+/* local globals - these local globals are for storing data necessary for
+ generating the exception table and code in the correct order.
+
+ ========================================================================= */
+
+/* holds the pc for doing "throw" */
+rtx saved_pc;
+/* holds the type of the thing being thrown. */
+rtx saved_throw_type;
+
+rtx throw_label;
+
+static struct ehStack ehstack;
+static struct ehQueue ehqueue;
+static struct ehQueue eh_table_output_queue;
+static struct exceptStack exceptstack;
+static struct labelNode *false_label_stack = NULL;
+static struct labelNode *caught_return_label_stack = NULL;
+/* ========================================================================= */
+
+/* function prototypes */
+static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
+static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
+static void push_except_stmts PROTO((struct exceptStack *exceptstack,
+ rtx catchstart, rtx catchend));
+static int pop_except_stmts PROTO((struct exceptStack *exceptstack,
+ rtx *catchstart, rtx *catchend));
+static rtx push_eh_entry PROTO((struct ehStack *stack));
+static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
+static void new_eh_queue PROTO((struct ehQueue *queue));
+static void new_eh_stack PROTO((struct ehStack *stack));
+static void new_except_stack PROTO((struct exceptStack *queue));
+static void push_last_insn PROTO(());
+static rtx pop_last_insn PROTO(());
+static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
+static rtx pop_label_entry PROTO((struct labelNode **labelstack));
+static rtx top_label_entry PROTO((struct labelNode **labelstack));
+static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
+
+
+
+/* All my cheesy stack/queue/misc data structure handling routines
+
+ ========================================================================= */
+
+static void
+push_label_entry (labelstack, label)
+ struct labelNode **labelstack;
+ rtx label;
{
- last_exception_field_types = NULL_TREE;
- last_exception_fields = NULL_TREE;
+ struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
+
+ newnode->label = label;
+ newnode->chain = *labelstack;
+ *labelstack = newnode;
}
-\f
-/* Statement-level exception semantics. */
-void
-cplus_expand_start_try (implicit)
- int implicit;
+static rtx
+pop_label_entry (labelstack)
+ struct labelNode **labelstack;
{
- tree call_to_setjmp;
- tree handler, ref;
+ rtx label;
+ struct labelNode *tempnode;
- /* Start a new block enclosing the whole handler. */
- if (implicit)
- {
- pushlevel_temporary (1);
- }
- else
- {
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
-
- /* Encompass whole exception handler in one big binding contour.
- If RAISE should throw out of the whole TRY/EXCEPT block, call
- `expand_start_bindings' with argument of 1. */
- expand_start_bindings (0);
- }
+ if (! *labelstack) return NULL_RTX;
- /* Allocate handler in that block. It's real name will come later.
- Note that it will be the first name in this binding contour. */
- handler = get_temp_name (EHS_type, 0);
- DECL_INITIAL (handler) = error_mark_node;
- finish_decl (handler, NULL_TREE, NULL_TREE, 0);
+ tempnode = *labelstack;
+ label = tempnode->label;
+ *labelstack = (*labelstack)->chain;
+ free (tempnode);
- /* Must come after call to `finish_decl', else the cleanup for the temp
- for the handler will cause the contour we just created to be popped. */
- if (implicit)
- declare_implicit_exception ();
+ return label;
+}
- /* Catch via `setjmp'. */
- ref = build_component_ref (handler, get_identifier ("handler"), NULL_TREE, 0);
- call_to_setjmp = build_function_call (BISJ, build_tree_list (NULL_TREE, ref));
+static rtx
+top_label_entry (labelstack)
+ struct labelNode **labelstack;
+{
+ if (! *labelstack) return NULL_RTX;
- /* RAISE throws to EXCEPT part. */
- expand_start_try (build_binary_op (EQ_EXPR, call_to_setjmp, integer_zero_node, 1), 0, 1);
+ return (*labelstack)->label;
}
-/* If KEEP is 1, then declarations in the TRY statement are worth keeping.
- If KEEP is 2, then the TRY statement was generated by the compiler.
- If KEEP is 0, the declarations in the TRY statement contain errors. */
-
-tree
-cplus_expand_end_try (keep)
- int keep;
+static void
+push_except_stmts (exceptstack, catchstart, catchend)
+ struct exceptStack *exceptstack;
+ rtx catchstart, catchend;
{
- tree decls, decl, block;
+ struct exceptNode *newnode = (struct exceptNode*)
+ xmalloc (sizeof (struct exceptNode));
- if (keep < 2)
- pop_implicit_try_blocks (NULL_TREE);
+ newnode->catchstart = catchstart;
+ newnode->catchend = catchend;
+ newnode->chain = exceptstack->top;
- decls = getdecls ();
+ exceptstack->top = newnode;
+}
- /* Emit code to avoid falling through into a default
- handler that might come later. */
- expand_end_try ();
+static int
+pop_except_stmts (exceptstack, catchstart, catchend)
+ struct exceptStack *exceptstack;
+ rtx *catchstart, *catchend;
+{
+ struct exceptNode *tempnode;
- /* Pops binding contour local to TRY, and get the exception handler
- object built by `...start_try'. */
- switch (keep)
- {
- case 0:
- expand_end_bindings (decls, 0, 1);
- block = poplevel (0, 0, 0);
- pop_momentary ();
- decl = getdecls ();
- break;
-
- case 1:
- expand_end_bindings (decls, 1, 1);
- block = poplevel (1, 1, 0);
- pop_momentary ();
- decl = getdecls ();
- break;
-
- default:
- decl = tree_last (decls);
- block = NULL_TREE;
- break;
- }
+ if (!exceptstack->top) {
+ *catchstart = *catchend = NULL_RTX;
+ return 0;
+ }
- my_friendly_assert (TREE_CODE (decl) == VAR_DECL
- && TREE_TYPE (decl) == EHS_type, 203);
- if (block)
- {
- BLOCK_HANDLER_BLOCK (block) = 1;
- TREE_USED (block) = 1;
- }
+ tempnode = exceptstack->top;
+ exceptstack->top = exceptstack->top->chain;
+
+ *catchstart = tempnode->catchstart;
+ *catchend = tempnode->catchend;
+ free (tempnode);
- /* Pass it back so that its rtl can be bound to its name
- (or vice versa). */
- return decl;
+ return 1;
}
+/* Push to permanent obstack for rtl generation.
+ One level only! */
+static struct obstack *saved_rtl_obstack;
void
-cplus_expand_start_except (name, decl)
- tree name, decl;
+push_rtl_perm ()
{
- int yes;
- tree tmp, init;
+ extern struct obstack permanent_obstack;
+ extern struct obstack *rtl_obstack;
+
+ saved_rtl_obstack = rtl_obstack;
+ rtl_obstack = &permanent_obstack;
+}
- expand_start_except (0, 1);
+/* Pop back to normal rtl handling. */
+static void
+pop_rtl_from_perm ()
+{
+ extern struct obstack permanent_obstack;
+ extern struct obstack *rtl_obstack;
+
+ rtl_obstack = saved_rtl_obstack;
+}
- /* This is internal `eh'. */
- current_exception_decl = decl;
- current_exception_name_as_rtx
- = expand_expr (build (COMPONENT_REF, ptr_type_node,
- current_exception_decl, TREE_OPERAND (EHS_name, 1)),
- 0, 0, 0);
- init = build (COMPONENT_REF, ptr_type_node, decl, TREE_OPERAND (EHS_parms, 1));
- current_exception_parms_as_rtx = expand_expr (init, 0, 0, 0);
+static rtx
+push_eh_entry (stack)
+ struct ehStack *stack;
+{
+ struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
+ struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
- if (name)
- {
- /* Get the exception object into scope (user declared `ex'). */
- tmp = pushdecl (build_decl (VAR_DECL, name, ptr_type_node));
- DECL_INITIAL (tmp) = error_mark_node;
- finish_decl (tmp, init, 0, 0);
- }
- current_exception_type = NULL_TREE;
- yes = suspend_momentary ();
- if (name)
- {
- /* From now on, send the user to our faked-up object. */
- current_exception_object = build1 (INDIRECT_REF, void_type_node, tmp);
- IDENTIFIER_LOCAL_VALUE (name) = current_exception_object;
- }
- resume_momentary (yes);
+ if (stack == NULL) {
+ free (node);
+ free (entry);
+ return NULL_RTX;
+ }
+
+ /* These are saved for the exception table. */
+ push_rtl_perm ();
+ entry->start_label = gen_label_rtx ();
+ entry->end_label = gen_label_rtx ();
+ entry->exception_handler_label = gen_label_rtx ();
+ pop_rtl_from_perm ();
+
+ entry->finalization = NULL_TREE;
- /* Pop exception handler stack. */
- expand_assignment (EHS_decl, EHS_prev, 0, 0);
+ node->entry = entry;
+ node->chain = stack->top;
+ stack->top = node;
+
+ enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
+
+ return entry->start_label;
}
-/* Generate the call to `unhandled_exception' that is appropriate
- for this particular unhandled exception. */
-static tree
-call_to_unhandled_exception ()
+static struct ehEntry *
+pop_eh_entry (stack)
+ struct ehStack *stack;
{
- extern int lineno;
- extern tree combine_strings ();
- tree parms = tree_cons (NULL_TREE,
- combine_strings (build_string (strlen (input_filename + 1), input_filename)),
- build_tree_list (NULL_TREE, build_int_2 (lineno, 0)));
- return build_function_call (BIUE, parms);
+ struct ehNode *tempnode;
+ struct ehEntry *tempentry;
+
+ if (stack && (tempnode = stack->top)) {
+ tempentry = tempnode->entry;
+ stack->top = stack->top->chain;
+ free (tempnode);
+
+ return tempentry;
+ }
+
+ return NULL;
}
-/* Note that this must be mirror image of `...start_try'.
- DFAULT is the default clause, if there was one.
- DFAULT is ERROR_MARK_NODE when this ends an implicit handler. */
-void
-cplus_expand_end_except (dfault)
- tree dfault;
+static struct ehEntry *
+copy_eh_entry (entry)
+ struct ehEntry *entry;
{
- tree decls, raised;
+ struct ehEntry *newentry;
- if (dfault == NULL_TREE)
- {
- /* Uncaught exception at outermost level. If raised locally,
- reraise the exception. Otherwise, generate code to call `abort'. */
- if (in_try_block (1) == 0)
- {
- expand_start_cond (build (EQ_EXPR, integer_type_node,
- exception_throw_decl, integer_zero_node), 0);
- expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0);
- expand_end_cond ();
- }
- /* Try the next handler. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- }
+ newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
+ memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
- raised = expand_end_except ();
+ return newentry;
+}
- decls = getdecls ();
- expand_end_bindings (decls, decls != 0, 1);
- poplevel (decls != 0, 1, 0);
+static void
+enqueue_eh_entry (queue, entry)
+ struct ehQueue *queue;
+ struct ehEntry *entry;
+{
+ struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
- /* Implicit handlers do not use the momentary obstack. */
- if (dfault != error_mark_node)
- pop_momentary ();
+ node->entry = entry;
+ node->chain = NULL;
- if (! in_try_block (1))
+ if (queue->head == NULL)
{
- /* Check that this function is not raising exceptions
- it is not supposed to. */
- while (raised)
- {
- cp_error ("exception `%D' raised but not declared raisable",
- TREE_VALUE (raised));
- raised = TREE_CHAIN (raised);
- }
+ queue->head = node;
}
- else if (dfault == NULL_TREE || dfault == error_mark_node)
+ else
{
- expand_start_cond (build (NE_EXPR, integer_type_node,
- exception_throw_decl,
- integer_zero_node), 0);
- /* We fell off the end of this try block. Try going to the next.
- The escape_label will be the beginning of the next try block. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- expand_end_cond ();
+ queue->tail->chain = node;
}
+ queue->tail = node;
}
-/* Generate code to raise exception RAISE_ID.
- If EXP is NULL_TREE, then PARMS is the list of parameters to use
- for constructing this exception.
- If EXP is non-NULL, then it is an already constructed object
- of the kind that we want.
+static struct ehEntry *
+dequeue_eh_entry (queue)
+ struct ehQueue *queue;
+{
+ struct ehNode *tempnode;
+ struct ehEntry *tempentry;
+
+ if (queue->head == NULL)
+ return NULL;
+
+ tempnode = queue->head;
+ queue->head = queue->head->chain;
+
+ tempentry = tempnode->entry;
+ free (tempnode);
+
+ return tempentry;
+}
+
+static void
+new_eh_queue (queue)
+ struct ehQueue *queue;
+{
+ queue->head = queue->tail = NULL;
+}
+
+static void
+new_eh_stack (stack)
+ struct ehStack *stack;
+{
+ stack->top = NULL;
+}
+
+static void
+new_except_stack (stack)
+ struct exceptStack *stack;
+{
+ stack->top = NULL;
+}
+/* ========================================================================= */
+
+
+/* sets up all the global eh stuff that needs to be initialized at the
+ start of compilation.
+
+ This includes:
+ - Setting up all the function call trees
+ - Initializing the ehqueue
+ - Initializing the eh_table_output_queue
+ - Initializing the ehstack
+ - Initializing the exceptstack
+*/
- FOR_RERAISE is non-zero if this raise is called by reraise. In
- this case we do not need to emit extra gotos to avoid warning messages;
- the caller will do that once after all the exceptions it reraises
- are handled and raised. */
void
-cplus_expand_raise (raise_id, parms, exp, for_reraise)
- tree raise_id;
- tree parms;
- tree exp;
- int for_reraise;
+init_exception_processing ()
{
- /* Allocate new exception of appropriate type, passing
- PARMS to its constructor. */
- tree cname, name;
- tree decl;
- tree xexp = exp;
-
- cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
- if (cname == error_mark_node)
- return;
- name = TREE_VALUE (raise_id);
+ extern tree define_function ();
+ tree unexpected_fndecl, terminate_fndecl;
+ tree set_unexpected_fndecl, set_terminate_fndecl;
+ tree catch_match_fndecl;
+ tree find_first_exception_match_fndecl;
+ tree unwind_fndecl;
+ tree temp, PFV;
- decl = lookup_exception_object (cname, name, 1);
- if (decl == NULL_TREE)
- return;
+ /* void (*)() */
+ PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
- if (exp == NULL_TREE)
- {
- exp = build_method_call (NULL_TREE, name, parms, NULL_TREE, LOOKUP_COMPLAIN);
- if (exp == error_mark_node)
- return;
- }
+ /* arg list for the build_function_type call for set_terminate () and
+ set_unexpected () */
+ temp = tree_cons (NULL_TREE, PFV, void_list_node);
- if (in_try_block (1))
- {
- expand_raise (decl);
- }
- else if (! current_function_decl)
+ push_lang_context (lang_name_c);
+
+ set_terminate_fndecl =
+ define_function ("set_terminate",
+ build_function_type (PFV, temp),
+ NOT_BUILT_IN,
+ pushdecl,
+ 0);
+ set_unexpected_fndecl =
+ define_function ("set_unexpected",
+ build_function_type (PFV, temp),
+ NOT_BUILT_IN,
+ pushdecl,
+ 0);
+
+ unexpected_fndecl =
+ define_function ("unexpected",
+ build_function_type (void_type_node, void_list_node),
+ NOT_BUILT_IN,
+ pushdecl,
+ 0);
+ terminate_fndecl =
+ define_function ("terminate",
+ build_function_type (void_type_node, void_list_node),
+ NOT_BUILT_IN,
+ pushdecl,
+ 0);
+ catch_match_fndecl =
+ define_function ("__throw_type_match",
+ build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, string_type_node, void_list_node))),
+ NOT_BUILT_IN,
+ pushdecl,
+ 0);
+ find_first_exception_match_fndecl =
+ define_function ("__find_first_exception_table_match",
+ build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node)),
+ NOT_BUILT_IN,
+ pushdecl,
+ 0);
+ unwind_fndecl =
+ define_function ("__unwind_function",
+ build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
+ NOT_BUILT_IN,
+ pushdecl,
+ 0);
+
+ Unexpected = default_conversion (unexpected_fndecl);
+ Terminate = default_conversion (terminate_fndecl);
+ SetTerminate = default_conversion (set_terminate_fndecl);
+ SetUnexpected = default_conversion (set_unexpected_fndecl);
+ CatchMatch = default_conversion (catch_match_fndecl);
+ FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
+ Unwind = default_conversion (unwind_fndecl);
+ BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
+
+ TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
+
+ pop_lang_context ();
+ throw_label = gen_label_rtx ();
+ saved_pc = gen_rtx (REG, Pmode, 16);
+ saved_throw_type = gen_rtx (REG, Pmode, 17);
+
+ new_eh_queue (&ehqueue);
+ new_eh_queue (&eh_table_output_queue);
+ new_eh_stack (&ehstack);
+ new_except_stack (&exceptstack);
+}
+
+/* call this to begin a block of unwind protection (ie: when an object is
+ constructed) */
+void
+start_protect ()
+{
+ if (doing_eh (0))
{
- if (xexp == NULL_TREE)
- cp_error ("invalid raise of `%D' outside of functions", decl);
- else
- cp_error ("invalid reraise of `%D' outside of functions", decl);
- }
- else
- {
- /* Test this raise against what this function permits. */
- tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
- while (names)
- {
- if (decl == TREE_TYPE (names))
- break;
- names = TREE_CHAIN (names);
- }
- if (names == NULL_TREE)
- {
- error ("current function not declared to raise exception `%s'",
- IDENTIFIER_POINTER (name));
- return;
- }
+ emit_label (push_eh_entry (&ehstack));
}
+}
+
+/* call this to end a block of unwind protection. the finalization tree is
+ the finalization which needs to be run in order to cleanly unwind through
+ this level of protection. (ie: call this when a scope is exited)*/
+void
+end_protect (finalization)
+ tree finalization;
+{
+ struct ehEntry *entry = pop_eh_entry (&ehstack);
- store_expr (exp, EHS_parms_as_rtx, 0);
+ if (! doing_eh (0))
+ return;
- /* Set the global exception handler stack's NAME field
- to the `name' of this exception. The global exception
- handler stack is the container for the exception object
- we just built.
+ emit_label (entry->end_label);
- We go through a function call to make life easier when debugging. */
-#if 0
- expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);
-#else
- parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0),
- build_tree_list (NULL_TREE,
- build_unary_op (ADDR_EXPR, decl, 0)));
- expand_expr (build_function_call (BIR, parms), 0, 0, 0);
-#endif
+ entry->finalization = finalization;
+
+ enqueue_eh_entry (&ehqueue, entry);
+}
- /* Activate thrower. If we are inside a TRY statement,
- we can cheat and not do this, saving a longjmp. */
- if (in_try_block (1) == 0)
+/* call this on start of a try block. */
+void
+expand_start_try_stmts ()
+{
+ if (doing_eh (1))
{
- sets_exception_throw_decl = 1;
- emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
+ start_protect ();
}
+}
- if (xexp == NULL_TREE)
- {
- /* Invoke destructors for current procedure or handler. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- /* Throw via `longjmp'... Done as side-effect of goto. */
- }
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (! for_reraise
- && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
+void
+expand_end_try_stmts ()
+{
+ end_protect (integer_zero_node);
}
-extern tree cplus_exception_name ();
+struct insn_save_node {
+ rtx last;
+ struct insn_save_node *chain;
+ };
-tree
-ansi_exception_object_lookup (type)
- tree type;
+static struct insn_save_node *InsnSave = NULL;
+
+
+/* Used to keep track of where the catch blocks start. */
+static void
+push_last_insn ()
{
- tree raise_id = cplus_exception_name (type);
- tree decl;
+ struct insn_save_node *newnode = (struct insn_save_node*)
+ xmalloc (sizeof (struct insn_save_node));
- decl = IDENTIFIER_GLOBAL_VALUE (raise_id);
- if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
- {
- push_obstacks_nochange ();
- end_temporary_allocation ();
- decl = build_decl (VAR_DECL, raise_id, ptr_type_node);
- TREE_PUBLIC (decl) = 1;
- TREE_STATIC (decl) = 1;
- pushdecl_top_level (decl);
- make_decl_rtl (decl, (char*)0, 1);
- pop_obstacks ();
- }
- return decl;
+ newnode->last = get_last_insn ();
+ newnode->chain = InsnSave;
+ InsnSave = newnode;
}
-/* Generate code to throw an exception using EXP.
- Usng ANSI syntax and semantics.
- If EXP is NULL_TREE< re-raise instead. */
+/* Use to keep track of where the catch blocks start. */
+static rtx
+pop_last_insn ()
+{
+ struct insn_save_node *tempnode;
+ rtx temprtx;
+
+ if (!InsnSave) return NULL_RTX;
+
+ tempnode = InsnSave;
+ temprtx = tempnode->last;
+ InsnSave = InsnSave->chain;
+
+ free (tempnode);
+
+ return temprtx;
+}
+/* call this to start processing of all the catch blocks. */
void
-cplus_expand_throw (exp)
- tree exp;
+expand_start_all_catch ()
{
- tree parms;
- int for_reraise;
- /* Allocate new exception of appropriate type, passing
- PARMS to its constructor. */
- tree decl = ansi_exception_object_lookup (TREE_TYPE (exp));
- tree xexp = exp;
-
- if (in_try_block (1))
+ struct ehEntry *entry;
+ rtx label;
+
+ if (! doing_eh (1))
+ return;
+
+ emit_line_note (input_filename, lineno);
+ label = gen_label_rtx ();
+ /* The label for the exception handling block we will save. */
+ emit_label (label);
+ push_label_entry (&caught_return_label_stack, label);
+
+ /* Remember where we started. */
+ push_last_insn ();
+
+ /* Will this help us not stomp on it? */
+ emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
+
+ while (1)
{
+ entry = dequeue_eh_entry (&ehqueue);
+ emit_label (entry->exception_handler_label);
+
+ expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+
+ /* When we get down to the matching entry, stop. */
+ if (entry->finalization == integer_zero_node)
+ break;
+
+ free (entry);
+ }
+
+ /* This goes when the below moves out of our way. */
#if 1
- my_friendly_abort (35);
-#else
- expand_raise (decl);
+ label = gen_label_rtx ();
+ emit_jump (label);
#endif
- }
- else if (! current_function_decl)
- error ("invalid throw outside of functions");
- else
- {
-#if 0
- /* Test this raise against what this function permits. */
- tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
- while (names)
- {
- if (decl == TREE_TYPE (names))
- break;
- names = TREE_CHAIN (names);
- }
- if (names == NULL_TREE)
- {
- error ("current function not declared to raise exception `%s'",
- IDENTIFIER_POINTER (name));
- return;
- }
+
+ /* All this should be out of line, and saved back in the exception handler
+ block area. */
+#if 1
+ entry->start_label = entry->exception_handler_label;
+ /* These are saved for the exception table. */
+ push_rtl_perm ();
+ entry->end_label = gen_label_rtx ();
+ entry->exception_handler_label = gen_label_rtx ();
+ entry->finalization = TerminateFunctionCall;
+ pop_rtl_from_perm ();
+ emit_label (entry->end_label);
+
+
+ enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
+
+ /* After running the finalization, continue on out to the next
+ cleanup, if we have nothing better to do. */
+ emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
+ /* Will this help us not stomp on it? */
+ emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
+ emit_jump (throw_label);
+ emit_label (entry->exception_handler_label);
+ expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+ emit_barrier ();
#endif
- }
+ emit_label (label);
+}
- store_expr (exp, EHS_parms_as_rtx, 0);
+/* call this to end processing of all the catch blocks. */
+void
+expand_end_all_catch ()
+{
+ rtx catchstart, catchend, last;
+ rtx label;
- /* Set the global exception handler stack's NAME field
- to the `name' of this exception. The global exception
- handler stack is the container for the exception object
- we just built.
+ if (! doing_eh (1))
+ return;
- We go through a function call to make life easier when debugging. */
-#if 0
- expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);
-#else
- parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0),
- build_tree_list (NULL_TREE,
- build_unary_op (ADDR_EXPR, decl, 0)));
- expand_expr (build_function_call (BIR, parms), 0, 0, 0);
-#endif
+ /* Find the start of the catch block. */
+ last = pop_last_insn ();
+ catchstart = NEXT_INSN (last);
+ catchend = get_last_insn ();
- /* Activate thrower. If we are inside a TRY statement,
- we can cheat and not do this, saving a longjmp. */
- if (in_try_block (1) == 0)
- {
- sets_exception_throw_decl = 1;
- emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
- }
+ NEXT_INSN (last) = 0;
+ set_last_insn (last);
- if (xexp == NULL_TREE)
- {
- /* Invoke destructors for current procedure or handler. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- /* Throw via `longjmp'... Done as side-effect of goto. */
- }
+ /* this level of catch blocks is done, so set up the successful catch jump
+ label for the next layer of catch blocks. */
+ pop_label_entry (&caught_return_label_stack);
- /* XXX: for_reraise is never set above here. */
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (! for_reraise
- && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
+ push_except_stmts (&exceptstack, catchstart, catchend);
+
+ /* Here was fall through into the continuation code. */
}
-tree
-cplus_expand_start_catch (raise_id)
- tree raise_id;
+
+/* this is called from expand_exception_blocks () to expand the toplevel
+ finalizations for a function. */
+void
+expand_leftover_cleanups ()
{
- tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
- tree decl;
- tree cond;
+ struct ehEntry *entry;
+ rtx first_label = NULL_RTX;
- if (cname == error_mark_node)
- {
- decl = error_mark_node;
- cond = error_mark_node;
- }
- else
+ if (! doing_eh (0))
+ return;
+
+ /* Will this help us not stomp on it? */
+ emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
+
+ while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
{
- decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1);
- if (decl == NULL_TREE)
- cond = error_mark_node;
- else
- cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0),
- build (COMPONENT_REF, ptr_type_node,
- current_exception_decl,
- TREE_OPERAND (EHS_name, 1)),
- 1);
- }
- expand_start_cond (cond, 0);
+ if (! first_label)
+ first_label = entry->exception_handler_label;
+ emit_label (entry->exception_handler_label);
+
+ expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
- /* Does nothing right now. */
- expand_catch (decl);
- if (current_exception_type
- && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
+ /* leftover try block, opps. */
+ if (entry->finalization == integer_zero_node)
+ abort ();
+
+ free (entry);
+ }
+ if (first_label)
{
- /* Make a cleanup for the name-specific exception object now in scope. */
- tree cleanup = maybe_build_cleanup (current_exception_object);
- expand_start_bindings (0);
- expand_decl_cleanup (NULL_TREE, cleanup);
+ rtx label;
+ struct ehEntry entry;
+ /* These are saved for the exception table. */
+ push_rtl_perm ();
+ label = gen_label_rtx ();
+ entry.start_label = first_label;
+ entry.end_label = label;
+ entry.exception_handler_label = gen_label_rtx ();
+ entry.finalization = TerminateFunctionCall;
+ pop_rtl_from_perm ();
+ emit_label (label);
+
+ enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
+
+ /* After running the finalization, continue on out to the next
+ cleanup, if we have nothing better to do. */
+ emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
+ /* Will this help us not stomp on it? */
+ emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
+ emit_jump (throw_label);
+ emit_label (entry.exception_handler_label);
+ expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
+ emit_barrier ();
}
- return decl;
}
-tree
-ansi_expand_start_catch (raise_type)
- tree raise_type;
-{
- tree decl = ansi_exception_object_lookup (raise_type);
- tree cond;
- if (decl == NULL_TREE)
- cond = error_mark_node;
- else
- cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0),
- build (COMPONENT_REF, ptr_type_node,
- current_exception_decl,
- TREE_OPERAND (EHS_name, 1)),
- 1);
- expand_start_cond (cond, 0);
-
- /* Does nothing right now. */
- expand_catch (decl);
- return decl;
-}
+/* call this to start a catch block. Typename is the typename, and identifier
+ is the variable to place the object in or NULL if the variable doesn't
+ matter. If typename is NULL, that means its a "catch (...)" or catch
+ everything. In that case we don't need to do any type checking.
+ (ie: it ends up as the "else" clause rather than an "else if" clause) */
void
-cplus_expand_end_catch (for_reraise)
- int for_reraise;
+expand_start_catch_block (typename, identifier)
+ tree typename, identifier;
{
- if (current_exception_type
- && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
- {
- /* Destroy the specific exception object now in scope. */
- expand_end_bindings (getdecls (), 0, 1);
- }
- if (for_reraise)
+ rtx false_label_rtx;
+ tree type;
+
+ if (! doing_eh (1))
+ return;
+
+ if (typename)
+ type = groktypename (typename);
+ else
+ type = NULL_TREE;
+
+ false_label_rtx = gen_label_rtx ();
+ push_label_entry (&false_label_stack, false_label_rtx);
+
+ if (type)
{
- if (! expand_escape_except ())
- my_friendly_abort (36);
+ tree params;
+ char *typestring;
+ rtx call_rtx, return_value_rtx;
+ tree catch_match_fcall;
+ tree catchmatch_arg, argval;
+
+ typestring = build_overload_name (type, 1, 1);
+
+ params = tree_cons (NULL_TREE,
+ combine_strings (build_string (strlen (typestring)+1, typestring)),
+ tree_cons (NULL_TREE,
+ make_tree (ptr_type_node, saved_throw_type),
+ NULL_TREE));
+ catch_match_fcall = build_function_call (CatchMatch, params);
+ call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0);
+
+ return_value_rtx =
+ hard_function_value (integer_type_node, catch_match_fcall);
+
+ /* did the throw type match function return TRUE? */
+ emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX,
+ GET_MODE (return_value_rtx), 0, 0);
+
+ /* if it returned FALSE, jump over the catch block, else fall into it */
+ emit_jump_insn (gen_bne (false_label_rtx));
}
else
{
- if (! expand_end_catch ())
- my_friendly_abort (37);
+ /* Fall into the catch all section. */
}
- expand_end_cond ();
+ emit_line_note (input_filename, lineno);
}
-/* Reraise an exception.
- If EXCEPTIONS is NULL_TREE, it means reraise whatever exception was caught.
- If EXCEPTIONS is an IDENTIFIER_NODE, it means reraise the exception
- object named by EXCEPTIONS. This must be a variable declared in
- an `except' clause.
- If EXCEPTIONS is a TREE_LIST, it is the list of exceptions we are
- willing to reraise. */
-void
-cplus_expand_reraise (exceptions)
- tree exceptions;
+/* Call this to end a catch block. Its responsible for emitting the
+ code to handle jumping back to the correct place, and for emitting
+ the label to jump to if this catch block didn't match. */
+void expand_end_catch_block ()
{
- tree ex_ptr;
- tree ex_object = current_exception_object;
- rtx ex_ptr_as_rtx;
-
- if (exceptions && TREE_CODE (exceptions) == IDENTIFIER_NODE)
+ if (doing_eh (1))
{
- /* Don't get tripped up if its TREE_TYPE is `error_mark_node'. */
- ex_object = IDENTIFIER_LOCAL_VALUE (exceptions);
- if (ex_object == NULL_TREE || TREE_CODE (ex_object) != INDIRECT_REF)
- {
- error ("`%s' is not an exception decl", IDENTIFIER_POINTER (exceptions));
- return;
- }
- my_friendly_assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL,
- 204);
- exceptions = NULL_TREE;
+ /* label we jump to if we caught the exception */
+ emit_jump (top_label_entry (&caught_return_label_stack));
+
+ /* label we emit to jump to if this catch block didn't match. */
+ emit_label (pop_label_entry (&false_label_stack));
}
+}
- ex_ptr = build1 (NOP_EXPR, ptr_type_node, TREE_OPERAND (ex_object, 0));
- ex_ptr_as_rtx = expand_expr (ex_ptr, 0, 0, 0);
+/* cheesyness to save some typing. returns the return value rtx */
+rtx
+do_function_call (func, params, return_type)
+ tree func, params, return_type;
+{
+ tree func_call;
+ func_call = build_function_call (func, params);
+ expand_call (func_call, NULL_RTX, 0);
+ if (return_type != NULL_TREE)
+ return hard_function_value (return_type, func_call);
+ return NULL_RTX;
+}
- /* reraise ALL, used by compiler. */
- if (exceptions == NULL_TREE)
- {
- /* Now treat reraise like catch/raise. */
- expand_catch (error_mark_node);
- expand_raise (error_mark_node);
- emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx);
- store_expr ((tree) EHS_parms_as_rtx, current_exception_parms_as_rtx, 0);
- if (in_try_block (1) == 0)
- {
- sets_exception_throw_decl = 1;
- emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
- }
- /* Set to zero so that destructor will not be called. */
- emit_move_insn (ex_ptr_as_rtx, const0_rtx);
- if (! expand_escape_except ())
- my_friendly_abort (38);
-
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
-
- return;
- }
- /* reraise from a list of exceptions. */
- while (exceptions)
- {
- tree type = lookup_exception_type (current_class_type, current_class_name,
- exceptions);
- if (type == NULL_TREE)
- {
- error ("`%s' is not an exception type",
- IDENTIFIER_POINTER (TREE_VALUE (exceptions)));
- current_exception_type = NULL_TREE;
- TREE_TYPE (ex_object) = error_mark_node;
- TREE_TYPE (ex_ptr) = error_mark_node;
- }
- else
- {
- current_exception_type = type;
- /* In-place union. */
- TREE_TYPE (ex_object) = type;
- TREE_TYPE (ex_ptr) = TYPE_POINTER_TO (type);
- }
+/* is called from expand_excpetion_blocks () to generate the code in a function
+ to "throw" if anything in the function needs to preform a throw.
- /* Now treat reraise like catch/raise. */
- cplus_expand_start_catch (exceptions);
- cplus_expand_raise (exceptions, NULL_TREE, ex_ptr, 1);
- /* Set to zero so that destructor will not be called. */
- if (TREE_TYPE (ex_ptr) != error_mark_node)
- emit_move_insn (ex_ptr_as_rtx, const0_rtx);
- cplus_expand_end_catch (1);
- exceptions = TREE_CHAIN (exceptions);
- }
- /* Don't propagate any unhandled exceptions. */
- expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0);
-
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
+ expands "throw" as the following psuedo code:
+
+ throw:
+ eh = find_first_exception_match (saved_pc);
+ if (!eh) goto gotta_rethrow_it;
+ goto eh;
+
+ gotta_rethrow_it:
+ saved_pc = __builtin_return_address (0);
+ pop_to_previous_level ();
+ goto throw;
+
+ */
+static void
+expand_builtin_throw ()
+{
+ tree fcall;
+ tree params;
+ rtx return_val_rtx;
+ rtx gotta_rethrow_it = gen_label_rtx ();
+ rtx gotta_call_terminate = gen_label_rtx ();
+ rtx unwind_and_throw = gen_label_rtx ();
+ rtx goto_unwind_and_throw = gen_label_rtx ();
+
+ emit_label (throw_label);
+
+ /* search for an exception handler for the saved_pc */
+ return_val_rtx = do_function_call (FirstExceptionMatch,
+ tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
+ ptr_type_node);
+
+ /* did we find one? */
+ emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
+ GET_MODE (return_val_rtx), 0, 0);
+
+ /* if not, jump to gotta_rethrow_it */
+ emit_jump_insn (gen_beq (gotta_rethrow_it));
+
+ /* we found it, so jump to it */
+ emit_indirect_jump (return_val_rtx);
+
+ /* code to deal with unwinding and looking for it again */
+ emit_label (gotta_rethrow_it);
+
+ /* call to __builtin_return_address () */
+ params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+ fcall = build_function_call (BuiltinReturnAddress, params);
+ return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
+
+ /* did __builtin_return_address () return a valid address? */
+ emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
+ GET_MODE (return_val_rtx), 0, 0);
+
+ emit_jump_insn (gen_beq (gotta_call_terminate));
+
+ /* yes it did */
+ emit_move_insn (saved_pc, return_val_rtx);
+ do_unwind (throw_label);
+ emit_jump (throw_label);
+
+ /* no it didn't --> therefore we need to call terminate */
+ emit_label (gotta_call_terminate);
+ do_function_call (Terminate, NULL_TREE, NULL_TREE);
}
-\f
+
+
+/* This is called to expand all the toplevel exception handling
+ finalization for a function. It should only be called once per
+ function. */
void
-setup_exception_throw_decl ()
+expand_exception_blocks ()
{
- tree call_to_longjmp, parms;
-
- int old = suspend_momentary ();
-
- exception_throw_decl = build_decl (VAR_DECL, get_identifier (THROW_NAME), integer_type_node);
- pushdecl (exception_throw_decl);
- parms = tree_cons (NULL_TREE, EHS_handler,
- build_tree_list (0, integer_one_node));
- call_to_longjmp = build_function_call (BILJ, parms);
-
- expand_decl (exception_throw_decl);
- expand_decl_cleanup (exception_throw_decl,
- build (COND_EXPR, void_type_node,
- exception_throw_decl,
- call_to_longjmp, integer_zero_node));
- DECL_INITIAL (exception_throw_decl) = integer_zero_node;
- sets_exception_throw_decl = 0;
- resume_momentary (old);
-
- /* Cache these, since they won't change throughout the function. */
- EHS_parms_as_rtx = expand_expr (EHS_parms, 0, 0, 0);
- EHS_name_as_rtx = expand_expr (EHS_name, 0, 0, 0);
+ rtx catchstart, catchend;
+ rtx last;
+ static rtx funcend;
+
+ funcend = gen_label_rtx ();
+ emit_jump (funcend);
+ /* expand_null_return (); */
+
+ while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
+ last = get_last_insn ();
+ NEXT_INSN (last) = catchstart;
+ PREV_INSN (catchstart) = last;
+ NEXT_INSN (catchend) = 0;
+ set_last_insn (catchend);
+ }
+
+ expand_leftover_cleanups ();
+
+ {
+ static int have_done = 0;
+ if (! have_done && TREE_PUBLIC (current_function_decl)
+ && ! DECL_INLINE (current_function_decl))
+ {
+ have_done = 1;
+ expand_builtin_throw ();
+ }
+ }
+ emit_label (funcend);
}
+
+/* call this to expand a throw statement. This follows the following
+ algorithm:
+
+ 1. Allocate space to save the current PC onto the stack.
+ 2. Generate and emit a label and save its address into the
+ newly allocate stack space since we can't save the pc directly.
+ 3. If this is the first call to throw in this function:
+ generate a label for the throw block
+ 4. jump to the throw block label. */
void
-init_exception_processing ()
+expand_throw (exp)
+ tree exp;
{
- extern tree build_function_type (), define_function ();
- extern tree unhandled_exception_fndecl;
- tree cname = get_identifier ("ExceptionHandler");
- tree field, chain;
- tree ctor, dtor;
- tree jmp_buf_type = build_array_type (integer_type_node,
- build_index_type (build_int_2 (_JBLEN-1, 0)));
- tree jmp_buf_arg_type = build_pointer_type (integer_type_node);
-
- tree parmtypes = hash_tree_chain (jmp_buf_arg_type, void_list_node);
- tree setjmp_fndecl, longjmp_fndecl, raise_fndecl;
-
- int old_interface_only = interface_only;
- int old_interface_unknown = interface_unknown;
- interface_only = 1;
- interface_unknown = 0;
- EHS_type = xref_tag (record_type_node, cname, NULL_TREE, 0);
- push_lang_context (lang_name_c);
- setjmp_fndecl = define_function ("setjmp",
- build_function_type (integer_type_node,
- parmtypes),
- NOT_BUILT_IN, pushdecl, 0);
- BISJ = default_conversion (setjmp_fndecl);
- parmtypes = hash_tree_chain (jmp_buf_arg_type,
- hash_tree_chain (integer_type_node, void_list_node));
- longjmp_fndecl = define_function ("longjmp",
- build_function_type (void_type_node, parmtypes),
- NOT_BUILT_IN, pushdecl, 0);
- raise_fndecl = define_function ("__raise_exception",
- build_function_type (void_type_node,
- hash_tree_chain (ptr_type_node,
- hash_tree_chain (build_pointer_type (ptr_type_node), void_list_node))),
- NOT_BUILT_IN, pushdecl, 0);
- BILJ = default_conversion (longjmp_fndecl);
- BIR = default_conversion (raise_fndecl);
- BIUE = default_conversion (unhandled_exception_fndecl);
+ tree raiseid = NULL_TREE;
+ rtx temp_size;
+ rtx label;
+ tree type;
- pop_lang_context ();
+ if (! doing_eh (1))
+ return;
- /* finish_struct will pop this. */
- pushclass (EHS_type, 0);
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node);
- chain = field;
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
- build_pointer_type (default_function_type));
- TREE_CHAIN (field) = chain;
- chain = field;
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type);
- TREE_CHAIN (field) = chain;
- chain = field;
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"),
- TYPE_POINTER_TO (EHS_type));
- TREE_CHAIN (field) = chain;
- chain = field;
-
- ctor = build_lang_decl (FUNCTION_DECL, cname,
- build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
- DECL_CONSTRUCTOR_P (ctor) = 1;
- TREE_STATIC (ctor) = 1;
- TREE_PUBLIC (ctor) = 1;
- DECL_EXTERNAL (ctor) = 1;
- grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0);
- grok_ctor_properties (EHS_type, ctor);
- finish_decl (pushdecl (ctor), NULL_TREE, NULL_TREE, 0);
- /* Must copy the node here because the FUNCTION_DECL
- used inside the struct ain't the same as the
- FUNCTION_DECL we stick into the global binding
- contour. */
- ctor = copy_node (ctor);
- TREE_CHAIN (ctor) = chain;
- chain = ctor;
- dtor = build_lang_decl (FUNCTION_DECL, cname,
- build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
- TREE_STATIC (dtor) = 1;
- TREE_PUBLIC (dtor) = 1;
- DECL_EXTERNAL (dtor) = 1;
- grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0);
- finish_decl (pushdecl (dtor), NULL_TREE, NULL_TREE, 0);
- /* Copy for the same reason as copying ctor. */
- dtor = copy_node (dtor);
- TREE_CHAIN (dtor) = chain;
- chain = dtor;
- TYPE_HAS_CONSTRUCTOR (EHS_type) = 1;
- TYPE_HAS_DESTRUCTOR (EHS_type) = 1;
- finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0);
- interface_only = old_interface_only;
- interface_unknown = old_interface_unknown;
+ label = gen_label_rtx ();
+ emit_label (label);
+ emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
+
+ if (exp)
+ {
+ /* throw variable */
+ /* First, decay it. */
+ exp = default_conversion (exp);
+ type = TREE_TYPE (exp);
+ }
+ else
+ type = void_type_node;
+
+ {
+ char *typestring = build_overload_name (type, 1, 1);
+ tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
+ rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
+ emit_move_insn (saved_throw_type, throw_type_rtx);
+ }
+
+ emit_jump (throw_label);
}
+
+/* output the exception table */
void
-init_exception_processing_1 ()
+build_exception_table ()
{
- register tree EHS_id = get_identifier ("exceptionHandlerStack");
+ extern FILE *asm_out_file;
+ struct ehEntry *entry;
- EHS_decl = IDENTIFIER_GLOBAL_VALUE (EHS_id);
+ if (! doing_eh (0))
+ return;
- /* If we have no other definition, default to library implementation. */
- if (EHS_decl == NULL_TREE)
- {
- EHS_decl = build_decl (VAR_DECL, EHS_id, TYPE_POINTER_TO (EHS_type));
- /* If we don't push this, its definition, should it be encountered,
- will not be seen. */
- EHS_decl = pushdecl (EHS_decl);
- DECL_EXTERNAL (EHS_decl) = 1;
- TREE_STATIC (EHS_decl) = 1;
- TREE_PUBLIC (EHS_decl) = 1;
- finish_decl (EHS_decl, NULL_TREE, NULL_TREE, 0);
- }
- else if (TREE_CODE (EHS_decl) != VAR_DECL
- || TREE_TYPE (EHS_decl) != TYPE_POINTER_TO (EHS_type))
- fatal ("exception handling declarations conflict with compiler's internal model");
+ exception_section ();
- if (EHS_prev == NULL_TREE)
- {
- register tree EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl);
- EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0);
- EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0);
- EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0);
- EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0);
- }
+ /* Beginning marker for table. */
+ fprintf (asm_out_file, " .global ___EXCEPTION_TABLE__\n");
+ fprintf (asm_out_file, " .align 4\n");
+ fprintf (asm_out_file, "___EXCEPTION_TABLE__:\n");
+ fprintf (asm_out_file, " .word 0, 0, 0\n");
+
+ while (entry = dequeue_eh_entry (&eh_table_output_queue)) {
+ output_exception_table_entry (asm_out_file,
+ entry->start_label, entry->end_label, entry->exception_handler_label);
+ }
+
+ /* Ending marker for table. */
+ fprintf (asm_out_file, " .global ___EXCEPTION_END__\n");
+ fprintf (asm_out_file, "___EXCEPTION_END__:\n");
+ fprintf (asm_out_file, " .word -1, -1, -1\n");
+}
+
+/* end of: my-cp-except.c */
+#endif
+
+
+/* Build a throw expression. */
+tree
+build_throw (e)
+ tree e;
+{
+ e = build1 (THROW_EXPR, void_type_node, e);
+ TREE_SIDE_EFFECTS (e) = 1;
+ return e;
}
case THUNK_DECL:
return DECL_RTL (exp);
+ case THROW_EXPR:
+ expand_throw (TREE_OPERAND (exp, 0));
+ return NULL;
+
default:
break;
}
__volatile, TYPE_QUAL, RID_VOLATILE
__volatile__, TYPE_QUAL, RID_VOLATILE
__wchar_t, TYPESPEC, RID_WCHAR /* Unique to ANSI C++ */,
-all, ALL, NORID /* Extension */,
-except, EXCEPT, NORID /* Extension */,
-exception, AGGR, RID_EXCEPTION /* Extension */,
-raise, RAISE, NORID /* Extension */,
-raises, RAISES, NORID /* Extension */,
-reraise, RERAISE, NORID /* Extension */,
-throw, THROW, NORID /* Extension */,
-try, TRY, NORID /* Extension */,
asm, ASM_KEYWORD, NORID,
auto, SCSPEC, RID_AUTO,
break, BREAK, NORID,
struct, AGGR, RID_RECORD,
switch, SWITCH, NORID,
this, THIS, NORID,
+throw, THROW, NORID,
template, TEMPLATE, NORID,
+try, TRY, NORID,
typedef, SCSPEC, RID_TYPEDEF,
typeof, TYPEOF, NORID,
typeid, TYPEID, NORID,
@node Top, Limitations of g++, (dir), (dir)
@chapter Internal Architecture of the Compiler
-This is meant to describe the C++ frontend for gcc in detail.
+This is meant to describe the C++ front-end for gcc in detail.
Questions and comments to mrs@@cygnus.com.
@menu
* Error Reporting::
* Parser::
* Copying Objects::
+* Exception Handling::
* Concept Index::
@end menu
@item DECL_IGNORED_P
A bit that can be set to inform the debug information output routines in
-the backend that a certain _DECL node should be totally ignored.
+the back-end that a certain _DECL node should be totally ignored.
Used in cases where it is known that the debugging information will be
output in another file, or where a sub-type is known not to be needed
@node Error Reporting, Parser, Access Control, Top
@section Error Reporting
-The C++ frontend uses a call-back mechanism to allow functions to print
+The C++ front-end uses a call-back mechanism to allow functions to print
out reasonable strings for types and functions without putting extra
logic in the functions where errors are found. The interface is through
the @code{cp_error} function (or @code{cp_warning}, etc.). The
Unlike the others, this ambiguity is not recognized by the Working Paper.
-@node Copying Objects, Concept Index, Parser, Top
+@node Copying Objects, Exception Handling, Parser, Top
@section Copying Objects
The generated copy assignment operator in g++ does not currently do the
This issue is currently under discussion in the core reflector
(2/28/94).
-@node Concept Index, , Copying Objects, Top
+@node Copying Objects, Concept Index, Copying Objects, Top
+@section Exception Handling
+
+This section describes the mapping of C++ exceptions in the C++
+front-end, into the back-end exception handling framework.
+
+The basic mechanism of exception handling in the back-end is
+unwind-protect a la elisp. This is a general, robust, and language
+independent representation for exceptions.
+
+The C++ front-end exceptions are mapping into the unwind-protect
+semantics by the C++ front-end. The mapping is describe below.
+
+Objects with RTTI support, should use the RTTI information to do mapping
+and checking. Objects without RTTI, like int and const char *, have to
+use another means of matching. Currently we use the normal mangling used in
+building functions names. Int's are "i", const char * is PCc, etc...
+
+Unfortunately, the standard allows standard type conversions on throw
+parameters so they can match catch handlers. This means we need a
+mechanism to handle type conversion at run time, ICK.
+
+In C++, all cleanups should be protected by exception regions. The
+region starts just after the reason why the cleanup is created has
+ended. For example, with an automatic variable, that has a constructor,
+it would be right after the constructor is run. The region ends just
+before the finalization is expanded. Since the backend may expand the
+cleanup multiple times along different paths, once for normal end of the
+region, once for non-local gotos, once for returns, etc, the backend
+must take special care to protect the finalization expansion, if the
+expansion is for any other reason than normal region end, and it is
+`inline' (it is inside the exception region). The backend can either
+choose to move them out of line, or it can created an exception region
+over the finalization to protect it, and in the handler associated with
+it, it would not run the finalization as it otherwise would have, but
+rather just rethrow to the outer handler, careful to skip the normal
+handler for the original region.
+
+In Ada, they will use the more runtime intensive approach of having
+fewer regions, but at the cost of additional work at run time, to keep a
+list of things that need cleanups. When a variable has finished
+construction, they add the cleanup to the list, when the come to the end
+of the lifetime of the variable, the run the list down. If the take a
+hit before the section finishes normally, they examine the list for
+actions to perform. I hope they add this logic into the back-end, as it
+would be nice to get that alternative approach in C++.
+
+@node Concept Index, , Exception Handling, Top
@section Concept Index
@printindex cp
/* Command-line: gperf -p -j1 -g -o -t -N is_reserved_word -k1,4,$,7 gplus.gperf */
struct resword { char *name; short token; enum rid rid;};
-#define TOTAL_KEYWORDS 86
+#define TOTAL_KEYWORDS 80
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 13
#define MIN_HASH_VALUE 4
-#define MAX_HASH_VALUE 196
-/* maximum key range = 193, duplicates = 0 */
+#define MAX_HASH_VALUE 166
+/* maximum key range = 163, duplicates = 0 */
#ifdef __GNUC__
inline
{
static unsigned char asso_values[] =
{
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
- 197, 197, 197, 197, 197, 0, 197, 93, 3, 35,
- 3, 0, 71, 8, 4, 78, 197, 3, 30, 6,
- 29, 18, 37, 197, 55, 0, 4, 11, 7, 20,
- 0, 8, 197, 197, 197, 197, 197, 197,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 0, 167, 36, 6, 60,
+ 17, 0, 16, 5, 41, 38, 167, 11, 22, 7,
+ 26, 0, 4, 167, 22, 0, 4, 44, 19, 8,
+ 5, 18, 167, 167, 167, 167, 167, 167,
};
register int hval = len;
{"",}, {"",},
{"__asm__", GCC_ASM_KEYWORD, NORID},
{"this", THIS, NORID,},
- {"delete", DELETE, NORID,},
- {"except", EXCEPT, NORID /* Extension */,},
- {"__asm", GCC_ASM_KEYWORD, NORID},
- {"double", TYPESPEC, RID_DOUBLE,},
- {"typeid", TYPEID, NORID,},
- {"switch", SWITCH, NORID,},
- {"try", TRY, NORID /* Extension */,},
- {"enum", ENUM, NORID,},
- {"void", TYPESPEC, RID_VOID,},
- {"",}, {"",}, {"",},
- {"struct", AGGR, RID_RECORD,},
- {"",},
- {"do", DO, NORID,},
- {"",}, {"",}, {"",}, {"",},
+ {"goto", GOTO, NORID,},
{"__headof__", HEADOF, NORID},
- {"",}, {"",},
+ {"",},
+ {"__asm", GCC_ASM_KEYWORD, NORID},
{"__const__", TYPE_QUAL, RID_CONST},
{"__volatile", TYPE_QUAL, RID_VOLATILE},
{"__const", TYPE_QUAL, RID_CONST},
{"__volatile__", TYPE_QUAL, RID_VOLATILE},
- {"extern", SCSPEC, RID_EXTERN,},
+ {"throw", THROW, NORID,},
+ {"enum", ENUM, NORID,},
+ {"do", DO, NORID,},
+ {"template", TEMPLATE, NORID,},
+ {"sigof", SIGOF, NORID /* Extension */,},
+ {"sizeof", SIZEOF, NORID,},
+ {"delete", DELETE, NORID,},
+ {"__headof", HEADOF, NORID},
+ {"try", TRY, NORID,},
+ {"typeof", TYPEOF, NORID,},
+ {"typeid", TYPEID, NORID,},
{"__typeof__", TYPEOF, NORID},
- {"",},
- {"signed", TYPESPEC, RID_SIGNED,},
- {"case", CASE, NORID,},
- {"class", AGGR, RID_CLASS,},
+ {"double", TYPESPEC, RID_DOUBLE,},
+ {"private", VISSPEC, RID_PRIVATE,},
+ {"short", TYPESPEC, RID_SHORT,},
+ {"extern", SCSPEC, RID_EXTERN,},
{"__classof__", CLASSOF, NORID},
- {"__extension__", EXTENSION, NORID},
- {"",},
- {"const", TYPE_QUAL, RID_CONST,},
- {"static", SCSPEC, RID_STATIC,},
{"",},
- {"throw", THROW, NORID /* Extension */,},
- {"goto", GOTO, NORID,},
- {"signature", AGGR, RID_SIGNATURE /* Extension */,},
+ {"while", WHILE, NORID,},
{"long", TYPESPEC, RID_LONG,},
- {"private", VISSPEC, RID_PRIVATE,},
{"new", NEW, NORID,},
- {"template", TEMPLATE, NORID,},
- {"",},
- {"while", WHILE, NORID,},
- {"",},
{"protected", VISSPEC, RID_PROTECTED,},
- {"continue", CONTINUE, NORID,},
- {"",},
- {"raise", RAISE, NORID /* Extension */,},
- {"raises", RAISES, NORID /* Extension */,},
- {"",},
- {"union", AGGR, RID_UNION,},
- {"short", TYPESPEC, RID_SHORT,},
- {"",},
- {"__inline", SCSPEC, RID_INLINE},
- {"",},
- {"__inline__", SCSPEC, RID_INLINE},
- {"",},
- {"__alignof__", ALIGNOF, NORID},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"sizeof", SIZEOF, NORID,},
- {"virtual", SCSPEC, RID_VIRTUAL,},
- {"catch", CATCH, NORID,},
{"friend", SCSPEC, RID_FRIEND,},
- {"typeof", TYPEOF, NORID,},
- {"",}, {"",},
- {"headof", HEADOF, NORID,},
+ {"auto", SCSPEC, RID_AUTO,},
+ {"for", FOR, NORID,},
+ {"__typeof", TYPEOF, NORID},
+ {"typedef", SCSPEC, RID_TYPEDEF,},
+ {"__extension__", EXTENSION, NORID},
{"int", TYPESPEC, RID_INT,},
- {"",}, {"",},
+ {"asm", ASM_KEYWORD, NORID,},
+ {"__classof", CLASSOF, NORID},
{"__signed__", TYPESPEC, RID_SIGNED},
- {"__signed", TYPESPEC, RID_SIGNED},
- {"",}, {"",}, {"",},
+ {"signed", TYPESPEC, RID_SIGNED,},
+ {"mutable", SCSPEC, RID_MUTABLE,},
+ {"switch", SWITCH, NORID,},
+ {"operator", OPERATOR, NORID,},
{"__attribute", ATTRIBUTE, NORID},
- {"sigof", SIGOF, NORID /* Extension */,},
+ {"struct", AGGR, RID_RECORD,},
{"__attribute__", ATTRIBUTE, NORID},
+ {"if", IF, NORID,},
+ {"void", TYPESPEC, RID_VOID,},
+ {"break", BREAK, NORID,},
+ {"__alignof__", ALIGNOF, NORID},
+ {"__inline", SCSPEC, RID_INLINE},
+ {"float", TYPESPEC, RID_FLOAT,},
+ {"__inline__", SCSPEC, RID_INLINE},
+ {"__signed", TYPESPEC, RID_SIGNED},
+ {"case", CASE, NORID,},
+ {"class", AGGR, RID_CLASS,},
{"",},
- {"__headof", HEADOF, NORID},
+ {"__label__", LABEL, NORID},
+ {"default", DEFAULT, NORID,},
+ {"const", TYPE_QUAL, RID_CONST,},
+ {"static", SCSPEC, RID_STATIC,},
{"",}, {"",},
- {"unsigned", TYPESPEC, RID_UNSIGNED,},
- {"return", RETURN, NORID,},
- {"asm", ASM_KEYWORD, NORID,},
- {"__wchar_t", TYPESPEC, RID_WCHAR /* Unique to ANSI C++ */,},
- {"break", BREAK, NORID,},
- {"__typeof", TYPEOF, NORID},
- {"mutable", SCSPEC, RID_MUTABLE,},
+ {"__alignof", ALIGNOF, NORID},
+ {"virtual", SCSPEC, RID_VIRTUAL,},
+ {"union", AGGR, RID_UNION,},
+ {"",}, {"",}, {"",},
+ {"signature", AGGR, RID_SIGNATURE /* Extension */,},
+ {"headof", HEADOF, NORID,},
{"",},
- {"public", VISSPEC, RID_PUBLIC,},
+ {"inline", SCSPEC, RID_INLINE,},
+ {"overload", OVERLOAD, NORID,},
{"",},
- {"__classof", CLASSOF, NORID},
- {"default", DEFAULT, NORID,},
+ {"volatile", TYPE_QUAL, RID_VOLATILE,},
{"",}, {"",}, {"",}, {"",},
- {"exception", AGGR, RID_EXCEPTION /* Extension */,},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"all", ALL, NORID /* Extension */,},
+ {"register", SCSPEC, RID_REGISTER,},
+ {"",},
+ {"public", VISSPEC, RID_PUBLIC,},
{"",}, {"",},
- {"for", FOR, NORID,},
+ {"__wchar_t", TYPESPEC, RID_WCHAR /* Unique to ANSI C++ */,},
{"",}, {"",},
- {"__label__", LABEL, NORID},
- {"auto", SCSPEC, RID_AUTO,},
- {"",}, {"",}, {"",}, {"",},
- {"volatile", TYPE_QUAL, RID_VOLATILE,},
- {"__alignof", ALIGNOF, NORID},
+ {"return", RETURN, NORID,},
+ {"classof", CLASSOF, NORID,},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"dynamic_cast", DYNAMIC_CAST, NORID,},
- {"",},
+ {"unsigned", TYPESPEC, RID_UNSIGNED,},
{"char", TYPESPEC, RID_CHAR,},
- {"",},
- {"if", IF, NORID,},
- {"",},
- {"typedef", SCSPEC, RID_TYPEDEF,},
- {"operator", OPERATOR, NORID,},
- {"reraise", RERAISE, NORID /* Extension */,},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"inline", SCSPEC, RID_INLINE,},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"continue", CONTINUE, NORID,},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",},
- {"float", TYPESPEC, RID_FLOAT,},
{"",}, {"",}, {"",},
- {"overload", OVERLOAD, NORID,},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"classof", CLASSOF, NORID,},
+ {"dynamic_cast", DYNAMIC_CAST, NORID,},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",}, {"",},
- {"register", SCSPEC, RID_REGISTER,},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+
+ {"catch", CATCH, NORID,},
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
}
-
- if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (type))
- {
- cplus_expand_start_try (1);
- push_exception_cleanup (build_unary_op (ADDR_EXPR, decl, 0));
- }
+ if (flag_handle_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
+ cp_warning ("caution, member `%D' may not be destroyed in the presense of an exception during construction", member);
}
/* Subroutine of emit_member_init. */
emit_line_note_force (DECL_SOURCE_FILE (current_function_decl),
DECL_SOURCE_LINE (current_function_decl));
- /* In this case, we always need IN_CHARGE_NODE, because we have
- to know whether to deallocate or not before exiting. */
- if (flag_handle_exceptions == 2
- && lookup_name (in_charge_identifier, 0) == NULL_TREE)
- {
- tree in_charge_node = pushdecl (build_decl (VAR_DECL, in_charge_identifier,
- integer_type_node));
- store_init_value (in_charge_node, build (EQ_EXPR, integer_type_node,
- current_class_decl,
- integer_zero_node));
- expand_decl (in_charge_node);
- expand_decl_init (in_charge_node);
- }
-
start = ! TYPE_USES_VIRTUAL_BASECLASSES (t);
for (pass = start; pass < 2; pass++)
{
expand_aggr_init_1 (t_binfo, 0,
build_indirect_ref (member, NULL_PTR), init,
BINFO_OFFSET_ZEROP (binfo), LOOKUP_COMPLAIN);
- if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
- {
- cplus_expand_start_try (1);
- push_exception_cleanup (member);
- }
}
if (pass == 0)
expand_aggr_init_1 (t_binfo, 0, ref, NULL_TREE,
BINFO_OFFSET_ZEROP (base_binfo),
LOOKUP_COMPLAIN);
- if (flag_handle_exceptions == 2
- && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
- {
- cplus_expand_start_try (1);
- push_exception_cleanup (base);
- }
}
}
CLEAR_BINFO_BASEINIT_MARKED (base_binfo);
do { struct resword *s = is_reserved_word (STRING, sizeof (STRING) - 1); \
if (s) s->name = ""; } while (0)
- if (flag_ansi_exceptions)
- flag_handle_exceptions = 2;
-
- if (!flag_ansi_exceptions)
+#if 0
+ /* let's parse things, and if they use it, then give them an error. */
+ if (!flag_handle_exceptions)
{
+ UNSET_RESERVED_WORD ("throw");
+ UNSET_RESERVED_WORD ("try");
UNSET_RESERVED_WORD ("catch");
}
+#endif
- if (! flag_handle_exceptions)
- {
- /* Easiest way to not recognize exception
- handling extensions... */
- UNSET_RESERVED_WORD ("all");
- UNSET_RESERVED_WORD ("except");
- UNSET_RESERVED_WORD ("exception");
- UNSET_RESERVED_WORD ("raise");
- UNSET_RESERVED_WORD ("raises");
- UNSET_RESERVED_WORD ("reraise");
- UNSET_RESERVED_WORD ("try");
- UNSET_RESERVED_WORD ("throw");
- }
- else if (flag_ansi_exceptions)
- {
- /* Easiest way to not recognize exception
- handling extensions... */
- UNSET_RESERVED_WORD ("exception");
- UNSET_RESERVED_WORD ("all");
- UNSET_RESERVED_WORD ("except");
- UNSET_RESERVED_WORD ("raise");
- UNSET_RESERVED_WORD ("raises");
- UNSET_RESERVED_WORD ("reraise");
- is_reserved_word ("try", sizeof ("try") - 1)->token = ANSI_TRY;
- is_reserved_word ("throw", sizeof ("throw") - 1)->token = ANSI_THROW;
- }
if (! (flag_gc || flag_dossier))
{
UNSET_RESERVED_WORD ("classof");
}
}
+ /* Remember that this name has been used in the class definition, as per
+ [class.scope0] */
+ if (id && current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && ! IDENTIFIER_CLASS_VALUE (token))
+ pushdecl_class_level (id);
+
if (!id || id == error_mark_node)
{
if (id == error_mark_node && current_class_type != NULL_TREE)
if (strcmp ("catch", token_buffer) == 0
|| strcmp ("throw", token_buffer) == 0
|| strcmp ("try", token_buffer) == 0)
- pedwarn ("`catch', `throw', and `try' are all C++ reserved words");
+ {
+ static int did_warn = 0;
+ if (! did_warn && ! flag_handle_exceptions)
+ {
+ pedwarn ("`catch', `throw', and `try' are all C++ reserved words");
+ did_warn = 1;
+ }
+ }
if (value == IDENTIFIER || value == TYPESPEC)
GNU_xref_ref (current_function_decl, token_buffer);
%left <code> POINTSAT '.' '(' '['
%right SCOPE /* C++ extension */
-%nonassoc NEW DELETE RAISE RAISES RERAISE TRY EXCEPT CATCH THROW
-%nonassoc ANSI_TRY ANSI_THROW
+%nonassoc NEW DELETE TRY CATCH THROW
%type <code> unop
%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
%type <ttype> maybe_attribute attribute_list attrib
-%type <ttype> compstmt except_stmts ansi_except_stmts implicitly_scoped_stmt
+%type <ttype> compstmt implicitly_scoped_stmt
%type <ttype> declarator notype_declarator after_type_declarator
%type <ttype> direct_notype_declarator direct_after_type_declarator
/* %type <ttype> primary_no_id */
%type <ttype> nonmomentary_expr
%type <itype> forhead.2 initdcl0 notype_initdcl0 member_init_list
-%type <itype> try ansi_try
%type <ttype> template_header template_parm_list template_parm
%type <ttype> template_type template_arg_list template_arg
%type <ttype> template_instantiation template_type_name tmpl.2
%type <ttype> template_instantiate_once template_instantiate_some
%type <itype> fn_tmpl_end
/* %type <itype> try_for_typename */
-%type <ttype> condition partially_scoped_stmt xcond paren_cond_or_null
-%type <strtype> .kindof_pushlevel
+%type <ttype> condition xcond paren_cond_or_null
%type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
%type <ttype> qualified_type_name complete_type_name notype_identifier
%type <ttype> complex_type_name nested_name_specifier_1
0, $<ttype>4);
cplus_decl_attributes (d, $6);
finish_decl (d, NULL_TREE, $5, 0);
- end_exception_decls ();
end_template_decl ($1, d, 0, def);
if (def)
{
}
| typed_declspecs initdecls ';'
{
- end_exception_decls ();
note_list_got_semicolon ($<ttype>$);
}
/* Normal case: make this fast. */
{ tree d;
d = start_decl ($<ttype>2, $<ttype>$, 0, NULL_TREE);
finish_decl (d, NULL_TREE, NULL_TREE, 0);
- end_exception_decls ();
note_list_got_semicolon ($<ttype>$);
}
| declmods ';'
| expr
;
-/* Used for the blocks controlled by a condition, to add any DECLs in
- the condition to the controlled block. */
-.kindof_pushlevel: /* empty */
- { tree d = getdecls ();
- emit_line_note (input_filename, lineno);
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
- if (d) pushdecl (d);
- }
- ;
-
-/* Like implicitly_scoped_stmt, but uses .kindof_pushlevel */
-partially_scoped_stmt:
- '{' .kindof_pushlevel '}'
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p (), 1);
- $$ = poplevel (kept_level_p (), 1, 0);
- pop_momentary ();
- finish_stmt (); }
- | '{' .kindof_pushlevel maybe_label_decls stmts '}'
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p (), 1);
- $$ = poplevel (kept_level_p (), 1, 0);
- pop_momentary ();
- finish_stmt (); }
- | '{' .kindof_pushlevel maybe_label_decls error '}'
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p (), 1);
- $$ = poplevel (kept_level_p (), 0, 0);
- pop_momentary ();
- finish_stmt (); }
- | .kindof_pushlevel simple_stmt
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p (), 1);
- $$ = poplevel (kept_level_p (), 1, 0);
- pop_momentary (); }
- ;
-
-already_scoped_stmt:
- '{' '}'
- { finish_stmt (); }
- | '{' maybe_label_decls stmts '}'
- { finish_stmt (); }
- | '{' maybe_label_decls error '}'
- { finish_stmt (); }
- | simple_stmt
- ;
-
nontrivial_exprlist:
expr_no_commas ',' expr_no_commas
{ $$ = tree_cons (NULL_TREE, $$,
$$ = rval;
else
$$ = build_modify_expr ($$, $2, $3); }
+ | THROW
+ { $$ = build_throw (NULL_TREE); }
+ | THROW expr_no_commas
+ { $$ = build_throw ($2); }
/* These extensions are not defined. The second arg to build_m_component_ref
is old, build_m_component_ref now does an implicit
build_indirect_ref (x, NULL_PTR) on the second argument.
{ $$ = decl_tree_cons (NULL_TREE, $$, $2); }
| declmods typespec reserved_declspecs
{ $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
- | declmods typespec reserved_typespecquals
- { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
- | declmods typespec reserved_typespecquals reserved_declspecs
- { $$ = decl_tree_cons (NULL_TREE, $2,
+ | declmods typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ | declmods typespec reserved_typespecquals reserved_declspecs
+ { $$ = decl_tree_cons (NULL_TREE, $2,
chainon ($3, chainon ($4, $$))); }
;
}
else
{
- error("`sigof' applied to non-aggregate type");
+ error("`sigof' applied to non-aggregate type");
$$ = error_mark_node;
}
}
/* $$ = $1 from default rule. */;
else if (CLASSTYPE_DECLARED_EXCEPTION ($$))
{
- if (! semi)
- $$ = finish_exception ($$, $3);
- else
- warning ("empty exception declaration\n");
}
else
{
typed_declspecs components
{
$$ = grok_x_components ($$, $2);
- end_exception_decls ();
}
| declmods notype_components
{
$$ = grok_x_components ($$, $2);
- end_exception_decls ();
}
| notype_declarator maybe_raises maybeasm maybe_attribute
{ $$ = grokfield ($$, NULL_TREE, $2, NULL_TREE, $3);
qualified_type_name:
type_name %prec EMPTY
+ {
+ /* Remember that this name has been used in the class
+ definition, as per [class.scope0] */
+ if (current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && ! IDENTIFIER_CLASS_VALUE ($$))
+ {
+ tree t = lookup_name ($$, -2);
+ if (t)
+ pushdecl_class_level (t);
+ }
+ }
| nested_type
;
;
compstmt: '{' .pushlevel '}'
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p(), 1);
+ { expand_end_bindings (getdecls (), kept_level_p(), 1);
$$ = poplevel (kept_level_p (), 1, 0);
pop_momentary (); }
| '{' .pushlevel maybe_label_decls stmts '}'
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p(), 1);
+ { expand_end_bindings (getdecls (), kept_level_p(), 1);
$$ = poplevel (kept_level_p (), 1, 0);
pop_momentary (); }
| '{' .pushlevel maybe_label_decls error '}'
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p(), 1);
+ { expand_end_bindings (getdecls (), kept_level_p(), 1);
$$ = poplevel (kept_level_p (), 0, 0);
pop_momentary (); }
;
.pushlevel paren_cond_or_null
{ emit_line_note (input_filename, lineno);
expand_start_cond (truthvalue_conversion ($4), 0); }
- partially_scoped_stmt
+ implicitly_scoped_stmt
;
implicitly_scoped_stmt:
compstmt
{ finish_stmt (); }
| .pushlevel simple_stmt
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), getdecls() != NULL_TREE, 1);
+ { expand_end_bindings (getdecls (), getdecls() != NULL_TREE, 1);
$$ = poplevel (kept_level_p (), 1, 0);
pop_momentary (); }
;
{ finish_stmt (); }
| expr ';'
{
- tree expr = $1;
+ tree expr = $1;
emit_line_note (input_filename, lineno);
/* Do default conversion if safe and possibly important,
in case within ({...}). */
finish_stmt (); }
| simple_if ELSE
{ expand_start_else (); }
- partially_scoped_stmt
+ implicitly_scoped_stmt
{ expand_end_cond ();
- pop_implicit_try_blocks (NULL_TREE);
expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
finish_stmt (); }
| simple_if %prec IF
{ expand_end_cond ();
- pop_implicit_try_blocks (NULL_TREE);
expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
cond_stmt_keyword = "while"; }
.pushlevel paren_cond_or_null
{ expand_exit_loop_if_false (0, truthvalue_conversion ($4)); }
- already_scoped_stmt
- { pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p (), 1);
+ implicitly_scoped_stmt
+ { expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
expand_end_loop ();
/* Don't let the tree nodes for $7 be discarded
by clear_momentary during the parsing of the next stmt. */
{ push_momentary (); }
- already_scoped_stmt
+ implicitly_scoped_stmt
{ emit_line_note (input_filename, lineno);
- pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p (), 1);
expand_loop_continue_here ();
if ($7) cplus_expand_expr_stmt ($7);
pop_momentary ();
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
expand_end_loop ();
by clear_momentary during the parsing of the next stmt. */
{ push_momentary ();
$<itype>8 = lineno; }
- already_scoped_stmt
+ implicitly_scoped_stmt
{ emit_line_note (input_filename, (int) $<itype>8);
- pop_implicit_try_blocks (NULL_TREE);
- expand_end_bindings (getdecls (), kept_level_p (), 1);
expand_loop_continue_here ();
if ($7) cplus_expand_expr_stmt ($7);
pop_momentary ();
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
expand_end_loop ();
/* Don't let the tree nodes for $4 be discarded by
clear_momentary during the parsing of the next stmt. */
push_momentary (); }
- partially_scoped_stmt
+ implicitly_scoped_stmt
{ expand_end_case ($4);
pop_momentary ();
- pop_implicit_try_blocks (NULL_TREE);
expand_end_bindings (getdecls (), kept_level_p (), 1);
poplevel (kept_level_p (), 1, 0);
pop_momentary ();
}
/* This is the case with clobbered registers as well. */
| asm_keyword maybe_type_qual '(' string ':' asm_operands ':'
- asm_operands ':' asm_clobbers ')' ';'
+ asm_operands ':' asm_clobbers ')' ';'
{ if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
emit_line_note (input_filename, lineno);
c_expand_asm_operands ($4, $6, $8, $10,
finish_stmt (); }
| ';'
{ finish_stmt (); }
-
- /* Exception handling extensions. */
- | ANSI_THROW ';' { cplus_expand_throw (NULL_TREE); }
- | ANSI_THROW expr ';' { cplus_expand_throw ($2); }
- | THROW raise_identifier '(' nonnull_exprlist ')' ';'
- { cplus_expand_raise ($2, $4, NULL_TREE, 0);
- finish_stmt (); }
- | THROW raise_identifier LEFT_RIGHT ';'
- { cplus_expand_raise ($2, NULL_TREE, NULL_TREE, 0);
- finish_stmt (); }
- | RAISE raise_identifier '(' nonnull_exprlist ')' ';'
- { cplus_expand_raise ($2, $4, NULL_TREE, 0);
- finish_stmt (); }
- | RAISE raise_identifier LEFT_RIGHT ';'
- { cplus_expand_raise ($2, NULL_TREE, NULL_TREE, 0);
- finish_stmt (); }
- | RAISE identifier ';'
- { cplus_expand_reraise ($2);
- finish_stmt (); }
- | try EXCEPT identifier '{'
- {
- tree decl = cplus_expand_end_try ($1);
- $<ttype>2 = current_exception_type;
- $<ttype>4 = current_exception_decl;
- $<ttype>$ = current_exception_object;
- cplus_expand_start_except ($3, decl);
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
- }
- except_stmts '}'
- {
- tree decls = getdecls ();
- /* If there is a default exception to handle,
- handle it here. */
- if ($6)
- {
- tree decl = build_decl (CPLUS_CATCH_DECL, NULL_TREE, 0);
- tree block;
-
- pushlevel (1);
- expand_start_bindings (0);
- expand_expr ($6, 0, 0, 0);
- expand_end_bindings (0, 1, 0);
- block = poplevel (1, 0, 0);
-
- /* This is a catch block. */
- TREE_LANG_FLAG_2 (block) = 1;
- BLOCK_VARS (block) = decl;
- }
-
- expand_end_bindings (decls, decls != 0, 1);
- poplevel (decls != 0, 1, 0);
- pop_momentary ();
- current_exception_type = $<ttype>2;
- current_exception_decl = $<ttype>4;
- current_exception_object = $<ttype>5;
- cplus_expand_end_except ($6);
- }
- | try error
- {
- cplus_expand_end_try ($1);
- /* These are the important actions of
- `cplus_expand_end_except' which we must emulate. */
- if (expand_escape_except ())
- expand_end_except ();
- expand_end_bindings (0, 0, 1);
- poplevel (0, 0, 0);
- }
- | ansi_try ansi_dummy ansi_dummy
- {
- tree decl = cplus_expand_end_try ($1);
- $<ttype>2 = current_exception_type;
- $<ttype>3 = current_exception_decl;
- $<ttype>$ = current_exception_object;
- cplus_expand_start_except (NULL, decl);
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
- }
- ansi_except_stmts
- {
- tree decls = getdecls ();
- /* If there is a default exception to handle,
- handle it here. */
- if ($5)
- {
- tree decl = build_decl (CPLUS_CATCH_DECL, NULL_TREE, 0);
- tree block;
-
- pushlevel (1);
- expand_start_bindings (0);
- expand_expr ($5, 0, 0, 0);
- expand_end_bindings (0, 1, 0);
- block = poplevel (1, 0, 0);
-
- /* This is a catch block. */
- TREE_LANG_FLAG_2 (block) = 1;
- BLOCK_VARS (block) = decl;
- }
-
- expand_end_bindings (decls, decls != 0, 1);
- poplevel (decls != 0, 1, 0);
- pop_momentary ();
- current_exception_type = $<ttype>2;
- current_exception_decl = $<ttype>3;
- current_exception_object = $<ttype>4;
- cplus_expand_end_except ($5);
- }
- | try RERAISE raise_identifiers /* ';' checked for at bottom. */
- { tree name = get_identifier ("(compiler error)");
- tree orig_ex_type = current_exception_type;
- tree orig_ex_decl = current_exception_decl;
- tree orig_ex_obj = current_exception_object;
- tree decl = cplus_expand_end_try ($1), decls;
-
- /* Start hidden EXCEPT. */
- cplus_expand_start_except (name, decl);
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- /* This sets up the reraise. */
- cplus_expand_reraise ($3);
-
- decls = getdecls ();
- expand_end_bindings (decls, decls != 0, 1);
- poplevel (decls != 0, 1, 0);
- pop_momentary ();
- current_exception_type = orig_ex_type;
- current_exception_decl = orig_ex_decl;
- current_exception_object = orig_ex_obj;
- /* This will reraise for us. */
- cplus_expand_end_except (error_mark_node);
- if (yychar == YYEMPTY)
- yychar = YYLEX;
- if (yychar != ';')
- error ("missing ';' after reraise statement");
- }
- | try %prec EMPTY
- { yyerror ("`except' missing after `try' statement");
- /* Terminate the binding contour started by special
- code in `.pushlevel'. Automagically pops off
- the conditional we started for `try' stmt. */
- cplus_expand_end_try ($1);
- expand_end_bindings (0, 0, 1);
- poplevel (0, 0, 0);
- pop_momentary ();
- YYERROR; }
- ;
-
-try: try_head '}'
- /* An empty try block is degenerate, but it's better to
- do extra work here than to do all the special-case work
- everywhere else. */
- {
- $$ = 1;
- pop_implicit_try_blocks (NULL_TREE);
- }
- | try_head stmts '}'
- {
- $$ = 1;
- pop_implicit_try_blocks (NULL_TREE);
- }
- | try_head error '}'
- {
- $$ = 0;
- pop_implicit_try_blocks (NULL_TREE);
- }
+ | try_block
;
-label_colon:
- IDENTIFIER ':'
- { tree label;
- do_label:
- label = define_label (input_filename, lineno, $1);
- if (label)
- expand_label (label);
- }
- | PTYPENAME ':'
- { goto do_label; }
+try_block:
+ TRY '{' .pushlevel
+ { expand_start_try_stmts (); }
+ ansi_try_stmts
+ { expand_end_try_stmts ();
+ expand_start_all_catch (); }
+ handler_seq
+ { expand_end_all_catch (); }
;
-try_head: TRY '{' { cplus_expand_start_try (0); } .pushlevel
-
-ansi_try: ansi_try_head '}'
+ansi_try_stmts:
+ '}'
/* An empty try block is degenerate, but it's better to
do extra work here than to do all the special-case work
everywhere else. */
- {
- $$ = 1;
- pop_implicit_try_blocks (NULL_TREE);
- }
- | ansi_try_head stmts '}'
- {
- $$ = 1;
- pop_implicit_try_blocks (NULL_TREE);
- }
- | ansi_try_head error '}'
- {
- $$ = 0;
- pop_implicit_try_blocks (NULL_TREE);
- }
- ;
-
-ansi_dummy: ; /* Temporary place-holder. */
-ansi_try_head: ANSI_TRY '{' { cplus_expand_start_try (0); } .pushlevel
-
-except_stmts:
- /* empty */
- { $$ = NULL_TREE; }
- | except_stmts raise_identifier
- {
- tree type = lookup_exception_type (current_class_type, current_class_name, $2);
- if (type == NULL_TREE)
- {
- error ("`%s' is not an exception type",
- IDENTIFIER_POINTER (TREE_VALUE ($2)));
- current_exception_type = NULL_TREE;
- TREE_TYPE (current_exception_object) = error_mark_node;
- }
- else
- {
- current_exception_type = type;
- /* In-place union. */
- TREE_TYPE (current_exception_object) = type;
- }
- $2 = cplus_expand_start_catch ($2);
- pushlevel (1);
- expand_start_bindings (0);
- }
- compstmt
- {
- expand_end_bindings (0, 1, 0);
- $4 = poplevel (1, 0, 0);
-
- cplus_expand_end_catch (0);
-
- /* Mark this as a catch block. */
- TREE_LANG_FLAG_2 ($4) = 1;
- if ($2 != error_mark_node)
- {
- tree decl = build_decl (CPLUS_CATCH_DECL, DECL_NAME ($2), 0);
- DECL_RTL (decl) = DECL_RTL ($2);
- TREE_CHAIN (decl) = BLOCK_VARS ($4);
- BLOCK_VARS ($4) = decl;
- }
+ { expand_end_bindings (0,1,1);
+ poplevel (2,0,0);
}
- | except_stmts DEFAULT
- {
- if ($1)
- error ("duplicate default in exception handler");
- current_exception_type = NULL_TREE;
- /* Takes it right out of scope. */
- TREE_TYPE (current_exception_object) = error_mark_node;
-
- if (! expand_catch_default ())
- compiler_error ("default catch botch");
-
- /* The default exception is handled as the
- last in the chain of exceptions handled. */
- do_pending_stack_adjust ();
- $1 = make_node (RTL_EXPR);
- TREE_TYPE ($1) = void_type_node;
- start_sequence_for_rtl_expr ($1);
+ | stmts '}'
+ { expand_end_bindings (0,1,1);
+ poplevel (2,0,0);
}
- compstmt
- {
- extern struct rtx_def *get_insns ();
- do_pending_stack_adjust ();
- if (! expand_catch (NULL_TREE))
- compiler_error ("except nesting botch");
- if (! expand_end_catch ())
- compiler_error ("except nesting botch");
- RTL_EXPR_SEQUENCE ($1) = get_insns ();
- if ($4)
- {
- /* Mark this block as the default catch block. */
- TREE_LANG_FLAG_1 ($4) = 1;
- TREE_LANG_FLAG_2 ($4) = 1;
- }
- end_sequence ();
+ | error '}'
+ { expand_end_bindings (0,1,1);
+ poplevel (2,0,0);
}
;
{ $$ = NULL_TREE; }
| identifier ;
-ansi_except_stmts:
+handler_seq:
/* empty */
- { $$ = NULL_TREE; }
- | ansi_except_stmts CATCH '(' type_id optional_identifier ')'
- {
- tree type = groktypename ($4);
- if (IS_SIGNATURE (type))
- {
- error ("exception cannot be of signature type");
- type = error_mark_node;
- }
- current_exception_type = type;
- /* In-place union. */
- if ($5)
- {
- tree tmp;
- tmp = pushdecl (build_decl (VAR_DECL, $5, type));
- current_exception_object =
- build1 (INDIRECT_REF, type, tmp);
- }
- $4 = ansi_expand_start_catch(type);
- pushlevel (1);
- expand_start_bindings (0);
- }
- compstmt
- {
- expand_end_bindings (0, 1, 0);
- $8 = poplevel (1, 0, 0);
+ | handler_seq CATCH
+ { emit_line_note (input_filename, lineno); }
+ handler_args compstmt
+ { expand_end_catch_block (); }
+ ;
- cplus_expand_end_catch (0);
+handler_args:
+ '(' ELLIPSIS ')'
+ { expand_start_catch_block (NULL_TREE, NULL_TREE); }
+ | '(' type_id optional_identifier ')'
+ { expand_start_catch_block ($2, $3); }
+ ;
- /* Mark this as a catch block. */
- TREE_LANG_FLAG_2 ($8) = 1;
- if ($4 != error_mark_node)
- {
- tree decl = build_decl (CPLUS_CATCH_DECL, DECL_NAME ($4), 0);
- DECL_RTL (decl) = DECL_RTL ($4);
- TREE_CHAIN (decl) = BLOCK_VARS ($8);
- BLOCK_VARS ($8) = decl;
- }
+label_colon:
+ IDENTIFIER ':'
+ { tree label;
+ do_label:
+ label = define_label (input_filename, lineno, $1);
+ if (label)
+ expand_label (label);
}
+ | PTYPENAME ':'
+ { goto do_label; }
;
forhead.1:
as it is ambiguous and must be disambiguated elsewhere. */
complex_parmlist:
parms
- {
+ {
$$ = chainon ($$, void_list_node);
TREE_PARMLIST ($$) = 1;
}
maybe_raises:
%prec EMPTY /* empty */
{ $$ = NULL_TREE; }
- | RAISES raise_identifiers %prec EMPTY
- { $$ = $2; }
- | ANSI_THROW '(' ansi_raise_identifiers ')' %prec EMPTY
+ | THROW '(' ansi_raise_identifiers ')' %prec EMPTY
{ $$ = $3; }
;
raise_identifier:
- ALL
- { $$ = void_list_node; }
- | IDENTIFIER
+/* ALL
+ { $$ = void_list_node; } */
+ IDENTIFIER
{ $$ = build_decl_list (NULL_TREE, $$); }
| TYPENAME
{ $$ = build_decl_list (NULL_TREE, $$); }
raise_identifier
| raise_identifiers ',' raise_identifier
{
- TREE_CHAIN ($3) = $$;
+ TREE_CHAIN ($3) = $$;
$$ = $3;
}
;
ansi_raise_identifier
| ansi_raise_identifiers ',' ansi_raise_identifier
{
- TREE_CHAIN ($3) = $$;
+ TREE_CHAIN ($3) = $$;
$$ = $3;
}
;
int constp = TYPE_READONLY (type);
int volatilep = TYPE_VOLATILE (type);
- if (raises && TREE_CHAIN (raises))
- {
- for (i = 0, t = raises; t; t = TREE_CHAIN (t), i++)
- a[i] = t;
- /* NULL terminator for list. */
- a[i] = NULL_TREE;
- qsort (a, i, sizeof (tree), id_cmp);
- while (i--)
- TREE_CHAIN (a[i]) = a[i+1];
- raises = a[0];
- }
- else if (raises)
- /* do nothing. */;
- else
- return build_type_variant (v, constp, volatilep);
-
- if (ctype)
- {
- cname = TYPE_NAME (ctype);
- if (TREE_CODE (cname) == TYPE_DECL)
- cname = DECL_NAME (cname);
- }
- else
- cname = NULL_TREE;
-
- for (t = raises; t; t = TREE_CHAIN (t))
- {
- /* See that all the exceptions we are thinking about
- raising have been declared. */
- tree this_cname = lookup_exception_cname (ctype, cname, t);
- tree decl = lookup_exception_object (this_cname, TREE_VALUE (t), 1);
-
- if (decl == NULL_TREE)
- decl = lookup_exception_object (this_cname, TREE_VALUE (t), 0);
- /* Place canonical exception decl into TREE_TYPE of RAISES list. */
- TREE_TYPE (t) = decl;
- }
-
for (v = TYPE_NEXT_VARIANT (v); v; v = TYPE_NEXT_VARIANT (v))
{
if (TYPE_READONLY (v) != constp
function, coerced_params, NULL_TREE);
TREE_SIDE_EFFECTS (result) = 1;
+ /* Remove this sometime. */
TREE_RAISES (result) |= !! TYPE_RAISES_EXCEPTIONS (fntype);
if (! require_complete)
return result;