From: Mike Stump Date: Fri, 6 May 1994 09:27:46 +0000 (+0000) Subject: 36th Cygnus<->FSF merge X-Git-Tag: misc/cutover-egcs-0~6722 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8d2733caec5ebdd4664d7645375262b1e097c418;p=thirdparty%2Fgcc.git 36th Cygnus<->FSF merge From-SVN: r7221 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d5443014a11a..1cf6db3f9662 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,55 @@ +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'. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index bc3b7314b911..8f8bac21925e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2924,18 +2924,6 @@ build_method_call (instance, name, parms, basetype_path, flags) 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. */ diff --git a/gcc/cp/class.c b/gcc/cp/class.c index fe169ad3e37c..730d0cac221f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2504,7 +2504,6 @@ finish_struct (t, list_of_fieldlists, warn_anon) int warn_anon; { extern int interface_only, interface_unknown; - extern tree EHS_type; int old; int round_up_size = 1; @@ -2727,10 +2726,25 @@ finish_struct (t, list_of_fieldlists, warn_anon) 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) { @@ -3129,9 +3143,8 @@ finish_struct (t, list_of_fieldlists, warn_anon) 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 */ diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 4f73664f24a7..4f33c9f28591 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -55,10 +55,9 @@ DEFTREECODE (TYPE_EXPR, "type_expr", "e", 1) 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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1a82e0bc96db..54dc2b2ae374 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -271,10 +271,6 @@ extern int interface_only, interface_unknown; 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; @@ -282,7 +278,7 @@ 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. */ @@ -1083,10 +1079,14 @@ struct lang_decl 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 @@ -1921,27 +1921,20 @@ extern tree lookup_name_nonclass PROTO((tree)); /* 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 */ @@ -2291,18 +2284,6 @@ extern void GNU_xref_assign PROTO((tree)); 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 */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1533f95620c0..e33db79a7656 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -41,6 +41,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #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; @@ -122,7 +124,6 @@ static tree grokparms PROTO((tree, int)); 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 *)); @@ -257,12 +258,6 @@ tree dtor_label; 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. */ @@ -564,11 +559,6 @@ struct binding_level 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; @@ -657,7 +647,6 @@ push_binding_level (newlevel, tag_transparent, keep) 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; @@ -751,23 +740,6 @@ declare_parm_level () 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 () { @@ -1105,7 +1077,7 @@ poplevel (keep, reverse, functionbody) } /* 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 @@ -1300,10 +1272,6 @@ print_binding_level (lvl) 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) { @@ -1664,6 +1632,7 @@ set_nested_typename (decl, classname, name, type) 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 @@ -2988,7 +2957,6 @@ pushdecl (x) /* 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)) { @@ -3001,7 +2969,7 @@ pushdecl (x) { 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)); } @@ -3107,6 +3075,21 @@ pushdecl_class_level (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) { @@ -3936,11 +3919,7 @@ lookup_name_real (name, prefer_type, nonclass) /* 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, @@ -4498,6 +4477,7 @@ init_decl_processing () 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, @@ -4911,23 +4891,13 @@ init_decl_processing () 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) @@ -5097,14 +5067,11 @@ shadow_tag (declspecs) 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 (); } @@ -5779,7 +5746,6 @@ finish_decl (decl, init, asmspec_tree, need_pop) 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; } @@ -6111,7 +6077,6 @@ finish_decl (decl, init, asmspec_tree, need_pop) 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); @@ -6146,14 +6111,6 @@ finish_decl (decl, init, asmspec_tree, need_pop) 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) @@ -6343,7 +6300,11 @@ finish_decl (decl, init, asmspec_tree, need_pop) 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; } @@ -8849,8 +8810,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises) 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 @@ -9869,10 +9828,8 @@ xref_tag (code_type_node, name, binfo, globalize) * 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); @@ -10267,6 +10224,7 @@ finish_enum (enumtype, values) 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)) @@ -10370,8 +10328,7 @@ build_enumerator (name, value) } 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; } } @@ -10404,8 +10361,6 @@ build_enumerator (name, value) 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 (); @@ -10439,6 +10394,7 @@ build_enumerator (name, value) 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; } @@ -10494,7 +10450,6 @@ start_function (declspecs, declarator, raises, pre_parsed_p) tree declarator, declspecs, raises; int pre_parsed_p; { - extern tree EHS_decl; tree decl1, olddecl; tree ctype = NULL_TREE; tree fntype; @@ -10503,9 +10458,6 @@ start_function (declspecs, declarator, raises, pre_parsed_p) 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); @@ -10829,7 +10781,6 @@ store_parm_decls () 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; @@ -10854,18 +10805,6 @@ store_parm_decls () /* 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. @@ -10919,7 +10858,9 @@ store_parm_decls () 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; } } @@ -10953,14 +10894,6 @@ store_parm_decls () 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. */ @@ -10975,7 +10908,8 @@ store_parm_decls () 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' @@ -11121,7 +11055,6 @@ finish_function (lineno, call_poplevel) 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; @@ -11344,8 +11277,6 @@ finish_function (lineno, call_poplevel) 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); } @@ -11377,41 +11308,6 @@ finish_function (lineno, call_poplevel) 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; @@ -11426,8 +11322,6 @@ finish_function (lineno, call_poplevel) { 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 (); } @@ -11460,14 +11354,6 @@ finish_function (lineno, call_poplevel) /* 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) { @@ -11545,19 +11431,6 @@ finish_function (lineno, 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); @@ -11590,6 +11463,9 @@ finish_function (lineno, call_poplevel) /* 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. */ @@ -11917,9 +11793,13 @@ hack_incomplete_structures (type) 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); @@ -11982,9 +11862,6 @@ maybe_build_cleanup (decl) 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); @@ -12024,27 +11901,8 @@ cplus_expand_expr_stmt (exp) 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 @@ -12082,95 +11940,6 @@ finish_stmt () 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. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 34b7499fcecb..d6eb5d959083 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -266,16 +266,10 @@ int write_virtuals; 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; @@ -354,9 +348,7 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] = {"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}, @@ -2493,6 +2485,8 @@ finish_file () tree vars = static_aggregates; int needs_cleaning = 0, needs_messing_up = 0; + build_exception_table (); + if (flag_detailed_statistics) dump_tree_statistics (); diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 66f12669b084..629c70b92b1b 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -559,14 +559,19 @@ dump_decl (t, v) 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: @@ -586,9 +591,8 @@ dump_decl (t, v) 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 (':', ':'); @@ -696,14 +700,7 @@ dump_decl (t, v) 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; diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 4a7d0f827fa0..60fd39208912 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1,6 +1,8 @@ /* 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 + Rewritten by Mike Stump , based upon an + initial re-implementation courtesy Tad Hunt. This file is part of GNU CC. @@ -26,1198 +28,1346 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #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 -#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 + +/* 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 */ +#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; } - -/* 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); } - + + +/* 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; } diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index b59fefe954e0..c2213d5f661d 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -214,6 +214,10 @@ cplus_expand_expr (exp, target, tmode, modifier) case THUNK_DECL: return DECL_RTL (exp); + case THROW_EXPR: + expand_throw (TREE_OPERAND (exp, 0)); + return NULL; + default: break; } diff --git a/gcc/cp/gxx.gperf b/gcc/cp/gxx.gperf index 20eadb6efbca..33f1d23500e7 100644 --- a/gcc/cp/gxx.gperf +++ b/gcc/cp/gxx.gperf @@ -26,14 +26,6 @@ __typeof__, TYPEOF, NORID __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, @@ -79,7 +71,9 @@ static, SCSPEC, RID_STATIC, 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, diff --git a/gcc/cp/gxxint.texi b/gcc/cp/gxxint.texi index d27fe70c7917..d91a97e4a59e 100644 --- a/gcc/cp/gxxint.texi +++ b/gcc/cp/gxxint.texi @@ -8,7 +8,7 @@ @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 @@ -24,6 +24,7 @@ Questions and comments to mrs@@cygnus.com. * Error Reporting:: * Parser:: * Copying Objects:: +* Exception Handling:: * Concept Index:: @end menu @@ -555,7 +556,7 @@ IDENTIFIER_NODEs for TYPE_DECLs @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 @@ -989,7 +990,7 @@ completely unrelated to access control! @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 @@ -1115,7 +1116,7 @@ conflicts. 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 @@ -1141,7 +1142,54 @@ them. 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 diff --git a/gcc/cp/hash.h b/gcc/cp/hash.h index fceaa63ccfc6..86bc4caea55a 100644 --- a/gcc/cp/hash.h +++ b/gcc/cp/hash.h @@ -3,12 +3,12 @@ /* 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 @@ -20,19 +20,19 @@ hash (str, len) { 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; @@ -68,127 +68,103 @@ is_reserved_word (str, 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) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 8a81db9ef5cf..8e7014310c80 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -217,12 +217,8 @@ perform_member_init (member, name, init, explicit) 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. */ @@ -390,20 +386,6 @@ emit_base_init (t, immediately) 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++) { @@ -521,11 +503,6 @@ emit_base_init (t, immediately) 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) @@ -594,12 +571,6 @@ emit_base_init (t, immediately) 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); diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 51cb77238e24..7c88ba561701 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -766,40 +766,16 @@ init_lex () 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"); @@ -3171,6 +3147,13 @@ do_identifier (token) } } + /* 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) @@ -3496,7 +3479,14 @@ real_yylex () 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); diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y index 32c5e524fd99..f46f70a22526 100644 --- a/gcc/cp/parse.y +++ b/gcc/cp/parse.y @@ -192,8 +192,7 @@ empty_parms () %left 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 unop @@ -209,7 +208,7 @@ empty_parms () %type asm_operands nonnull_asm_operands asm_operand asm_clobbers %type maybe_attribute attribute_list attrib -%type compstmt except_stmts ansi_except_stmts implicitly_scoped_stmt +%type compstmt implicitly_scoped_stmt %type declarator notype_declarator after_type_declarator %type direct_notype_declarator direct_after_type_declarator @@ -251,15 +250,13 @@ empty_parms () /* %type primary_no_id */ %type nonmomentary_expr %type forhead.2 initdcl0 notype_initdcl0 member_init_list -%type try ansi_try %type template_header template_parm_list template_parm %type template_type template_arg_list template_arg %type template_instantiation template_type_name tmpl.2 %type template_instantiate_once template_instantiate_some %type fn_tmpl_end /* %type try_for_typename */ -%type condition partially_scoped_stmt xcond paren_cond_or_null -%type .kindof_pushlevel +%type condition xcond paren_cond_or_null %type type_name nested_name_specifier nested_type ptr_to_mem %type qualified_type_name complete_type_name notype_identifier %type complex_type_name nested_name_specifier_1 @@ -486,7 +483,6 @@ template_def: 0, $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) { @@ -530,7 +526,6 @@ datadef: } | typed_declspecs initdecls ';' { - end_exception_decls (); note_list_got_semicolon ($$); } /* Normal case: make this fast. */ @@ -538,7 +533,6 @@ datadef: { tree d; d = start_decl ($2, $$, 0, NULL_TREE); finish_decl (d, NULL_TREE, NULL_TREE, 0); - end_exception_decls (); note_list_got_semicolon ($$); } | declmods ';' @@ -959,56 +953,6 @@ condition: | 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, $$, @@ -1262,6 +1206,10 @@ expr_no_commas: $$ = 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. @@ -1767,10 +1715,10 @@ typed_declspecs1: { $$ = 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, $$))); } ; @@ -1873,7 +1821,7 @@ typespec: structsp } else { - error("`sigof' applied to non-aggregate type"); + error("`sigof' applied to non-aggregate type"); $$ = error_mark_node; } } @@ -2150,10 +2098,6 @@ structsp: /* $$ = $1 from default rule. */; else if (CLASSTYPE_DECLARED_EXCEPTION ($$)) { - if (! semi) - $$ = finish_exception ($$, $3); - else - warning ("empty exception declaration\n"); } else { @@ -2546,12 +2490,10 @@ component_decl_1: 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); @@ -2764,6 +2706,18 @@ after_type_declarator: 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 ; @@ -3072,18 +3026,15 @@ compstmt_or_error: ; 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 (); } ; @@ -3094,15 +3045,14 @@ simple_if: .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 (); } ; @@ -3118,7 +3068,7 @@ simple_stmt: { 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 ({...}). */ @@ -3131,16 +3081,14 @@ simple_stmt: 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 (); @@ -3152,9 +3100,8 @@ simple_stmt: 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 (); @@ -3184,13 +3131,12 @@ simple_stmt: /* 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 (); @@ -3207,13 +3153,12 @@ simple_stmt: by clear_momentary during the parsing of the next stmt. */ { push_momentary (); $8 = lineno; } - already_scoped_stmt + implicitly_scoped_stmt { emit_line_note (input_filename, (int) $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 (); @@ -3225,10 +3170,9 @@ simple_stmt: /* 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 (); @@ -3422,7 +3366,7 @@ simple_stmt: } /* 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, @@ -3447,291 +3391,34 @@ simple_stmt: 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); - $2 = current_exception_type; - $4 = current_exception_decl; - $$ = 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 = $2; - current_exception_decl = $4; - current_exception_object = $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); - $2 = current_exception_type; - $3 = current_exception_decl; - $$ = 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 = $2; - current_exception_decl = $3; - current_exception_object = $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); } ; @@ -3740,47 +3427,31 @@ optional_identifier: { $$ = 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: @@ -3869,7 +3540,7 @@ parmlist: /* empty */ as it is ambiguous and must be disambiguated elsewhere. */ complex_parmlist: parms - { + { $$ = chainon ($$, void_list_node); TREE_PARMLIST ($$) = 1; } @@ -4029,16 +3700,14 @@ bad_parm: 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, $$); } @@ -4057,7 +3726,7 @@ raise_identifiers: raise_identifier | raise_identifiers ',' raise_identifier { - TREE_CHAIN ($3) = $$; + TREE_CHAIN ($3) = $$; $$ = $3; } ; @@ -4066,7 +3735,7 @@ ansi_raise_identifiers: ansi_raise_identifier | ansi_raise_identifiers ',' ansi_raise_identifier { - TREE_CHAIN ($3) = $$; + TREE_CHAIN ($3) = $$; $$ = $3; } ; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index f035d6d6c7d7..edb0b78a4916 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1494,44 +1494,6 @@ build_exception_variant (ctype, type, raises) 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 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 55f5f86f3c37..03ca722b5e2e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2280,6 +2280,7 @@ build_function_call_real (function, params, require_complete, flags) 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;