From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26160 invoked by alias); 6 Nov 2002 07:03:56 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 26152 invoked from network); 6 Nov 2002 07:03:53 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 6 Nov 2002 07:03:53 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id gA66fKw28006 for ; Wed, 6 Nov 2002 01:41:20 -0500 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id gA673nf26758; Wed, 6 Nov 2002 02:03:49 -0500 Received: from frogsleap.quesejoda.com (sebastian-int.corp.redhat.com [172.16.52.221]) by pobox.corp.redhat.com (8.11.6/8.11.6) with ESMTP id gA673lT03436; Wed, 6 Nov 2002 02:03:48 -0500 Received: by frogsleap.quesejoda.com (Postfix, from userid 500) id 601653C270; Tue, 5 Nov 2002 23:06:22 -0800 (PST) Date: Tue, 05 Nov 2002 23:03:00 -0000 From: Aldy Hernandez To: Richard Henderson , gcc-patches@gcc.gnu.org, jakub@redhat.com, jason@redhat.com Subject: Re: [basic-improvements] try/finally support for c/c++ Message-ID: <20021106070622.GA31658@redhat.com> References: <20021105231902.GA13127@redhat.com> <20021105235718.GC20967@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline In-Reply-To: <20021105235718.GC20967@redhat.com> User-Agent: Mutt/1.4i X-SW-Source: 2002-11/txt/msg00259.txt.bz2 All your suggestions (and Geoff's) addressed. > > + Add new text at the end of section 2. > > + > > + @quotation > > + Before control is transferred to the desired destination, the > > + __finally block is executed. After such block is executed, control is > > + transferred to the desired destination. > > + @end quotation > > There's got to be a better way to say this... Dunno what though. See next attempt. > > + @quotation > > + If code within a @i{try} block (or within code called from a try > > + block) causes an exception that is not caught by the subsequent > > + @i{catch} blocks, the code in @i{__finally} executes as the stack > > + unwinds upwards. > > + @end quotation > > "Upwards" is bad language. See the existing language that > uses "path". See next attempt. > You probably need to define __finally in terms of destructors > in order for this to work out properly. E.g. a finally block > is the destructor for an anonymous object of an anonymous type. > Or something. Perhaps Jason or Mark could help here? Help, help. I'm being repressed. Jason, Mark? BTW: If you're comfortable with the code I can start just posting the doc/extend.texi patches so we can iterate over that and not spam the list every time with the enire patchset. How does this new version look? Aldy 2002-11-05 Aldy Hernandez * Makefile.in (LIB2FUNCS_EXTRA): Add eh-personality-c.c. (c-semantics.o): Depend on libfuncs.h and except.h. * testsuite/gcc.c-torture/execute/try-finally-1.c: New. * testsuite/gcc.c-torture/execute/try-finally-2.c: New. * c-decl.c (c_init_decl_processing): Set eh_personality_libfunc. Use EH for cleanups. Include libfuncs.h, except.h. * eh-personality-c.c: New file. * c-common.def (TRY_FINALLY_STMT): New. * c-semantics.c (expand_stmt): Add TRY_FINALLY_STMT case. (genrtl_try_finally_stmt): New. * c-tree.h: Add prototype to build_try_finally_stmt. * c-typeck.c (build_try_finally_stmt): New. * c-common.c (statement_code_p): Add case for TRY_FINALLY_STMT. * c-common.h (enum rid): Add RID_FINALLY. Add prototype for genrtl_try_finally_stmt. (TRY_FINALLY_TRY): New. (TRY_FINALLY_FINALLY): New. * c-parse.in: Add FINALLY tokens. (reswords): Add __try and __finally. (rid_to_yy): Add RID_FINALLY. Enable RID_TRY. (stmt): Add try/finally grammar case. (try_finally_begin): New production. * cp/lex.c (reswords): Add __finally, __try tokens. (rid_to_yy): Add FINALLY. * doc/extend.texi: Add documentation for try/finally. 2002-11-05 Jason Merrill * cp/cp-tree.h: Add prototypes for finish_try_finally_try and finish_try_finally_finally. * cp/parse.y: Add FINALLY token. Add handler_seq and finally_stmt productions. Modify try_block to handle try/finally. * cp/pt.c (tsubst_expr): Add case for TRY_FINALLY_STMT. * cp/semantics.c (genrtl_try_block): Handle try/finally. (begin_try_finally): New. (finish_try_finally_try): New. (finish_try_finally_finally): New. Index: Makefile.in =================================================================== RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v retrieving revision 1.939.2.10 diff -c -p -r1.939.2.10 Makefile.in *** Makefile.in 21 Oct 2002 17:51:50 -0000 1.939.2.10 --- Makefile.in 6 Nov 2002 06:58:05 -0000 *************** USE_COLLECT2 = collect2$(exeext) *** 435,441 **** # List of extra C and assembler files to add to static and shared libgcc2. # Assembler files should have names ending in `.asm'. ! LIB2FUNCS_EXTRA = # List of extra C and assembler files to add to static libgcc2. # Assembler files should have names ending in `.asm'. --- 435,441 ---- # List of extra C and assembler files to add to static and shared libgcc2. # Assembler files should have names ending in `.asm'. ! LIB2FUNCS_EXTRA = $(srcdir)/eh-personality-c.c # List of extra C and assembler files to add to static libgcc2. # Assembler files should have names ending in `.asm'. *************** c-format.o : c-format.c $(CONFIG_H) $(SY *** 1252,1257 **** --- 1252,1258 ---- c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) \ flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ + libfuncs.h except.h \ $(EXPR_H) $(PREDICT_H) c-dump.o : c-dump.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) tree-dump.h Index: eh-personality-c.c =================================================================== RCS file: eh-personality-c.c diff -N eh-personality-c.c *** /dev/null 1 Jan 1970 00:00:00 -0000 --- eh-personality-c.c 6 Nov 2002 06:58:10 -0000 *************** *** 0 **** --- 1,185 ---- + /* Supporting functions for C exception handling. + + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Aldy Hernandez . + Shamelessly stolen from the Java front end. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + #include "tconfig.h" + #include "tsystem.h" + #include "unwind.h" + #include "unwind-pe.h" + + typedef struct + { + _Unwind_Ptr Start; + _Unwind_Ptr LPStart; + _Unwind_Ptr ttype_base; + const unsigned char *TType; + const unsigned char *action_table; + unsigned char ttype_encoding; + unsigned char call_site_encoding; + } lsda_header_info; + + static const unsigned char * + parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, + lsda_header_info *info) + { + _Unwind_Word tmp; + unsigned char lpstart_encoding; + + info->Start = (context ? _Unwind_GetRegionStart (context) : 0); + + /* Find @LPStart, the base to which landing pad offsets are relative. */ + lpstart_encoding = *p++; + if (lpstart_encoding != DW_EH_PE_omit) + p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); + else + info->LPStart = info->Start; + + /* Find @TType, the base of the handler and exception spec type data. */ + info->ttype_encoding = *p++; + if (info->ttype_encoding != DW_EH_PE_omit) + { + p = read_uleb128 (p, &tmp); + info->TType = p + tmp; + } + else + info->TType = 0; + + /* The encoding and length of the call-site table; the action table + immediately follows. */ + info->call_site_encoding = *p++; + p = read_uleb128 (p, &tmp); + info->action_table = p + tmp; + + return p; + } + + #ifdef __USING_SJLJ_EXCEPTIONS__ + #define PERSONALITY_FUNCTION __gcc_personality_sj0 + #define __builtin_eh_return_data_regno(x) x + #else + #define PERSONALITY_FUNCTION __gcc_personality_v0 + #endif + #define PERSONALITY_FUNCTION __gcc_personality_v0 + + _Unwind_Reason_Code + PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, + struct _Unwind_Exception *, struct _Unwind_Context *); + + _Unwind_Reason_Code + PERSONALITY_FUNCTION (int version, + _Unwind_Action actions, + _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) + { + lsda_header_info info; + const unsigned char *language_specific_data, *p, *action_record; + _Unwind_Ptr landing_pad, ip; + + if (version != 1) + return _URC_FATAL_PHASE1_ERROR; + + /* Currently we only support cleanups for C. */ + if (!(actions &_UA_CLEANUP_PHASE)) + return _URC_CONTINUE_UNWIND; + + language_specific_data = (const unsigned char *) + _Unwind_GetLanguageSpecificData (context); + + /* If no LSDA, then there are no handlers or cleanups. */ + if (! language_specific_data) + return _URC_CONTINUE_UNWIND; + + /* Parse the LSDA header. */ + p = parse_lsda_header (context, language_specific_data, &info); + ip = _Unwind_GetIP (context) - 1; + landing_pad = 0; + + #ifdef __USING_SJLJ_EXCEPTIONS__ + /* The given "IP" is an index into the call-site table, with two + exceptions -- -1 means no-action, and 0 means terminate. But + since we're using uleb128 values, we've not got random access + to the array. */ + if ((int) ip <= 0) + return _URC_CONTINUE_UNWIND; + else + { + _Unwind_Word cs_lp, cs_action; + do + { + p = read_uleb128 (p, &cs_lp); + p = read_uleb128 (p, &cs_action); + } + while (--ip); + + /* Can never have null landing pad for sjlj -- that would have + been indicated by a -1 call site index. */ + landing_pad = cs_lp + 1; + if (cs_action) + action_record = info.action_table + cs_action - 1; + goto found_something; + } + #else + /* Search the call-site table for the action associated with this IP. */ + while (p < info.action_table) + { + _Unwind_Ptr cs_start, cs_len, cs_lp; + _Unwind_Word cs_action; + + /* Note that all call-site encodings are "absolute" displacements. */ + p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); + p = read_uleb128 (p, &cs_action); + + /* The table is sorted, so if we've passed the ip, stop. */ + if (ip < info.Start + cs_start) + p = info.action_table; + else if (ip < info.Start + cs_start + cs_len) + { + if (cs_lp) + landing_pad = info.LPStart + cs_lp; + if (cs_action) + action_record = info.action_table + cs_action - 1; + goto found_something; + } + } + + #endif + + /* Blahhh. IP is not in table. Run away. */ + return _URC_CONTINUE_UNWIND; + + found_something: + if (landing_pad == 0) + { + /* IP is present, but has a null landing pad. No handler to be + run. */ + return _URC_CONTINUE_UNWIND; + } + + _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), + (_Unwind_Ptr) ue_header); + _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); + _Unwind_SetIP (context, landing_pad); + return _URC_INSTALL_CONTEXT; + } Index: c-common.def =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-common.def,v retrieving revision 1.11.8.2 diff -c -p -r1.11.8.2 c-common.def *** c-common.def 1 Oct 2002 17:31:37 -0000 1.11.8.2 --- c-common.def 6 Nov 2002 06:58:10 -0000 *************** DEFTREECODE (SCOPE_STMT, "scope_stmt", ' *** 96,101 **** --- 96,105 ---- other semantics. FILE_STMT_FILENAME gives the name. */ DEFTREECODE (FILE_STMT, "file_stmt", 'e', 1) + /* Describe a try/finally construct. TRY_FINALLY_TRY gives the try + block. TRY_FINALLY_FINALLY gives the finally block. */ + DEFTREECODE (TRY_FINALLY_STMT, "try_finally_stmt", 'e', 2) + /* Used to represent a CASE_LABEL. The operands are CASE_LOW and CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a 'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case Index: c-semantics.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-semantics.c,v retrieving revision 1.44.4.4 diff -c -p -r1.44.4.4 c-semantics.c *** c-semantics.c 1 Oct 2002 17:31:38 -0000 1.44.4.4 --- c-semantics.c 6 Nov 2002 06:58:10 -0000 *************** Software Foundation, 59 Temple Place - S *** 37,42 **** --- 37,44 ---- #include "output.h" #include "timevar.h" #include "predict.h" + #include "except.h" + #include "libfuncs.h" /* If non-NULL, the address of a language-specific function for expanding statements. */ *************** genrtl_decl_cleanup (t) *** 762,767 **** --- 764,813 ---- expand_decl_cleanup_eh (decl, CLEANUP_EXPR (t), CLEANUP_EH_ONLY (t)); } + /* Generate the RTL for a TRY_FINALLY_STMT. */ + + void + genrtl_try_finally_stmt (t) + tree t; + { + tree try_block, finally_block; + static bool eh_initialized_p; + + if (!TRY_FINALLY_FINALLY (t)) + { + /* For a C++ try-block, we create both a TRY_FINALLY_STMT and a + TRY_BLOCK, even if one of them is unnecessary. We have to do this + because they need to be added before the contents of the + try-block. Hopefully this will be fixed with the new parser. + + If there's no finally block, ignore the TRY_FINALLY_STMT. */ + expand_stmt (TRY_FINALLY_TRY (t)); + return; + } + + if (flag_exceptions && !eh_initialized_p) + { + eh_initialized_p = true; + eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS + ? "__gcc_personality_sj0" + : "__gcc_personality_v0"); + using_eh_for_cleanups (); + } + + try_block = TRY_FINALLY_TRY (t); + finally_block = TRY_FINALLY_FINALLY (t); + + try_block = build1 (STMT_EXPR, void_type_node, try_block); + finally_block = build1 (STMT_EXPR, void_type_node, finally_block); + TREE_SIDE_EFFECTS (try_block) = 1; + TREE_SIDE_EFFECTS (finally_block) = 1; + + /* Wrap in TRY_FINALLY_EXPR and punt it off. */ + t = build (TRY_FINALLY_EXPR, void_type_node, try_block, finally_block); + expand_expr (t, NULL, VOIDmode, EXPAND_NORMAL); + return; + } + /* We're about to expand T, a statement. Set up appropriate context for the substitution. */ *************** expand_stmt (t) *** 874,879 **** --- 920,929 ---- case CLEANUP_STMT: genrtl_decl_cleanup (t); + break; + + case TRY_FINALLY_STMT: + genrtl_try_finally_stmt (t); break; default: Index: c-tree.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v retrieving revision 1.105.4.2 diff -c -p -r1.105.4.2 c-tree.h *** c-tree.h 17 Sep 2002 22:58:37 -0000 1.105.4.2 --- c-tree.h 6 Nov 2002 06:58:10 -0000 *************** extern void c_finish_case *** 296,301 **** --- 296,302 ---- extern tree simple_asm_stmt PARAMS ((tree)); extern tree build_asm_stmt PARAMS ((tree, tree, tree, tree, tree)); + extern tree build_try_finally_stmt PARAMS ((tree, tree)); extern tree c_convert_parm_for_inlining PARAMS ((tree, tree, tree)); /* Set to 0 at beginning of a function definition, set to 1 if Index: c-typeck.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v retrieving revision 1.203.4.5 diff -c -p -r1.203.4.5 c-typeck.c *** c-typeck.c 15 Oct 2002 01:32:45 -0000 1.203.4.5 --- c-typeck.c 6 Nov 2002 06:58:15 -0000 *************** build_asm_stmt (cv_qualifier, string, ou *** 6904,6909 **** --- 6904,6919 ---- outputs, inputs, clobbers)); } + tree + build_try_finally_stmt (try_block, finally_block) + tree try_block, finally_block; + { + tree t; + + t = build (TRY_FINALLY_STMT, void_type_node, try_block, finally_block); + return t; + } + /* Expand an ASM statement with operands, handling output operands that are not variables or INDIRECT_REFS by transforming such cases into cases that expand_asm_operands can handle. Index: c-common.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-common.c,v retrieving revision 1.366.4.6 diff -c -p -r1.366.4.6 c-common.c *** c-common.c 21 Oct 2002 17:51:51 -0000 1.366.4.6 --- c-common.c 6 Nov 2002 06:58:19 -0000 *************** statement_code_p (code) *** 3914,3919 **** --- 3914,3920 ---- case ASM_STMT: case FILE_STMT: case CASE_LABEL: + case TRY_FINALLY_STMT: return 1; default: Index: c-common.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-common.h,v retrieving revision 1.154.4.3 diff -c -p -r1.154.4.3 c-common.h *** c-common.h 1 Oct 2002 17:31:37 -0000 1.154.4.3 --- c-common.h 6 Nov 2002 06:58:20 -0000 *************** enum rid *** 77,82 **** --- 77,83 ---- RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG, RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_PTRBASE, RID_PTREXTENT, RID_PTRVALUE, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, + RID_FINALLY, /* Too many ways of getting the name of a function as a string */ RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME, *************** extern tree strip_array_types *** 1097,1102 **** --- 1098,1110 ---- #define FILE_STMT_FILENAME(NODE) \ (IDENTIFIER_POINTER (FILE_STMT_FILENAME_NODE (NODE))) + /* The try block of a try/finally construct. */ + #define TRY_FINALLY_TRY(NODE) \ + (TREE_OPERAND (TRY_FINALLY_STMT_CHECK (NODE), 0)) + /* The finally block of a try/finally construct. */ + #define TRY_FINALLY_FINALLY(NODE) \ + (TREE_OPERAND (TRY_FINALLY_STMT_CHECK (NODE), 1)) + /* The line-number at which a statement began. But if STMT_LINENO_FOR_FN_P does holds, then this macro gives the line number for the end of the current function instead. */ *************** extern void genrtl_asm_stmt *** 1146,1151 **** --- 1154,1160 ---- tree, tree, tree, int)); extern void genrtl_decl_cleanup PARAMS ((tree)); + extern void genrtl_try_finally_stmt PARAMS ((tree)); extern int stmts_are_full_exprs_p PARAMS ((void)); extern int anon_aggr_type_p PARAMS ((tree)); Index: c-parse.in =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v retrieving revision 1.152 diff -c -p -r1.152 c-parse.in *** c-parse.in 15 Aug 2002 21:16:23 -0000 1.152 --- c-parse.in 6 Nov 2002 06:58:22 -0000 *************** do { \ *** 150,155 **** --- 150,156 ---- %token ATTRIBUTE EXTENSION LABEL %token REALPART IMAGPART VA_ARG CHOOSE_EXPR TYPES_COMPATIBLE_P %token PTR_VALUE PTR_BASE PTR_EXTENT + %token TRY FINALLY /* function name can be a string const or a var decl. */ %token STRING_FUNC_NAME VAR_FUNC_NAME *************** do { \ *** 212,218 **** %type any_word extension %type compstmt compstmt_start compstmt_nostart compstmt_primary_start ! %type do_stmt_start poplevel stmt label %type c99_block_start c99_block_end %type declarator --- 213,219 ---- %type any_word extension %type compstmt compstmt_start compstmt_nostart compstmt_primary_start ! %type do_stmt_start poplevel stmt label try_finally_begin %type c99_block_start c99_block_end %type declarator *************** for_init_stmt: *** 2363,2372 **** --- 2364,2386 ---- { check_for_loop_decls (); } ; + try_finally_begin: TRY + { + $$ = add_stmt (build_stmt (TRY_FINALLY_STMT, NULL_TREE)); + } + ; + /* Parse a single real statement, not including any labels. */ stmt: compstmt { stmt_count++; $$ = $1; } + | try_finally_begin compstmt + { RECHAIN_STMTS ($1, TRY_FINALLY_TRY ($1)); } + FINALLY compstmt + { stmt_count++; + RECHAIN_STMTS ($1, TRY_FINALLY_FINALLY ($1)); + $$ = $1; + } | expr ';' { stmt_count++; $$ = c_expand_expr_stmt ($1); } *************** static const struct resword reswords[] = *** 3322,3327 **** --- 3336,3342 ---- { "__const", RID_CONST, 0 }, { "__const__", RID_CONST, 0 }, { "__extension__", RID_EXTENSION, 0 }, + { "__finally", RID_FINALLY, 0 }, { "__func__", RID_C99_FUNCTION_NAME, 0 }, { "__imag", RID_IMAGPART, 0 }, { "__imag__", RID_IMAGPART, 0 }, *************** static const struct resword reswords[] = *** 3341,3346 **** --- 3356,3362 ---- { "__signed", RID_SIGNED, 0 }, { "__signed__", RID_SIGNED, 0 }, { "__thread", RID_THREAD, 0 }, + { "__try", RID_TRY, 0 }, { "__typeof", RID_TYPEOF, 0 }, { "__typeof__", RID_TYPEOF, 0 }, { "__unbounded", RID_UNBOUNDED, 0 }, *************** static const short rid_to_yy[RID_MAX] = *** 3493,3498 **** --- 3509,3516 ---- /* RID_CHOOSE_EXPR */ CHOOSE_EXPR, /* RID_TYPES_COMPATIBLE_P */ TYPES_COMPATIBLE_P, + /* RID_FINALLY */ FINALLY, + /* RID_FUNCTION_NAME */ STRING_FUNC_NAME, /* RID_PRETTY_FUNCTION_NAME */ STRING_FUNC_NAME, /* RID_C99_FUNCTION_NAME */ VAR_FUNC_NAME, *************** static const short rid_to_yy[RID_MAX] = *** 3515,3521 **** /* RID_THIS */ 0, /* RID_THROW */ 0, /* RID_TRUE */ 0, ! /* RID_TRY */ 0, /* RID_TYPENAME */ 0, /* RID_TYPEID */ 0, /* RID_USING */ 0, --- 3533,3539 ---- /* RID_THIS */ 0, /* RID_THROW */ 0, /* RID_TRUE */ 0, ! /* RID_TRY */ TRY, /* RID_TYPENAME */ 0, /* RID_TYPEID */ 0, /* RID_USING */ 0, Index: testsuite/gcc.c-torture/execute/try-finally-1.c =================================================================== RCS file: testsuite/gcc.c-torture/execute/try-finally-1.c diff -N testsuite/gcc.c-torture/execute/try-finally-1.c *** /dev/null 1 Jan 1970 00:00:00 -0000 --- testsuite/gcc.c-torture/execute/try-finally-1.c 6 Nov 2002 06:58:22 -0000 *************** *** 0 **** --- 1,43 ---- + int caught; + + void doit (void) + { + __try { + return; + } __finally { + caught = 1; + } + } + + void doit_again (void) + { + caught = 0; + + while (1) { + __try { + __try { + return; + } __finally { + caught = 1; + } + } __finally { + if (!caught) + abort (); + caught = 2; + } + } + abort (); + } + + int main () + { + doit (); + if (caught != 1) + abort (); + + doit_again (); + if (caught != 2) + abort (); + + return 0; + } Index: testsuite/gcc.c-torture/execute/try-finally-2.c =================================================================== RCS file: testsuite/gcc.c-torture/execute/try-finally-2.c diff -N testsuite/gcc.c-torture/execute/try-finally-2.c *** /dev/null 1 Jan 1970 00:00:00 -0000 --- testsuite/gcc.c-torture/execute/try-finally-2.c 6 Nov 2002 06:58:22 -0000 *************** *** 0 **** --- 1,26 ---- + int caught; + + void doit (int i) + { + caught = 0; + __try { + if (!i) + return; + } __finally { + caught = 1; + } + caught = 2; + } + + int main () + { + doit (0); + if (caught != 1) + abort (); + + doit (1); + if (caught != 2) + abort (); + + return 0; + } Index: cp/lex.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/lex.c,v retrieving revision 1.289.4.3 diff -c -p -r1.289.4.3 lex.c *** cp/lex.c 21 Oct 2002 17:52:56 -0000 1.289.4.3 --- cp/lex.c 6 Nov 2002 06:58:23 -0000 *************** static const struct resword reswords[] = *** 345,350 **** --- 345,351 ---- { "__const__", RID_CONST, 0 }, { "__extension__", RID_EXTENSION, 0 }, { "__func__", RID_C99_FUNCTION_NAME, 0 }, + { "__finally", RID_FINALLY, 0 }, { "__imag", RID_IMAGPART, 0 }, { "__imag__", RID_IMAGPART, 0 }, { "__inline", RID_INLINE, 0 }, *************** static const struct resword reswords[] = *** 358,363 **** --- 359,365 ---- { "__signed", RID_SIGNED, 0 }, { "__signed__", RID_SIGNED, 0 }, { "__thread", RID_THREAD, 0 }, + { "__try", RID_TRY, 0 }, { "__typeof", RID_TYPEOF, 0 }, { "__typeof__", RID_TYPEOF, 0 }, { "__volatile", RID_VOLATILE, 0 }, *************** const short rid_to_yy[RID_MAX] = *** 507,512 **** --- 509,515 ---- /* RID_PTRVALUE */ 0, /* RID_CHOOSE_EXPR */ 0, /* RID_TYPES_COMPATIBLE_P */ 0, + /* RID_FINALLY */ FINALLY, /* RID_FUNCTION_NAME */ VAR_FUNC_NAME, /* RID_PRETTY_FUNCTION_NAME */ VAR_FUNC_NAME, Index: cp/cp-tree.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v retrieving revision 1.744.4.7 diff -c -p -r1.744.4.7 cp-tree.h *** cp/cp-tree.h 21 Oct 2002 17:52:51 -0000 1.744.4.7 --- cp/cp-tree.h 6 Nov 2002 06:58:27 -0000 *************** extern void finish_handler_parms *** 4106,4111 **** --- 4106,4113 ---- extern void begin_catch_block PARAMS ((tree)); extern void finish_handler PARAMS ((tree)); extern void finish_cleanup PARAMS ((tree, tree)); + extern void finish_try_finally_try PARAMS ((tree)); + extern void finish_try_finally_finally PARAMS ((tree)); extern tree begin_compound_stmt PARAMS ((int)); extern tree finish_compound_stmt PARAMS ((int, tree)); extern tree finish_asm_stmt PARAMS ((tree, tree, tree, tree, tree)); Index: cp/parse.y =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/parse.y,v retrieving revision 1.279.4.3 diff -c -p -r1.279.4.3 parse.y *** cp/parse.y 21 Oct 2002 17:52:57 -0000 1.279.4.3 --- cp/parse.y 6 Nov 2002 06:58:29 -0000 *************** check_class_key (key, aggr) *** 323,328 **** --- 323,329 ---- %token SIGOF %token ATTRIBUTE EXTENSION LABEL %token REALPART IMAGPART VA_ARG + %token FINALLY /* the reserved words... C++ extensions */ %token AGGR *************** check_class_key (key, aggr) *** 463,468 **** --- 464,470 ---- %type identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN %type handler_args %type self_template_type finish_template_type_ + %type handler_seq finally_stmt %token NSNAME %type NSNAME *************** function_try_block: *** 3552,3575 **** try_block: TRY ! { $$ = begin_try_block (); } compstmt { finish_try_block ($2); } handler_seq ! { finish_handler_sequence ($2); } ; handler_seq: handler | handler_seq handler | /* empty */ { /* Generate a fake handler block to avoid later aborts. */ tree fake_handler = begin_handler (); finish_handler_parms (NULL_TREE, fake_handler); finish_handler (fake_handler); ! $$ = fake_handler; ! ! error ("must have at least one catch per try block"); } ; --- 3554,3597 ---- try_block: TRY ! { ! $1 = begin_try_finally (); ! $$ = begin_try_block (); ! } compstmt { finish_try_block ($2); } handler_seq ! { ! finish_handler_sequence ($2); ! finish_try_finally_try ($1); ! } ! finally_stmt ! { ! finish_try_finally_finally ($1); ! ! if (!$5 && !$7) ! error ("must have at least one catch per try block"); ! } ! ; ! ! finally_stmt: ! FINALLY compstmt ! { $$ = 1; } ! | /* empty */ ! { $$ = 0; } ; handler_seq: handler + { $$ = 1; } | handler_seq handler + { $$ = 1; } | /* empty */ { /* Generate a fake handler block to avoid later aborts. */ tree fake_handler = begin_handler (); finish_handler_parms (NULL_TREE, fake_handler); finish_handler (fake_handler); ! $$ = 0; } ; Index: cp/pt.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v retrieving revision 1.610.4.4 diff -c -p -r1.610.4.4 pt.c *** cp/pt.c 15 Oct 2002 01:33:31 -0000 1.610.4.4 --- cp/pt.c 6 Nov 2002 06:58:35 -0000 *************** tsubst_expr (t, args, complain, in_decl) *** 7657,7662 **** --- 7657,7671 ---- finish_handler_sequence (stmt); } break; + + case TRY_FINALLY_STMT: + prep_stmt (t); + stmt = begin_try_finally (); + tsubst_expr (TRY_FINALLY_TRY (t), args, complain, in_decl); + finish_try_finally_try (stmt); + tsubst_expr (TRY_FINALLY_FINALLY (t), args, complain, in_decl); + finish_try_finally_finally (stmt); + break; case HANDLER: { Index: cp/semantics.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v retrieving revision 1.274.4.5 diff -c -p -r1.274.4.5 semantics.c *** cp/semantics.c 21 Oct 2002 17:52:57 -0000 1.274.4.5 --- cp/semantics.c 6 Nov 2002 06:58:37 -0000 *************** static void *** 598,603 **** --- 598,615 ---- genrtl_try_block (t) tree t; { + if (!TRY_HANDLERS (t)) + { + /* For a C++ try-block, we create both a TRY_FINALLY_STMT and a + TRY_BLOCK, even if one of them is unnecessary. We have to do this + because they need to be added before the contents of the + try-block. Hopefully this will be fixed with the new parser. + + If there are no handlers, ignore the TRY_BLOCK. */ + expand_stmt (TRY_STMTS (t)); + return; + } + if (CLEANUP_P (t)) { expand_eh_region_start (); *************** finish_handler (handler) *** 805,810 **** --- 817,854 ---- expand_end_catch_block (); do_poplevel (); RECHAIN_STMTS (handler, HANDLER_BODY (handler)); + } + + /* Begin a try/finally construct. The parser calls this immediately before + begin_try_block, as one 'try' could start either a normal C++ try-block, + a try/finally construct, or both. */ + + tree + begin_try_finally () + { + tree r = build_stmt (TRY_FINALLY_STMT, NULL_TREE, NULL_TREE); + add_stmt (r); + return r; + } + + /* Finish the body of a try/finally construct. This usually consists of a + TRY_BLOCK. */ + + void + finish_try_finally_try (try_finally) + tree try_finally; + { + RECHAIN_STMTS (try_finally, TRY_FINALLY_TRY (try_finally)); + } + + /* Finish the finally block of a try/finally construct. This will be + NULL_TREE in the case of a normal C++ try-block. */ + + void + finish_try_finally_finally (try_finally) + tree try_finally; + { + RECHAIN_STMTS (try_finally, TRY_FINALLY_FINALLY (try_finally)); } /* Begin a compound-statement. If HAS_NO_SCOPE is nonzero, the Index: doc/extend.texi =================================================================== RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v retrieving revision 1.95.4.5 diff -c -p -r1.95.4.5 extend.texi *** doc/extend.texi 21 Oct 2002 17:52:59 -0000 1.95.4.5 --- doc/extend.texi 6 Nov 2002 06:58:43 -0000 *************** extensions, accepted by GCC in C89 mode *** 473,478 **** --- 473,479 ---- * Target Builtins:: Built-in functions specific to particular targets. * Pragmas:: Pragmas accepted by GCC. * Unnamed Fields:: Unnamed struct/union fields within structs/unions. + * Try-finally:: Try/finally construct. * Thread-Local:: Per-thread variables. @end menu *************** struct @{ *** 6506,6511 **** --- 6507,6746 ---- It is ambiguous which @code{a} is being referred to with @samp{foo.a}. Such constructs are not supported and must be avoided. In the future, such constructs may be detected and treated as compilation errors. + + @node Try-finally + @section Try/finally exceptions + @cindex Try/finally exceptions + @cindex try-finally + @cindex __try + @cindex __finally + + The @code{__try/__finally} statement consists of a @code{__try} block + containing one or statements, and a @code{__finally} block contatining + one or more statements. The @code{__finally} block will execute after + the @code{__try} block but before the code following the + @code{__try/__finally} construct, even if the @code{__try} block exits + the current function. + + For example: + + @example + __try @{ + do_something(); + return; + @} __finally @{ + fin = 1; + @} + @end example + + In the above example, @code{fin} will get set to 1 before the function + returns to its caller. + + You can nest more than one @code{__try/__finally} construct. + + Since C++ already has a @code{try} keyword, both @code{try} and + @code{__try} variations are allowed. Also, the C++ implementation + allows using @code{__finally} after a series of @code{try/catch} + blocks. The @code{__finally} code will be executed after the + applicable @code{catch}. For example: + + @example + try @{ + do_something(); + @} catch (blah) @{ + x = 0; + @} catch (...) @{ + x = 1; + @} __finally @{ + y = 2; + @} + @end example + + In the example above, @code{y} will be set after the set to @code{x} + in the catch clause. + + It is possible to have a C @code{__try/__finally} construct call C++ + code that throws an exception. As part of the unwind process, the C + @code{__finally} block will be called before control is returned to + the C's calling routine. + + Exiting out of a finally block through a @code{return} or @code{goto} + has undefined behaviour. + + GCC's @code{__try/__finally} implementation is analogous to the + corresponding construct in Java. + + @menu + * C99 Try-Finally Edits:: + * C++98 Try-Finally Edits:: + @end menu + + @node C99 Try-Finally Edits + @subsection ISO/IEC 9899:1999 Edits for Try-Finally + + The following are a set of changes to ISO/IEC 9899:1999 (aka C99) + that document the exact semantics of the language extension. + + @itemize @bullet + @item + @cite{6.4.1 Keywords} + + Add @code{__try}. + Add @code{__finally}. + + @item + @cite{6.8.2b The try/finally statement} + + New section. + + @quotation + Syntax: + @example + try-finally-statement: + @b{__try} + @i{compound-statement} + @b{__finally} + @i{compound-statement} + + @end example + @end quotation + + The @code{__try} block is executed. After the __try block exits, + control is transferred to the @code{__finally} block regardless of how + the __try block exits (with the exception of program termination or + longjump exits out of the try block). + + The __finally block is guaranteed to execute after the __try block, + provided the program does not terminate while inside such block. + After the __finally block executes, the flow of the program will + continue where the __try block was meant to transfer control to, had + there been no __finally block. + + A @code{goto}, @code{break}, @code{return}, or @code{continue} + statement can be used to transfer control out of a try block but not + into one. Also, a longjump may not be used to transfer control into a + try or finally block. If done, the behavior is undefined. + + statement can be used to transfer control out of a try block but not + into one. If such a statement is used to transfer control into + + This construct is meant to provide a mechanism through which a series + of cleanups can be executed upon exit from a block (the __try block). + If somewhere inside the __try block an exception occurs and the + corresponding exception handler lies in the frame above the __finally + block, the __finally block will execute before control reaches the + exception handler above. + + This mechanism is by no ways a complete exception handling system for + C. + + @end itemize + + @node C++98 Try-Finally Edits + @subsection ISO/IEC 14882:1998 Edits for Try-Finally + + @itemize @bullet + @item + @cite{2.11 Keywords: Table 3} + + Add @code{__finally}. + + @item + @cite{15 Exception handling} + + Rename the @code{handler-seq} production by the following: + + @example + handler-seq: + handler-seq-catch finally-block-opt + finally-block + + handler-seq-catch: + handler handler-seq-catch + + finally-block-opt: + finally-block + + finally-block: + @b{__finally} compound-statement + @end example + + Add new text at the end of section 2. + + @quotation + When control is transferred from a try block to a destination (say + destination @b{A}), be it through a @code{continue}, @code{break}, + @code{return}, or @code{goto}, control is first redirected to the + finally block. When the finally block finishes, control is then + transferred to destination @b{A}. + @end quotation + + Add to code below to the example in section 3. + + @example + __finally + @{ + // code to be executed after the try block and + // applicable catch block is executed. + @} + @end example + + Add new example at the end of section 3. + + @quotation + The following code samples are equivalent. + @end quotation + + @example + A) + __try @{ + A; + @} catch (...) @{ + B; + @} __finally @{ + C; + @} + + B) + __try @{ + __try @{ + A; + @} catch (...) @{ + B; + @} + @} __finally @{ + C; + @} + @end example + + @item + @cite{15.2 Constructors and destructors} + + Add new text to section 3. + + @quotation + If code within a @i{try} block (or within code called from a try + block) causes an exception that is not caught by the subsequent + @i{catch} blocks, the code in @i{__finally} executes on the path up to + the handler that will catch the exception (if one is available). + @end quotation + + Add new text to section 7. + + @quotation + If the try block has a corresponding __finally block, the code in the + __finally block will execute before control reaches the dynamically + surrounding try block. + @end quotation + + Add new section 2. + + @quotation + If the __finally block contains a jump outside stated block, the + program is ill-formed and the behavior is undefined. + @end quotation + + @end itemize @node Thread-Local @section Thread-Local Storage