This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

ia64 eh, part 20b [c++]


This is the C++ front end change.  With the exception of the
Java bits in cp/except.c, it is basically unchanged from the
last time Jason reviewed it.


r~


	IA-64 ABI Exception Handling:
	* cp-tree.def (EH_SPEC_BLOCK): New.
	(MUST_NOT_THROW_EXPR): New.
	* cp-tree.h: Update changed function declarations.
	(CPTI_PUSH_EXCEPTION_IDENTIFIER): Remove.
	(CPTI_CALL_UNEXPECTED): New.
	(struct cp_language_function): Rename x_eh_spec_try_block
	to x_eh_spec_block.
	(EH_SPEC_STMTS, EH_SPEC_RAISES): New.
	* decl.c (current_binding_level): If no current function 
	bindings, revert to scope_chain.
	(initialize_predefined_identifiers): Remove __cp_push_exception.
	(store_parm_decls): Use begin_eh_spec_block.
	(finish_function): Use finish_eh_spec_block.
	(mark_lang_function): Update for name changes.
	* decl2.c (finish_file): No mark_all_runtime_matches.
	* dump.c (cp_dump_tree): Handle new tree codes.
	* error.c (dump_expr) [BIND_EXPR]: Fix typo.
	* except.c (catch_language_init, catch_language): Remove.
	(init_exception_processing): Don't set language code.
	Initialize call_unexpected_node, protect_cleanup_actions,
	eh_personality_libfunc, lang_eh_runtime_type.
	(call_eh_info, push_eh_info, get_eh_info, get_eh_value): Remove.
	(get_eh_type, get_eh_caught, get_eh_handlers): Remove.
	(prepare_eh_type): Split out type canonicalizations ...
	(build_eh_type_type): ... from here.
	(build_eh_type_type_ref): Remove.
	(mark_all_runtime_matches): Remove.
	(build_exc_ptr): New.
	(do_begin_catch, do_end_catch): New.
	(do_pop_exception): Remove.
	(build_terminate_handler): Remove.
	(choose_personality_routine): Split out language choice from ...
	(initialize_handler_parm): ... here.
	Use MUST_NOT_THROW_EXPR.
	(expand_start_catch_block): Use do_begin_catch.  Simplify Java
	exception object handling.
	(expand_start_eh_spec, expand_end_eh_spec): Remove.
	(expand_exception_blocks, alloc_eh_object): Remove.
	(begin_eh_spec_block, finish_eh_spec_block): New.
	(do_allocate_exception, do_free_exception): New.
	(expand_throw): Merge into ...
	(build_throw): ... here.  Update for abi.
	* expr.c (cplus_expand_expr): No expand_internal_throw.
	Handle MUST_NOT_THROW_EXPR.
	* pt.c (tsubst_expr): Handle EH_SPEC_BLOCK.
	* semantics.c (*) Update for except.h name changes.
	(genrtl_try_block): No protect_with_terminate.
	(genrtl_eh_spec_block): New.
	(genrtl_handler): Don't emit the goto here.
	(cp_expand_stmt): Handle EH_SPEC_BLOCK.
	(genrtl_finish_function): Don't expand_exception_blocks.
	* tree.c (cp_statement_code_p): Handle EH_SPEC_BLOCK.

Index: cp-tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.def,v
retrieving revision 1.54
diff -c -p -d -r1.54 cp-tree.def
*** cp-tree.def	2001/01/05 11:41:27	1.54
--- cp-tree.def	2001/03/28 09:49:49
*************** DEFTREECODE (START_CATCH_STMT, "start_ca
*** 236,242 ****
--- 236,247 ----
  DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
  DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
  DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
+ DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
  DEFTREECODE (HANDLER, "handler", 'e', 2)
+ 
+ /* A MUST_NOT_THROW_EXPR wraps an expression that may not
+    throw, and must call terminate if it does.  */
+ DEFTREECODE (MUST_NOT_THROW_EXPR, "must_not_throw_expr", 'e', 1)
  
  DEFTREECODE (TAG_DEFN, "tag_defn", 'e', 0)
  
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.591
diff -c -p -d -r1.591 cp-tree.h
*** cp-tree.h	2001/03/28 08:25:45	1.591
--- cp-tree.h	2001/03/28 09:49:49
*************** enum cp_tree_index
*** 616,622 ****
      CPTI_PFN_IDENTIFIER,
      CPTI_PFN_OR_DELTA2_IDENTIFIER,
      CPTI_VPTR_IDENTIFIER,
-     CPTI_PUSH_EXCEPTION_IDENTIFIER,
      CPTI_STD_IDENTIFIER,
  
      CPTI_LANG_NAME_C,
--- 616,621 ----
*************** enum cp_tree_index
*** 627,632 ****
--- 626,632 ----
      CPTI_NULL,
      CPTI_JCLASS,
      CPTI_TERMINATE,
+     CPTI_CALL_UNEXPECTED,
      CPTI_ATEXIT,
      CPTI_DSO_HANDLE,
      CPTI_DCAST,
*************** extern tree cp_global_trees[CPTI_MAX];
*** 740,748 ****
  #define pfn_identifier                  cp_global_trees[CPTI_PFN_IDENTIFIER]
  #define pfn_or_delta2_identifier        cp_global_trees[CPTI_PFN_OR_DELTA2_IDENTIFIER]
  #define vptr_identifier                 cp_global_trees[CPTI_VPTR_IDENTIFIER]
- /* The name of the function to call to push an exception onto the
-    exception stack.  */
- #define cp_push_exception_identifier    cp_global_trees[CPTI_PUSH_EXCEPTION_IDENTIFIER]
  /* The name of the std namespace.  */
  #define std_identifier                  cp_global_trees[CPTI_STD_IDENTIFIER]
  #define lang_name_c                     cp_global_trees[CPTI_LANG_NAME_C]
--- 740,745 ----
*************** extern tree cp_global_trees[CPTI_MAX];
*** 761,766 ****
--- 758,766 ----
  /* The declaration for `std::terminate'.  */
  #define terminate_node                  cp_global_trees[CPTI_TERMINATE]
  
+ /* The declaration for "__cxa_call_unexpected".  */
+ #define call_unexpected_node            cp_global_trees[CPTI_CALL_UNEXPECTED]
+ 
  /* A pointer to `std::atexit'.  */
  #define atexit_node                     cp_global_trees[CPTI_ATEXIT]
  
*************** struct cp_language_function
*** 872,878 ****
    tree x_dtor_label;
    tree x_current_class_ptr;
    tree x_current_class_ref;
!   tree x_eh_spec_try_block;
    tree x_in_charge_parm;
    tree x_vtt_parm;
  
--- 872,878 ----
    tree x_dtor_label;
    tree x_current_class_ptr;
    tree x_current_class_ref;
!   tree x_eh_spec_block;
    tree x_in_charge_parm;
    tree x_vtt_parm;
  
*************** struct cp_language_function
*** 916,925 ****
  #define current_class_ref \
    (cfun ? cp_function_chain->x_current_class_ref : NULL_TREE)
  
! /* The TRY_BLOCK for the exception-specifiers for the current
     function, if any.  */
  
! #define current_eh_spec_try_block cp_function_chain->x_eh_spec_try_block
  
  /* The `__in_chrg' parameter for the current function.  Only used for
     constructors and destructors.  */
--- 916,925 ----
  #define current_class_ref \
    (cfun ? cp_function_chain->x_current_class_ref : NULL_TREE)
  
! /* The EH_SPEC_BLOCK for the exception-specifiers for the current
     function, if any.  */
  
! #define current_eh_spec_block cp_function_chain->x_eh_spec_block
  
  /* The `__in_chrg' parameter for the current function.  Only used for
     constructors and destructors.  */
*************** extern int flag_new_for_scope;
*** 3035,3040 ****
--- 3035,3043 ----
  #define TRY_STMTS(NODE)         TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0)
  #define TRY_HANDLERS(NODE)      TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 1)
  
+ #define EH_SPEC_STMTS(NODE)     TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 0)
+ #define EH_SPEC_RAISES(NODE)    TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 1)
+ 
  /* Nonzero if this try block is a function try block.  */
  #define FN_TRY_BLOCK_P(NODE)    TREE_LANG_FLAG_3 (TRY_BLOCK_CHECK (NODE))
  #define HANDLER_PARMS(NODE)     TREE_OPERAND (HANDLER_CHECK (NODE), 0)
*************** extern void init_exception_processing		P
*** 4000,4008 ****
  extern tree expand_start_catch_block		PARAMS ((tree));
  extern void expand_end_catch_block		PARAMS ((tree));
  extern void expand_builtin_throw		PARAMS ((void));
! extern tree expand_start_eh_spec		PARAMS ((void));
! extern void expand_end_eh_spec		        PARAMS ((tree, tree));
  extern void expand_exception_blocks		PARAMS ((void));
  extern tree build_throw				PARAMS ((tree));
  extern void mark_all_runtime_matches            PARAMS ((void));
  extern int nothrow_libfn_p			PARAMS ((tree));
--- 4003,4011 ----
  extern tree expand_start_catch_block		PARAMS ((tree));
  extern void expand_end_catch_block		PARAMS ((tree));
  extern void expand_builtin_throw		PARAMS ((void));
! extern void expand_eh_spec_block	        PARAMS ((tree));
  extern void expand_exception_blocks		PARAMS ((void));
+ extern tree build_exc_ptr			PARAMS ((void));
  extern tree build_throw				PARAMS ((tree));
  extern void mark_all_runtime_matches            PARAMS ((void));
  extern int nothrow_libfn_p			PARAMS ((tree));
*************** extern tree finish_case_label           
*** 4256,4261 ****
--- 4259,4266 ----
  extern tree finish_goto_stmt                    PARAMS ((tree));
  extern tree begin_try_block                     PARAMS ((void));
  extern void finish_try_block                    PARAMS ((tree));
+ extern tree begin_eh_spec_block			PARAMS ((void));
+ extern void finish_eh_spec_block		PARAMS ((tree, tree));
  extern void finish_handler_sequence             PARAMS ((tree));
  extern tree begin_function_try_block            PARAMS ((void));
  extern void finish_function_try_block           PARAMS ((tree));
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.766
diff -c -p -d -r1.766 decl.c
*** decl.c	2001/03/28 08:25:45	1.766
--- decl.c	2001/03/28 09:49:49
*************** struct binding_level
*** 478,484 ****
  /* The binding level currently in effect.  */
  
  #define current_binding_level			\
!   (cfun						\
     ? cp_function_chain->bindings		\
     : scope_chain->bindings)
  
--- 478,484 ----
  /* The binding level currently in effect.  */
  
  #define current_binding_level			\
!   (cfun && cp_function_chain->bindings		\
     ? cp_function_chain->bindings		\
     : scope_chain->bindings)
  
*************** initialize_predefined_identifiers ()
*** 6306,6312 ****
      { VTABLE_PFN_NAME, &pfn_identifier, 0 },
      { "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
      { "_vptr", &vptr_identifier, 0 },
-     { "__cp_push_exception", &cp_push_exception_identifier, 0 },
      { "__vtt_parm", &vtt_parm_identifier, 0 },
      { "std", &std_identifier, 0 },
      { NULL, NULL, 0 }
--- 6306,6311 ----
*************** store_parm_decls (current_function_parms
*** 13721,13727 ****
    if (flag_exceptions && !processing_template_decl
        && flag_enforce_eh_specs
        && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
!     current_eh_spec_try_block = expand_start_eh_spec ();
  }
  
  
--- 13720,13726 ----
    if (flag_exceptions && !processing_template_decl
        && flag_enforce_eh_specs
        && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
!     current_eh_spec_block = begin_eh_spec_block ();
  }
  
  
*************** finish_function (flags)
*** 13966,13974 ****
        if (flag_exceptions && !processing_template_decl
  	  && flag_enforce_eh_specs
  	  && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
! 	expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
! 			    (TREE_TYPE (current_function_decl)),
! 			    current_eh_spec_try_block);
      }
  
    /* If we're saving up tree structure, tie off the function now.  */
--- 13965,13973 ----
        if (flag_exceptions && !processing_template_decl
  	  && flag_enforce_eh_specs
  	  && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
! 	finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS
! 			      (TREE_TYPE (current_function_decl)),
! 			      current_eh_spec_block);
      }
  
    /* If we're saving up tree structure, tie off the function now.  */
*************** mark_lang_function (p)
*** 14395,14401 ****
    ggc_mark_tree (p->x_dtor_label);
    ggc_mark_tree (p->x_current_class_ptr);
    ggc_mark_tree (p->x_current_class_ref);
!   ggc_mark_tree (p->x_eh_spec_try_block);
    ggc_mark_tree_varray (p->x_local_names);
  
    mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
--- 14394,14400 ----
    ggc_mark_tree (p->x_dtor_label);
    ggc_mark_tree (p->x_current_class_ptr);
    ggc_mark_tree (p->x_current_class_ref);
!   ggc_mark_tree (p->x_eh_spec_block);
    ggc_mark_tree_varray (p->x_local_names);
  
    mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.448
diff -c -p -d -r1.448 decl2.c
*** decl2.c	2001/03/22 00:55:11	1.448
--- decl2.c	2001/03/28 09:49:49
*************** finish_file ()
*** 3621,3630 ****
  	    }
  	}
  
