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