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