-       /* Mark all functions that might deal with exception-handling as
- 	 referenced.  */
-       mark_all_runtime_matches ();
- 
        /* We lie to the back-end, pretending that some functions are
  	 not defined when they really are.  This keeps these functions
  	 from being put out unnecessarily.  But, we must stop lying
--- 3621,3626 ----
Index: dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/dump.c,v
retrieving revision 1.53
diff -c -p -d -r1.53 dump.c
*** dump.c	2001/03/27 04:52:21	1.53
--- dump.c	2001/03/28 09:49:49
*************** cp_dump_tree (di, t)
*** 188,193 ****
--- 188,200 ----
        dump_next_stmt (di, t);
        break;
  
+     case EH_SPEC_BLOCK:
+       dump_stmt (di, t);
+       dump_child ("body", EH_SPEC_STMTS (t));
+       dump_child ("raises", EH_SPEC_RAISES (t));
+       dump_next_stmt (di, t);
+       break;
+ 
      case PTRMEM_CST:
        dump_child ("clas", PTRMEM_CST_CLASS (t));
        dump_child ("mbr", PTRMEM_CST_MEMBER (t));
*************** cp_dump_tree (di, t)
*** 224,229 ****
--- 231,242 ----
      case HANDLER:
        dump_stmt (di, t);
        dump_child ("body", HANDLER_BODY (t));
+       dump_next_stmt (di, t);
+       break;
+ 
+     case MUST_NOT_THROW_EXPR:
+       dump_stmt (di, t);
+       dump_child ("body", TREE_OPERAND (t, 0));
        dump_next_stmt (di, t);
        break;
  
Index: error.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.153
diff -c -p -d -r1.153 error.c
*** error.c	2001/03/26 23:41:23	1.153
--- error.c	2001/03/28 09:49:49
*************** dump_expr (t, flags)
*** 2104,2110 ****
        break;
  
      case BIND_EXPR:
!       output_add_character (scratch_buffer, '}');
        dump_expr (TREE_OPERAND (t, 1), flags & ~TFF_EXPR_IN_PARENS);
        output_add_character (scratch_buffer, '}');
        break;
--- 2104,2110 ----
        break;
  
      case BIND_EXPR:
!       output_add_character (scratch_buffer, '{');
        dump_expr (TREE_OPERAND (t, 1), flags & ~TFF_EXPR_IN_PARENS);
        output_add_character (scratch_buffer, '}');
        break;
Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/except.c,v
retrieving revision 1.127
diff -c -p -d -r1.127 except.c
*** except.c	2001/03/28 08:25:45	1.127
--- except.c	2001/03/28 09:49:49
*************** Boston, MA 02111-1307, USA.  */
*** 34,332 ****
  #include "output.h"
  #include "except.h"
  #include "toplev.h"
- #include "eh-common.h"
  
  static void push_eh_cleanup PARAMS ((tree));
  static tree build_eh_type_type PARAMS ((tree));
! static tree call_eh_info PARAMS ((void));
! static void push_eh_info PARAMS ((void));
! static tree get_eh_info PARAMS ((void));
! static tree get_eh_value PARAMS ((void));
! #if 0
! static tree get_eh_type PARAMS ((void));
! static tree get_eh_caught PARAMS ((void));
! static tree get_eh_handlers PARAMS ((void));
! #endif
  static int dtor_nothrow PARAMS ((tree));
! static tree do_pop_exception PARAMS ((tree));
! static tree build_eh_type_type_ref PARAMS ((tree));
! static tree build_terminate_handler PARAMS ((void));
! static tree alloc_eh_object PARAMS ((tree));
  static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
  static bool is_admissible_throw_operand PARAMS ((tree));
  static int can_convert_eh PARAMS ((tree, tree));
  static void check_handlers_1 PARAMS ((tree, tree));
