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