|
|
1.1 ! root 1: /* Handle exceptional things in C++. ! 2: Copyright (C) 1989, 1992 Free Software Foundation, Inc. ! 3: Contributed by Michael Tiemann ([email protected]) ! 4: ! 5: This file is part of GNU CC. ! 6: ! 7: GNU CC is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 2, or (at your option) ! 10: any later version. ! 11: ! 12: GNU CC is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 21: ! 22: /* High-level class interface. */ ! 23: ! 24: #define NULL 0 ! 25: ! 26: /* This should be part of `ansi_opname', or at least be defined by the std. */ ! 27: #define EXCEPTION_NAME_PREFIX "__ex" ! 28: #define EXCEPTION_NAME_LENGTH 4 ! 29: ! 30: #include "config.h" ! 31: #include "tree.h" ! 32: #include "cp-tree.h" ! 33: #include "flags.h" ! 34: #include "assert.h" ! 35: /* On Suns this can get you to the right definition if you ! 36: set the right value for TARGET. */ ! 37: #include <setjmp.h> ! 38: #ifdef sequent ! 39: /* Can you believe they forgot this? */ ! 40: #define _JBLEN 11 ! 41: #endif ! 42: ! 43: #ifndef _JBLEN ! 44: #define _JBLEN (sizeof(jmp_buf)/sizeof(int)) ! 45: #endif ! 46: ! 47: extern struct rtx_def *expand_expr (); ! 48: extern struct rtx_def *const0_rtx, *const1_rtx; ! 49: ! 50: void init_exception_processing (); ! 51: void init_exception_processing_1 (); ! 52: ! 53: /* If non-zero, a VAR_DECL whose cleanup will cause a throw to the ! 54: next exception handler. Its value says whether to throw or not. ! 55: In the case of functions which do not issue a RAISE, it should be ! 56: possible to optimize away this VAR_DECL (and overhead associated ! 57: with it). */ ! 58: tree exception_throw_decl; ! 59: /* Use this to know that we did not set `exception_throw_decl', ! 60: until GCC optimizer is smart enough to figure it out for itself. */ ! 61: int sets_exception_throw_decl; ! 62: ! 63: /* The exception `type' currently in scope, or NULL_TREE if none. */ ! 64: tree current_exception_type; ! 65: ! 66: /* The exception handler object for the given scope. */ ! 67: tree current_exception_decl; ! 68: struct rtx_def *current_exception_name_as_rtx; ! 69: struct rtx_def *current_exception_parms_as_rtx; ! 70: ! 71: /* The ``object'' view of the current exception parameters. ! 72: We cast up from the `parms' field to `current_exception_type'. */ ! 73: tree current_exception_object; ! 74: ! 75: /* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception' ! 76: after default conversion. Maybe later they will get built-in. */ ! 77: static tree BISJ, BILJ, BIR, BIUE; ! 78: ! 79: /* Local variables which give the appearance that exception ! 80: handling is part of the language and the execution model. */ ! 81: ! 82: /* The type of the exception handler stack. */ ! 83: static tree EHS_type; ! 84: ! 85: /* The global handler stack. */ ! 86: tree EHS_decl; ! 87: ! 88: /* Cached component refs to fields of `EHS_decl'. */ ! 89: static tree EHS_prev, EHS_handler, EHS_parms, EHS_name; ! 90: static struct rtx_def *EHS_parms_as_rtx, *EHS_name_as_rtx; ! 91: ! 92: /* The parameter names of this exception type. */ ! 93: ! 94: static tree last_exception_fields; ! 95: static tree last_exception_field_types; ! 96: ! 97: /* When ID is VOID_TYPE_NODE, it means ``raise all''. ! 98: Cannot be inline, since it uses `alloca', and that ! 99: breaks code which pushes the result of this function ! 100: on the stack. */ ! 101: static tree ! 102: exception_object_name (prefix, id) ! 103: tree prefix; ! 104: tree id; ! 105: { ! 106: /* First, cons up the `name' of this exception. */ ! 107: char *name; ! 108: int length = (id == void_type_node ? 3 : IDENTIFIER_LENGTH (id)) + EXCEPTION_NAME_LENGTH; ! 109: ! 110: if (prefix) ! 111: length += IDENTIFIER_LENGTH (prefix) + 2; ! 112: ! 113: name = (char *)alloca (length); ! 114: strcpy (name, EXCEPTION_NAME_PREFIX); ! 115: length = EXCEPTION_NAME_LENGTH; ! 116: if (prefix) ! 117: { ! 118: strcpy (name + length, IDENTIFIER_POINTER (prefix)); ! 119: name[length + IDENTIFIER_LENGTH (prefix)] = JOINER; ! 120: length += IDENTIFIER_LENGTH (prefix) + 1; ! 121: } ! 122: if (id == void_type_node) ! 123: strcpy (name + length, "all"); ! 124: else ! 125: strcpy (name + length, IDENTIFIER_POINTER (id)); ! 126: return get_identifier (name); ! 127: } ! 128: ! 129: tree ! 130: lookup_exception_cname (ctype, cname, raise_id) ! 131: tree ctype, cname; ! 132: tree raise_id; ! 133: { ! 134: tree this_cname = TREE_PURPOSE (raise_id); ! 135: if (this_cname == NULL_TREE) ! 136: { ! 137: if (cname) ! 138: { ! 139: tree name = TREE_VALUE (raise_id); ! 140: if (purpose_member (name, CLASSTYPE_TAGS (ctype))) ! 141: this_cname = cname; ! 142: } ! 143: } ! 144: else if (this_cname == void_type_node) ! 145: this_cname = NULL_TREE; ! 146: else if (TREE_CODE (this_cname) != IDENTIFIER_NODE) ! 147: { ! 148: sorry ("multiple scope refs in `cplus_expand_raise_stmt'"); ! 149: this_cname = error_mark_node; ! 150: } ! 151: return this_cname; ! 152: } ! 153: ! 154: tree ! 155: lookup_exception_tname (oname) ! 156: tree oname; ! 157: { ! 158: return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH); ! 159: } ! 160: ! 161: tree ! 162: lookup_exception_object (cname, name, complain) ! 163: tree cname, name; ! 164: int complain; ! 165: { ! 166: tree oname; ! 167: tree decl; ! 168: ! 169: if (cname == void_type_node) ! 170: cname = NULL_TREE; ! 171: else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE) ! 172: { ! 173: sorry ("multiple scope refs in `lookup_exception_object'"); ! 174: cname = NULL_TREE; ! 175: } ! 176: oname = exception_object_name (cname, name); ! 177: decl = IDENTIFIER_GLOBAL_VALUE (oname); ! 178: if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL) ! 179: { ! 180: if (complain) ! 181: { ! 182: push_obstacks_nochange (); ! 183: ! 184: if (cname) ! 185: error ("no exception name object for name `%s::%s'", ! 186: IDENTIFIER_POINTER (cname), ! 187: IDENTIFIER_POINTER (name)); ! 188: else ! 189: error ("no exception name object for name `%s'", ! 190: IDENTIFIER_POINTER (name)); ! 191: end_temporary_allocation (); ! 192: /* Avoid further error messages. */ ! 193: pushdecl_top_level (build_lang_field_decl (VAR_DECL, ! 194: exception_object_name (cname, name), ! 195: error_mark_node)); ! 196: pop_obstacks (); ! 197: } ! 198: return NULL_TREE; ! 199: } ! 200: return decl; ! 201: } ! 202: ! 203: tree ! 204: lookup_exception_type (ctype, cname, raise_id) ! 205: tree ctype, cname; ! 206: tree raise_id; ! 207: { ! 208: tree name = TREE_VALUE (raise_id); ! 209: tree purpose = TREE_PURPOSE (raise_id); ! 210: ! 211: if (cname && purpose == NULL_TREE) ! 212: purpose = cname; ! 213: ! 214: if (purpose && purpose != void_type_node) ! 215: { ! 216: tree link = NULL_TREE; ! 217: ! 218: if (TREE_CODE (purpose) != IDENTIFIER_NODE) ! 219: { ! 220: sorry ("multiple scope refs in `lookup_exception_type'"); ! 221: TREE_PURPOSE (raise_id) = NULL_TREE; ! 222: return NULL_TREE; ! 223: } ! 224: if (! is_aggr_typedef (purpose, 1)) ! 225: return NULL_TREE; ! 226: ctype = IDENTIFIER_TYPE_VALUE (purpose); ! 227: link = purpose_member (name, CLASSTYPE_TAGS (ctype)); ! 228: if (link) ! 229: return TREE_VALUE (link); ! 230: } ! 231: ! 232: ctype = lookup_name (name, 1); ! 233: if (ctype && TREE_CODE (ctype) == TYPE_DECL) ! 234: ctype = TREE_TYPE (ctype); ! 235: if (ctype && TREE_CODE (ctype) == RECORD_TYPE ! 236: && CLASSTYPE_DECLARED_EXCEPTION (ctype)) ! 237: return ctype; ! 238: return NULL_TREE; ! 239: } ! 240: ! 241: tree ! 242: finish_exception (e, list_of_fieldlists) ! 243: tree e; ! 244: tree list_of_fieldlists; ! 245: { ! 246: tree parmtypes = NULL_TREE, name_field; ! 247: tree cname = TYPE_NAME (e); ! 248: ! 249: if (TREE_CODE (cname) == TYPE_DECL) ! 250: cname = DECL_NAME (cname); ! 251: ! 252: if (last_exception_fields) ! 253: error ("cannot declare exceptions within exceptions"); ! 254: if (list_of_fieldlists && ! ANON_AGGRNAME_P (cname)) ! 255: error_with_aggr_type (e, "exception name `%s' must follow body declaration"); ! 256: if (list_of_fieldlists) ! 257: { ! 258: tree prev, field; ! 259: ! 260: /* Note: no public, private, or protected allowed. */ ! 261: if (TREE_CHAIN (list_of_fieldlists)) ! 262: error ("visibility declarations invalid in exception declaration"); ! 263: else if (TREE_PURPOSE (list_of_fieldlists) != (tree)visibility_default) ! 264: error ("visibility declarations invalid in exception declaration"); ! 265: TREE_PURPOSE (list_of_fieldlists) = (tree)visibility_default; ! 266: ! 267: /* Note also: no member function declarations allowed. */ ! 268: for (prev = 0, field = TREE_VALUE (list_of_fieldlists); ! 269: field; prev = field, field = TREE_CHAIN (field)) ! 270: { ! 271: switch (TREE_CODE (field)) ! 272: { ! 273: case FIELD_DECL: ! 274: /* ok. */ ! 275: parmtypes = tree_cons (NULL_TREE, TREE_TYPE (field), parmtypes); ! 276: continue; ! 277: case FUNCTION_DECL: ! 278: error_with_decl (field, "declaration of function `%s' in exception invalid"); ! 279: break; ! 280: case VAR_DECL: ! 281: if (TREE_STATIC (field)) ! 282: error_with_decl (field, "declaration of static variable `%s' in exception invalid"); ! 283: else ! 284: error_with_decl (field, "declaration of constant field `%s' in exception invalid"); ! 285: break; ! 286: case CONST_DECL: ! 287: error_with_decl (field, "declaration of enum value `%s' in exception invalid"); ! 288: break; ! 289: case SCOPE_REF: ! 290: error ("use of `::' in exception context invalid"); ! 291: break; ! 292: } ! 293: if (prev) ! 294: TREE_CHAIN (prev) = TREE_CHAIN (field); ! 295: else ! 296: TREE_VALUE (list_of_fieldlists) = TREE_CHAIN (field); ! 297: } ! 298: } ! 299: ! 300: /* Now that we've cleaned up the fields, add a name identifier at front. */ ! 301: name_field = build_lang_field_decl (FIELD_DECL, get_identifier ("__name"), ! 302: ptr_type_node); ! 303: if (list_of_fieldlists) ! 304: { ! 305: TREE_CHAIN (name_field) = TREE_VALUE (list_of_fieldlists); ! 306: TREE_VALUE (list_of_fieldlists) = name_field; ! 307: } ! 308: else ! 309: list_of_fieldlists = build_tree_list (NULL_TREE, name_field); ! 310: ! 311: last_exception_fields = TREE_VALUE (list_of_fieldlists); ! 312: if (parmtypes) ! 313: { ! 314: last_exception_field_types = nreverse (parmtypes); ! 315: /* Set the TREE_CHAIN of what is now at the end of the ! 316: list to `void_list_node'. */ ! 317: TREE_CHAIN (parmtypes) = void_list_node; ! 318: } ! 319: else ! 320: last_exception_field_types = void_list_node; ! 321: ! 322: popclass (0); ! 323: ! 324: #if 0 ! 325: /* Remove aggregate types from the list of tags, ! 326: since these appear at global scope. */ ! 327: while (x && IS_AGGR_TYPE (TREE_VALUE (x))) ! 328: x = TREE_CHAIN (x); ! 329: CLASSTYPE_TAGS (t) = x; ! 330: y = x; ! 331: while (x) ! 332: { ! 333: if (IS_AGGR_TYPE (TREE_VALUE (x))) ! 334: TREE_CHAIN (y) = TREE_CHAIN (x); ! 335: x = TREE_CHAIN (x); ! 336: } ! 337: #endif ! 338: ! 339: if (flag_cadillac) ! 340: cadillac_finish_exception (e); ! 341: ! 342: return e; ! 343: } ! 344: ! 345: void ! 346: finish_exception_decl (cname, decl) ! 347: tree cname, decl; ! 348: { ! 349: /* In cp-decl.h. */ ! 350: extern tree last_function_parms; ! 351: ! 352: /* An exception declaration. */ ! 353: tree t, ctor; ! 354: tree parmdecls = NULL_TREE, fields; ! 355: tree list_of_fieldlists = temp_tree_cons (NULL_TREE, ! 356: copy_list (last_exception_fields), ! 357: NULL_TREE); ! 358: tree edecl = build_lang_field_decl (VAR_DECL, ! 359: exception_object_name (cname, DECL_NAME (decl)), ! 360: ptr_type_node); ! 361: ! 362: DECL_LANGUAGE (edecl) = lang_c; ! 363: TREE_STATIC (edecl) = 1; ! 364: TREE_PUBLIC (edecl) = 1; ! 365: finish_decl (pushdecl (edecl), 0, 0, 0); ! 366: ! 367: /* Now instantiate the exception decl. */ ! 368: t = xref_tag (exception_type_node, DECL_NAME (decl), NULL_TREE); ! 369: ! 370: /* finish_struct will pop this. */ ! 371: pushclass (t, 0); ! 372: ! 373: /* Now add a constructor which takes as parameters all the types we ! 374: just defined. */ ! 375: ctor = build_lang_decl (FUNCTION_DECL, DECL_NAME (decl), ! 376: build_cplus_method_type (t, TYPE_POINTER_TO (t), ! 377: last_exception_field_types)); ! 378: /* Don't take `name'. The constructor handles that. */ ! 379: fields = TREE_CHAIN (TREE_VALUE (list_of_fieldlists)); ! 380: while (fields) ! 381: { ! 382: tree parm = build_decl (PARM_DECL, DECL_NAME (fields), TREE_TYPE (fields)); ! 383: /* Since there is a prototype, args are passed in their own types. */ ! 384: DECL_ARG_TYPE (parm) = TREE_TYPE (parm); ! 385: #ifdef PROMOTE_PROTOTYPES ! 386: if (TREE_CODE (TREE_TYPE (fields)) == INTEGER_TYPE ! 387: && TYPE_PRECISION (TREE_TYPE (fields)) < TYPE_PRECISION (integer_type_node)) ! 388: DECL_ARG_TYPE (parm) = integer_type_node; ! 389: #endif ! 390: TREE_CHAIN (parm) = parmdecls; ! 391: parmdecls = parm; ! 392: fields = TREE_CHAIN (fields); ! 393: } ! 394: fields = TREE_VALUE (list_of_fieldlists); ! 395: last_function_parms = nreverse (parmdecls); ! 396: ! 397: DECL_CONSTRUCTOR_P (ctor) = 1; ! 398: TYPE_HAS_CONSTRUCTOR (t) = 1; ! 399: grokclassfn (t, DECL_NAME (decl), ctor, NO_SPECIAL, NULL_TREE); ! 400: TREE_EXTERNAL (ctor) = 1; ! 401: TREE_STATIC (ctor) = 1; ! 402: TREE_PUBLIC (ctor) = 0; ! 403: TREE_INLINE (ctor) = 1; ! 404: make_decl_rtl (ctor, 0, 1); ! 405: finish_decl (ctor, NULL_TREE, 0, 0); ! 406: TREE_CHAIN (ctor) = TREE_VALUE (list_of_fieldlists); ! 407: TREE_VALUE (list_of_fieldlists) = ctor; ! 408: ! 409: finish_struct (t, list_of_fieldlists, 0, 0); ! 410: ! 411: if (current_function_decl) ! 412: error ("cannot define exception inside function scope"); ! 413: else ! 414: { ! 415: enum debug_info_type old_write_symbols = write_symbols; ! 416: write_symbols = NO_DEBUG; ! 417: ! 418: /* Now build the constructor for this exception. */ ! 419: parmdecls = DECL_ARGUMENTS (ctor); ! 420: start_function (NULL_TREE, ctor, 0, 1); ! 421: store_parm_decls (); ! 422: pushlevel (0); ! 423: clear_last_expr (); ! 424: push_momentary (); ! 425: expand_start_bindings (0); ! 426: ! 427: /* Move all the parameters to the fields, skipping `this'. */ ! 428: parmdecls = TREE_CHAIN (parmdecls); ! 429: /* Install `name' of this exception handler. */ ! 430: DECL_INITIAL (fields) = build_unary_op (ADDR_EXPR, edecl, 0); ! 431: fields = TREE_CHAIN (fields); ! 432: /* Install all the values. */ ! 433: while (fields) ! 434: { ! 435: /* Set up the initialization for this field. */ ! 436: DECL_INITIAL (fields) = parmdecls; ! 437: fields = TREE_CHAIN (fields); ! 438: parmdecls = TREE_CHAIN (parmdecls); ! 439: } ! 440: emit_base_init (t, 0); ! 441: ! 442: finish_function (DECL_SOURCE_LINE (ctor), 1); ! 443: write_symbols = old_write_symbols; ! 444: } ! 445: } ! 446: ! 447: void ! 448: end_exception_decls () ! 449: { ! 450: last_exception_field_types = NULL_TREE; ! 451: last_exception_fields = NULL_TREE; ! 452: } ! 453: ! 454: /* Statement-level exception semantics. */ ! 455: ! 456: void ! 457: cplus_expand_start_try (implicit) ! 458: int implicit; ! 459: { ! 460: tree call_to_setjmp; ! 461: tree handler, ref; ! 462: ! 463: /* Start a new block enclosing the whole handler. */ ! 464: if (implicit) ! 465: { ! 466: pushlevel_temporary (1); ! 467: } ! 468: else ! 469: { ! 470: pushlevel (0); ! 471: clear_last_expr (); ! 472: push_momentary (); ! 473: ! 474: /* Encompass whole exception handler in one big binding contour. ! 475: If RAISE should throw out of the whole TRY/EXCEPT block, call ! 476: `expand_start_bindings' with argument of 1. */ ! 477: expand_start_bindings (0); ! 478: } ! 479: ! 480: /* Allocate handler in that block. It's real name will come later. ! 481: Note that it will be the first name in this binding contour. */ ! 482: handler = get_temp_name (EHS_type, 0); ! 483: DECL_INITIAL (handler) = error_mark_node; ! 484: finish_decl (handler, NULL_TREE, 0, 0); ! 485: ! 486: /* Must come after call to `finish_decl', else the cleanup for the temp ! 487: for the handler will cause the contour we just created to be popped. */ ! 488: if (implicit) ! 489: declare_implicit_exception (); ! 490: ! 491: /* Catch via `setjmp'. */ ! 492: ref = build_component_ref (handler, get_identifier ("handler"), NULL_TREE, 0); ! 493: call_to_setjmp = build_function_call (BISJ, build_tree_list (NULL_TREE, ref)); ! 494: ! 495: /* RAISE throws to EXCEPT part. */ ! 496: expand_start_try (build_binary_op (EQ_EXPR, call_to_setjmp, integer_zero_node), 0, 1); ! 497: } ! 498: ! 499: /* If KEEP is 1, then declarations in the TRY statement are worth keeping. ! 500: If KEEP is 2, then the TRY statement was generated by the compiler. ! 501: If KEEP is 0, the declarations in the TRY statement contain errors. */ ! 502: ! 503: tree ! 504: cplus_expand_end_try (keep) ! 505: int keep; ! 506: { ! 507: tree decls, decl, block; ! 508: ! 509: if (keep < 2) ! 510: pop_implicit_try_blocks (NULL_TREE); ! 511: ! 512: decls = getdecls (); ! 513: ! 514: /* Emit code to avoid falling through into a default ! 515: handler that might come later. */ ! 516: expand_end_try (); ! 517: ! 518: /* Pops binding contour local to TRY, and get the exception handler ! 519: object built by `...start_try'. */ ! 520: switch (keep) ! 521: { ! 522: case 0: ! 523: expand_end_bindings (decls, 0, 1); ! 524: block = poplevel (0, 0, 0); ! 525: pop_momentary (); ! 526: decl = getdecls (); ! 527: break; ! 528: ! 529: case 1: ! 530: expand_end_bindings (decls, 1, 1); ! 531: block = poplevel (1, 1, 0); ! 532: pop_momentary (); ! 533: decl = getdecls (); ! 534: break; ! 535: ! 536: default: ! 537: decl = tree_last (decls); ! 538: block = NULL_TREE; ! 539: break; ! 540: } ! 541: ! 542: assert (TREE_CODE (decl) == VAR_DECL && TREE_TYPE (decl) == EHS_type); ! 543: if (block) ! 544: { ! 545: BLOCK_HANDLER_BLOCK (block) = 1; ! 546: TREE_USED (block) = 1; ! 547: } ! 548: ! 549: /* Pass it back so that its rtl can be bound to its name ! 550: (or vice versa). */ ! 551: return decl; ! 552: } ! 553: ! 554: void ! 555: cplus_expand_start_except (name, decl) ! 556: tree name, decl; ! 557: { ! 558: int yes; ! 559: tree tmp, init; ! 560: ! 561: expand_start_except (0, 1); ! 562: ! 563: /* This is internal `eh'. */ ! 564: current_exception_decl = decl; ! 565: current_exception_name_as_rtx ! 566: = expand_expr (build (COMPONENT_REF, ptr_type_node, ! 567: current_exception_decl, TREE_OPERAND (EHS_name, 1)), ! 568: 0, 0, 0); ! 569: init = build (COMPONENT_REF, ptr_type_node, decl, TREE_OPERAND (EHS_parms, 1)); ! 570: current_exception_parms_as_rtx = expand_expr (init, 0, 0, 0); ! 571: ! 572: if (name) ! 573: { ! 574: /* Get the exception object into scope (user declared `ex'). */ ! 575: tmp = pushdecl (build_decl (VAR_DECL, name, ptr_type_node)); ! 576: DECL_INITIAL (tmp) = error_mark_node; ! 577: finish_decl (tmp, init, 0, 0); ! 578: } ! 579: current_exception_type = NULL_TREE; ! 580: yes = suspend_momentary (); ! 581: if (name) ! 582: { ! 583: /* From now on, send the user to our faked-up object. */ ! 584: current_exception_object = build1 (INDIRECT_REF, void_type_node, tmp); ! 585: IDENTIFIER_LOCAL_VALUE (name) = current_exception_object; ! 586: } ! 587: resume_momentary (yes); ! 588: ! 589: /* Pop exception handler stack. */ ! 590: expand_assignment (EHS_decl, EHS_prev, 0, 0); ! 591: } ! 592: ! 593: /* Generate the call to `unhandled_exception' that is appropriate ! 594: for this particular unhandled exception. */ ! 595: static tree ! 596: call_to_unhandled_exception () ! 597: { ! 598: extern int lineno; ! 599: tree parms = tree_cons (NULL_TREE, ! 600: combine_strings (build_string (strlen (input_filename + 1), input_filename)), ! 601: build_tree_list (NULL_TREE, build_int_2 (lineno, 0))); ! 602: return build_function_call (BIUE, parms); ! 603: } ! 604: ! 605: /* Note that this must be mirror image of `...start_try'. ! 606: DFAULT is the default clause, if there was one. ! 607: DFAULT is ERROR_MARK_NODE when this ends an implicit handler. */ ! 608: void ! 609: cplus_expand_end_except (dfault) ! 610: tree dfault; ! 611: { ! 612: extern tree expand_end_except (); /* stmt.c. */ ! 613: tree decls, raised; ! 614: ! 615: if (dfault == NULL_TREE) ! 616: { ! 617: /* Uncaught exception at outermost level. If raised locally, ! 618: reraise the exception. Otherwise, generate code to call `abort'. */ ! 619: if (in_try_block (1) == 0) ! 620: { ! 621: expand_start_cond (build (EQ_EXPR, integer_type_node, ! 622: exception_throw_decl, integer_zero_node), 0); ! 623: expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0); ! 624: expand_end_cond (); ! 625: } ! 626: /* Try the next handler. */ ! 627: if (! expand_escape_except ()) ! 628: compiler_error ("except nesting botch"); ! 629: } ! 630: ! 631: raised = expand_end_except (); ! 632: ! 633: decls = getdecls (); ! 634: expand_end_bindings (decls, decls != 0, 1); ! 635: poplevel (decls != 0, 1, 0); ! 636: ! 637: /* Implicit handlers do not use the momentary obstack. */ ! 638: if (dfault != error_mark_node) ! 639: pop_momentary (); ! 640: ! 641: if (! in_try_block (1)) ! 642: { ! 643: /* Check that this function is not raising exceptions ! 644: it is not supposed to. */ ! 645: while (raised) ! 646: { ! 647: error_with_decl (TREE_VALUE (raised), "exception `%s' raised but not declared raisable"); ! 648: raised = TREE_CHAIN (raised); ! 649: } ! 650: } ! 651: else if (dfault == NULL_TREE || dfault == error_mark_node) ! 652: { ! 653: expand_start_cond (build (NE_EXPR, integer_type_node, ! 654: exception_throw_decl, ! 655: integer_zero_node), 0); ! 656: /* We fell off the end of this try block. Try going to the next. ! 657: The escape_label will be the beginning of the next try block. */ ! 658: if (! expand_escape_except ()) ! 659: compiler_error ("except nesting botch"); ! 660: expand_end_cond (); ! 661: } ! 662: } ! 663: ! 664: /* Generate code to raise exception RAISE_ID. ! 665: If EXP is NULL_TREE, then PARMS is the list of parameters to use ! 666: for constructing this exception. ! 667: If EXP is non-NULL, then it is an already constructed object ! 668: of the kind that we want. ! 669: ! 670: FOR_RERAISE is non-zero if this raise is called by reraise. In ! 671: this case we do not need to emit extra gotos to avoid warning messages; ! 672: the caller will do that once after all the exceptions it reraises ! 673: are handled and raised. */ ! 674: void ! 675: cplus_expand_raise (raise_id, parms, exp, for_reraise) ! 676: tree raise_id; ! 677: tree parms; ! 678: tree exp; ! 679: int for_reraise; ! 680: { ! 681: /* Allocate new exception of appropriate type, passing ! 682: PARMS to its constructor. */ ! 683: tree cname, name; ! 684: tree decl; ! 685: tree xexp = exp; ! 686: ! 687: cname = lookup_exception_cname (current_class_type, current_class_name, raise_id); ! 688: if (cname == error_mark_node) ! 689: return; ! 690: name = TREE_VALUE (raise_id); ! 691: ! 692: decl = lookup_exception_object (cname, name, 1); ! 693: if (decl == NULL_TREE) ! 694: return; ! 695: ! 696: if (exp == NULL_TREE) ! 697: { ! 698: exp = build_method_call (NULL_TREE, name, parms, NULL_TREE, LOOKUP_COMPLAIN); ! 699: if (exp == error_mark_node) ! 700: return; ! 701: } ! 702: ! 703: if (in_try_block (1)) ! 704: { ! 705: expand_raise (decl); ! 706: } ! 707: else if (! current_function_decl) ! 708: { ! 709: if (xexp == NULL_TREE) ! 710: error_with_decl (decl, "invalid raise of `%s' outside of functions"); ! 711: else ! 712: error_with_decl (decl, "invalid reraise of `%s' outside of functions"); ! 713: } ! 714: else ! 715: { ! 716: /* Test this raise against what this function permits. */ ! 717: tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)); ! 718: while (names) ! 719: { ! 720: if (decl == TREE_TYPE (names)) ! 721: break; ! 722: names = TREE_CHAIN (names); ! 723: } ! 724: if (names == NULL_TREE) ! 725: { ! 726: error ("current function not declared to raise exception `%s'", ! 727: IDENTIFIER_POINTER (name)); ! 728: return; ! 729: } ! 730: } ! 731: ! 732: store_expr (exp, EHS_parms_as_rtx, 0); ! 733: ! 734: /* Set the global exception handler stack's NAME field ! 735: to the `name' of this exception. The global exception ! 736: handler stack is the container for the exception object ! 737: we just built. ! 738: ! 739: We go through a function call to make life easier when debugging. */ ! 740: #if 0 ! 741: expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0); ! 742: #else ! 743: parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0), ! 744: build_tree_list (NULL_TREE, ! 745: build_unary_op (ADDR_EXPR, decl, 0))); ! 746: expand_expr (build_function_call (BIR, parms), 0, 0, 0); ! 747: #endif ! 748: ! 749: /* Activate thrower. If we are inside a TRY statement, ! 750: we can cheat and not do this, saving a longjmp. */ ! 751: if (in_try_block (1) == 0) ! 752: { ! 753: sets_exception_throw_decl = 1; ! 754: emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); ! 755: } ! 756: ! 757: if (xexp == NULL_TREE) ! 758: { ! 759: /* Invoke destructors for current procedure or handler. */ ! 760: if (! expand_escape_except ()) ! 761: compiler_error ("except nesting botch"); ! 762: /* Throw via `longjmp'... Done as side-effect of goto. */ ! 763: } ! 764: /* To avoid spurious warning messages, we add a goto to the end ! 765: of the function. This code is dead, and the compiler should ! 766: know how to delete it, but for now, we are stuck with it. */ ! 767: if (! for_reraise ! 768: && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) ! 769: expand_null_return (); ! 770: } ! 771: ! 772: extern tree cplus_exception_name (); ! 773: ! 774: tree ! 775: ansi_exception_object_lookup (type) ! 776: { ! 777: tree raise_id = cplus_exception_name (type); ! 778: tree decl; ! 779: ! 780: decl = IDENTIFIER_GLOBAL_VALUE (raise_id); ! 781: if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL) ! 782: { ! 783: push_obstacks_nochange (); ! 784: end_temporary_allocation (); ! 785: decl = build_decl (VAR_DECL, raise_id, ptr_type_node); ! 786: TREE_PUBLIC (decl) = 1; ! 787: TREE_STATIC (decl) = 1; ! 788: pushdecl_top_level (decl); ! 789: make_decl_rtl (decl, (char*)0, 1); ! 790: pop_obstacks (); ! 791: } ! 792: return decl; ! 793: } ! 794: ! 795: /* Generate code to throw an exception using EXP. ! 796: Usng ANSI syntax and semantics. ! 797: If EXP is NULL_TREE< re-raise instead. */ ! 798: ! 799: void ! 800: cplus_expand_throw (exp) ! 801: tree exp; ! 802: { ! 803: tree parms; ! 804: int for_reraise; ! 805: /* Allocate new exception of appropriate type, passing ! 806: PARMS to its constructor. */ ! 807: tree cname, name; ! 808: tree decl = ansi_exception_object_lookup (TREE_TYPE (exp)); ! 809: tree xexp = exp; ! 810: tree raise_id; ! 811: ! 812: ! 813: if (in_try_block (1)) ! 814: { ! 815: #if 1 ! 816: abort(); ! 817: #else ! 818: expand_raise (decl); ! 819: #endif ! 820: } ! 821: else if (! current_function_decl) ! 822: error ("invalid throw outside of functions"); ! 823: else ! 824: { ! 825: #if 0 ! 826: /* Test this raise against what this function permits. */ ! 827: tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)); ! 828: while (names) ! 829: { ! 830: if (decl == TREE_TYPE (names)) ! 831: break; ! 832: names = TREE_CHAIN (names); ! 833: } ! 834: if (names == NULL_TREE) ! 835: { ! 836: error ("current function not declared to raise exception `%s'", ! 837: IDENTIFIER_POINTER (name)); ! 838: return; ! 839: } ! 840: #endif ! 841: } ! 842: ! 843: store_expr (exp, EHS_parms_as_rtx, 0); ! 844: ! 845: /* Set the global exception handler stack's NAME field ! 846: to the `name' of this exception. The global exception ! 847: handler stack is the container for the exception object ! 848: we just built. ! 849: ! 850: We go through a function call to make life easier when debugging. */ ! 851: #if 0 ! 852: expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0); ! 853: #else ! 854: parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0), ! 855: build_tree_list (NULL_TREE, ! 856: build_unary_op (ADDR_EXPR, decl, 0))); ! 857: expand_expr (build_function_call (BIR, parms), 0, 0, 0); ! 858: #endif ! 859: ! 860: /* Activate thrower. If we are inside a TRY statement, ! 861: we can cheat and not do this, saving a longjmp. */ ! 862: if (in_try_block (1) == 0) ! 863: { ! 864: sets_exception_throw_decl = 1; ! 865: emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); ! 866: } ! 867: ! 868: if (xexp == NULL_TREE) ! 869: { ! 870: /* Invoke destructors for current procedure or handler. */ ! 871: if (! expand_escape_except ()) ! 872: compiler_error ("except nesting botch"); ! 873: /* Throw via `longjmp'... Done as side-effect of goto. */ ! 874: } ! 875: /* To avoid spurious warning messages, we add a goto to the end ! 876: of the function. This code is dead, and the compiler should ! 877: know how to delete it, but for now, we are stuck with it. */ ! 878: if (! for_reraise ! 879: && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) ! 880: expand_null_return (); ! 881: } ! 882: ! 883: tree ! 884: cplus_expand_start_catch (raise_id) ! 885: tree raise_id; ! 886: { ! 887: tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id); ! 888: tree decl; ! 889: tree cond; ! 890: ! 891: if (cname == error_mark_node) ! 892: { ! 893: decl = error_mark_node; ! 894: cond = error_mark_node; ! 895: } ! 896: else ! 897: { ! 898: decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1); ! 899: if (decl == NULL_TREE) ! 900: cond = error_mark_node; ! 901: else ! 902: cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), ! 903: build (COMPONENT_REF, ptr_type_node, ! 904: current_exception_decl, TREE_OPERAND (EHS_name, 1))); ! 905: } ! 906: expand_start_cond (cond, 0); ! 907: ! 908: /* Does nothing right now. */ ! 909: expand_catch (decl); ! 910: if (current_exception_type ! 911: && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) ! 912: { ! 913: /* Make a cleanup for the name-specific exception object now in scope. */ ! 914: tree cleanup = maybe_build_cleanup (current_exception_object); ! 915: expand_start_bindings (0); ! 916: expand_decl_cleanup (NULL_TREE, cleanup); ! 917: } ! 918: return decl; ! 919: } ! 920: tree ! 921: ansi_expand_start_catch (raise_type) ! 922: tree raise_type; ! 923: { ! 924: tree decl = ansi_exception_object_lookup (raise_type); ! 925: tree cond; ! 926: ! 927: if (decl == NULL_TREE) ! 928: cond = error_mark_node; ! 929: else ! 930: cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), ! 931: build (COMPONENT_REF, ptr_type_node, ! 932: current_exception_decl, ! 933: TREE_OPERAND (EHS_name, 1))); ! 934: expand_start_cond (cond, 0); ! 935: ! 936: /* Does nothing right now. */ ! 937: expand_catch (decl); ! 938: return decl; ! 939: } ! 940: ! 941: void ! 942: cplus_expand_end_catch (for_reraise) ! 943: int for_reraise; ! 944: { ! 945: if (current_exception_type ! 946: && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) ! 947: { ! 948: /* Destroy the specific exception object now in scope. */ ! 949: expand_end_bindings (getdecls (), 0, 1); ! 950: } ! 951: if (for_reraise) ! 952: { ! 953: if (! expand_escape_except ()) ! 954: abort (); ! 955: } ! 956: else ! 957: { ! 958: if (! expand_end_catch ()) ! 959: abort (); ! 960: } ! 961: expand_end_cond (); ! 962: } ! 963: ! 964: /* Reraise an exception. ! 965: If EXCEPTIONS is NULL_TREE, it means reraise whatever exception was caught. ! 966: If EXCEPTIONS is an IDENTIFIER_NODE, it means reraise the exception ! 967: object named by EXCEPTIONS. This must be a variable declared in ! 968: an `except' clause. ! 969: If EXCEPTIONS is a TREE_LIST, it is the list of exceptions we are ! 970: willing to reraise. */ ! 971: ! 972: void ! 973: cplus_expand_reraise (exceptions) ! 974: tree exceptions; ! 975: { ! 976: tree ex_ptr; ! 977: tree ex_object = current_exception_object; ! 978: struct rtx_def *ex_ptr_as_rtx; ! 979: ! 980: if (exceptions && TREE_CODE (exceptions) == IDENTIFIER_NODE) ! 981: { ! 982: /* Don't get tripped up if its TREE_TYPE is `error_mark_node'. */ ! 983: ex_object = IDENTIFIER_LOCAL_VALUE (exceptions); ! 984: if (ex_object == NULL_TREE || TREE_CODE (ex_object) != INDIRECT_REF) ! 985: { ! 986: error ("`%s' is not an exception decl", IDENTIFIER_POINTER (exceptions)); ! 987: return; ! 988: } ! 989: assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL); ! 990: exceptions = NULL_TREE; ! 991: } ! 992: ! 993: ex_ptr = build1 (NOP_EXPR, ptr_type_node, TREE_OPERAND (ex_object, 0)); ! 994: ex_ptr_as_rtx = expand_expr (ex_ptr, 0, 0, 0); ! 995: ! 996: /* reraise ALL, used by compiler. */ ! 997: if (exceptions == NULL_TREE) ! 998: { ! 999: /* Now treat reraise like catch/raise. */ ! 1000: expand_catch (error_mark_node); ! 1001: expand_raise (error_mark_node); ! 1002: emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx, 0); ! 1003: store_expr (EHS_parms_as_rtx, current_exception_parms_as_rtx, 0); ! 1004: if (in_try_block (1) == 0) ! 1005: { ! 1006: sets_exception_throw_decl = 1; ! 1007: emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); ! 1008: } ! 1009: /* Set to zero so that destructor will not be called. */ ! 1010: emit_move_insn (ex_ptr_as_rtx, const0_rtx); ! 1011: if (! expand_escape_except ()) ! 1012: abort (); ! 1013: ! 1014: /* To avoid spurious warning messages, we add a goto to the end ! 1015: of the function. This code is dead, and the compiler should ! 1016: know how to delete it, but for now, we are stuck with it. */ ! 1017: if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) ! 1018: expand_null_return (); ! 1019: ! 1020: return; ! 1021: } ! 1022: ! 1023: /* reraise from a list of exceptions. */ ! 1024: while (exceptions) ! 1025: { ! 1026: tree type = lookup_exception_type (current_class_type, current_class_name, ! 1027: exceptions); ! 1028: if (type == NULL_TREE) ! 1029: { ! 1030: error ("`%s' is not an exception type", ! 1031: IDENTIFIER_POINTER (TREE_VALUE (exceptions))); ! 1032: current_exception_type = NULL_TREE; ! 1033: TREE_TYPE (ex_object) = error_mark_node; ! 1034: TREE_TYPE (ex_ptr) = error_mark_node; ! 1035: } ! 1036: else ! 1037: { ! 1038: current_exception_type = type; ! 1039: /* In-place union. */ ! 1040: TREE_TYPE (ex_object) = type; ! 1041: TREE_TYPE (ex_ptr) = TYPE_POINTER_TO (type); ! 1042: } ! 1043: ! 1044: /* Now treat reraise like catch/raise. */ ! 1045: cplus_expand_start_catch (exceptions); ! 1046: cplus_expand_raise (exceptions, NULL_TREE, ex_ptr, 1); ! 1047: /* Set to zero so that destructor will not be called. */ ! 1048: if (TREE_TYPE (ex_ptr) != error_mark_node) ! 1049: emit_move_insn (ex_ptr_as_rtx, const0_rtx); ! 1050: cplus_expand_end_catch (1); ! 1051: exceptions = TREE_CHAIN (exceptions); ! 1052: } ! 1053: /* Don't propagate any unhandled exceptions. */ ! 1054: expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0); ! 1055: ! 1056: /* To avoid spurious warning messages, we add a goto to the end ! 1057: of the function. This code is dead, and the compiler should ! 1058: know how to delete it, but for now, we are stuck with it. */ ! 1059: if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) ! 1060: expand_null_return (); ! 1061: } ! 1062: ! 1063: void ! 1064: setup_exception_throw_decl () ! 1065: { ! 1066: tree call_to_longjmp, parms; ! 1067: ! 1068: int old = suspend_momentary (); ! 1069: ! 1070: exception_throw_decl = build_decl (VAR_DECL, get_identifier (THROW_NAME), integer_type_node); ! 1071: pushdecl (exception_throw_decl); ! 1072: parms = tree_cons (NULL_TREE, EHS_handler, ! 1073: build_tree_list (0, integer_one_node)); ! 1074: call_to_longjmp = build_function_call (BILJ, parms); ! 1075: ! 1076: expand_decl (exception_throw_decl); ! 1077: expand_decl_cleanup (exception_throw_decl, ! 1078: build (COND_EXPR, void_type_node, ! 1079: exception_throw_decl, ! 1080: call_to_longjmp, integer_zero_node)); ! 1081: DECL_INITIAL (exception_throw_decl) = integer_zero_node; ! 1082: sets_exception_throw_decl = 0; ! 1083: resume_momentary (old); ! 1084: ! 1085: /* Cache these, since they won't change throughout the function. */ ! 1086: EHS_parms_as_rtx = expand_expr (EHS_parms, 0, 0, 0); ! 1087: EHS_name_as_rtx = expand_expr (EHS_name, 0, 0, 0); ! 1088: } ! 1089: ! 1090: void ! 1091: init_exception_processing () ! 1092: { ! 1093: extern tree unhandled_exception_fndecl; ! 1094: tree cname = get_identifier ("ExceptionHandler"); ! 1095: tree field, chain; ! 1096: tree ctor, dtor; ! 1097: tree jmp_buf_type = build_array_type (integer_type_node, ! 1098: build_index_type (build_int_2 (_JBLEN-1, 0))); ! 1099: tree jmp_buf_arg_type = build_pointer_type (integer_type_node); ! 1100: ! 1101: tree parmtypes = hash_tree_chain (jmp_buf_arg_type, void_list_node); ! 1102: tree setjmp_fndecl, longjmp_fndecl, raise_fndecl; ! 1103: ! 1104: int old_interface_only = interface_only; ! 1105: int old_interface_unknown = interface_unknown; ! 1106: interface_only = 1; ! 1107: interface_unknown = 0; ! 1108: EHS_type = xref_tag (record_type_node, cname, NULL_TREE); ! 1109: push_lang_context (lang_name_c); ! 1110: setjmp_fndecl = define_function ("setjmp", ! 1111: build_function_type (integer_type_node, ! 1112: parmtypes), ! 1113: NOT_BUILT_IN, pushdecl, 0); ! 1114: BISJ = default_conversion (setjmp_fndecl); ! 1115: parmtypes = hash_tree_chain (jmp_buf_arg_type, ! 1116: hash_tree_chain (integer_type_node, void_list_node)); ! 1117: longjmp_fndecl = define_function ("longjmp", ! 1118: build_function_type (void_type_node, parmtypes), ! 1119: NOT_BUILT_IN, pushdecl, 0); ! 1120: raise_fndecl = define_function ("__raise_exception", ! 1121: build_function_type (void_type_node, ! 1122: hash_tree_chain (ptr_type_node, ! 1123: hash_tree_chain (build_pointer_type (ptr_type_node), void_list_node))), ! 1124: NOT_BUILT_IN, pushdecl, 0); ! 1125: BILJ = default_conversion (longjmp_fndecl); ! 1126: BIR = default_conversion (raise_fndecl); ! 1127: BIUE = default_conversion (unhandled_exception_fndecl); ! 1128: ! 1129: pop_lang_context (); ! 1130: ! 1131: /* finish_struct will pop this. */ ! 1132: pushclass (EHS_type, 0); ! 1133: field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node); ! 1134: chain = field; ! 1135: field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"), ! 1136: build_pointer_type (default_function_type)); ! 1137: TREE_CHAIN (field) = chain; ! 1138: chain = field; ! 1139: field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type); ! 1140: TREE_CHAIN (field) = chain; ! 1141: chain = field; ! 1142: field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"), ! 1143: TYPE_POINTER_TO (EHS_type)); ! 1144: TREE_CHAIN (field) = chain; ! 1145: chain = field; ! 1146: ! 1147: ctor = build_lang_decl (FUNCTION_DECL, cname, ! 1148: build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); ! 1149: DECL_CONSTRUCTOR_P (ctor) = 1; ! 1150: TREE_STATIC (ctor) = 1; ! 1151: TREE_PUBLIC (ctor) = 1; ! 1152: TREE_EXTERNAL (ctor) = 1; ! 1153: grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0); ! 1154: grok_ctor_properties (EHS_type, ctor); ! 1155: finish_decl (pushdecl (ctor), 0, 0, 0); ! 1156: /* Must copy the node here because the FUNCTION_DECL ! 1157: used inside the struct ain't the same as the ! 1158: FUNCTION_DECL we stick into the global binding ! 1159: contour. */ ! 1160: ctor = copy_node (ctor); ! 1161: TREE_CHAIN (ctor) = chain; ! 1162: chain = ctor; ! 1163: dtor = build_lang_decl (FUNCTION_DECL, cname, ! 1164: build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); ! 1165: TREE_STATIC (dtor) = 1; ! 1166: TREE_PUBLIC (dtor) = 1; ! 1167: TREE_EXTERNAL (dtor) = 1; ! 1168: grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0); ! 1169: finish_decl (pushdecl (dtor), 0, 0, 0); ! 1170: /* Copy for the same reason as copying ctor. */ ! 1171: dtor = copy_node (dtor); ! 1172: TREE_CHAIN (dtor) = chain; ! 1173: chain = dtor; ! 1174: TYPE_HAS_CONSTRUCTOR (EHS_type) = 1; ! 1175: TYPE_HAS_DESTRUCTOR (EHS_type) = 1; ! 1176: finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0, 0); ! 1177: interface_only = old_interface_only; ! 1178: interface_unknown = old_interface_unknown; ! 1179: } ! 1180: ! 1181: void ! 1182: init_exception_processing_1 () ! 1183: { ! 1184: register tree EHS_id = get_identifier ("exceptionHandlerStack"); ! 1185: ! 1186: EHS_decl = IDENTIFIER_GLOBAL_VALUE (EHS_id); ! 1187: ! 1188: /* If we have no other definition, default to library implementation. */ ! 1189: if (EHS_decl == NULL_TREE) ! 1190: { ! 1191: EHS_decl = build_decl (VAR_DECL, EHS_id, TYPE_POINTER_TO (EHS_type)); ! 1192: /* If we don't push this, its definition, should it be encountered, ! 1193: will not be seen. */ ! 1194: EHS_decl = pushdecl (EHS_decl); ! 1195: TREE_EXTERNAL (EHS_decl) = 1; ! 1196: TREE_STATIC (EHS_decl) = 1; ! 1197: TREE_PUBLIC (EHS_decl) = 1; ! 1198: finish_decl (EHS_decl, 0, 0, 0); ! 1199: } ! 1200: else if (TREE_CODE (EHS_decl) != VAR_DECL ! 1201: || TREE_TYPE (EHS_decl) != TYPE_POINTER_TO (EHS_type)) ! 1202: fatal ("exception handling declarations conflict with compiler's internal model"); ! 1203: ! 1204: if (EHS_prev == NULL_TREE) ! 1205: { ! 1206: register tree EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl); ! 1207: EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0); ! 1208: EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0); ! 1209: EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0); ! 1210: EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0); ! 1211: } ! 1212: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.