- static void initialize_handler_parm PARAMS ((tree));
- static tree expand_throw PARAMS ((tree));
- static int decl_is_java_type PARAMS ((tree decl, int err));
  
  #include "decl.h"
  #include "obstack.h"
- 
- /* In a given translation unit we are constrained to catch only C++
-    types or only Java types.  `catch_language' holds the current type,
-    and `catch_language_init' registers whether `catch_language' has
-    been set.  */
  
! static int catch_language_init = 0;
! static int catch_language;
! 
! /* ======================================================================
!    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 eh_entry it
!      created when push_eh_entry () was called.  The eh_entry 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 eh_entry structure.  Otherwise
!      the finalization variable is set to NULL to reflect the fact that
!      it is the end of a try block.  Next, this modified eh_entry 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 can use sequences to defer the catch sections.
!      When the start of a catch block is encountered, we start the
!      sequence.  After the catch block is generated, we end the
!      sequence.
! 
!      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 eh_queue 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 eh_entry 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.
!      
!      ===================================================================== */
! 
! /* ====================================================================== */
! 
! /* sets up all the global eh stuff that needs to be initialized at the
     start of compilation.  */
  
  void
  init_exception_processing ()
  {
!   /* void vtype () */
!   tree vtype = build_function_type (void_type_node, void_list_node);
!   
    if (flag_honor_std)
      push_namespace (std_identifier);
!   terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
    TREE_THIS_VOLATILE (terminate_node) = 1;
    TREE_NOTHROW (terminate_node) = 1;
    if (flag_honor_std)
      pop_namespace ();
- 
-   set_exception_lang_code (EH_LANG_C_plus_plus);
-   set_exception_version_code (1);
- 
-   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
-      be protected with __terminate.  */
-   protect_cleanup_actions_with_terminate = 1;
- }
- 
- /* Retrieve a pointer to the cp_eh_info node for the current exception.  */
- 
- static tree
- call_eh_info ()
- {
-   tree fn;
- 
-   fn = get_identifier ("__start_cp_handler");
-   if (IDENTIFIER_GLOBAL_VALUE (fn))
-     fn = IDENTIFIER_GLOBAL_VALUE (fn);
-   else
-     {
-       tree eh_info_type;
-       tree cleanup_fn_type;
-       tree matcher_fn_type;
-       tree cp_eh_info_type;
-       tree exception_desc_type;
-       tree fields[8];
- 
-       eh_info_type = make_aggr_type (RECORD_TYPE);
-       exception_desc_type = make_aggr_type (RECORD_TYPE);
-       
-       /* void * (*) (__eh_info *, void *, exception_descriptor *); */
-       matcher_fn_type = tree_cons
-           (NULL_TREE, build_pointer_type (eh_info_type), tree_cons
-             (NULL_TREE, ptr_type_node, tree_cons
-               (NULL_TREE, build_pointer_type (exception_desc_type),
-                 void_list_node)));
-       matcher_fn_type = build_function_type (ptr_type_node, matcher_fn_type);
-       matcher_fn_type = build_pointer_type (matcher_fn_type);
- 
-       /* void (*) (void *); */
-       cleanup_fn_type = tree_cons
-           (NULL_TREE, ptr_type_node, void_list_node);
-       cleanup_fn_type = build_function_type (void_type_node, cleanup_fn_type);
-       cleanup_fn_type = build_pointer_type (cleanup_fn_type);
- 
-       /* eh-common.h
-         struct __eh_info 
-         {
-           __eh_matcher match_function;
-           short language;
-           short version;
-         };  */
-       fields[0] = build_decl (FIELD_DECL,
- 		    get_identifier ("match_function"), ptr_type_node);
-       fields[1] = build_decl (FIELD_DECL, 
-                     get_identifier ("language"), short_integer_type_node);
-       fields[2] = build_decl (FIELD_DECL, 
-                     get_identifier ("version"), short_integer_type_node);
-       /* N.B.: The fourth field LEN is expected to be
- 	 the number of fields - 1, not the total number of fields.  */
-       finish_builtin_type (eh_info_type, "__eh_info", fields, 2, ptr_type_node);
-       
-       /* exception_support.h
-         struct cp_eh_info
-         {
-           __eh_info eh_info;
-           void *value;
-           void *type;
-           cleanup_fn cleanup;
-           bool caught;
-           cp_eh_info *next;
-           long handlers;
-           void *original_value;
-         };  */
-       cp_eh_info_type = make_aggr_type (RECORD_TYPE);
-       fields[0] = build_decl (FIELD_DECL, get_identifier ("eh_info"),
-                               eh_info_type);
-       fields[1] = build_decl (FIELD_DECL, get_identifier ("value"),
- 			      ptr_type_node);
-       fields[2] = build_decl (FIELD_DECL, get_identifier ("type"),
- 			      ptr_type_node);
-       fields[3] = build_decl (FIELD_DECL, get_identifier ("cleanup"),
-                               cleanup_fn_type);
-       fields[4] = build_decl (FIELD_DECL, get_identifier ("caught"),
- 			      boolean_type_node);
-       fields[5] = build_decl (FIELD_DECL, get_identifier ("next"),
- 			      build_pointer_type (cp_eh_info_type));
-       fields[6] = build_decl (FIELD_DECL, get_identifier ("handlers"),
-                               long_integer_type_node);
-       fields[7] = build_decl (FIELD_DECL, get_identifier ("original_value"),
-                               ptr_type_node);
-       /* N.B.: The fourth field LEN is expected to be
- 	 the number of fields - 1, not the total number of fields.  */
-       finish_builtin_type (cp_eh_info_type, "cp_eh_info", fields, 7, ptr_type_node);
- 
-       /* And now the function.  */
-       fn = push_library_fn (fn,
-               build_function_type (build_pointer_type (cp_eh_info_type),
-                                    void_list_node));
-     }
-   return build_function_call (fn, NULL_TREE);
- }
- 
- /* Retrieve a pointer to the cp_eh_info node for the current exception
-    and save it in the current binding level.  */
- 
- static void
- push_eh_info ()
- {
-   tree decl, fn = call_eh_info ();
- 
-   /* Remember the pointer to the current exception info; it won't change
-      during this catch block.  */
-   decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
- 		     TREE_TYPE (fn));
-   DECL_ARTIFICIAL (decl) = 1;
-   DECL_INITIAL (decl) = fn;
-   decl = pushdecl (decl);
-   cp_finish_decl (decl, fn, NULL_TREE, 0);
- }
- 
- /* Returns a reference to the cp_eh_info node for the current exception.  */
- 
- static tree
- get_eh_info ()
- {
-   /* Look for the pointer pushed in push_eh_info.  */
-   tree t = lookup_name (get_identifier ("__exception_info"), 0);
-   return build_indirect_ref (t, NULL_PTR);
- }
- 
- /* Returns a reference to the current exception object.  */
- 
- static tree
- get_eh_value ()
- {
-   return build_component_ref (get_eh_info (), get_identifier ("value"),
- 			      NULL_TREE, 0);
- }
- 
- /* Returns a reference to the current exception type.  */
- 
- #if 0
- static tree
- get_eh_type ()
- {
-   return build_component_ref (get_eh_info (), get_identifier ("type"),
- 			      NULL_TREE, 0);
- }
  
! /* Returns a reference to whether or not the current exception
!    has been caught.  */
  
! static tree
! get_eh_caught ()
! {
!   return build_component_ref (get_eh_info (), get_identifier ("caught"),
! 			      NULL_TREE, 0);
! }
  
! /* Returns a reference to whether or not the current exception
!    has been caught.  */
  
! static tree
! get_eh_handlers ()
! {
!   return build_component_ref (get_eh_info (), get_identifier ("handlers"),
! 			      NULL_TREE, 0);
  }
- #endif
  
- /* Build a type value for use at runtime for a type that is matched
-    against by the exception handling system.  */
- 
  static tree
