This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[basic-improvements] try/finally support for c/c++
- From: Aldy Hernandez <aldyh at redhat dot com>
- To: rth at redhat dot com, gcc-patches at gcc dot gnu dot org, jakub at redhat dot com
- Cc: jason at redhat dot com
- Date: Tue, 5 Nov 2002 15:19:02 -0800
- Subject: [basic-improvements] try/finally support for c/c++
As promised. Here are the try/finally patches for C and C++.
As can be seen by the ChangeLog, the C++ bits were kindly supplied by
Jason Merrill (thank-you beers still pending).
Jakub has some tests for try/finally mixing C and C++ exceptions.
He'll be posting those later, right? :)
In a nutshell, try/finally is the coolest thing since sliced bread.
Now you can do stuff like:
__try {
blah;
blah;
return;
}
__finally {
/* guaranteed to run before the return */
}
Even cooler would be code in the kernel:
__try {
clear_interrupts();
stuff;
stuff;
}
__finally {
set_interrupts();
}
That way you'll never forget to turn on interrupts again :). Well...
You can even have C call C++, C++ throw an exception, and the finally
clause in C execute as the stack unwinds up to the caller.
C_function() {
__try {
C++_function_that_throws_exception();
}
__finally {
/* guaranteed to be executed as the stack unwinds up to
C_function's caller */
}
}
Bootstrapped on x86 (c, c++, java, fortran). Regtest almost done.
Ok?
2002-11-05 Aldy Hernandez <aldyh@redhat.com>
* Makefile.in (LIB2ADDEH): Add unwind-c.c.
(c-semantics.o): Depend on libfuncs.h and except.h.
* config/t-linux (LIB2ADDEH): Same.
* config/ia64/t-ia64 (LIB2ADDEH): Add unwind-c.c.
* 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.
* unwind-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 <jason@redhat.com>
* 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 5 Nov 2002 23:01:34 -0000
*************** CRTSTUFF_CFLAGS = -O2 $(GCC_CFLAGS) $(IN
*** 399,405 ****
# Additional sources to handle exceptions; overridden by targets as needed.
LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \
! $(srcdir)/unwind-sjlj.c
LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h
# nm flags to list global symbols in libgcc object files.
--- 399,405 ----
# Additional sources to handle exceptions; overridden by targets as needed.
LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \
! $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h
# nm flags to list global symbols in libgcc object files.
*************** 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: unwind-c.c
===================================================================
RCS file: unwind-c.c
diff -N unwind-c.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- unwind-c.c 5 Nov 2002 23:01:38 -0000
***************
*** 0 ****
--- 1,185 ----
+ /* Supporting functions for C exception handling.
+
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Contributed by Aldy Hernandez <aldy@quesejoda.com>.
+ 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 5 Nov 2002 23:01:39 -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 5 Nov 2002 23:01:39 -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 5 Nov 2002 23:01:39 -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 5 Nov 2002 23:01:44 -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 5 Nov 2002 23:01:48 -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 5 Nov 2002 23:01:49 -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 5 Nov 2002 23:01:51 -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 <ttype> any_word extension
%type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start
! %type <ttype> do_stmt_start poplevel stmt label
%type <ttype> c99_block_start c99_block_end
%type <ttype> declarator
--- 213,219 ----
%type <ttype> any_word extension
%type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start
! %type <ttype> do_stmt_start poplevel stmt label try_finally_begin
%type <ttype> c99_block_start c99_block_end
%type <ttype> 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: config/t-linux
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/t-linux,v
retrieving revision 1.12
diff -c -p -r1.12 t-linux
*** config/t-linux 15 Dec 2001 11:46:55 -0000 1.12
--- config/t-linux 5 Nov 2002 23:01:51 -0000
*************** SHLIB_MAPFILES += $(srcdir)/config/libgc
*** 12,16 ****
# Use unwind-dw2-fde-glibc
LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \
! $(srcdir)/unwind-sjlj.c
LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c
--- 12,16 ----
# Use unwind-dw2-fde-glibc
LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \
! $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c
Index: config/ia64/t-ia64
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/t-ia64,v
retrieving revision 1.13.20.2
diff -c -p -r1.13.20.2 t-ia64
*** config/ia64/t-ia64 17 Sep 2002 22:59:00 -0000 1.13.20.2
--- config/ia64/t-ia64 5 Nov 2002 23:01:51 -0000
*************** crtendS.o: $(srcdir)/config/ia64/crtend.
*** 34,40 ****
crtfastmath.o: $(srcdir)/config/ia64/crtfastmath.c $(GCC_PASSES)
$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -c -o crtfastmath.o $(srcdir)/config/ia64/crtfastmath.c
! LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c
ia64-c.o: $(srcdir)/config/ia64/ia64-c.c $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(CPPLIB_H) $(C_COMMON_H) c-pragma.h toplev.h
--- 34,41 ----
crtfastmath.o: $(srcdir)/config/ia64/crtfastmath.c $(GCC_PASSES)
$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -c -o crtfastmath.o $(srcdir)/config/ia64/crtfastmath.c
! LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c $(srcdir
! )/unwind-c.c
ia64-c.o: $(srcdir)/config/ia64/ia64-c.c $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(CPPLIB_H) $(C_COMMON_H) c-pragma.h toplev.h
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 5 Nov 2002 23:01:51 -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 5 Nov 2002 23:01:51 -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 5 Nov 2002 23:01:52 -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 5 Nov 2002 23:01:55 -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 5 Nov 2002 23:01:57 -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 <ttype> AGGR
*************** check_class_key (key, aggr)
*** 463,468 ****
--- 464,470 ----
%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
%type <ttype> handler_args
%type <ttype> self_template_type finish_template_type_
+ %type <itype> handler_seq finally_stmt
%token NSNAME
%type <ttype> NSNAME
*************** function_try_block:
*** 3552,3575 ****
try_block:
TRY
! { $<ttype>$ = begin_try_block (); }
compstmt
{ finish_try_block ($<ttype>2); }
handler_seq
! { finish_handler_sequence ($<ttype>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);
! $<ttype>$ = fake_handler;
!
! error ("must have at least one catch per try block");
}
;
--- 3554,3597 ----
try_block:
TRY
! {
! $<ttype>1 = begin_try_finally ();
! $<ttype>$ = begin_try_block ();
! }
compstmt
{ finish_try_block ($<ttype>2); }
handler_seq
! {
! finish_handler_sequence ($<ttype>2);
! finish_try_finally_try ($<ttype>1);
! }
! finally_stmt
! {
! finish_try_finally_finally ($<ttype>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 5 Nov 2002 23:02:04 -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 5 Nov 2002 23:02:05 -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 5 Nov 2002 23:02:12 -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,6715 ----
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}
+ @b{@{} block-item-list @b{@}}
+ @b{__finally}
+ @b{@{} block-item-list @b{@}}
+
+ @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.
+
+ 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.
+
+ 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}.
+ 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
+
+ handler-seq-catch:
+ handler handler-seq-catch
+
+ finally-block:
+ @b{__finally} compound-statement
+ @end example
+
+ 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
+
+ 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
+
+ @item
+ @cite{15.1 Throwing an exception}
+
+ Add new section before section 2 and 3.
+
+ @quotation
+ After an exception is caught by an applicable handler (if present),
+ but before control is transferred elsewhere (provided the program does
+ not exit), the code in the __finally block is executed.
+ @end quotation
+
+ @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 as the stack
+ unwinds upwards.
+ @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