1/* Handle exceptional things in C++.
2   Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc.
3   Contributed by Michael Tiemann <tiemann@cygnus.com>
4   Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
5   initial re-implementation courtesy Tad Hunt.
6
7This file is part of GNU CC.
8
9GNU CC is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
13
14GNU CC is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU CC; see the file COPYING.  If not, write to
21the Free Software Foundation, 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA.  */
23
24
25#include "config.h"
26#include "system.h"
27#include "tree.h"
28#include "rtl.h"
29#include "cp-tree.h"
30#include "flags.h"
31#include "obstack.h"
32#include "expr.h"
33#include "output.h"
34#include "except.h"
35#include "function.h"
36#include "defaults.h"
37#include "toplev.h"
38#include "eh-common.h"
39
40rtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
41
42/* Holds the fndecl for __builtin_return_address.  */
43tree builtin_return_address_fndecl;
44
45/* A couple of backend routines from m88k.c */
46
47static void push_eh_cleanup PROTO((void));
48static tree build_eh_type_type PROTO((tree));
49static tree build_eh_type PROTO((tree));
50static void expand_end_eh_spec PROTO((tree));
51static tree call_eh_info PROTO((void));
52static void push_eh_info PROTO((void));
53static tree get_eh_info PROTO((void));
54static tree get_eh_value PROTO((void));
55#if 0
56static tree get_eh_type PROTO((void));
57static tree get_eh_caught PROTO((void));
58static tree get_eh_handlers PROTO((void));
59#endif
60static tree do_pop_exception PROTO((void));
61static void process_start_catch_block PROTO((tree, tree));
62static tree build_eh_type_type_ref PROTO((tree));
63static tree build_terminate_handler PROTO((void));
64static tree alloc_eh_object PROTO((tree));
65
66#if 0
67/* This is the startup, and finish stuff per exception table.  */
68
69/* XXX - Tad: exception handling section */
70#ifndef EXCEPT_SECTION_ASM_OP
71#define EXCEPT_SECTION_ASM_OP	"section\t.gcc_except_table,\"a\",@progbits"
72#endif
73
74#ifdef EXCEPT_SECTION_ASM_OP
75
76 /* on machines which support it, the exception table lives in another section,
77	but it needs a label so we can reference it...  This sets up that
78    label! */
79asm (EXCEPT_SECTION_ASM_OP);
80exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
81asm (TEXT_SECTION_ASM_OP);
82
83#endif /* EXCEPT_SECTION_ASM_OP */
84
85#ifdef EXCEPT_SECTION_ASM_OP
86
87 /* we need to know where the end of the exception table is... so this
88    is how we do it! */
89
90asm (EXCEPT_SECTION_ASM_OP);
91exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
92asm (TEXT_SECTION_ASM_OP);
93
94#endif /* EXCEPT_SECTION_ASM_OP */
95
96#endif
97
98#include "decl.h"
99#include "insn-flags.h"
100#include "obstack.h"
101
102/* ======================================================================
103   Briefly the algorithm works like this:
104
105     When a constructor or start of a try block is encountered,
106     push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
107     new entry in the unwind protection stack and returns a label to
108     output to start the protection for that block.
109
110     When a destructor or end try block is encountered, pop_eh_entry
111     (&eh_stack) is called.  Pop_eh_entry () returns the eh_entry it
112     created when push_eh_entry () was called.  The eh_entry structure
113     contains three things at this point.  The start protect label,
114     the end protect label, and the exception handler label.  The end
115     protect label should be output before the call to the destructor
116     (if any). If it was a destructor, then its parse tree is stored
117     in the finalization variable in the eh_entry structure.  Otherwise
118     the finalization variable is set to NULL to reflect the fact that
119     it is the end of a try block.  Next, this modified eh_entry node
120     is enqueued in the finalizations queue by calling
121     enqueue_eh_entry (&queue,entry).
122
123	+---------------------------------------------------------------+
124	|XXX: Will need modification to deal with partially		|
125	|			constructed arrays of objects		|
126	|								|
127	|	Basically, this consists of keeping track of how many	|
128	|	of the objects have been constructed already (this	|
129	|	should be in a register though, so that shouldn't be a	|
130	|	problem.						|
131	+---------------------------------------------------------------+
132
133     When a catch block is encountered, there is a lot of work to be
134     done.
135
136     Since we don't want to generate the catch block inline with the
137     regular flow of the function, we need to have some way of doing
138     so.  Luckily, we can use sequences to defer the catch sections.
139     When the start of a catch block is encountered, we start the
140     sequence.  After the catch block is generated, we end the
141     sequence.
142
143     Next we must insure that when the catch block is executed, all
144     finalizations for the matching try block have been completed.  If
145     any of those finalizations throw an exception, we must call
146     terminate according to the ARM (section r.15.6.1).  What this
147     means is that we need to dequeue and emit finalizations for each
148     entry in the eh_queue until we get to an entry with a NULL
149     finalization field.  For any of the finalization entries, if it
150     is not a call to terminate (), we must protect it by giving it
151     another start label, end label, and exception handler label,
152     setting its finalization tree to be a call to terminate (), and
153     enqueue'ing this new eh_entry to be output at an outer level.
154     Finally, after all that is done, we can get around to outputting
155     the catch block which basically wraps all the "catch (...) {...}"
156     statements in a big if/then/else construct that matches the
157     correct block to call.
158
159     ===================================================================== */
160
161/* local globals for function calls
162   ====================================================================== */
163
164/* Used to cache "terminate" and "__throw_type_match*".  */
165static tree Terminate, CatchMatch;
166
167/* Used to cache __find_first_exception_table_match for throw.  */
168static tree FirstExceptionMatch;
169
170/* Used to cache a call to __unwind_function.  */
171static tree Unwind;
172
173/* ====================================================================== */
174
175
176/* ========================================================================= */
177
178
179
180/* local globals - these local globals are for storing data necessary for
181   generating the exception table and code in the correct order.
182
183   ========================================================================= */
184
185extern rtx catch_clauses;
186extern tree const_ptr_type_node;
187
188/* ========================================================================= */
189
190/* sets up all the global eh stuff that needs to be initialized at the
191   start of compilation.
192
193   This includes:
194		- Setting up all the function call trees.  */
195
196void
197init_exception_processing ()
198{
199  /* void vtype () */
200  tree vtype = build_function_type (void_type_node, void_list_node);
201
202  if (flag_honor_std)
203    push_namespace (get_identifier ("std"));
204  Terminate = auto_function (get_identifier ("terminate"),
205			     vtype, NOT_BUILT_IN);
206  TREE_THIS_VOLATILE (Terminate) = 1;
207  if (flag_honor_std)
208    pop_namespace ();
209
210  push_lang_context (lang_name_c);
211
212  set_exception_lang_code (EH_LANG_C_plus_plus);
213  set_exception_version_code (1);
214
215  CatchMatch
216    = builtin_function (flag_rtti
217			? "__throw_type_match_rtti"
218			: "__throw_type_match",
219			build_function_type (ptr_type_node,
220					     tree_cons (NULL_TREE, const_ptr_type_node,
221							tree_cons (NULL_TREE, const_ptr_type_node,
222								   tree_cons (NULL_TREE, ptr_type_node,
223									      void_list_node)))),
224			NOT_BUILT_IN, NULL_PTR);
225  FirstExceptionMatch
226    = builtin_function ("__find_first_exception_table_match",
227			build_function_type (ptr_type_node,
228					     tree_cons (NULL_TREE, ptr_type_node,
229							void_list_node)),
230			NOT_BUILT_IN, NULL_PTR);
231  Unwind
232    = builtin_function ("__unwind_function",
233			build_function_type (void_type_node,
234					     tree_cons (NULL_TREE, ptr_type_node,
235							void_list_node)),
236			NOT_BUILT_IN, NULL_PTR);
237
238  pop_lang_context ();
239
240  /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
241     be protected with __terminate.  */
242  protect_cleanup_actions_with_terminate = 1;
243}
244
245/* Retrieve a pointer to the cp_eh_info node for the current exception.  */
246
247static tree
248call_eh_info ()
249{
250  tree fn;
251
252  fn = get_identifier ("__start_cp_handler");
253  if (IDENTIFIER_GLOBAL_VALUE (fn))
254    fn = IDENTIFIER_GLOBAL_VALUE (fn);
255  else
256    {
257      tree t1, t, fields[7];
258
259      /* Declare cp_eh_info * __start_cp_handler (void),
260	 as defined in exception.cc. */
261      push_obstacks_nochange ();
262      end_temporary_allocation ();
263
264      /* struct cp_eh_info.  This must match exception.cc.  Note that this
265	 type is not pushed anywhere.  */
266      t1= make_lang_type (RECORD_TYPE);
267      fields[0] = build_lang_field_decl (FIELD_DECL,
268                    get_identifier ("handler_label"), ptr_type_node);
269      fields[1] = build_lang_field_decl (FIELD_DECL,
270                    get_identifier ("dynamic_handler_chain"), ptr_type_node);
271      fields[2] = build_lang_field_decl (FIELD_DECL,
272                    get_identifier ("info"), ptr_type_node);
273      fields[3] = build_lang_field_decl (FIELD_DECL,
274                    get_identifier ("table_index"), ptr_type_node);
275      /* N.B.: The fourth field LEN is expected to be
276	 the number of fields - 1, not the total number of fields.  */
277      finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
278      t1 = build_pointer_type (t1);
279
280      t1= make_lang_type (RECORD_TYPE);
281      fields[0] = build_lang_field_decl (FIELD_DECL,
282                    get_identifier ("match_function"), ptr_type_node);
283      fields[1] = build_lang_field_decl (FIELD_DECL,
284                    get_identifier ("language"), short_integer_type_node);
285      fields[2] = build_lang_field_decl (FIELD_DECL,
286                    get_identifier ("version"), short_integer_type_node);
287      /* N.B.: The fourth field LEN is expected to be
288	 the number of fields - 1, not the total number of fields.  */
289      finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
290      t = make_lang_type (RECORD_TYPE);
291      fields[0] = build_lang_field_decl (FIELD_DECL,
292                                              get_identifier ("eh_info"), t1);
293      fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
294					 ptr_type_node);
295      fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
296					 ptr_type_node);
297      fields[3] = build_lang_field_decl
298	(FIELD_DECL, get_identifier ("cleanup"),
299	 build_pointer_type (build_function_type
300			     (ptr_type_node, tree_cons
301			      (NULL_TREE, ptr_type_node, void_list_node))));
302      fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
303					 boolean_type_node);
304      fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
305					 build_pointer_type (t));
306      fields[6] = build_lang_field_decl
307	(FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
308      /* N.B.: The fourth field LEN is expected to be
309	 the number of fields - 1, not the total number of fields.  */
310      finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
311      t = build_pointer_type (t);
312
313      /* And now the function.  */
314      fn = build_lang_decl (FUNCTION_DECL, fn,
315			    build_function_type (t, void_list_node));
316      DECL_EXTERNAL (fn) = 1;
317      TREE_PUBLIC (fn) = 1;
318      DECL_ARTIFICIAL (fn) = 1;
319      pushdecl_top_level (fn);
320      make_function_rtl (fn);
321      pop_obstacks ();
322    }
323  mark_used (fn);
324  return build_function_call (fn, NULL_TREE);
325}
326
327/* Retrieve a pointer to the cp_eh_info node for the current exception
328   and save it in the current binding level.  */
329
330static void
331push_eh_info ()
332{
333  tree decl, fn = call_eh_info ();
334
335  /* Remember the pointer to the current exception info; it won't change
336     during this catch block.  */
337  decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
338		     TREE_TYPE (fn));
339  DECL_ARTIFICIAL (decl) = 1;
340  DECL_INITIAL (decl) = fn;
341  decl = pushdecl (decl);
342  cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
343}
344
345/* Returns a reference to the cp_eh_info node for the current exception.  */
346
347static tree
348get_eh_info ()
349{
350  /* Look for the pointer pushed in push_eh_info.  */
351  tree t = lookup_name (get_identifier ("__exception_info"), 0);
352  return build_indirect_ref (t, NULL_PTR);
353}
354
355/* Returns a reference to the current exception object.  */
356
357static tree
358get_eh_value ()
359{
360  return build_component_ref (get_eh_info (), get_identifier ("value"),
361			      NULL_TREE, 0);
362}
363
364/* Returns a reference to the current exception type.  */
365
366#if 0
367static tree
368get_eh_type ()
369{
370  return build_component_ref (get_eh_info (), get_identifier ("type"),
371			      NULL_TREE, 0);
372}
373
374/* Returns a reference to whether or not the current exception
375   has been caught.  */
376
377static tree
378get_eh_caught ()
379{
380  return build_component_ref (get_eh_info (), get_identifier ("caught"),
381			      NULL_TREE, 0);
382}
383
384/* Returns a reference to whether or not the current exception
385   has been caught.  */
386
387static tree
388get_eh_handlers ()
389{
390  return build_component_ref (get_eh_info (), get_identifier ("handlers"),
391			      NULL_TREE, 0);
392}
393#endif
394
395/* Build a type value for use at runtime for a type that is matched
396   against by the exception handling system.  */
397
398static tree
399build_eh_type_type (type)
400     tree type;
401{
402  const char *typestring;
403  tree exp;
404
405  if (type == error_mark_node)
406    return error_mark_node;
407
408  /* peel back references, so they match.  */
409  if (TREE_CODE (type) == REFERENCE_TYPE)
410    type = TREE_TYPE (type);
411
412  /* Peel off cv qualifiers.  */
413  type = TYPE_MAIN_VARIANT (type);
414
415  if (flag_rtti)
416    return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
417
418  typestring = build_overload_name (type, 1, 1);
419  exp = combine_strings (build_string (strlen (typestring)+1, typestring));
420  return build1 (ADDR_EXPR, ptr_type_node, exp);
421}
422
423/* Build the address of a runtime type for use in the runtime matching
424   field of the new exception model */
425
426static tree
427build_eh_type_type_ref (type)
428     tree type;
429{
430  const char *typestring;
431  tree exp;
432
433  if (type == error_mark_node)
434    return error_mark_node;
435
436  /* peel back references, so they match.  */
437  if (TREE_CODE (type) == REFERENCE_TYPE)
438    type = TREE_TYPE (type);
439
440  /* Peel off cv qualifiers.  */
441  type = TYPE_MAIN_VARIANT (type);
442
443  push_obstacks_nochange ();
444  end_temporary_allocation ();
445
446  if (flag_rtti)
447    {
448      exp = get_tinfo_fn (type);
449      TREE_USED (exp) = 1;
450      mark_inline_for_output (exp);
451      exp = build1 (ADDR_EXPR, ptr_type_node, exp);
452    }
453  else
454    {
455      typestring = build_overload_name (type, 1, 1);
456      exp = combine_strings (build_string (strlen (typestring)+1, typestring));
457      exp = build1 (ADDR_EXPR, ptr_type_node, exp);
458    }
459  pop_obstacks ();
460  return (exp);
461}
462
463
464/* Build a type value for use at runtime for a exp that is thrown or
465   matched against by the exception handling system.  */
466
467static tree
468build_eh_type (exp)
469     tree exp;
470{
471  if (flag_rtti)
472    {
473      exp = build_typeid (exp);
474      return build1 (ADDR_EXPR, ptr_type_node, exp);
475    }
476  return build_eh_type_type (TREE_TYPE (exp));
477}
478
479/* This routine is called to mark all the symbols representing runtime
480   type functions in the exception table as haveing been referenced.
481   This will make sure code is emitted for them. Called from finish_file. */
482void
483mark_all_runtime_matches ()
484{
485  int x,num;
486  void **ptr;
487  tree exp;
488
489  num = find_all_handler_type_matches (&ptr);
490  if (num == 0 || ptr == NULL)
491    return;
492
493  for (x=0; x <num; x++)
494    {
495      exp = (tree) ptr[x];
496      if (TREE_CODE (exp) == ADDR_EXPR)
497        {
498          exp = TREE_OPERAND (exp, 0);
499          if (TREE_CODE (exp) == FUNCTION_DECL)
500            TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
501        }
502    }
503
504  free (ptr);
505}
506
507/* Build up a call to __cp_pop_exception, to destroy the exception object
508   for the current catch block.  HANDLER is either true or false, telling
509   the library whether or not it is being called from an exception handler;
510   if it is, it avoids destroying the object on rethrow.  */
511
512static tree
513do_pop_exception ()
514{
515  tree fn, cleanup;
516  fn = get_identifier ("__cp_pop_exception");
517  if (IDENTIFIER_GLOBAL_VALUE (fn))
518    fn = IDENTIFIER_GLOBAL_VALUE (fn);
519  else
520    {
521      /* Declare void __cp_pop_exception (void *),
522	 as defined in exception.cc. */
523      push_obstacks_nochange ();
524      end_temporary_allocation ();
525      fn = build_lang_decl
526	(FUNCTION_DECL, fn,
527	 build_function_type (void_type_node, tree_cons
528			      (NULL_TREE, ptr_type_node, void_list_node)));
529      DECL_EXTERNAL (fn) = 1;
530      TREE_PUBLIC (fn) = 1;
531      DECL_ARTIFICIAL (fn) = 1;
532      pushdecl_top_level (fn);
533      make_function_rtl (fn);
534      pop_obstacks ();
535    }
536
537  mark_used (fn);
538  /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
539  cleanup = lookup_name (get_identifier ("__exception_info"), 0);
540  cleanup = build_function_call (fn, expr_tree_cons
541				 (NULL_TREE, cleanup, NULL_TREE));
542  return cleanup;
543}
544
545/* This routine creates the cleanup for the current exception.  */
546
547static void
548push_eh_cleanup ()
549{
550  int yes;
551
552  yes = suspend_momentary ();
553  /* All cleanups must last longer than normal.  */
554  expand_decl_cleanup (NULL_TREE, do_pop_exception ());
555  resume_momentary (yes);
556}
557
558/* Build up a call to terminate on the function obstack, for use as an
559   exception handler.  */
560
561static tree
562build_terminate_handler ()
563{
564  int yes = suspend_momentary ();
565  tree term = build_function_call (Terminate, NULL_TREE);
566  resume_momentary (yes);
567  return term;
568}
569
570/* Call this to start a catch block. Typename is the typename, and identifier
571   is the variable to place the object in or NULL if the variable doesn't
572   matter.  If typename is NULL, that means its a "catch (...)" or catch
573   everything.  In that case we don't need to do any type checking.
574   (ie: it ends up as the "else" clause rather than an "else if" clause) */
575
576void
577expand_start_catch_block (declspecs, declarator)
578     tree declspecs, declarator;
579{
580  tree decl;
581
582  if (processing_template_decl)
583    {
584      if (declspecs)
585	{
586	  decl = grokdeclarator (declarator, declspecs, CATCHPARM,
587				 1, NULL_TREE);
588	  pushdecl (decl);
589	  decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
590			       copy_to_permanent (declspecs),
591			       NULL_TREE);
592	  add_tree (decl);
593	}
594      return;
595    }
596
597  if (! doing_eh (1))
598    return;
599
600  process_start_catch_block (declspecs, declarator);
601}
602
603
604/* This function performs the expand_start_catch_block functionality for
605   exceptions implemented in the new style. __throw determines whether
606   a handler needs to be called or not, so the handler itself has to do
607   nothing additional. */
608
609static void
610process_start_catch_block (declspecs, declarator)
611     tree declspecs, declarator;
612{
613  tree decl = NULL_TREE;
614  tree init;
615
616  /* Create a binding level for the eh_info and the exception object
617     cleanup.  */
618  pushlevel (0);
619  expand_start_bindings (0);
620
621
622  if (declspecs)
623    {
624      decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
625
626      if (decl == NULL_TREE)
627	error ("invalid catch parameter");
628    }
629
630  if (decl)
631    start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
632  else
633    start_catch_handler (CATCH_ALL_TYPE);
634
635  emit_line_note (input_filename, lineno);
636
637  push_eh_info ();
638
639  if (decl)
640    {
641      tree exp;
642      tree init_type;
643
644      /* Make sure we mark the catch param as used, otherwise we'll get
645	 a warning about an unused ((anonymous)).  */
646      TREE_USED (decl) = 1;
647
648      /* Figure out the type that the initializer is.  */
649      init_type = TREE_TYPE (decl);
650      if (TREE_CODE (init_type) != REFERENCE_TYPE
651	  && TREE_CODE (init_type) != POINTER_TYPE)
652	init_type = build_reference_type (init_type);
653
654      exp = get_eh_value ();
655
656      /* Since pointers are passed by value, initialize a reference to
657	 pointer catch parm with the address of the value slot.  */
658      if (TREE_CODE (init_type) == REFERENCE_TYPE
659	  && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
660	exp = build_unary_op (ADDR_EXPR, exp, 1);
661
662      exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
663
664      push_eh_cleanup ();
665
666      /* Create a binding level for the parm.  */
667      pushlevel (0);
668      expand_start_bindings (0);
669
670      init = convert_from_reference (exp);
671
672      /* If the constructor for the catch parm exits via an exception, we
673         must call terminate.  See eh23.C.  */
674      if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
675	{
676	  /* Generate the copy constructor call directly so we can wrap it.
677	     See also expand_default_init.  */
678	  init = ocp_convert (TREE_TYPE (decl), init,
679			      CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
680	  init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
681			build_terminate_handler ());
682	}
683
684      /* Let `cp_finish_decl' know that this initializer is ok.  */
685      DECL_INITIAL (decl) = init;
686      decl = pushdecl (decl);
687
688      start_decl_1 (decl);
689      cp_finish_decl (decl, init, NULL_TREE, 0,
690		      LOOKUP_ONLYCONVERTING|DIRECT_BIND);
691    }
692  else
693    {
694      push_eh_cleanup ();
695
696      /* Create a binding level for the parm.  */
697      pushlevel (0);
698      expand_start_bindings (0);
699
700      /* Fall into the catch all section.  */
701    }
702
703  emit_line_note (input_filename, lineno);
704}
705
706
707/* Call this to end a catch block.  Its responsible for emitting the
708   code to handle jumping back to the correct place, and for emitting
709   the label to jump to if this catch block didn't match.  */
710
711void
712expand_end_catch_block ()
713{
714  if (! doing_eh (1))
715    return;
716
717  /* Cleanup the EH parameter.  */
718  expand_end_bindings (getdecls (), kept_level_p (), 0);
719  poplevel (kept_level_p (), 1, 0);
720
721  /* Cleanup the EH object.  */
722  expand_end_bindings (getdecls (), kept_level_p (), 0);
723  poplevel (kept_level_p (), 1, 0);
724
725  /* Fall to outside the try statement when done executing handler and
726     we fall off end of handler.  This is jump Lresume in the
727     documentation.  */
728  expand_goto (top_label_entry (&caught_return_label_stack));
729
730  end_catch_handler ();
731}
732
733/* An exception spec is implemented more or less like:
734
735   try {
736     function body;
737   } catch (...) {
738     void *p[] = { typeid(raises) };
739     __check_eh_spec (p, count);
740   }
741
742   __check_eh_spec in exception.cc handles all the details.  */
743
744void
745expand_start_eh_spec ()
746{
747  expand_start_try_stmts ();
748}
749
750static void
751expand_end_eh_spec (raises)
752     tree raises;
753{
754  tree tmp, fn, decl, types = NULL_TREE;
755  int count = 0;
756
757  expand_start_all_catch ();
758  expand_start_catch_block (NULL_TREE, NULL_TREE);
759
760  /* Build up an array of type_infos.  */
761  for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
762    {
763      types = expr_tree_cons
764	(NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
765      ++count;
766    }
767
768  types = build_nt (CONSTRUCTOR, NULL_TREE, types);
769  TREE_HAS_CONSTRUCTOR (types) = 1;
770
771  /* We can't pass the CONSTRUCTOR directly, so stick it in a variable.  */
772  tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
773  decl = build_decl (VAR_DECL, NULL_TREE, tmp);
774  DECL_ARTIFICIAL (decl) = 1;
775  DECL_INITIAL (decl) = types;
776  cp_finish_decl (decl, types, NULL_TREE, 0, 0);
777
778  decl = decay_conversion (decl);
779
780  fn = get_identifier ("__check_eh_spec");
781  if (IDENTIFIER_GLOBAL_VALUE (fn))
782    fn = IDENTIFIER_GLOBAL_VALUE (fn);
783  else
784    {
785      push_obstacks_nochange ();
786      end_temporary_allocation ();
787
788      tmp = tree_cons
789	(NULL_TREE, integer_type_node, tree_cons
790	 (NULL_TREE, TREE_TYPE (decl), void_list_node));
791      tmp = build_function_type	(void_type_node, tmp);
792
793      fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
794      DECL_EXTERNAL (fn) = 1;
795      TREE_PUBLIC (fn) = 1;
796      DECL_ARTIFICIAL (fn) = 1;
797      TREE_THIS_VOLATILE (fn) = 1;
798      pushdecl_top_level (fn);
799      make_function_rtl (fn);
800      pop_obstacks ();
801    }
802
803  mark_used (fn);
804  tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
805			(NULL_TREE, decl, NULL_TREE));
806  tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
807  expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
808
809  expand_end_catch_block ();
810  expand_end_all_catch ();
811}
812
813/* This is called to expand all the toplevel exception handling
814   finalization for a function.  It should only be called once per
815   function.  */
816
817void
818expand_exception_blocks ()
819{
820  do_pending_stack_adjust ();
821  push_to_sequence (catch_clauses);
822  expand_leftover_cleanups ();
823  do_pending_stack_adjust ();
824  catch_clauses = get_insns ();
825  end_sequence ();
826
827  /* Do this after we expand leftover cleanups, so that the
828     expand_eh_region_end that expand_end_eh_spec does will match the
829     right expand_eh_region_start, and make sure it comes out before
830     the terminate protected region.  */
831  if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
832    {
833     expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
834     do_pending_stack_adjust ();
835     push_to_sequence (catch_clauses);
836     expand_leftover_cleanups ();
837     do_pending_stack_adjust ();
838     catch_clauses = get_insns ();
839     end_sequence ();
840    }
841
842  if (catch_clauses)
843    {
844      rtx funcend = gen_label_rtx ();
845      emit_jump (funcend);
846
847      /* We cannot protect n regions this way if we must flow into the
848	 EH region through the top of the region, as we have to with
849	 the setjmp/longjmp approach.  */
850      if (exceptions_via_longjmp == 0)
851	expand_eh_region_start ();
852
853      emit_insns (catch_clauses);
854      catch_clauses = NULL_RTX;
855
856      if (exceptions_via_longjmp == 0)
857	expand_eh_region_end (build_terminate_handler ());
858
859      expand_leftover_cleanups ();
860
861      emit_label (funcend);
862    }
863}
864
865tree
866start_anon_func ()
867{
868  static int counter = 0;
869  int old_interface_unknown = interface_unknown;
870  char name[32];
871  tree params;
872  tree t;
873
874  push_cp_function_context (NULL_TREE);
875  push_to_top_level ();
876
877  /* No need to mangle this.  */
878  push_lang_context (lang_name_c);
879
880  interface_unknown = 1;
881
882  params = void_list_node;
883  /* tcf stands for throw clean function.  */
884  sprintf (name, "__tcf_%d", counter++);
885  t = make_call_declarator (get_identifier (name), params, NULL_TREE,
886			    NULL_TREE);
887  start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
888				  void_list_node),
889		  t, NULL_TREE, 0);
890  store_parm_decls ();
891  pushlevel (0);
892  clear_last_expr ();
893  push_momentary ();
894  expand_start_bindings (0);
895  emit_line_note (input_filename, lineno);
896
897  interface_unknown = old_interface_unknown;
898
899  pop_lang_context ();
900
901  return current_function_decl;
902}
903
904void
905end_anon_func ()
906{
907  expand_end_bindings (getdecls (), 1, 0);
908  poplevel (1, 0, 0);
909  pop_momentary ();
910
911  finish_function (lineno, 0, 0);
912
913  pop_from_top_level ();
914  pop_cp_function_context (NULL_TREE);
915}
916
917/* Return a pointer to a buffer for an exception object of type TYPE.  */
918
919static tree
920alloc_eh_object (type)
921     tree type;
922{
923  tree fn, exp;
924
925  fn = get_identifier ("__eh_alloc");
926  if (IDENTIFIER_GLOBAL_VALUE (fn))
927    fn = IDENTIFIER_GLOBAL_VALUE (fn);
928  else
929    {
930      /* Declare __eh_alloc (size_t), as defined in exception.cc.  */
931      tree tmp;
932      push_obstacks_nochange ();
933      end_temporary_allocation ();
934      tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
935      fn = build_lang_decl (FUNCTION_DECL, fn,
936			    build_function_type (ptr_type_node, tmp));
937      DECL_EXTERNAL (fn) = 1;
938      TREE_PUBLIC (fn) = 1;
939      DECL_ARTIFICIAL (fn) = 1;
940      pushdecl_top_level (fn);
941      make_function_rtl (fn);
942      pop_obstacks ();
943    }
944
945  mark_used (fn);
946  exp = build_function_call (fn, expr_tree_cons
947			     (NULL_TREE, size_in_bytes (type), NULL_TREE));
948  exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
949  return exp;
950}
951
952/* Expand a throw statement.  This follows the following
953   algorithm:
954
955	1. Allocate space to save the current PC onto the stack.
956	2. Generate and emit a label and save its address into the
957		newly allocated stack space since we can't save the pc directly.
958	3. If this is the first call to throw in this function:
959		generate a label for the throw block
960	4. jump to the throw block label.  */
961
962void
963expand_throw (exp)
964     tree exp;
965{
966  tree fn;
967  static tree cleanup_type;
968
969  if (! doing_eh (1))
970    return;
971
972  if (exp)
973    {
974      tree throw_type;
975      tree cleanup = NULL_TREE, e;
976
977      /* throw expression */
978      /* First, decay it.  */
979      exp = decay_conversion (exp);
980
981      /* cleanup_type is void (*)(void *, int),
982	 the internal type of a destructor. */
983      if (cleanup_type == NULL_TREE)
984	{
985	  push_obstacks_nochange ();
986	  end_temporary_allocation ();
987	  cleanup_type = build_pointer_type
988	    (build_function_type
989	     (void_type_node, tree_cons
990	      (NULL_TREE, ptr_type_node, tree_cons
991	       (NULL_TREE, integer_type_node, void_list_node))));
992	  pop_obstacks ();
993	}
994
995      if (TYPE_PTR_P (TREE_TYPE (exp)))
996	throw_type = build_eh_type (exp);
997      else
998	{
999	  tree object, ptr;
1000
1001	  /* OK, this is kind of wacky.  The WP says that we call
1002	     terminate
1003
1004	     when the exception handling mechanism, after completing
1005	     evaluation of the expression to be thrown but before the
1006	     exception is caught (_except.throw_), calls a user function
1007	     that exits via an uncaught exception.
1008
1009	     So we have to protect the actual initialization of the
1010	     exception object with terminate(), but evaluate the expression
1011	     first.  We also expand the call to __eh_alloc
1012	     first.  Since there could be temps in the expression, we need
1013	     to handle that, too.  */
1014
1015	  expand_start_target_temps ();
1016
1017#if 0
1018	  /* Unfortunately, this doesn't work.  */
1019	  preexpand_calls (exp);
1020#else
1021	  /* Store the throw expression into a temp.  This can be less
1022	     efficient than storing it into the allocated space directly, but
1023	     oh well.  To do this efficiently we would need to insinuate
1024	     ourselves into expand_call.  */
1025	  if (TREE_SIDE_EFFECTS (exp))
1026	    {
1027	      tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
1028	      DECL_ARTIFICIAL (temp) = 1;
1029	      DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
1030	      DECL_INITIAL (temp) = exp;
1031	      cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1032	      exp = temp;
1033	    }
1034#endif
1035
1036	  /* Allocate the space for the exception.  */
1037	  ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
1038	  expand_expr (ptr, const0_rtx, VOIDmode, 0);
1039
1040	  expand_eh_region_start ();
1041
1042	  object = build_indirect_ref (ptr, NULL_PTR);
1043	  exp = build_modify_expr (object, INIT_EXPR, exp);
1044
1045	  if (exp == error_mark_node)
1046	    error ("  in thrown expression");
1047
1048	  expand_expr (exp, const0_rtx, VOIDmode, 0);
1049	  expand_eh_region_end (build_terminate_handler ());
1050	  expand_end_target_temps ();
1051
1052	  throw_type = build_eh_type (object);
1053
1054	  if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1055	    {
1056	      cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1057					 dtor_identifier, 0);
1058	      cleanup = TREE_VALUE (cleanup);
1059	      mark_used (cleanup);
1060	      mark_addressable (cleanup);
1061	      /* Pretend it's a normal function.  */
1062	      cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1063	    }
1064
1065	  exp = ptr;
1066	}
1067
1068      /* Cast EXP to `void *' so that it will match the prototype for
1069	 __cp_push_exception.  */
1070      exp = convert (ptr_type_node, exp);
1071
1072      if (cleanup == NULL_TREE)
1073	{
1074	  cleanup = build_int_2 (0, 0);
1075	  TREE_TYPE (cleanup) = cleanup_type;
1076	}
1077
1078      fn = get_identifier ("__cp_push_exception");
1079      if (IDENTIFIER_GLOBAL_VALUE (fn))
1080	fn = IDENTIFIER_GLOBAL_VALUE (fn);
1081      else
1082	{
1083	  /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1084	     as defined in exception.cc.  */
1085	  tree tmp;
1086	  push_obstacks_nochange ();
1087	  end_temporary_allocation ();
1088	  tmp = tree_cons
1089	    (NULL_TREE, ptr_type_node, tree_cons
1090	     (NULL_TREE, ptr_type_node, tree_cons
1091	      (NULL_TREE, cleanup_type, void_list_node)));
1092	  fn = build_lang_decl (FUNCTION_DECL, fn,
1093				build_function_type (void_type_node, tmp));
1094	  DECL_EXTERNAL (fn) = 1;
1095	  TREE_PUBLIC (fn) = 1;
1096	  DECL_ARTIFICIAL (fn) = 1;
1097	  pushdecl_top_level (fn);
1098	  make_function_rtl (fn);
1099	  pop_obstacks ();
1100	}
1101
1102      mark_used (fn);
1103      e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1104			  (NULL_TREE, throw_type, expr_tree_cons
1105			   (NULL_TREE, cleanup, NULL_TREE)));
1106      e = build_function_call (fn, e);
1107      expand_expr (e, const0_rtx, VOIDmode, 0);
1108    }
1109  else
1110    {
1111      /* rethrow current exception; note that it's no longer caught.  */
1112
1113      tree fn = get_identifier ("__uncatch_exception");
1114      if (IDENTIFIER_GLOBAL_VALUE (fn))
1115	fn = IDENTIFIER_GLOBAL_VALUE (fn);
1116      else
1117	{
1118	  /* Declare void __uncatch_exception (void)
1119	     as defined in exception.cc. */
1120	  push_obstacks_nochange ();
1121	  end_temporary_allocation ();
1122	  fn = build_lang_decl (FUNCTION_DECL, fn,
1123				build_function_type (void_type_node,
1124						     void_list_node));
1125	  DECL_EXTERNAL (fn) = 1;
1126	  TREE_PUBLIC (fn) = 1;
1127	  DECL_ARTIFICIAL (fn) = 1;
1128	  pushdecl_top_level (fn);
1129	  make_function_rtl (fn);
1130	  pop_obstacks ();
1131	}
1132
1133      mark_used (fn);
1134      exp = build_function_call (fn, NULL_TREE);
1135      expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1136    }
1137
1138  expand_internal_throw ();
1139}
1140
1141/* Build a throw expression.  */
1142
1143tree
1144build_throw (e)
1145     tree e;
1146{
1147  if (e == error_mark_node)
1148    return e;
1149
1150  if (processing_template_decl)
1151    return build_min (THROW_EXPR, void_type_node, e);
1152
1153  if (e == null_node)
1154    cp_warning ("throwing NULL, which has integral, not pointer type");
1155
1156  e = build1 (THROW_EXPR, void_type_node, e);
1157  TREE_SIDE_EFFECTS (e) = 1;
1158  TREE_USED (e) = 1;
1159
1160  return e;
1161}
1162