! build_eh_type_type (type)
       tree type;
  {
    if (type == error_mark_node)
      return error_mark_node;
  
--- 34,100 ----
  #include "output.h"
  #include "except.h"
  #include "toplev.h"
  
  static void push_eh_cleanup PARAMS ((tree));
+ static tree prepare_eh_type PARAMS ((tree));
  static tree build_eh_type_type PARAMS ((tree));
! static tree do_begin_catch PARAMS ((void));
  static int dtor_nothrow PARAMS ((tree));
! static tree do_end_catch PARAMS ((tree));
! static void push_eh_cleanup PARAMS ((tree));
! static bool decl_is_java_type PARAMS ((tree decl, int err));
! static void choose_personality_routine PARAMS ((bool));
! static void initialize_handler_parm PARAMS ((tree, tree));
! static tree do_allocate_exception PARAMS ((tree));
! static tree do_free_exception PARAMS ((tree));
  static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
  static bool is_admissible_throw_operand PARAMS ((tree));
  static int can_convert_eh PARAMS ((tree, tree));
  static void check_handlers_1 PARAMS ((tree, tree));
  
  #include "decl.h"
  #include "obstack.h"
  
! /* Sets up all the global eh stuff that needs to be initialized at the
     start of compilation.  */
  
  void
  init_exception_processing ()
  {
!   tree tmp;
! 
    if (flag_honor_std)
      push_namespace (std_identifier);
! 
!   /* void std::terminate (); */
!   tmp = build_function_type (void_type_node, void_list_node);
!   terminate_node = build_cp_library_fn_ptr ("terminate", tmp);
    TREE_THIS_VOLATILE (terminate_node) = 1;
    TREE_NOTHROW (terminate_node) = 1;
    if (flag_honor_std)
      pop_namespace ();
  
!   protect_cleanup_actions = build_call (terminate_node, NULL_TREE);
  
!   /* void __cxa_call_unexpected(void *); */
!   tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
!   tmp = build_function_type (void_type_node, tmp);
!   call_unexpected_node
!     = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
  
!   eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
! 					     ? "__gxx_personality_sj0"
! 					     : "__gxx_personality_v0");
  
!   lang_eh_runtime_type = build_eh_type_type;
  }
  
  static tree
! prepare_eh_type (type)
       tree type;
  {
+   if (type == NULL_TREE)
+     return type;
    if (type == error_mark_node)
      return error_mark_node;
  
*************** build_eh_type_type (type)
*** 337,350 ****
    /* Peel off cv qualifiers.  */
    type = TYPE_MAIN_VARIANT (type);
  
!   return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
  }
  
  /* Build the address of a typeinfo decl for use in the runtime
!    matching field of the new exception model */
  
  static tree
! build_eh_type_type_ref (type)
       tree type;
  {
    tree exp;
--- 105,118 ----
    /* Peel off cv qualifiers.  */
    type = TYPE_MAIN_VARIANT (type);
  
!   return type;
  }
  
  /* Build the address of a typeinfo decl for use in the runtime
!    matching field of the exception model.   */
  
  static tree
! build_eh_type_type (type)
       tree type;
  {
    tree exp;
*************** build_eh_type_type_ref (type)
*** 352,398 ****
    if (type == NULL_TREE || type == error_mark_node)
      return type;
  
!   /* peel back references, so they match.  */
!   if (TREE_CODE (type) == REFERENCE_TYPE)
!     type = TREE_TYPE (type);
! 
!   /* Peel off cv qualifiers.  */
!   type = TYPE_MAIN_VARIANT (type);
  
-   exp = get_tinfo_decl (type);
    mark_used (exp);
    exp = build1 (ADDR_EXPR, ptr_type_node, exp);
  
!   return (exp);
  }
  
! /* This routine is called to mark all the symbols representing runtime
!    type functions in the exception table as having been referenced.
!    This will make sure code is emitted for them. Called from finish_file. */
  
! void 
! mark_all_runtime_matches () 
  {
!   int x,num;
!   void **ptr;
!   tree exp;
!   
!   num = find_all_handler_type_matches (&ptr);
!   if (num == 0 || ptr == NULL)
!     return;
!   
!   for (x=0; x <num; x++)
      {
!       exp = (tree) ptr[x];
!       if (TREE_CODE (exp) == ADDR_EXPR)
!         {
!           exp = TREE_OPERAND (exp, 0);
!           if (TREE_CODE (exp) == FUNCTION_DECL)
!             TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
!         }
      }
!   
!   free (ptr);
  }
  
  /* Returns nonzero if cleaning up an exception of type TYPE (which can be
--- 120,162 ----
    if (type == NULL_TREE || type == error_mark_node)
      return type;
  
!   if (decl_is_java_type (type, 0))
!     exp = build_java_class_ref (TREE_TYPE (type));
!   else
!     exp = get_tinfo_decl (type);
  
    mark_used (exp);
    exp = build1 (ADDR_EXPR, ptr_type_node, exp);
  
!   return exp;
  }
  
! tree
! build_exc_ptr ()
! {
!   return build (EXC_PTR_EXPR, ptr_type_node);
! }
  
! /* Build up a call to __cxa_begin_catch, to tell the runtime that the
!    exception has been handled.  */
! 
! static tree
! do_begin_catch ()
  {
!   tree fn;
! 
!   fn = get_identifier ("__cxa_begin_catch");
!   if (IDENTIFIER_GLOBAL_VALUE (fn))
!     fn = IDENTIFIER_GLOBAL_VALUE (fn);
!   else
      {
!       /* Declare void* __cxa_begin_catch (void *).  */
!       tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
!       fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
      }
! 
!   return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
! 					     NULL_TREE));
  }
  
  /* Returns nonzero if cleaning up an exception of type TYPE (which can be
*************** dtor_nothrow (type)
*** 415,446 ****
    return TREE_NOTHROW (fn);
  }
  
! /* Build up a call to __cp_pop_exception, to destroy the exception object
     for the current catch block if no others are currently using it.  */
  
  static tree
! do_pop_exception (type)
       tree type;
  {
    tree fn, cleanup;
!   fn = get_identifier ("__cp_pop_exception");
    if (IDENTIFIER_GLOBAL_VALUE (fn))
      fn = IDENTIFIER_GLOBAL_VALUE (fn);
    else
      {
!       /* Declare void __cp_pop_exception (void *),
! 	 as defined in exception.cc. */
!       fn = push_void_library_fn
! 	(fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node));
        /* This can throw if the destructor for the exception throws.  */
        TREE_NOTHROW (fn) = 0;
      }
  
!   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
!   cleanup = lookup_name (get_identifier ("__exception_info"), 0);
!   cleanup = build_function_call (fn, tree_cons
! 				 (NULL_TREE, cleanup, NULL_TREE));
    TREE_NOTHROW (cleanup) = dtor_nothrow (type);
    return cleanup;
  }
  
--- 179,207 ----
    return TREE_NOTHROW (fn);
  }
  
! /* Build up a call to __cxa_end_catch, to destroy the exception object
     for the current catch block if no others are currently using it.  */
  
  static tree
! do_end_catch (type)
       tree type;
  {
    tree fn, cleanup;
! 
!   fn = get_identifier ("__cxa_end_catch");
    if (IDENTIFIER_GLOBAL_VALUE (fn))
      fn = IDENTIFIER_GLOBAL_VALUE (fn);
    else
      {
!       /* Declare void __cxa_end_catch ().  */
!       fn = push_void_library_fn (fn, void_list_node);
        /* This can throw if the destructor for the exception throws.  */
        TREE_NOTHROW (fn) = 0;
      }
  
!   cleanup = build_function_call (fn, NULL_TREE);
    TREE_NOTHROW (cleanup) = dtor_nothrow (type);
+ 
    return cleanup;
  }
  
*************** static void
*** 450,478 ****
  push_eh_cleanup (type)
       tree type;
  {
!   finish_decl_cleanup (NULL_TREE, do_pop_exception (type));
! }
! 
! /* Build up a call to terminate on the function obstack, for use as an
!    exception handler.  */
! 
! static tree
! build_terminate_handler ()
! {
!   return build_function_call (terminate_node, NULL_TREE);
  }
  
  /* Return nonzero value if DECL is a Java type suitable for catch or
     throw.  */
  
