]> gcc.gnu.org Git - gcc.git/blame - gcc/cp/except.c
Daily bump.
[gcc.git] / gcc / cp / except.c
CommitLineData
8d08fdba 1/* Handle exceptional things in C++.
d6a8bdff 2 Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
158991b7 3 Free Software Foundation, Inc.
8d2733ca
MS
4 Contributed by Michael Tiemann <tiemann@cygnus.com>
5 Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
6 initial re-implementation courtesy Tad Hunt.
8d08fdba
MS
7
8This file is part of GNU CC.
9
10GNU CC is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2, or (at your option)
13any later version.
14
15GNU CC is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with GNU CC; see the file COPYING. If not, write to
e9fa0c7c
RK
22the Free Software Foundation, 59 Temple Place - Suite 330,
23Boston, MA 02111-1307, USA. */
8d08fdba
MS
24
25
8d08fdba 26#include "config.h"
8d052bc7 27#include "system.h"
8d08fdba
MS
28#include "tree.h"
29#include "rtl.h"
30#include "cp-tree.h"
31#include "flags.h"
8d2733ca
MS
32#include "obstack.h"
33#include "expr.h"
21451173 34#include "output.h"
6467930b 35#include "except.h"
0021b564 36#include "defaults.h"
54f92bfb 37#include "toplev.h"
9a0d1e1b 38#include "eh-common.h"
8d08fdba 39
93ca4ba7 40static void push_eh_cleanup PARAMS ((tree));
158991b7
KG
41static tree build_eh_type_type PARAMS ((tree));
42static tree call_eh_info PARAMS ((void));
43static void push_eh_info PARAMS ((void));
44static tree get_eh_info PARAMS ((void));
45static tree get_eh_value PARAMS ((void));
87603ed0 46#if 0
158991b7
KG
47static tree get_eh_type PARAMS ((void));
48static tree get_eh_caught PARAMS ((void));
49static tree get_eh_handlers PARAMS ((void));
e833cb11 50#endif
93ca4ba7
JM
51static int dtor_nothrow PARAMS ((tree));
52static tree do_pop_exception PARAMS ((tree));
158991b7
KG
53static tree build_eh_type_type_ref PARAMS ((tree));
54static tree build_terminate_handler PARAMS ((void));
55static tree alloc_eh_object PARAMS ((tree));
56static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
fbd40359
ZW
57static int can_convert_eh PARAMS ((tree, tree));
58static void check_handlers_1 PARAMS ((tree, tree));
158991b7
KG
59static void initialize_handler_parm PARAMS ((tree));
60static tree expand_throw PARAMS ((tree));
e97f22c9 61static int decl_is_java_type PARAMS ((tree decl, int err));
8d2733ca 62
8d2733ca 63#if 0
e92cc029 64/* This is the startup, and finish stuff per exception table. */
8d08fdba 65
8d2733ca
MS
66/* XXX - Tad: exception handling section */
67#ifndef EXCEPT_SECTION_ASM_OP
68#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
69#endif
8d08fdba 70
8d2733ca 71#ifdef EXCEPT_SECTION_ASM_OP
8d08fdba 72
8d2733ca
MS
73 /* on machines which support it, the exception table lives in another section,
74 but it needs a label so we can reference it... This sets up that
75 label! */
76asm (EXCEPT_SECTION_ASM_OP);
77exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
78asm (TEXT_SECTION_ASM_OP);
8d08fdba 79
8d2733ca 80#endif /* EXCEPT_SECTION_ASM_OP */
8d08fdba 81
8d2733ca
MS
82#ifdef EXCEPT_SECTION_ASM_OP
83
84 /* we need to know where the end of the exception table is... so this
85 is how we do it! */
86
87asm (EXCEPT_SECTION_ASM_OP);
88exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
89asm (TEXT_SECTION_ASM_OP);
90
91#endif /* EXCEPT_SECTION_ASM_OP */
92
93#endif
8d08fdba 94
8d2733ca 95#include "decl.h"
8d2733ca
MS
96#include "insn-flags.h"
97#include "obstack.h"
8d2733ca 98
e97f22c9
TT
99/* In a given translation unit we are constrained to catch only C++
100 types or only Java types. `catch_language' holds the current type,
101 and `catch_language_init' registers whether `catch_language' has
102 been set. */
103
104static int catch_language_init = 0;
105static int catch_language;
106
8d2733ca
MS
107/* ======================================================================
108 Briefly the algorithm works like this:
109
110 When a constructor or start of a try block is encountered,
111 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
112 new entry in the unwind protection stack and returns a label to
113 output to start the protection for that block.
114
115 When a destructor or end try block is encountered, pop_eh_entry
6467930b
MS
116 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
117 created when push_eh_entry () was called. The eh_entry structure
8d2733ca
MS
118 contains three things at this point. The start protect label,
119 the end protect label, and the exception handler label. The end
120 protect label should be output before the call to the destructor
121 (if any). If it was a destructor, then its parse tree is stored
6467930b 122 in the finalization variable in the eh_entry structure. Otherwise
8d2733ca 123 the finalization variable is set to NULL to reflect the fact that
38e01259 124 it is the end of a try block. Next, this modified eh_entry node
8d2733ca
MS
125 is enqueued in the finalizations queue by calling
126 enqueue_eh_entry (&queue,entry).
127
128 +---------------------------------------------------------------+
129 |XXX: Will need modification to deal with partially |
130 | constructed arrays of objects |
131 | |
132 | Basically, this consists of keeping track of how many |
133 | of the objects have been constructed already (this |
134 | should be in a register though, so that shouldn't be a |
135 | problem. |
136 +---------------------------------------------------------------+
137
138 When a catch block is encountered, there is a lot of work to be
139 done.
140
141 Since we don't want to generate the catch block inline with the
142 regular flow of the function, we need to have some way of doing
f30432d7
MS
143 so. Luckily, we can use sequences to defer the catch sections.
144 When the start of a catch block is encountered, we start the
145 sequence. After the catch block is generated, we end the
146 sequence.
147
8d2733ca
MS
148 Next we must insure that when the catch block is executed, all
149 finalizations for the matching try block have been completed. If
150 any of those finalizations throw an exception, we must call
151 terminate according to the ARM (section r.15.6.1). What this
152 means is that we need to dequeue and emit finalizations for each
6467930b 153 entry in the eh_queue until we get to an entry with a NULL
8d2733ca
MS
154 finalization field. For any of the finalization entries, if it
155 is not a call to terminate (), we must protect it by giving it
156 another start label, end label, and exception handler label,
157 setting its finalization tree to be a call to terminate (), and
6467930b 158 enqueue'ing this new eh_entry to be output at an outer level.
8d2733ca
MS
159 Finally, after all that is done, we can get around to outputting
160 the catch block which basically wraps all the "catch (...) {...}"
161 statements in a big if/then/else construct that matches the
162 correct block to call.
163
164 ===================================================================== */
165
8d2733ca
MS
166/* ====================================================================== */
167
8d2733ca 168/* sets up all the global eh stuff that needs to be initialized at the
bbd0d54a 169 start of compilation. */
8d08fdba 170
8d08fdba 171void
8d2733ca 172init_exception_processing ()
8d08fdba 173{
6633d636
MS
174 /* void vtype () */
175 tree vtype = build_function_type (void_type_node, void_list_node);
176
2c73f9f5
ML
177 if (flag_honor_std)
178 push_namespace (get_identifier ("std"));
0c11ada6 179 terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
9cd64686 180 TREE_THIS_VOLATILE (terminate_node) = 1;
0c11ada6 181 TREE_NOTHROW (terminate_node) = 1;
2c73f9f5
ML
182 if (flag_honor_std)
183 pop_namespace ();
8ccc31eb 184
9a0d1e1b
AM
185 set_exception_lang_code (EH_LANG_C_plus_plus);
186 set_exception_version_code (1);
9a0d1e1b 187
eb66be0e
MS
188 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
189 be protected with __terminate. */
190 protect_cleanup_actions_with_terminate = 1;
8d2733ca
MS
191}
192
95e8dcba 193/* Retrieve a pointer to the cp_eh_info node for the current exception. */
6874c264 194
95e8dcba
JM
195static tree
196call_eh_info ()
6874c264 197{
95e8dcba 198 tree fn;
6874c264 199
e6cfb550 200 fn = get_identifier ("__start_cp_handler");
6874c264
JM
201 if (IDENTIFIER_GLOBAL_VALUE (fn))
202 fn = IDENTIFIER_GLOBAL_VALUE (fn);
203 else
204 {
a1622f83 205 tree t1, t, fields[7];
6874c264 206
e6cfb550 207 /* Declare cp_eh_info * __start_cp_handler (void),
6874c264 208 as defined in exception.cc. */
6874c264
JM
209
210 /* struct cp_eh_info. This must match exception.cc. Note that this
211 type is not pushed anywhere. */
33848bb0 212 t1= make_aggr_type (RECORD_TYPE);
721c3b42 213 fields[0] = build_decl (FIELD_DECL,
9a0d1e1b 214 get_identifier ("handler_label"), ptr_type_node);
721c3b42 215 fields[1] = build_decl (FIELD_DECL,
9a0d1e1b 216 get_identifier ("dynamic_handler_chain"), ptr_type_node);
721c3b42 217 fields[2] = build_decl (FIELD_DECL,
9a0d1e1b 218 get_identifier ("info"), ptr_type_node);
721c3b42 219 fields[3] = build_decl (FIELD_DECL,
e6cfb550 220 get_identifier ("table_index"), ptr_type_node);
9a0d1e1b
AM
221 /* N.B.: The fourth field LEN is expected to be
222 the number of fields - 1, not the total number of fields. */
e6cfb550 223 finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
9a0d1e1b
AM
224 t1 = build_pointer_type (t1);
225
33848bb0 226 t1= make_aggr_type (RECORD_TYPE);
721c3b42 227 fields[0] = build_decl (FIELD_DECL,
9a0d1e1b 228 get_identifier ("match_function"), ptr_type_node);
721c3b42 229 fields[1] = build_decl (FIELD_DECL,
9a0d1e1b 230 get_identifier ("language"), short_integer_type_node);
721c3b42 231 fields[2] = build_decl (FIELD_DECL,
9a0d1e1b
AM
232 get_identifier ("version"), short_integer_type_node);
233 /* N.B.: The fourth field LEN is expected to be
234 the number of fields - 1, not the total number of fields. */
5816cb14 235 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
33848bb0 236 t = make_aggr_type (RECORD_TYPE);
721c3b42
MM
237 fields[0] = build_decl (FIELD_DECL,
238 get_identifier ("eh_info"), t1);
239 fields[1] = build_decl (FIELD_DECL, get_identifier ("value"),
240 ptr_type_node);
241 fields[2] = build_decl (FIELD_DECL, get_identifier ("type"),
242 ptr_type_node);
243 fields[3] = build_decl
6874c264
JM
244 (FIELD_DECL, get_identifier ("cleanup"),
245 build_pointer_type (build_function_type
246 (ptr_type_node, tree_cons
247 (NULL_TREE, ptr_type_node, void_list_node))));
721c3b42
MM
248 fields[4] = build_decl (FIELD_DECL, get_identifier ("caught"),
249 boolean_type_node);
250 fields[5] = build_decl (FIELD_DECL, get_identifier ("next"),
251 build_pointer_type (t));
252 fields[6] = build_decl
20b90169 253 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
cf9d67e3
BK
254 /* N.B.: The fourth field LEN is expected to be
255 the number of fields - 1, not the total number of fields. */
a1622f83 256 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
6874c264
JM
257 t = build_pointer_type (t);
258
259 /* And now the function. */
0c11ada6 260 fn = push_library_fn (fn, build_function_type (t, void_list_node));
6874c264 261 }
95e8dcba
JM
262 return build_function_call (fn, NULL_TREE);
263}
264
265/* Retrieve a pointer to the cp_eh_info node for the current exception
266 and save it in the current binding level. */
267
268static void
269push_eh_info ()
270{
271 tree decl, fn = call_eh_info ();
6874c264
JM
272
273 /* Remember the pointer to the current exception info; it won't change
274 during this catch block. */
275 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
276 TREE_TYPE (fn));
277 DECL_ARTIFICIAL (decl) = 1;
278 DECL_INITIAL (decl) = fn;
279 decl = pushdecl (decl);
cd9f6678 280 cp_finish_decl (decl, fn, NULL_TREE, 0);
6874c264
JM
281}
282
283/* Returns a reference to the cp_eh_info node for the current exception. */
284
285static tree
286get_eh_info ()
287{
288 /* Look for the pointer pushed in push_eh_info. */
289 tree t = lookup_name (get_identifier ("__exception_info"), 0);
290 return build_indirect_ref (t, NULL_PTR);
291}
292
293/* Returns a reference to the current exception object. */
294
295static tree
296get_eh_value ()
297{
298 return build_component_ref (get_eh_info (), get_identifier ("value"),
299 NULL_TREE, 0);
300}
301
302/* Returns a reference to the current exception type. */
303
87603ed0 304#if 0
6874c264
JM
305static tree
306get_eh_type ()
307{
308 return build_component_ref (get_eh_info (), get_identifier ("type"),
309 NULL_TREE, 0);
310}
311
312/* Returns a reference to whether or not the current exception
313 has been caught. */
314
315static tree
316get_eh_caught ()
317{
318 return build_component_ref (get_eh_info (), get_identifier ("caught"),
319 NULL_TREE, 0);
320}
321
20b90169
JM
322/* Returns a reference to whether or not the current exception
323 has been caught. */
324
325static tree
326get_eh_handlers ()
327{
328 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
329 NULL_TREE, 0);
330}
e833cb11 331#endif
20b90169 332
f30432d7
MS
333/* Build a type value for use at runtime for a type that is matched
334 against by the exception handling system. */
6467930b 335
f30432d7
MS
336static tree
337build_eh_type_type (type)
338 tree type;
8d08fdba 339{
f30432d7
MS
340 if (type == error_mark_node)
341 return error_mark_node;
8d2733ca 342
e92cc029 343 /* peel back references, so they match. */
f30432d7
MS
344 if (TREE_CODE (type) == REFERENCE_TYPE)
345 type = TREE_TYPE (type);
8d08fdba 346
e92cc029 347 /* Peel off cv qualifiers. */
f30432d7 348 type = TYPE_MAIN_VARIANT (type);
8d2733ca 349
db48b831 350 return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
8d08fdba 351}
8d08fdba 352
e5f614d7 353/* Build the address of a typeinfo decl for use in the runtime
db48b831 354 matching field of the new exception model */
5816cb14
AM
355
356static tree
357build_eh_type_type_ref (type)
358 tree type;
359{
5816cb14 360 tree exp;
5816cb14 361
93ca4ba7
JM
362 if (type == NULL_TREE || type == error_mark_node)
363 return type;
5816cb14
AM
364
365 /* peel back references, so they match. */
366 if (TREE_CODE (type) == REFERENCE_TYPE)
367 type = TREE_TYPE (type);
368
369 /* Peel off cv qualifiers. */
370 type = TYPE_MAIN_VARIANT (type);
371
e5f614d7
NS
372 exp = get_tinfo_decl (type);
373 mark_used (exp);
db48b831 374 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
5816cb14 375
5816cb14
AM
376 return (exp);
377}
378
9c606f69 379/* This routine is called to mark all the symbols representing runtime
ae673f14 380 type functions in the exception table as having been referenced.
9c606f69 381 This will make sure code is emitted for them. Called from finish_file. */
93ca4ba7 382
9c606f69
AM
383void
384mark_all_runtime_matches ()
385{
386 int x,num;
387 void **ptr;
388 tree exp;
389
390 num = find_all_handler_type_matches (&ptr);
391 if (num == 0 || ptr == NULL)
392 return;
393
394 for (x=0; x <num; x++)
395 {
396 exp = (tree) ptr[x];
397 if (TREE_CODE (exp) == ADDR_EXPR)
398 {
399 exp = TREE_OPERAND (exp, 0);
400 if (TREE_CODE (exp) == FUNCTION_DECL)
401 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
402 }
403 }
404
405 free (ptr);
406}
407
93ca4ba7
JM
408/* Returns nonzero if cleaning up an exception of type TYPE (which can be
409 NULL_TREE for a ... handler) will not throw an exception. */
410
411static int
412dtor_nothrow (type)
413 tree type;
414{
415 tree fn;
416
417 if (type == NULL_TREE)
418 return 0;
419
420 if (! TYPE_HAS_DESTRUCTOR (type))
421 return 1;
422
423 fn = lookup_member (type, dtor_identifier, 0, 0);
424 fn = TREE_VALUE (fn);
425 return TREE_NOTHROW (fn);
426}
427
c7ae64f2 428/* Build up a call to __cp_pop_exception, to destroy the exception object
93ca4ba7 429 for the current catch block if no others are currently using it. */
6467930b 430
c7ae64f2 431static tree
93ca4ba7
JM
432do_pop_exception (type)
433 tree type;
72b7eeff 434{
6874c264 435 tree fn, cleanup;
6874c264
JM
436 fn = get_identifier ("__cp_pop_exception");
437 if (IDENTIFIER_GLOBAL_VALUE (fn))
438 fn = IDENTIFIER_GLOBAL_VALUE (fn);
439 else
440 {
c7ae64f2
JM
441 /* Declare void __cp_pop_exception (void *),
442 as defined in exception.cc. */
0c11ada6
JM
443 fn = push_void_library_fn
444 (fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node));
445 /* This can throw if the destructor for the exception throws. */
446 TREE_NOTHROW (fn) = 0;
6874c264 447 }
72b7eeff
MS
448
449 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
c7ae64f2 450 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
e1b3e07d 451 cleanup = build_function_call (fn, tree_cons
de35891e 452 (NULL_TREE, cleanup, NULL_TREE));
93ca4ba7 453 TREE_NOTHROW (cleanup) = dtor_nothrow (type);
c0700ea5 454 return cleanup;
c7ae64f2
JM
455}
456
457/* This routine creates the cleanup for the current exception. */
72b7eeff 458
c7ae64f2 459static void
93ca4ba7
JM
460push_eh_cleanup (type)
461 tree type;
c7ae64f2 462{
93ca4ba7 463 finish_decl_cleanup (NULL_TREE, do_pop_exception (type));
c7ae64f2 464}
72b7eeff 465
f4a23343
JM
466/* Build up a call to terminate on the function obstack, for use as an
467 exception handler. */
468
c6160f8f 469static tree
f4a23343
JM
470build_terminate_handler ()
471{
80048418 472 return build_function_call (terminate_node, NULL_TREE);
f4a23343
JM
473}
474
e97f22c9
TT
475/* Return nonzero value if DECL is a Java type suitable for catch or
476 throw. */
477
478static int
479decl_is_java_type (decl, err)
480 tree decl;
481 int err;
482{
483 int r = (TREE_CODE (decl) == POINTER_TYPE
484 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
485 && TYPE_FOR_JAVA (TREE_TYPE (decl)));
486
487 if (err)
488 {
489 if (TREE_CODE (decl) == REFERENCE_TYPE
490 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
491 && TYPE_FOR_JAVA (TREE_TYPE (decl)))
492 {
493 /* Can't throw a reference. */
494 cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
495 decl);
496 }
497
498 if (r)
499 {
500 tree jthrow_node
501 = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
502 if (jthrow_node == NULL_TREE)
503 fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
504 jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
505
506 if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
507 {
508 /* Thrown object must be a Throwable. */
509 cp_error ("type `%T' is not derived from `java::lang::Throwable'",
510 TREE_TYPE (decl));
511 }
512 }
513 }
514
515 return r;
516}
517
b35d4555 518/* Initialize the catch parameter DECL. */
6467930b 519
b35d4555
MM
520static void
521initialize_handler_parm (decl)
3c5c0849 522 tree decl;
8d08fdba 523{
b35d4555
MM
524 tree exp;
525 tree init;
526 tree init_type;
e97f22c9 527 int lang;
b35d4555
MM
528
529 /* Make sure we mark the catch param as used, otherwise we'll get a
530 warning about an unused ((anonymous)). */
531 TREE_USED (decl) = 1;
532
533 /* Figure out the type that the initializer is. */
534 init_type = TREE_TYPE (decl);
535 if (TREE_CODE (init_type) != REFERENCE_TYPE
536 && TREE_CODE (init_type) != POINTER_TYPE)
537 init_type = build_reference_type (init_type);
538
e97f22c9
TT
539 if (decl_is_java_type (init_type, 0))
540 {
541 tree fn
542 = builtin_function ("_Jv_exception_info",
543 build_function_type (ptr_type_node,
544 tree_cons (NULL_TREE,
545 void_type_node,
546 NULL_TREE)),
547 0, NOT_BUILT_IN, NULL_PTR);
548
549 exp = build (CALL_EXPR, ptr_type_node,
550 build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
551 fn),
552 NULL_TREE, NULL_TREE);
553 TREE_SIDE_EFFECTS (exp) = 1;
554 lang = EH_LANG_Java;
555
556 set_exception_lang_code (EH_LANG_Java);
557 set_exception_version_code (1);
558 }
559 else
560 {
561 exp = get_eh_value ();
562 lang = EH_LANG_C_plus_plus;
563 }
564
565 if (catch_language_init)
566 {
567 if (lang != catch_language)
568 error ("mixing C++ and Java `catch'es in single translation unit");
569 }
570 else
571 {
572 catch_language_init = 1;
573 catch_language = lang;
574 }
b35d4555
MM
575
576 /* Since pointers are passed by value, initialize a reference to
577 pointer catch parm with the address of the value slot. */
578 if (TREE_CODE (init_type) == REFERENCE_TYPE
579 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
580 exp = build_unary_op (ADDR_EXPR, exp, 1);
581
582 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
583
584 init = convert_from_reference (exp);
585
586 /* If the constructor for the catch parm exits via an exception, we
587 must call terminate. See eh23.C. */
588 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
faf5394a 589 {
b35d4555
MM
590 /* Generate the copy constructor call directly so we can wrap it.
591 See also expand_default_init. */
592 init = ocp_convert (TREE_TYPE (decl), init,
593 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
594 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
595 build_terminate_handler ());
faf5394a
MS
596 }
597
b35d4555
MM
598 /* Let `cp_finish_decl' know that this initializer is ok. */
599 DECL_INITIAL (decl) = error_mark_node;
600 decl = pushdecl (decl);
8d2733ca 601
b35d4555 602 start_decl_1 (decl);
cd9f6678 603 cp_finish_decl (decl, init, NULL_TREE,
b35d4555 604 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
5816cb14
AM
605}
606
b35d4555 607/* Call this to start a catch block. DECL is the catch parameter. */
5816cb14 608
b35d4555
MM
609tree
610expand_start_catch_block (decl)
3c5c0849 611 tree decl;
5816cb14 612{
b35d4555
MM
613 tree compound_stmt_1;
614 tree compound_stmt_2;
5816cb14 615
b35d4555
MM
616 if (! doing_eh (1))
617 return NULL_TREE;
5816cb14 618
b35d4555 619 /* Make sure this declaration is reasonable. */
3c5c0849
MM
620 if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
621 decl = NULL_TREE;
5816cb14 622
b35d4555
MM
623 /* Create a binding level for the eh_info and the exception object
624 cleanup. */
625 compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
626
e97f22c9
TT
627 if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
628 {
629 /* The ordinary C++ case. */
93ca4ba7 630 tree type;
5816cb14 631
e97f22c9 632 if (decl)
93ca4ba7 633 type = TREE_TYPE (decl);
e97f22c9
TT
634 else
635 type = NULL_TREE;
93ca4ba7 636 begin_catch_block (build_eh_type_type_ref (type));
e97f22c9
TT
637
638 push_eh_info ();
93ca4ba7 639 push_eh_cleanup (type);
e97f22c9
TT
640 }
641 else
642 {
643 /* The Java case. In this case, the match_info is a pointer to
644 the Java class object. We assume that the class is a
645 compiled class. */
646 tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
647 begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
648 }
5816cb14 649
b35d4555
MM
650 /* Create a binding level for the parm. */
651 compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
5816cb14 652
b35d4555
MM
653 if (decl)
654 initialize_handler_parm (decl);
5816cb14 655
b35d4555 656 return build_tree_list (compound_stmt_1, compound_stmt_2);
5816cb14
AM
657}
658
f30432d7 659
8d2733ca
MS
660/* Call this to end a catch block. Its responsible for emitting the
661 code to handle jumping back to the correct place, and for emitting
662 the label to jump to if this catch block didn't match. */
6467930b 663
824b9a4c 664void
b35d4555
MM
665expand_end_catch_block (blocks)
666 tree blocks;
8d08fdba 667{
b35d4555
MM
668 tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
669 tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
670
f30432d7
MS
671 if (! doing_eh (1))
672 return;
8d2733ca 673
0dde4175
JM
674 /* The exception being handled is rethrown if control reaches the end of
675 a handler of the function-try-block of a constructor or destructor. */
676 if (in_function_try_handler
677 && (DECL_CONSTRUCTOR_P (current_function_decl)
678 || DECL_DESTRUCTOR_P (current_function_decl)))
b35d4555 679 finish_expr_stmt (build_throw (NULL_TREE));
0dde4175 680
c7ae64f2 681 /* Cleanup the EH parameter. */
b35d4555 682 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
46e8c075 683 /* Cleanup the EH object. */
4a6ef811 684 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
8d2733ca 685}
8d08fdba 686
6c20b7e9
JM
687/* An exception spec is implemented more or less like:
688
689 try {
690 function body;
691 } catch (...) {
692 void *p[] = { typeid(raises) };
693 __check_eh_spec (p, count);
694 }
695
696 __check_eh_spec in exception.cc handles all the details. */
8d2733ca 697
b35d4555 698tree
f30432d7
MS
699expand_start_eh_spec ()
700{
b35d4555 701 return begin_try_block ();
f30432d7
MS
702}
703
b35d4555
MM
704void
705expand_end_eh_spec (raises, try_block)
f30432d7 706 tree raises;
b35d4555 707 tree try_block;
f30432d7 708{
6c20b7e9 709 tree tmp, fn, decl, types = NULL_TREE;
b35d4555
MM
710 tree blocks;
711 tree handler;
6c20b7e9 712 int count = 0;
f30432d7 713
b35d4555
MM
714 finish_try_block (try_block);
715 handler = begin_handler ();
716 blocks = finish_handler_parms (NULL_TREE, handler);
f30432d7 717
1ef9f749 718 if (TREE_VALUE (raises) == NULL_TREE)
6c20b7e9 719 {
1ef9f749
JM
720 fn = get_identifier ("__check_null_eh_spec");
721 if (IDENTIFIER_GLOBAL_VALUE (fn))
722 fn = IDENTIFIER_GLOBAL_VALUE (fn);
723 else
724 {
725 tmp = build_function_type (void_type_node, void_list_node);
726 fn = push_throw_library_fn (fn, tmp);
727 /* Since the spec doesn't allow any exceptions, this call
728 will never throw. */
729 TREE_NOTHROW (fn) = 1;
730 }
731 tmp = NULL_TREE;
6c20b7e9 732 }
1ef9f749
JM
733 else
734 {
735 /* Build up an array of type_infos. */
736 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
737 {
738 types = tree_cons
739 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
740 ++count;
741 }
eb66be0e 742
1ef9f749
JM
743 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
744 TREE_HAS_CONSTRUCTOR (types) = 1;
6874c264 745
1ef9f749
JM
746 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
747 tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
748 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
749 DECL_ARTIFICIAL (decl) = 1;
750 DECL_INITIAL (decl) = types;
751 DECL_CONTEXT (decl) = current_function_decl;
752 cp_finish_decl (decl, types, NULL_TREE, 0);
6c20b7e9 753
1ef9f749 754 decl = decay_conversion (decl);
6874c264 755
1ef9f749
JM
756 fn = get_identifier ("__check_eh_spec");
757 if (IDENTIFIER_GLOBAL_VALUE (fn))
758 fn = IDENTIFIER_GLOBAL_VALUE (fn);
759 else
760 {
761 tmp = tree_cons
762 (NULL_TREE, integer_type_node, tree_cons
763 (NULL_TREE, TREE_TYPE (decl), void_list_node));
764 tmp = build_function_type (void_type_node, tmp);
765
766 fn = push_throw_library_fn (fn, tmp);
767 }
0c11ada6 768
1ef9f749
JM
769 tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
770 tree_cons (NULL_TREE, decl, NULL_TREE));
6c20b7e9
JM
771 }
772
0c11ada6 773 tmp = build_call (fn, tmp);
b35d4555 774 finish_expr_stmt (tmp);
6c20b7e9 775
b35d4555
MM
776 finish_handler (blocks, handler);
777 finish_handler_sequence (try_block);
f30432d7
MS
778}
779
8d2733ca
MS
780/* This is called to expand all the toplevel exception handling
781 finalization for a function. It should only be called once per
782 function. */
6467930b 783
8d08fdba 784void
8d2733ca 785expand_exception_blocks ()
8d08fdba 786{
92b96838 787 do_pending_stack_adjust ();
eb448459 788
e00737d2 789 if (catch_clauses)
f30432d7 790 {
e00737d2
MS
791 rtx funcend = gen_label_rtx ();
792 emit_jump (funcend);
793
eb66be0e
MS
794 /* We cannot protect n regions this way if we must flow into the
795 EH region through the top of the region, as we have to with
796 the setjmp/longjmp approach. */
797 if (exceptions_via_longjmp == 0)
fb98cff6 798 expand_eh_region_start ();
f30432d7 799
e00737d2 800 emit_insns (catch_clauses);
c14f7160 801 catch_clauses = catch_clauses_last = NULL_RTX;
eb66be0e
MS
802
803 if (exceptions_via_longjmp == 0)
f4a23343 804 expand_eh_region_end (build_terminate_handler ());
eb66be0e 805
4a6ef811 806 emit_insns (catch_clauses);
c14f7160 807 catch_clauses = catch_clauses_last = NULL_RTX;
e00737d2
MS
808 emit_label (funcend);
809 }
8d08fdba
MS
810}
811
f4a23343
JM
812/* Return a pointer to a buffer for an exception object of type TYPE. */
813
c6160f8f 814static tree
f4a23343
JM
815alloc_eh_object (type)
816 tree type;
817{
818 tree fn, exp;
819
820 fn = get_identifier ("__eh_alloc");
821 if (IDENTIFIER_GLOBAL_VALUE (fn))
822 fn = IDENTIFIER_GLOBAL_VALUE (fn);
823 else
824 {
825 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
0c11ada6
JM
826 tree tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
827 fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
f4a23343
JM
828 }
829
e1b3e07d 830 exp = build_function_call (fn, tree_cons
f4a23343
JM
831 (NULL_TREE, size_in_bytes (type), NULL_TREE));
832 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
833 return exp;
834}
835
6467930b 836/* Expand a throw statement. This follows the following
8d2733ca
MS
837 algorithm:
838
839 1. Allocate space to save the current PC onto the stack.
840 2. Generate and emit a label and save its address into the
e1cd6e56 841 newly allocated stack space since we can't save the pc directly.
8d2733ca
MS
842 3. If this is the first call to throw in this function:
843 generate a label for the throw block
844 4. jump to the throw block label. */
6467930b 845
225ff119 846static tree
8d2733ca
MS
847expand_throw (exp)
848 tree exp;
8d08fdba 849{
6874c264 850 tree fn;
8d08fdba 851
8d2733ca 852 if (! doing_eh (1))
59ccf49d 853 return error_mark_node;
8d08fdba 854
e97f22c9
TT
855 if (exp
856 && decl_is_java_type (TREE_TYPE (exp), 1))
857 {
858 /* A Java `throw' statement. */
859 tree args = tree_cons (NULL_TREE, exp, NULL);
860
861 fn = get_identifier (exceptions_via_longjmp
d9420976 862 ? "_Jv_Sjlj_Throw"
e97f22c9
TT
863 : "_Jv_Throw");
864 if (IDENTIFIER_GLOBAL_VALUE (fn))
865 fn = IDENTIFIER_GLOBAL_VALUE (fn);
866 else
867 {
868 /* Declare _Jv_Throw (void *), as defined in Java's
869 exception.cc. */
0c11ada6
JM
870 tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
871 tmp = build_function_type (ptr_type_node, tmp);
872 fn = push_library_fn (fn, tmp);
12a22e76 873 TREE_THIS_VOLATILE (fn) = 1;
0c11ada6 874 TREE_NOTHROW (fn) = 0;
e97f22c9
TT
875 }
876
877 exp = build_function_call (fn, args);
878 }
879 else if (exp)
8d2733ca 880 {
faae18ab 881 tree throw_type;
6874c264 882 tree cleanup = NULL_TREE, e;
59ccf49d
MM
883 tree stmt_expr;
884 tree compound_stmt;
885 tree try_block;
886
887 begin_init_stmts (&stmt_expr, &compound_stmt);
faae18ab 888
a3b49ccd 889 /* throw expression */
e92cc029 890 /* First, decay it. */
f30432d7 891 exp = decay_conversion (exp);
a3b49ccd 892
298d6f60
MM
893 /* The CLEANUP_TYPE is the internal type of a destructor. Under
894 the old ABI, destructors are two-argument functions; under
895 the new ABI they take only one argument. */
6874c264 896 if (cleanup_type == NULL_TREE)
298d6f60
MM
897 {
898 tree arg_types;
899
900 arg_types = void_list_node;
901 if (!flag_new_abi)
902 arg_types = tree_cons (NULL_TREE, integer_type_node, arg_types);
903 arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
904 cleanup_type = (build_pointer_type
905 (build_function_type (void_type_node, arg_types)));
906 }
6874c264 907
08b24bda 908 if (TYPE_PTR_P (TREE_TYPE (exp)))
db48b831 909 throw_type = build_eh_type_type (TREE_TYPE (exp));
f30432d7
MS
910 else
911 {
f4a23343
JM
912 tree object, ptr;
913
cab1f180 914 /* OK, this is kind of wacky. The standard says that we call
46e8c075
MM
915 terminate when the exception handling mechanism, after
916 completing evaluation of the expression to be thrown but
917 before the exception is caught (_except.throw_), calls a
918 user function that exits via an uncaught exception.
f4a23343
JM
919
920 So we have to protect the actual initialization of the
921 exception object with terminate(), but evaluate the expression
922 first. We also expand the call to __eh_alloc
923 first. Since there could be temps in the expression, we need
924 to handle that, too. */
a50f0918 925
59ccf49d 926 my_friendly_assert (stmts_are_full_exprs_p == 1, 19990926);
f4a23343 927
f4a23343
JM
928 /* Store the throw expression into a temp. This can be less
929 efficient than storing it into the allocated space directly, but
930 oh well. To do this efficiently we would need to insinuate
931 ourselves into expand_call. */
932 if (TREE_SIDE_EFFECTS (exp))
933 {
f1dedc31 934 tree temp = create_temporary_var (TREE_TYPE (exp));
c37dc68e 935 DECL_INITIAL (temp) = exp;
cd9f6678 936 cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
f4a23343
JM
937 exp = temp;
938 }
f4a23343
JM
939
940 /* Allocate the space for the exception. */
941 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
59ccf49d 942 finish_expr_stmt (ptr);
f4a23343 943
59ccf49d 944 try_block = begin_try_block ();
f4a23343
JM
945 object = build_indirect_ref (ptr, NULL_PTR);
946 exp = build_modify_expr (object, INIT_EXPR, exp);
faae18ab 947
f30432d7 948 if (exp == error_mark_node)
8251199e 949 error (" in thrown expression");
faae18ab 950
59ccf49d
MM
951 finish_expr_stmt (exp);
952 finish_cleanup_try_block (try_block);
953 finish_cleanup (build_terminate_handler (), try_block);
f4a23343 954
db48b831 955 throw_type = build_eh_type_type (TREE_TYPE (object));
72b7eeff 956
6874c264
JM
957 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
958 {
959 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
298d6f60
MM
960 (flag_new_abi
961 ? complete_dtor_identifier
962 : dtor_identifier),
963 0);
6874c264 964 cleanup = TREE_VALUE (cleanup);
e872bb7a 965 mark_used (cleanup);
6874c264
JM
966 mark_addressable (cleanup);
967 /* Pretend it's a normal function. */
968 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
969 }
f4a23343
JM
970
971 exp = ptr;
f30432d7 972 }
faae18ab 973
bbeeb2b0
MM
974 /* Cast EXP to `void *' so that it will match the prototype for
975 __cp_push_exception. */
c37dc68e 976 exp = convert (ptr_type_node, exp);
bbeeb2b0 977
6874c264
JM
978 if (cleanup == NULL_TREE)
979 {
980 cleanup = build_int_2 (0, 0);
981 TREE_TYPE (cleanup) = cleanup_type;
982 }
72b7eeff 983
298d6f60 984 fn = cp_push_exception_identifier;
6874c264
JM
985 if (IDENTIFIER_GLOBAL_VALUE (fn))
986 fn = IDENTIFIER_GLOBAL_VALUE (fn);
987 else
988 {
989 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
990 as defined in exception.cc. */
991 tree tmp;
6874c264
JM
992 tmp = tree_cons
993 (NULL_TREE, ptr_type_node, tree_cons
994 (NULL_TREE, ptr_type_node, tree_cons
995 (NULL_TREE, cleanup_type, void_list_node)));
0c11ada6 996 fn = push_void_library_fn (fn, tmp);
6874c264 997 }
72b7eeff 998
e1b3e07d
MM
999 e = tree_cons (NULL_TREE, exp, tree_cons
1000 (NULL_TREE, throw_type, tree_cons
1001 (NULL_TREE, cleanup, NULL_TREE)));
59ccf49d
MM
1002 finish_expr_stmt (build_function_call (fn, e));
1003
1004 exp = finish_init_stmts (stmt_expr, compound_stmt);
8d2733ca
MS
1005 }
1006 else
a3b49ccd 1007 {
6874c264
JM
1008 /* rethrow current exception; note that it's no longer caught. */
1009
1010 tree fn = get_identifier ("__uncatch_exception");
1011 if (IDENTIFIER_GLOBAL_VALUE (fn))
1012 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1013 else
0c11ada6
JM
1014 /* Declare void __uncatch_exception (void)
1015 as defined in exception.cc. */
1016 fn = push_void_library_fn (fn, void_list_node);
6874c264
JM
1017
1018 exp = build_function_call (fn, NULL_TREE);
a3b49ccd 1019 }
8d2733ca 1020
59ccf49d 1021 return exp;
f376e137 1022}
8d2733ca
MS
1023
1024/* Build a throw expression. */
6467930b 1025
8d2733ca
MS
1026tree
1027build_throw (e)
1028 tree e;
1029{
02020185
JM
1030 if (e == error_mark_node)
1031 return e;
1032
1033 if (processing_template_decl)
1034 return build_min (THROW_EXPR, void_type_node, e);
1035
e0f9a8bc 1036 if (e == null_node)
8251199e 1037 cp_warning ("throwing NULL, which has integral, not pointer type");
980c394c
NS
1038
1039 if (e != NULL_TREE)
1040 {
4cfbc546
NS
1041 if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
1042 return error_mark_node;
980c394c 1043 }
02020185 1044
59ccf49d 1045 e = expand_throw (e);
02020185
JM
1046 e = build1 (THROW_EXPR, void_type_node, e);
1047 TREE_SIDE_EFFECTS (e) = 1;
1048 TREE_USED (e) = 1;
1049
8d2733ca 1050 return e;
8d08fdba 1051}
4cfbc546
NS
1052
1053/* Make sure TYPE is complete, pointer to complete, reference to
1054 complete, or pointer to cv void. Issue diagnostic on failure.
1055 Return the zero on failure and non-zero on success. FROM can be
1056 the expr or decl from whence TYPE came, if available. */
1057
1058static int
1059complete_ptr_ref_or_void_ptr_p (type, from)
1060 tree type;
1061 tree from;
1062{
1063 int is_ptr;
1064
1065 /* Check complete. */
1066 type = complete_type_or_else (type, from);
1067 if (!type)
1068 return 0;
1069
1070 /* Or a pointer or ref to one, or cv void *. */
1071 is_ptr = TREE_CODE (type) == POINTER_TYPE;
1072 if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
1073 {
1074 tree core = TREE_TYPE (type);
1075
1076 if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
1077 /* OK */;
1078 else if (!complete_type_or_else (core, from))
1079 return 0;
1080 }
1081 return 1;
1082}
1083
1660cb3a
JM
1084/* Returns nonzero if FN is a declaration of a standard C library
1085 function which is known not to throw.
1086
1087 [lib.res.on.exception.handling]: None of the functions from the
1088 Standard C library shall report an error by throwing an
1089 exception, unless it calls a program-supplied function that
1090 throws an exception. */
1091
1092#include "cfns.h"
1093
1094int
1095nothrow_libfn_p (fn)
1096 tree fn;
1097{
1098 tree id;
1099
1100 if (TREE_PUBLIC (fn)
1101 && DECL_EXTERNAL (fn)
eb68cb58 1102 && DECL_EXTERN_C_P (fn))
1660cb3a
JM
1103 /* OK */;
1104 else
1105 /* Can't be a C library function. */
1106 return 0;
1107
1108 id = DECL_ASSEMBLER_NAME (fn);
1109 return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
1110}
2bc9f1d1
JM
1111
1112/* Returns nonzero if an exception of type FROM will be caught by a
1113 handler for type TO, as per [except.handle]. */
1114
1115static int
1116can_convert_eh (to, from)
1117 tree to, from;
1118{
1119 if (TREE_CODE (to) == REFERENCE_TYPE)
1120 to = TREE_TYPE (to);
1121 if (TREE_CODE (from) == REFERENCE_TYPE)
1122 from = TREE_TYPE (from);
1123
1124 if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE)
1125 {
1126 to = TREE_TYPE (to);
1127 from = TREE_TYPE (from);
1128
1129 if (! at_least_as_qualified_p (to, from))
1130 return 0;
1131
1132 if (TREE_CODE (to) == VOID_TYPE)
1133 return 1;
1134
1135 /* else fall through */
1136 }
1137
1138 if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
1139 && PUBLICLY_UNIQUELY_DERIVED_P (to, from))
1140 return 1;
1141
1142 return 0;
1143}
1144
1145/* Check whether any of HANDLERS are shadowed by another handler accepting
1146 TYPE. Note that the shadowing may not be complete; even if an exception
1147 of type B would be caught by a handler for A, there could be a derived
1148 class C for which A is an ambiguous base but B is not, so the handler
1149 for B would catch an exception of type C. */
1150
1151static void
1152check_handlers_1 (master, handlers)
1153 tree master;
1154 tree handlers;
1155{
1156 tree type = TREE_TYPE (master);
1157 tree handler;
1158
1159 for (handler = handlers; handler; handler = TREE_CHAIN (handler))
1160 if (TREE_TYPE (handler)
1161 && can_convert_eh (type, TREE_TYPE (handler)))
1162 {
1163 lineno = STMT_LINENO (handler);
1164 cp_warning ("exception of type `%T' will be caught",
1165 TREE_TYPE (handler));
1166 lineno = STMT_LINENO (master);
1167 cp_warning (" by earlier handler for `%T'", type);
1168 break;
1169 }
1170}
1171
1172/* Given a chain of HANDLERs, make sure that they're OK. */
1173
1174void
1175check_handlers (handlers)
1176 tree handlers;
1177{
1178 tree handler;
1179 int save_line = lineno;
1180 for (handler = handlers; handler; handler = TREE_CHAIN (handler))
1181 {
1182 if (TREE_CHAIN (handler) == NULL_TREE)
1183 /* No more handlers; nothing to shadow. */;
1184 else if (TREE_TYPE (handler) == NULL_TREE)
1185 {
1186 lineno = STMT_LINENO (handler);
1187 cp_pedwarn
1188 ("`...' handler must be the last handler for its try block");
1189 }
1190 else
1191 check_handlers_1 (handler, TREE_CHAIN (handler));
1192 }
1193 lineno = save_line;
1194}
This page took 0.822553 seconds and 5 git commands to generate.