! static int
  decl_is_java_type (decl, err)
       tree decl;
       int err;
  {
!   int r = (TREE_CODE (decl) == POINTER_TYPE
! 	   && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
! 	   && TYPE_FOR_JAVA (TREE_TYPE (decl)));
  
    if (err)
      {
--- 211,230 ----
  push_eh_cleanup (type)
       tree type;
  {
!   finish_decl_cleanup (NULL_TREE, do_end_catch (type));
  }
  
  /* Return nonzero value if DECL is a Java type suitable for catch or
     throw.  */
  
! static bool
  decl_is_java_type (decl, err)
       tree decl;
       int err;
  {
!   bool r = (TREE_CODE (decl) == POINTER_TYPE
! 	    && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
! 	    && TYPE_FOR_JAVA (TREE_TYPE (decl)));
  
    if (err)
      {
*************** decl_is_java_type (decl, err)
*** 508,578 ****
    return r;
  }
  
  /* Initialize the catch parameter DECL.  */
  
  static void 
! initialize_handler_parm (decl)
       tree decl;
  {
-   tree exp;
    tree init;
    tree init_type;
-   int lang;
  
    /* Make sure we mark the catch param as used, otherwise we'll get a
       warning about an unused ((anonymous)).  */
    TREE_USED (decl) = 1;
  
!   /* Figure out the type that the initializer is.  */
    init_type = TREE_TYPE (decl);
!   if (TREE_CODE (init_type) != REFERENCE_TYPE
!       && TREE_CODE (init_type) != POINTER_TYPE)
      init_type = build_reference_type (init_type);
- 
-   if (decl_is_java_type (init_type, 0))
-     {
-       tree fn
- 	= builtin_function ("_Jv_exception_info", 
- 			    build_function_type (ptr_type_node,
- 						 tree_cons (NULL_TREE,
- 							    void_type_node,
- 							    NULL_TREE)),
- 			    0, NOT_BUILT_IN, NULL_PTR);
- 
-       exp = build (CALL_EXPR, ptr_type_node,
- 		   build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
- 			   fn),
- 		   NULL_TREE, NULL_TREE);
-       TREE_SIDE_EFFECTS (exp) = 1;
-       lang = EH_LANG_Java;
  
!       set_exception_lang_code (EH_LANG_Java);
!       set_exception_version_code (1);
!     }
!   else
!     {
!       exp = get_eh_value ();
!       lang = EH_LANG_C_plus_plus;
!     }
! 
!   if (catch_language_init)
!     {
!       if (lang != catch_language)
! 	error ("mixing C++ and Java `catch'es in single translation unit");
!     }
!   else
!     {
!       catch_language_init = 1;
!       catch_language = lang;
!     }
  
    /* Since pointers are passed by value, initialize a reference to
!      pointer catch parm with the address of the value slot.  */ 
    if (TREE_CODE (init_type) == REFERENCE_TYPE 
        && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
      exp = build_unary_op (ADDR_EXPR, exp, 1);
  
!   exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
  
    init = convert_from_reference (exp);
  
--- 260,333 ----
    return r;
  }
  
+ static void
+ choose_personality_routine (is_java)
+      bool is_java;
+ {
+   static enum {
+     chose_none,
+     chose_cpp,
+     chose_java,
+     gave_error
+   } state;
+ 
+   switch (state)
+     {
+     case chose_none:
+       /* We defaulted to C++ in init_exception_processing.
+ 	 Reconfigure for Java if we changed our minds.  */
+       if (is_java)
+ 	eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ 						   ? "__gcj_personality_sj0"
+ 						   : "__gcj_personality_v0");
+       state = (is_java ? chose_java : chose_cpp);
+       break;
+ 
+     case chose_cpp:
+     case chose_java:
+       if (state != (is_java ? chose_java : chose_cpp))
+ 	{
+ 	  error ("mixing C++ and Java catches in a single translation unit");
+ 	  state = gave_error;
+ 	}
+       break;
+ 
+     case gave_error:
+       break;
+     }
+ }
+ 
  /* Initialize the catch parameter DECL.  */
  
  static void 
! initialize_handler_parm (decl, exp)
       tree decl;
+      tree exp;
  {
    tree init;
    tree init_type;
  
    /* Make sure we mark the catch param as used, otherwise we'll get a
       warning about an unused ((anonymous)).  */
    TREE_USED (decl) = 1;
  
!   /* Figure out the type that the initializer is.  Pointers are returned
!      adjusted by value from __cxa_begin_catch.  Others are returned by 
!      reference.  */
    init_type = TREE_TYPE (decl);
!   if (TREE_CODE (init_type) != POINTER_TYPE
!       && TREE_CODE (init_type) != REFERENCE_TYPE)
      init_type = build_reference_type (init_type);
  
!   choose_personality_routine (decl_is_java_type (init_type, 0));
  
    /* Since pointers are passed by value, initialize a reference to
!      pointer catch parm with the address of the temporary.  */
    if (TREE_CODE (init_type) == REFERENCE_TYPE 
        && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
      exp = build_unary_op (ADDR_EXPR, exp, 1);
  
!   exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
  
    init = convert_from_reference (exp);
  
*************** initialize_handler_parm (decl)
*** 584,591 ****
  	 See also expand_default_init.  */
        init = ocp_convert (TREE_TYPE (decl), init,
  			  CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
!       init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
! 		    build_terminate_handler ());
      }
  
    /* Let `cp_finish_decl' know that this initializer is ok.  */
--- 339,345 ----
  	 See also expand_default_init.  */
        init = ocp_convert (TREE_TYPE (decl), init,
  			  CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
!       init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init);
      }
  
    /* Let `cp_finish_decl' know that this initializer is ok.  */
*************** expand_start_catch_block (decl)
*** 605,610 ****
--- 359,367 ----
  {
    tree compound_stmt_1;
    tree compound_stmt_2;
+   tree exp = NULL_TREE;
+   tree type;
+   bool is_java;
  
    if (! doing_eh (1))
      return NULL_TREE;
*************** expand_start_catch_block (decl)
*** 618,651 ****
    compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
    note_level_for_catch ();
  
!   if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
      {
!       /* The ordinary C++ case.  */
!       tree type;
  
!       if (decl)
! 	type = TREE_TYPE (decl);
        else
! 	type = NULL_TREE;
!       begin_catch_block (build_eh_type_type_ref (type));
! 
!       push_eh_info ();
!       push_eh_cleanup (type);
      }
    else
!     {
!       /* The Java case.  In this case, the match_info is a pointer to
! 	 the Java class object.  We assume that the class is a
! 	 compiled class.  */
!       tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
!       begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
!     }
  
    /* Create a binding level for the parm.  */
    compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
  
    if (decl)
!     initialize_handler_parm (decl);
  
    return build_tree_list (compound_stmt_1, compound_stmt_2);
  }
--- 375,428 ----
    compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
    note_level_for_catch ();
  
!   if (decl)
!     type = prepare_eh_type (TREE_TYPE (decl));
!   else
!     type = NULL_TREE;
!   begin_catch_block (type);
! 
!   is_java = false;
!   if (decl)
      {
!       tree init;
  
!       if (decl_is_java_type (type, 1))
! 	{
! 	  /* Java only passes object via pointer and doesn't require
! 	     adjusting.  The java object is immediately before the
! 	     generic exception header.  */
! 	  init = build_exc_ptr ();
! 	  init = build1 (NOP_EXPR, build_pointer_type (type), init);
! 	  init = build (MINUS_EXPR, TREE_TYPE (init), init,
! 			TYPE_SIZE_UNIT (TREE_TYPE (init)));
! 	  init = build_indirect_ref (init, NULL_PTR);
! 	  is_java = true;
! 	}
        else
! 	{
! 	  /* C++ requires that we call __cxa_begin_catch to get the
! 	     pointer to the actual object.  */
! 	  init = do_begin_catch ();
! 	}
! 	  
!       exp = create_temporary_var (ptr_type_node);
!       DECL_REGISTER (exp) = 1;
!       cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
!       finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
      }
    else
!     finish_expr_stmt (do_begin_catch ());
  
+   /* C++ requires that we call __cxa_end_catch at the end of
+      processing the exception.  */
+   if (! is_java)
+     push_eh_cleanup (type);
+ 
    /* Create a binding level for the parm.  */
    compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
  
    if (decl)
!     initialize_handler_parm (decl, exp);
  
    return build_tree_list (compound_stmt_1, compound_stmt_2);
  }
*************** expand_end_catch_block (blocks)
*** 678,1043 ****
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
  }
  
- /* An exception spec is implemented more or less like:
- 
-    try {
-      function body;
-    } catch (...) {
-      void *p[] = { typeid(raises) };
-      __check_eh_spec (p, count);
-    }
- 
-    __check_eh_spec in exception.cc handles all the details.  */
- 
  tree
! expand_start_eh_spec ()
  {
!   return begin_try_block ();
  }
  
  void
! expand_end_eh_spec (raises, try_block)
!      tree raises;
!      tree try_block;
  {
!   tree tmp, fn, decl, types = NULL_TREE;
!   tree blocks;
!   tree handler;
!   int count = 0;
! 
!   finish_try_block (try_block);
!   handler = begin_handler ();
!   blocks = finish_handler_parms (NULL_TREE, handler);
! 
!   if (TREE_VALUE (raises) == NULL_TREE)
!     {
!       fn = get_identifier ("__check_null_eh_spec");
!       if (IDENTIFIER_GLOBAL_VALUE (fn))
! 	fn = IDENTIFIER_GLOBAL_VALUE (fn);
!       else
! 	{
! 	  tmp = build_function_type (void_type_node, void_list_node);
! 	  fn = push_throw_library_fn (fn, tmp);
! 	  /* Since the spec doesn't allow any exceptions, this call will
! 	     never throw.  We use push_throw_library_fn because we do want
! 	     TREE_THIS_VOLATILE to be set.  */
! 	  TREE_NOTHROW (fn) = 1;
! 	}
!       tmp = NULL_TREE;
!     }
!   else
!     {
!       /* Build up an array of type_infos.  */
!       for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
! 	{
! 	  types = tree_cons
! 	    (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
! 	  ++count;
! 	}
! 
!       types = build_nt (CONSTRUCTOR, NULL_TREE, types);
!       TREE_HAS_CONSTRUCTOR (types) = 1;
! 
!       /* We can't pass the CONSTRUCTOR directly, so stick it in a variable.  */
!       tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
!       decl = build_decl (VAR_DECL, NULL_TREE, tmp);
!       DECL_ARTIFICIAL (decl) = 1;
!       DECL_INITIAL (decl) = types;
!       DECL_CONTEXT (decl) = current_function_decl;
!       cp_finish_decl (decl, types, NULL_TREE, 0);
! 
!       decl = decay_conversion (decl);
! 
!       fn = get_identifier ("__check_eh_spec");
!       if (IDENTIFIER_GLOBAL_VALUE (fn))
! 	fn = IDENTIFIER_GLOBAL_VALUE (fn);
!       else
! 	{
! 	  tmp = tree_cons
! 	    (NULL_TREE, integer_type_node, tree_cons
! 	     (NULL_TREE, TREE_TYPE (decl), void_list_node));
! 	  tmp = build_function_type (void_type_node, tmp);
! 
! 	  fn = push_throw_library_fn (fn, tmp);
! 	}
  
!       tmp = tree_cons (NULL_TREE, build_int_2 (count, 0), 
! 		       tree_cons (NULL_TREE, decl, NULL_TREE));
!     }
  
!   tmp = build_call (fn, tmp);
!   finish_expr_stmt (tmp);
  
!   finish_handler (blocks, handler);
!   finish_handler_sequence (try_block);
  }
  
! /* This is called to expand all the toplevel exception handling
!    finalization for a function.  It should only be called once per
!    function.  */
  
! void
! expand_exception_blocks ()
  {
!   do_pending_stack_adjust ();
  
!   if (catch_clauses)
      {
!       rtx funcend = gen_label_rtx ();
!       emit_jump (funcend);
! 
!       /* We cannot protect n regions this way if we must flow into the
! 	 EH region through the top of the region, as we have to with
! 	 the setjmp/longjmp approach.  */
!       if (USING_SJLJ_EXCEPTIONS == 0)
! 	expand_eh_region_start ();
! 
!       emit_insns (catch_clauses);
!       catch_clauses = catch_clauses_last = NULL_RTX;
! 
!       if (USING_SJLJ_EXCEPTIONS == 0)
! 	expand_eh_region_end (build_terminate_handler ());
! 
!       emit_insns (catch_clauses);
!       catch_clauses = catch_clauses_last = NULL_RTX;
!       emit_label (funcend);
      }
  }
  
! /* Return a pointer to a buffer for an exception object of type TYPE.  */
  
  static tree
! alloc_eh_object (type)
!      tree type;
  {
!   tree fn, exp;
  
!   fn = get_identifier ("__eh_alloc");
    if (IDENTIFIER_GLOBAL_VALUE (fn))
      fn = IDENTIFIER_GLOBAL_VALUE (fn);
    else
      {
!       /* Declare __eh_alloc (size_t), as defined in exception.cc.  */
!       tree tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
!       fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
      }
  
!   exp = build_function_call (fn, tree_cons
! 			     (NULL_TREE, size_in_bytes (type), NULL_TREE));
!   exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
!   return exp;
  }
  
! /* 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 allocated 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.  */
  
! static tree
! expand_throw (exp)
       tree exp;
  {
    tree fn;
  
    if (! doing_eh (1))
      return error_mark_node;
  
!   if (exp
!       && decl_is_java_type (TREE_TYPE (exp), 1))
      {
!       /* A Java `throw' statement.  */
!       tree args = tree_cons (NULL_TREE, exp, NULL);
! 
!       fn = get_identifier (USING_SJLJ_EXCEPTIONS
! 			   ? "_Jv_Sjlj_Throw"
! 			   : "_Jv_Throw");
        if (IDENTIFIER_GLOBAL_VALUE (fn))
  	fn = IDENTIFIER_GLOBAL_VALUE (fn);
        else
  	{
! 	  /* Declare _Jv_Throw (void *), as defined in Java's
! 	     exception.cc.  */
  	  tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
  	  tmp = build_function_type (ptr_type_node, tmp);
  	  fn = push_throw_library_fn (fn, tmp);
  	}
  
!       exp = build_function_call (fn, args);
      }
    else if (exp)
      {
        tree throw_type;
!       tree cleanup = NULL_TREE, e;
        tree stmt_expr;
        tree compound_stmt;
        tree try_block;
  
        begin_init_stmts (&stmt_expr, &compound_stmt);
  
        /* throw expression */
        /* First, decay it.  */
        exp = decay_conversion (exp);
  
!       /* The CLEANUP_TYPE is the internal type of a destructor.  Under
! 	 the old ABI, destructors are two-argument functions; under
! 	 the new ABI they take only one argument.  */
!       if (cleanup_type == NULL_TREE)
! 	{
! 	  tree arg_types;
! 	  
! 	  arg_types = void_list_node;
! 	  arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
! 	  cleanup_type = (build_pointer_type 
! 			  (build_function_type (void_type_node, arg_types)));
! 	}
! 
!       if (TYPE_PTR_P (TREE_TYPE (exp)))
! 	throw_type = build_eh_type_type (TREE_TYPE (exp));
!       else
! 	{
! 	  tree object, ptr;
! 
! 	  /* OK, this is kind of wacky.  The standard says that we call
! 	     terminate when the exception handling mechanism, after
! 	     completing evaluation of the expression to be thrown but
! 	     before the exception is caught (_except.throw_), calls a
! 	     user function that exits via an uncaught exception.
  
! 	     So we have to protect the actual initialization of the
! 	     exception object with terminate(), but evaluate the
! 	     expression first.  Since there could be temps in the
! 	     expression, we need to handle that, too.  We also expand
! 	     the call to __eh_alloc first (which doesn't matter, since
! 	     it can't throw).  */
  
! 	  my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926);
  
! 	  /* Store the throw expression into a temp.  This can be less
! 	     efficient than storing it into the allocated space directly, but
! 	     if we allocated the space first we would have to deal with
! 	     cleaning it up if evaluating this expression throws.  */
! 	  if (TREE_SIDE_EFFECTS (exp))
! 	    {
! 	      tree temp = create_temporary_var (TREE_TYPE (exp));
! 	      DECL_INITIAL (temp) = exp;
! 	      cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
! 	      exp = temp;
! 	    }
  
! 	  /* Allocate the space for the exception.  */
! 	  ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
! 	  finish_expr_stmt (ptr);
  
! 	  try_block = begin_try_block ();
! 	  object = build_indirect_ref (ptr, NULL_PTR);
! 	  exp = build_modify_expr (object, INIT_EXPR, exp);
  
! 	  if (exp == error_mark_node)
! 	    error ("  in thrown expression");
  
! 	  finish_expr_stmt (exp);
! 	  finish_cleanup_try_block (try_block);
! 	  finish_cleanup (build_terminate_handler (), try_block);
  
! 	  throw_type = build_eh_type_type (TREE_TYPE (object));
  
! 	  if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
! 	    {
! 	      cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! 					 complete_dtor_identifier,
! 					 0);
! 	      cleanup = TREE_VALUE (cleanup);
! 	      mark_used (cleanup);
! 	      mark_addressable (cleanup);
! 	      /* Pretend it's a normal function.  */
! 	      cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
! 	    }
  
! 	  exp = ptr;
  	}
! 
!       /* Cast EXP to `void *' so that it will match the prototype for
! 	 __cp_push_exception.  */
!       exp = convert (ptr_type_node, exp);
! 
!       if (cleanup == NULL_TREE)
  	{
  	  cleanup = build_int_2 (0, 0);
  	  TREE_TYPE (cleanup) = cleanup_type;
  	}
  
!       fn = cp_push_exception_identifier;
!       if (IDENTIFIER_GLOBAL_VALUE (fn))
! 	fn = IDENTIFIER_GLOBAL_VALUE (fn);
!       else
! 	{
! 	  /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
! 	     as defined in exception.cc.  */
! 	  tree tmp;
! 	  tmp = tree_cons
! 	    (NULL_TREE, ptr_type_node, tree_cons
! 	     (NULL_TREE, ptr_type_node, tree_cons
! 	      (NULL_TREE, cleanup_type, void_list_node)));
! 	  fn = push_void_library_fn (fn, tmp);
! 	}
  
!       e = tree_cons (NULL_TREE, exp, tree_cons
! 		     (NULL_TREE, throw_type, tree_cons
! 		      (NULL_TREE, cleanup, NULL_TREE)));
!       finish_expr_stmt (build_function_call (fn, e));
  
        exp = finish_init_stmts (stmt_expr, compound_stmt);
      }
    else
      {
!       /* rethrow current exception; note that it's no longer caught.  */
  
!       tree fn = get_identifier ("__uncatch_exception");
        if (IDENTIFIER_GLOBAL_VALUE (fn))
  	fn = IDENTIFIER_GLOBAL_VALUE (fn);
        else
! 	/* Declare void __uncatch_exception (void)
! 	   as defined in exception.cc. */
! 	fn = push_void_library_fn (fn, void_list_node);
  
        exp = build_function_call (fn, NULL_TREE);
      }
- 
-   return exp;
- }
- 
- /* Build a throw expression.  */
- 
- tree
- build_throw (e)
-      tree e;
- {
-   if (e == error_mark_node)
-     return e;
- 
-   if (processing_template_decl)
-     return build_min (THROW_EXPR, void_type_node, e);
- 
-   if (e == null_node)
-     cp_warning ("throwing NULL, which has integral, not pointer type");
-   
-   if (e != NULL_TREE)
-     {
-       if (!is_admissible_throw_operand (e))
-         return error_mark_node;
-     }
  
!   e = expand_throw (e);
!   e = build1 (THROW_EXPR, void_type_node, e);
!   TREE_SIDE_EFFECTS (e) = 1;
!   TREE_USED (e) = 1;
  
!   return e;
  }
  
  /* Make sure TYPE is complete, pointer to complete, reference to
--- 455,709 ----
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
  }
  
  tree
! begin_eh_spec_block ()
  {
!   tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
!   add_stmt (r);
!   return r;
  }
  
  void
! finish_eh_spec_block (raw_raises, eh_spec_block)
!      tree raw_raises;
!      tree eh_spec_block;
  {
!   tree raises;
  
!   RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block));
  
!   /* Strip cv quals, etc, from the specification types.  */
!   for (raises = NULL_TREE;
!        raw_raises && TREE_VALUE (raw_raises);
!        raw_raises = TREE_CHAIN (raw_raises))
!     raises = tree_cons (NULL_TREE, prepare_eh_type (TREE_VALUE (raw_raises)),
! 			raises);
  
!   EH_SPEC_RAISES (eh_spec_block) = raises;
  }
  
! /* Return a pointer to a buffer for an exception object of type TYPE.  */
  
! static tree
! do_allocate_exception (type)
!      tree type;
  {
!   tree fn;
  
!   fn = get_identifier ("__cxa_allocate_exception");
!   if (IDENTIFIER_GLOBAL_VALUE (fn))
!     fn = IDENTIFIER_GLOBAL_VALUE (fn);
!   else
      {
!       /* Declare void *__cxa_allocate_exception(size_t).  */
!       tree tmp = tree_cons (NULL_TREE, c_size_type_node, void_list_node);
!       fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
      }
+   
+   return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type),
+ 					     NULL_TREE));
  }
  
! /* Call __cxa_free_exception from a cleanup.  This is invoked when
!    a constructor for a thrown object throws.  */
  
  static tree
! do_free_exception (ptr)
!      tree ptr;
  {
!   tree fn;
  
!   fn = get_identifier ("__cxa_free_exception");
    if (IDENTIFIER_GLOBAL_VALUE (fn))
      fn = IDENTIFIER_GLOBAL_VALUE (fn);
    else
      {
!       /* Declare void __cxa_free_exception (void *).  */
!       fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node,
! 						void_list_node));
      }
  
!   return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE));
  }
  
! /* Build a throw expression.  */
  
! tree
! build_throw (exp)
       tree exp;
  {
    tree fn;
  
+   if (exp == error_mark_node)
+     return exp;
+ 
+   if (processing_template_decl)
+     return build_min (THROW_EXPR, void_type_node, exp);
+ 
+   if (exp == null_node)
+     cp_warning ("throwing NULL, which has integral, not pointer type");
+   
+   if (exp != NULL_TREE)
+     {
+       if (!is_admissible_throw_operand (exp))
+         return error_mark_node;
+     }
+ 
    if (! doing_eh (1))
      return error_mark_node;
  
!   if (exp && decl_is_java_type (TREE_TYPE (exp), 1))
      {
!       tree fn = get_identifier ("_Jv_Throw");
        if (IDENTIFIER_GLOBAL_VALUE (fn))
  	fn = IDENTIFIER_GLOBAL_VALUE (fn);
        else
  	{
! 	  /* Declare void _Jv_Throw (void *).  */
  	  tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
  	  tmp = build_function_type (ptr_type_node, tmp);
  	  fn = push_throw_library_fn (fn, tmp);
  	}
  
!       exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE));
      }
    else if (exp)
      {
        tree throw_type;
!       tree cleanup;
        tree stmt_expr;
        tree compound_stmt;
        tree try_block;
+       tree object, ptr;
+       tree tmp;
  
+       fn = get_identifier ("__cxa_throw");
+       if (IDENTIFIER_GLOBAL_VALUE (fn))
+ 	fn = IDENTIFIER_GLOBAL_VALUE (fn);
+       else
+ 	{
+ 	  /* The CLEANUP_TYPE is the internal type of a destructor.  */
+ 	  if (cleanup_type == NULL_TREE)
+ 	    {
+ 	      tmp = void_list_node;
+ 	      tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ 	      tmp = build_function_type (void_type_node, tmp);
+ 	      cleanup_type = build_pointer_type (tmp);
+ 	    }
+ 
+ 	  /* Declare void __cxa_throw (void*, void*, void (*)(void*)).  */
+ 	  /* ??? Second argument is supposed to be "std::type_info*".  */
+ 	  tmp = void_list_node;
+ 	  tmp = tree_cons (NULL_TREE, cleanup_type, tmp);
+ 	  tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ 	  tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ 	  tmp = build_function_type (void_type_node, tmp);
+ 	  fn = push_throw_library_fn (fn, tmp);
+ 	}
+ 
        begin_init_stmts (&stmt_expr, &compound_stmt);
  
        /* throw expression */
        /* First, decay it.  */
        exp = decay_conversion (exp);
  
!       /* OK, this is kind of wacky.  The standard says that we call
! 	 terminate when the exception handling mechanism, after
! 	 completing evaluation of the expression to be thrown but
! 	 before the exception is caught (_except.throw_), calls a
! 	 user function that exits via an uncaught exception.
  
! 	 So we have to protect the actual initialization of the
! 	 exception object with terminate(), but evaluate the
! 	 expression first.  Since there could be temps in the
! 	 expression, we need to handle that, too.  We also expand
! 	 the call to __cxa_allocate_exception first (which doesn't
! 	 matter, since it can't throw).  */
  
!       my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926);
  
!       /* Store the throw expression into a temp.  This can be less
! 	 efficient than storing it into the allocated space directly, but
! 	 if we allocated the space first we would have to deal with
! 	 cleaning it up if evaluating this expression throws.  */
!       if (TREE_SIDE_EFFECTS (exp))
! 	{
! 	  tmp = create_temporary_var (TREE_TYPE (exp));
! 	  DECL_INITIAL (tmp) = exp;
! 	  cp_finish_decl (tmp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
! 	  exp = tmp;
! 	}
  
!       /* Allocate the space for the exception.  */
!       ptr = create_temporary_var (ptr_type_node);
!       DECL_REGISTER (ptr) = 1;
!       cp_finish_decl (ptr, NULL_TREE, NULL_TREE, LOOKUP_ONLYCONVERTING);
!       tmp = do_allocate_exception (TREE_TYPE (exp));
!       tmp = build_modify_expr (ptr, INIT_EXPR, tmp);
!       finish_expr_stmt (tmp);
  
!       object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr);
!       object = build_indirect_ref (object, NULL_PTR);
  
!       try_block = begin_try_block ();
  
!       exp = build_modify_expr (object, INIT_EXPR, exp);
!       if (exp == error_mark_node)
! 	error ("  in thrown expression");
  
!       finish_expr_stmt (exp);
!       finish_cleanup_try_block (try_block);
!       finish_cleanup (do_free_exception (ptr), try_block);
  
!       throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
  
!       if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
! 	{
! 	  cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! 				     complete_dtor_identifier, 0);
! 	  cleanup = TREE_VALUE (cleanup);
! 	  mark_used (cleanup);
! 	  mark_addressable (cleanup);
! 	  /* Pretend it's a normal function.  */
! 	  cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
  	}
!       else
  	{
  	  cleanup = build_int_2 (0, 0);
  	  TREE_TYPE (cleanup) = cleanup_type;
  	}
  
!       tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE);
!       tmp = tree_cons (NULL_TREE, throw_type, tmp);
!       tmp = tree_cons (NULL_TREE, ptr, tmp);
!       tmp = build_function_call (fn, tmp);
  
!       /* ??? Indicate that this function call throws throw_type.  */
  
+       finish_expr_stmt (tmp);
+ 
        exp = finish_init_stmts (stmt_expr, compound_stmt);
      }
    else
      {
!       /* Rethrow current exception.  */
  
!       tree fn = get_identifier ("__cxa_rethrow");
        if (IDENTIFIER_GLOBAL_VALUE (fn))
  	fn = IDENTIFIER_GLOBAL_VALUE (fn);
        else
! 	{
! 	  /* Declare void __cxa_rethrow (void).  */
! 	  fn = push_throw_library_fn
! 	    (fn, build_function_type (void_type_node, void_list_node));
! 	}
  
        exp = build_function_call (fn, NULL_TREE);
      }
  
!   exp = build1 (THROW_EXPR, void_type_node, exp);
  
!   return exp;
  }
  
  /* Make sure TYPE is complete, pointer to complete, reference to
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/expr.c,v
retrieving revision 1.56
diff -c -p -d -r1.56 expr.c
*** expr.c	2001/02/12 09:58:18	1.56
--- expr.c	2001/03/28 09:49:49
*************** cplus_expand_expr (exp, target, tmode, m
*** 88,93 ****
--- 88,94 ----
    tree type = TREE_TYPE (exp);
    register enum machine_mode mode = TYPE_MODE (type);
    register enum tree_code code = TREE_CODE (exp);
+   rtx ret;
  
    /* No sense saving up arithmetic to be done
       if it's all in the wrong mode to form part of an address.
*************** cplus_expand_expr (exp, target, tmode, m
*** 103,117 ****
  			  target, tmode, modifier);
  
      case OFFSET_REF:
!       {
! 	return expand_expr (default_conversion (resolve_offset_ref (exp)),
! 			    target, tmode, EXPAND_NORMAL);
!       }
  
      case THROW_EXPR:
        expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
-       expand_internal_throw ();
        return NULL;
  
      case EMPTY_CLASS_EXPR:
        /* We don't need to generate any code for an empty class.  */
--- 104,121 ----
  			  target, tmode, modifier);
  
      case OFFSET_REF:
!       return expand_expr (default_conversion (resolve_offset_ref (exp)),
! 			  target, tmode, EXPAND_NORMAL);
  
      case THROW_EXPR:
        expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
        return NULL;
+ 
+     case MUST_NOT_THROW_EXPR:
+       expand_eh_region_start ();
+       ret = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+       expand_eh_region_end_must_not_throw (build_call (terminate_node, 0));
+       return ret;
  
      case EMPTY_CLASS_EXPR:
        /* We don't need to generate any code for an empty class.  */
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.197
diff -c -p -d -r1.197 semantics.c
*** semantics.c	2001/03/28 08:25:45	1.197
--- semantics.c	2001/03/28 09:49:49
*************** static tree simplify_aggr_init_exprs_r P
*** 51,56 ****
--- 51,57 ----
  static void deferred_type_access_control PARAMS ((void));
  static void emit_associated_thunks PARAMS ((tree));
  static void genrtl_try_block PARAMS ((tree));
+ static void genrtl_eh_spec_block PARAMS ((tree));
  static void genrtl_handler PARAMS ((tree));
  static void genrtl_catch_block PARAMS ((tree));
  static void genrtl_ctor_stmt PARAMS ((tree));
*************** genrtl_try_block (t)
*** 575,588 ****
      {
        expand_eh_region_start ();
        expand_stmt (TRY_STMTS (t));
!       expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t)));
      }
    else
      {
        if (!FN_TRY_BLOCK_P (t)) 
  	emit_line_note (input_filename, lineno);
-       expand_start_try_stmts ();
  
        expand_stmt (TRY_STMTS (t));
  
        if (FN_TRY_BLOCK_P (t))
--- 576,589 ----
      {
        expand_eh_region_start ();
        expand_stmt (TRY_STMTS (t));
!       expand_eh_region_end_cleanup (TRY_HANDLERS (t));
      }
    else
      {
        if (!FN_TRY_BLOCK_P (t)) 
  	emit_line_note (input_filename, lineno);
  
+       expand_eh_region_start ();
        expand_stmt (TRY_STMTS (t));
  
        if (FN_TRY_BLOCK_P (t))
*************** genrtl_try_block (t)
*** 603,608 ****
--- 604,624 ----
      }
  }
  
+ /* Generate the RTL for T, which is an EH_SPEC_BLOCK. */
+ 
+ static void 
+ genrtl_eh_spec_block (t)
+      tree t;
+ {
+   expand_eh_region_start ();
+   expand_stmt (EH_SPEC_STMTS (t));
+   expand_eh_region_end_allowed (EH_SPEC_RAISES (t),
+ 				build_call (call_unexpected_node,
+ 					    tree_cons (NULL_TREE,
+ 						       build_exc_ptr (),
+ 						       NULL_TREE)));
+ }
+ 
  /* Begin a try-block.  Returns a newly-created TRY_BLOCK if
     appropriate.  */
  
*************** genrtl_handler (t)
*** 706,718 ****
    genrtl_do_pushlevel ();
    expand_stmt (HANDLER_BODY (t));
    if (!processing_template_decl)
!     {
!       /* Fall to outside the try statement when done executing
! 	 handler and we fall off end of handler.  This is jump
! 	 Lresume in the documentation.  */
!       expand_goto (top_label_entry (&caught_return_label_stack));
!       end_catch_handler ();
!     }
  }
  
  /* Begin a handler.  Returns a HANDLER if appropriate.  */
--- 722,728 ----
    genrtl_do_pushlevel ();
    expand_stmt (HANDLER_BODY (t));
    if (!processing_template_decl)
!     expand_end_catch ();
  }
  
  /* Begin a handler.  Returns a HANDLER if appropriate.  */
*************** finish_handler_parms (decl, handler)
*** 757,769 ****
    return blocks;
  }
  
! /* Generate the RTL for a CATCH_BLOCK. */
  
  static void
  genrtl_catch_block (type)
       tree type;
  {
!   start_catch_handler (type);
  }
  
  /* Note the beginning of a handler for TYPE.  This function is called
--- 767,779 ----
    return blocks;
  }
  
! /* Generate the RTL for a START_CATCH_STMT. */
  
  static void
  genrtl_catch_block (type)
       tree type;
  {
!   expand_start_catch (type);
  }
  
  /* Note the beginning of a handler for TYPE.  This function is called
*************** cp_expand_stmt (t)
*** 2209,2214 ****
--- 2219,2228 ----
        genrtl_try_block (t);
        break;
  
+     case EH_SPEC_BLOCK:
+       genrtl_eh_spec_block (t);
+       break;
+ 
      case HANDLER:
        genrtl_handler (t);
        break;
*************** genrtl_finish_function (fn)
*** 2614,2622 ****
        && current_function_return_value == NULL_TREE
        && ! DECL_NAME (DECL_RESULT (current_function_decl)))
      no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- 
-   if (flag_exceptions)
-     expand_exception_blocks ();
  
    /* If this function is supposed to return a value, ensure that
       we do not fall into the cleanups by mistake.  The end of our
--- 2628,2633 ----
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.237
diff -c -p -d -r1.237 tree.c
*** tree.c	2001/03/23 01:49:11	1.237
--- tree.c	2001/03/28 09:49:50
*************** cp_statement_code_p (code)
*** 1037,1042 ****
--- 1037,1043 ----
      case RETURN_INIT:
      case TRY_BLOCK:
      case HANDLER:
+     case EH_SPEC_BLOCK:
        return 1;
  
      default:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]