* [basic-improvements] try/finally support for c/c++ @ 2002-11-05 15:16 Aldy Hernandez 2002-11-05 15:57 ` Richard Henderson ` (2 more replies) 0 siblings, 3 replies; 128+ messages in thread From: Aldy Hernandez @ 2002-11-05 15:16 UTC (permalink / raw) To: rth, gcc-patches, jakub; +Cc: jason 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 ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 15:16 [basic-improvements] try/finally support for c/c++ Aldy Hernandez @ 2002-11-05 15:57 ` Richard Henderson 2002-11-05 23:03 ` Aldy Hernandez ` (2 more replies) 2002-11-05 16:40 ` Stan Shebs 2002-11-06 9:43 ` [basic-improvements] try/finally support for c/c++ - more tests Jakub Jelinek 2 siblings, 3 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-05 15:57 UTC (permalink / raw) To: Aldy Hernandez; +Cc: gcc-patches, jakub, jason On Tue, Nov 05, 2002 at 03:19:02PM -0800, Aldy Hernandez wrote: > + /* Currently we only support cleanups for C. */ > + if (actions != _UA_CLEANUP_PHASE) > + return _URC_CONTINUE_UNWIND; IIRC, Jakub already pointed out that actions is a bit mask. Should be if (!(actions & _UA_CLEANUP_PHASE)) > + try-finally-statement: > + @b{__try} > + @b{@{} block-item-list @b{@}} > + @b{__finally} > + @b{@{} block-item-list @b{@}} The braces should not be required. This should be @b{__try} @i{statement} @b{__finally} @i{statement} and, indeed, we should have a test for __try q = 1; __finally x = 2; or something. Hmm. I see that C++ *does* require the braces. In which case you should use compound-statment instead of calling block-item-list directly. > + 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. This implies that longjmp is try/finally aware, which is false. Probably should have text similar to C++ 15/2, such that you can't goto into a try handler. (I think that breaks with sjlj exceptions.) > + @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}. "finally" is not a keyword. > + @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 This says __finally is required. Which is false. Also doesn't indicate that __finally can be used without catch. Should probabably mention that try { A; } catch (...) { B; } __finally { C; } is equivalent to try { try { A; } catch (...) { B; } } __finally { C; } > + 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. > + @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 This isn't needed if you define try/finally correctly elsewhere. > + @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 "Upwards" is bad language. See the existing language that uses "path". 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? r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 15:57 ` Richard Henderson @ 2002-11-05 23:03 ` Aldy Hernandez 2002-11-06 0:44 ` Joseph S. Myers 2002-11-06 4:20 ` Gabriel Dos Reis 2002-11-06 6:05 ` Jason Merrill 2 siblings, 1 reply; 128+ messages in thread From: Aldy Hernandez @ 2002-11-05 23:03 UTC (permalink / raw) To: Richard Henderson, gcc-patches, jakub, jason 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 <aldyh@redhat.com> * 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 <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 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 <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 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 <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: 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 <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 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 ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 23:03 ` Aldy Hernandez @ 2002-11-06 0:44 ` Joseph S. Myers 2002-11-06 0:52 ` Jakub Jelinek 2002-11-06 10:29 ` Aldy Hernandez 0 siblings, 2 replies; 128+ messages in thread From: Joseph S. Myers @ 2002-11-06 0:44 UTC (permalink / raw) To: Aldy Hernandez; +Cc: Richard Henderson, gcc-patches, jakub, jason On Tue, 5 Nov 2002, Aldy Hernandez wrote: > + The @code{__try/__finally} statement consists of a @code{__try} block "/" should not be in @code here and below. > + 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. There should be a corresponding mention of longjmp to that in the formal edits. > + Exiting out of a finally block through a @code{return} or @code{goto} > + has undefined behaviour. ^^^^ ior > + 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). That's @code{longjmp}. Also use consistent terminology; you're using "@code{__try} block", "__try block" and "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. I believe the intention is that variables defined outside the try block are live, but variables definied within it are not, while the finally block is executing, regardless of how entered? Also, if the try block terminates by falling off the end, the intended point of transfer of control is after the end of the 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. @code{longjmp}. May it be used to jump out of such a block? All the rules that jumps into try blocks are not permitted (and you'll need to add switch to the statements that might jump into a block) should be listed as constraints (with corresponding testcases for the errors from the constraint violations); although violating them at runtime with GNU C computed gotos would be undefined. May a finally block be jumped into (and if so, where does execution pass after the finally block is finished)? May a finally block be jumped out of? > + > + 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 > + Stray partial paragraph. -- Joseph S. Myers jsm28@cam.ac.uk ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 0:44 ` Joseph S. Myers @ 2002-11-06 0:52 ` Jakub Jelinek 2002-11-06 3:02 ` Michael Matz 2002-11-06 10:29 ` Aldy Hernandez 1 sibling, 1 reply; 128+ messages in thread From: Jakub Jelinek @ 2002-11-06 0:52 UTC (permalink / raw) To: Joseph S. Myers; +Cc: Aldy Hernandez, Richard Henderson, gcc-patches, jason On Wed, Nov 06, 2002 at 08:44:01AM +0000, Joseph S. Myers wrote: > > + 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. > > I believe the intention is that variables defined outside the try block > are live, but variables definied within it are not, while the finally > block is executing, regardless of how entered? Also, if the try block > terminates by falling off the end, the intended point of transfer of > control is after the end of the finally block? If __try block was exited by return, then the function returns after finishing the __finally block (unless inside other __try block), if __try is exited normally, then execution continues after the end of the finally block, if __try block is exited through exception being thrown (or forced unwinding), then after __finally block exits the exception is resumed or forced unwinding continues. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 0:52 ` Jakub Jelinek @ 2002-11-06 3:02 ` Michael Matz 2002-11-06 3:11 ` Jakub Jelinek 0 siblings, 1 reply; 128+ messages in thread From: Michael Matz @ 2002-11-06 3:02 UTC (permalink / raw) To: Jakub Jelinek Cc: Joseph S. Myers, Aldy Hernandez, Richard Henderson, gcc-patches, jason Hi, On Wed, 6 Nov 2002, Jakub Jelinek wrote: > If __try block was exited by return, then the function returns after > finishing the __finally block (unless inside other __try block), if > __try is exited normally, then execution continues after the end > of the finally block, This would be fairly weird semantic. If the finally is formulated as a destructor of an anonymous object (like Richard suggested) then it should be run after the __try block exits, in _whichever_ way it does so. This also makes much more sense to me. I wouldn't like to have to write: __try { if (bla()) return; } __finally { cleanup(); } cleanup(); just because the __finally block isn't executed sometimes. It also makes the rule quite easy. The finally is executed after the try block, no matter what. Ciao, Michael. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 3:02 ` Michael Matz @ 2002-11-06 3:11 ` Jakub Jelinek 2002-11-06 4:16 ` Michael Matz 0 siblings, 1 reply; 128+ messages in thread From: Jakub Jelinek @ 2002-11-06 3:11 UTC (permalink / raw) To: Michael Matz Cc: Joseph S. Myers, Aldy Hernandez, Richard Henderson, gcc-patches, jason On Wed, Nov 06, 2002 at 12:02:42PM +0100, Michael Matz wrote: > Hi, > > On Wed, 6 Nov 2002, Jakub Jelinek wrote: > > > If __try block was exited by return, then the function returns after > > finishing the __finally block (unless inside other __try block), if > > __try is exited normally, then execution continues after the end > > of the finally block, > > This would be fairly weird semantic. If the finally is formulated as a > destructor of an anonymous object (like Richard suggested) then it should > be run after the __try block exits, in _whichever_ way it does so. This > also makes much more sense to me. I wouldn't like to have to write: > > __try { > if (bla()) > return; > } > __finally { > cleanup(); > } > cleanup(); > > just because the __finally block isn't executed sometimes. It also makes > the rule quite easy. The finally is executed after the try block, no > matter what. The __finally block is executed in all cases, the question was what is executed AFTER the __finally block. __try { if (bla()) return; } __finally { code1(); } code2(); will do: 1) if bla() returns non-zero, code1() is called and then the function returns. 2) if bla() returns zero, code1() is called, then code2(). 3) if exception is thrown from within bla or forced unwinding, then code1() is executed and the stack unwinding continues Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 3:11 ` Jakub Jelinek @ 2002-11-06 4:16 ` Michael Matz 0 siblings, 0 replies; 128+ messages in thread From: Michael Matz @ 2002-11-06 4:16 UTC (permalink / raw) To: Jakub Jelinek Cc: Joseph S. Myers, Aldy Hernandez, Richard Henderson, gcc-patches, jason Hi, On Wed, 6 Nov 2002, Jakub Jelinek wrote: > The __finally block is executed in all cases, the question was what is > executed AFTER the __finally block. Ahh, that was unclear (to me) in your message. Ok, then we all agree again ;-) Ciao, Michael. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 0:44 ` Joseph S. Myers 2002-11-06 0:52 ` Jakub Jelinek @ 2002-11-06 10:29 ` Aldy Hernandez 2002-11-06 10:53 ` Richard Henderson ` (2 more replies) 1 sibling, 3 replies; 128+ messages in thread From: Aldy Hernandez @ 2002-11-06 10:29 UTC (permalink / raw) To: Joseph S. Myers; +Cc: Richard Henderson, gcc-patches, jakub, jason On Wed, Nov 06, 2002 at 08:44:01AM +0000, Joseph S. Myers wrote: > On Tue, 5 Nov 2002, Aldy Hernandez wrote: > > > + The @code{__try/__finally} statement consists of a @code{__try} block > > "/" should not be in @code here and below. Fixed. > > > + 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. > > There should be a corresponding mention of longjmp to that in the formal > edits. I don't understand what you want here. Could you elaborate please? > > + Exiting out of a finally block through a @code{return} or @code{goto} > > + has undefined behaviour. > ^^^^ ior fixed. > > + 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). > > That's @code{longjmp}. Also use consistent terminology; you're using > "@code{__try} block", "__try block" and "try block". Fixed. Using "try block" and "finally block" all throughout now. > > + 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. > > I believe the intention is that variables defined outside the try block > are live, but variables definied within it are not, while the finally > block is executing, regardless of how entered? Also, if the try block > terminates by falling off the end, the intended point of transfer of > control is after the end of the finally block? Added Jakub's description. > > + 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. > > @code{longjmp}. May it be used to jump out of such a block? All the > rules that jumps into try blocks are not permitted (and you'll need to add > switch to the statements that might jump into a block) should be listed as > constraints (with corresponding testcases for the errors from the > constraint violations); although violating them at runtime with GNU C > computed gotos would be undefined. May a finally block be jumped into > (and if so, where does execution pass after the finally block is > finished)? May a finally block be jumped out of? Richard could you elaborate here? It was my understanding that longjmp may not be used to jump into a try/finally block or out of one? What are the actual restrictions? > > + 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 > > + > > Stray partial paragraph. Fixed. Joseph, how does this one look? Aldy 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 18:26:48 -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,6747 ---- 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}/@code{__finally} statement consists of a try block + containing one or more statements, and a finally block contatining one + or more statements. The finally block will execute after the try + block but before the code following the @code{__try}/@code{__finally} + construct, even if the 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}/@code{__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}/@code{catch} blocks. The finally block 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}/@code{__finally} construct + call C++ code that throws an exception. As part of the unwind + process, the C 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 behavior. + + GCC's @code{__try}/@code{__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 try block is executed. After the __try block exits, control is + transferred to the finally block regardless of how the try block exits + (with the exception of program termination or @code{longjmp} exits out + of the try block). + + If a try block was exited by @code{return}, then the function returns + after finishing the finally block (unless inside other try block). If + a try block is exited normally, then execution continues after the end + of the finally block. If a try block is exited through an exception + being thrown (or forced unwinding), then after finally block exits, + the exception is resumed or forced unwinding continues. + + 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 @code{longjmp} may not be used to transfer control + into a try or finally block. If done, the behavior is undefined. + + 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 try block (or within code called from a try + block) causes an exception that is not caught by the subsequent + catch blocks, the code in __finally executes on the path up to + the handler that will catch the exception (if one is available). + + Even though the code in the finally block is run on exit from the try + block, exiting a try block with a corresponding finally block via + longjmp or computed goto has undefined behavior. + @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 ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:29 ` Aldy Hernandez @ 2002-11-06 10:53 ` Richard Henderson 2002-11-06 10:56 ` Aldy Hernandez ` (3 more replies) 2002-11-06 11:22 ` Joseph S. Myers 2002-11-06 17:21 ` Fergus Henderson 2 siblings, 4 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-06 10:53 UTC (permalink / raw) To: Aldy Hernandez; +Cc: Joseph S. Myers, gcc-patches, jakub, jason On Wed, Nov 06, 2002 at 10:32:15AM -0800, Aldy Hernandez wrote: > > > + 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. > > > > @code{longjmp}. May it be used to jump out of such a block? All the > > rules that jumps into try blocks are not permitted (and you'll need to add > > switch to the statements that might jump into a block) should be listed as > > constraints (with corresponding testcases for the errors from the > > constraint violations); although violating them at runtime with GNU C > > computed gotos would be undefined. May a finally block be jumped into > > (and if so, where does execution pass after the finally block is > > finished)? May a finally block be jumped out of? > > Richard could you elaborate here? It was my understanding that > longjmp may not be used to jump into a try/finally block or out of > one? What are the actual restrictions? Well, longjmp pretty much bypasses all the logic one would care to ask about. I would say that such would have to be undefined. There is mention in the IA-64 psABI docs of a separate longjmp_unwind function that _is_ EH aware, but that's the exception not the rule. So leaving a try block via longjmp is going to have to be undefined. I don't see how one could enter a try block via longjmp. Something I just thought of here is GCC's computed goto extension. I don't know if the middle-end cleanup code handles this properly. We should have a test in the testsuite for this. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:53 ` Richard Henderson @ 2002-11-06 10:56 ` Aldy Hernandez 2002-11-06 11:24 ` Joseph S. Myers ` (2 subsequent siblings) 3 siblings, 0 replies; 128+ messages in thread From: Aldy Hernandez @ 2002-11-06 10:56 UTC (permalink / raw) To: Richard Henderson, Joseph S. Myers, gcc-patches, jakub, jason > I don't see how one could enter a try block via longjmp. So, you can't enter or leave a try/finally block with longjmp. > Something I just thought of here is GCC's computed goto extension. > I don't know if the middle-end cleanup code handles this properly. > We should have a test in the testsuite for this. Jason, in his blurb, mentioned that leaving try/f via computed gotos would be undefined. Aldy ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:53 ` Richard Henderson 2002-11-06 10:56 ` Aldy Hernandez @ 2002-11-06 11:24 ` Joseph S. Myers 2002-11-06 13:49 ` Richard Henderson 2002-11-06 17:45 ` Fergus Henderson 2002-11-06 17:48 ` Fergus Henderson 3 siblings, 1 reply; 128+ messages in thread From: Joseph S. Myers @ 2002-11-06 11:24 UTC (permalink / raw) To: Richard Henderson; +Cc: Aldy Hernandez, gcc-patches, jakub, jason On Wed, 6 Nov 2002, Richard Henderson wrote: > I don't see how one could enter a try block via longjmp. setjmp within the block. longjmp after it's finished executing but before the containing function has returned (whether within the finally block or after that too has finished). -- Joseph S. Myers jsm28@cam.ac.uk ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 11:24 ` Joseph S. Myers @ 2002-11-06 13:49 ` Richard Henderson 0 siblings, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-06 13:49 UTC (permalink / raw) To: Joseph S. Myers; +Cc: Aldy Hernandez, gcc-patches, jakub, jason On Wed, Nov 06, 2002 at 07:24:27PM +0000, Joseph S. Myers wrote: > setjmp within the block. longjmp after it's finished executing but before > the containing function has returned (whether within the finally block or > after that too has finished). Ah, yes. While I suspect that in the current implementation this would work as expected, I certainly don't want to promise anything of the sort in the specification. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:53 ` Richard Henderson 2002-11-06 10:56 ` Aldy Hernandez 2002-11-06 11:24 ` Joseph S. Myers @ 2002-11-06 17:45 ` Fergus Henderson 2002-11-07 9:54 ` Richard Henderson 2002-11-06 17:48 ` Fergus Henderson 3 siblings, 1 reply; 128+ messages in thread From: Fergus Henderson @ 2002-11-06 17:45 UTC (permalink / raw) To: Richard Henderson, Aldy Hernandez, Joseph S. Myers, gcc-patches, jakub, jason On 06-Nov-2002, Richard Henderson <rth@redhat.com> wrote: > On Wed, Nov 06, 2002 at 10:32:15AM -0800, Aldy Hernandez wrote: > > > > Richard could you elaborate here? It was my understanding that > > longjmp may not be used to jump into a try/finally block or out of > > one? What are the actual restrictions? > > Well, longjmp pretty much bypasses all the logic one would care to > ask about. I would say that such would have to be undefined. If longjumping out of a try/finally block results in undefined behaviour, then either (1) programmers should avoid using longjmp() (2) programmers should avoid using try/finally (3) programmers must take great care when using longjmp() or try/finally to ensure that the two are not used together in a way that will result in undefined behaviour. This requires global (or at least non-local) analysis of the program. The analysis must be redone whenever any code is added which uses try/finally or longjmp, or even just when code which might use those constructs is rearranged. Furthermore, there are no tools which will help in this analysis, no support for run-time checking of this property, and bugs caused in this way may only show up on some platforms, so on some platforms testing will never detect the bug. OUCH! Which is it? In C++ the answer is (1). This makes sense, because C++ has exceptions, which provide a replacement for longjmp(). But it doesn't work for GNU C with try/finally. (3) is bad since it makes programs using either longjmp() or try/finally much harder to write and maintain. (2) works, but there's no point adding try/finally and then immediately deprecating it ;-) longjmp() is a very useful feature. If you're not going to provide a replacement, then please don't make longjmp() harder to use! > Something I just thought of here is GCC's computed goto extension. Another issue is using goto to jump out of nested functions. This has similar properties to longjmp or throwing exceptions, i.e. it unwinds the stack. The relationship between that and __try/__finally needs to be documented. -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 17:45 ` Fergus Henderson @ 2002-11-07 9:54 ` Richard Henderson 0 siblings, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-07 9:54 UTC (permalink / raw) To: Fergus Henderson Cc: Aldy Hernandez, Joseph S. Myers, gcc-patches, jakub, jason On Thu, Nov 07, 2002 at 12:45:08PM +1100, Fergus Henderson wrote: > (3) programmers must take great care when using longjmp() > or try/finally to ensure that the two are not used together in > a way that will result in undefined behaviour. This requires > global (or at least non-local) analysis of the program. > The analysis must be redone whenever any code is added which > uses try/finally or longjmp, or even just when code which > might use those constructs is rearranged. Furthermore, > there are no tools which will help in this analysis, no > support for run-time checking of this property, and bugs > caused in this way may only show up on some platforms, > so on some platforms testing will never detect the bug. > OUCH! 3, really. Though ideally we'd have the function longjmp_unwind, which is mentioned in the IA-64 psABI as a function that runs cleanups along the path to the setjmp target. > Another issue is using goto to jump out of nested functions. > This has similar properties to longjmp or throwing exceptions, > i.e. it unwinds the stack. The relationship between that and > __try/__finally needs to be documented. Same problem, though I'm happy to deprecate it. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:53 ` Richard Henderson ` (2 preceding siblings ...) 2002-11-06 17:45 ` Fergus Henderson @ 2002-11-06 17:48 ` Fergus Henderson 2002-11-07 9:58 ` Richard Henderson 3 siblings, 1 reply; 128+ messages in thread From: Fergus Henderson @ 2002-11-06 17:48 UTC (permalink / raw) To: Richard Henderson, Aldy Hernandez, Joseph S. Myers, gcc-patches, jakub, jason On 06-Nov-2002, Richard Henderson <rth@redhat.com> wrote: > longjmp pretty much bypasses all the logic one would care to > ask about. I would say that such would have to be undefined. There > is mention in the IA-64 psABI docs of a separate longjmp_unwind > function that _is_ EH aware, but that's the exception not the rule. > So leaving a try block via longjmp is going to have to be undefined. Undefined behaviour is pretty drastic. Would it be sufficient to just make it implementation-defined whether or not longjmp() invokes cleanups (i.e. destructors and finally blocks)? -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 17:48 ` Fergus Henderson @ 2002-11-07 9:58 ` Richard Henderson 0 siblings, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-07 9:58 UTC (permalink / raw) To: Fergus Henderson Cc: Aldy Hernandez, Joseph S. Myers, gcc-patches, jakub, jason On Thu, Nov 07, 2002 at 12:48:32PM +1100, Fergus Henderson wrote: > Undefined behaviour is pretty drastic. Would it be sufficient to just > make it implementation-defined whether or not longjmp() invokes cleanups > (i.e. destructors and finally blocks)? If you're using sjlj exceptions, you'll actually confuse the unwinder by using longjmp. Something that might be fixable, but requires more processor-specific code. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:29 ` Aldy Hernandez 2002-11-06 10:53 ` Richard Henderson @ 2002-11-06 11:22 ` Joseph S. Myers 2002-11-06 14:00 ` Richard Henderson 2002-11-06 17:21 ` Fergus Henderson 2 siblings, 1 reply; 128+ messages in thread From: Joseph S. Myers @ 2002-11-06 11:22 UTC (permalink / raw) To: Aldy Hernandez; +Cc: Richard Henderson, gcc-patches, jakub, jason On Wed, 6 Nov 2002, Aldy Hernandez wrote: > > > + 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. > > > > There should be a corresponding mention of longjmp to that in the formal > > edits. > > I don't understand what you want here. Could you elaborate please? It must be made clear in the user docs that exiting via longjmp yields undefined behavior, rather than the finally block executing before longjmp goes to its destination. > Joseph, how does this one look? You still need to make the jumps that aren't permitted into constraint violations (with corresponding testcases for the diagnostics) except for longjmp and computed goto cases (undefined behavior at runtime). I don't think it's yet been stated whether you may jump into the finally block from outside, or what happens after the execution of the finally block if you do. > + If a try block was exited by @code{return}, then the function returns > + after finishing the finally block (unless inside other try block). If > + a try block is exited normally, then execution continues after the end > + of the finally block. If a try block is exited through an exception > + being thrown (or forced unwinding), then after finally block exits, > + the exception is resumed or forced unwinding continues. This paragraph fails to mention what happens if the try block is exited by a jump (goto, break or continue). Whichever cases of computed goto are defined / undefined need to be documented. > + 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 @code{longjmp} may not be used to transfer control > + into a try or finally block. If done, the behavior is undefined. You need to include @code{switch} in the statements that aren't permitted to transfer control into a try block. Wasn't it intended that longjmp can't jump out either? (Note: I'm not examining the C++98 edits, there may be similar issues there.) -- Joseph S. Myers jsm28@cam.ac.uk ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 11:22 ` Joseph S. Myers @ 2002-11-06 14:00 ` Richard Henderson 0 siblings, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-06 14:00 UTC (permalink / raw) To: Joseph S. Myers; +Cc: Aldy Hernandez, gcc-patches, jakub, jason On Wed, Nov 06, 2002 at 07:22:33PM +0000, Joseph S. Myers wrote: > I don't think it's yet been stated whether you may jump into the finally > block from outside, or what happens after the execution of the finally > block if you do. No, you cannot jump into the finally block. There is no well-defined "next" block for us to proceed to after executing the finally block. I wouldn't even want to consider the consequences of a goto from the try block into its finally block. > > + If a try block was exited by @code{return}, then the function returns > > + after finishing the finally block (unless inside other try block). If > > + a try block is exited normally, then execution continues after the end > > + of the finally block. If a try block is exited through an exception > > + being thrown (or forced unwinding), then after finally block exits, > > + the exception is resumed or forced unwinding continues. > > This paragraph fails to mention what happens if the try block is exited by > a jump (goto, break or continue). Indeed, I think this paragraph should follow C++ in enumerating the ways in which you *may* leave a block, rather than enumerating the ways in which you may not leave a block. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:29 ` Aldy Hernandez 2002-11-06 10:53 ` Richard Henderson 2002-11-06 11:22 ` Joseph S. Myers @ 2002-11-06 17:21 ` Fergus Henderson 2 siblings, 0 replies; 128+ messages in thread From: Fergus Henderson @ 2002-11-06 17:21 UTC (permalink / raw) To: Aldy Hernandez; +Cc: gcc-patches On 06-Nov-2002, Aldy Hernandez <aldyh@redhat.com> wrote: > Index: doc/extend.texi > + @section Try/finally exceptions ... > + Since C++ already has a @code{try} keyword, both @code{try} and > + @code{__try} variations are allowed. "try" is not a keyword in C if -ansi (or equivalent) is specified, I assume. This should be mentioned here and/or in the "Alternate Keywords" section. -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 15:57 ` Richard Henderson 2002-11-05 23:03 ` Aldy Hernandez @ 2002-11-06 4:20 ` Gabriel Dos Reis 2002-11-06 9:05 ` Aldy Hernandez 2002-11-06 6:05 ` Jason Merrill 2 siblings, 1 reply; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-06 4:20 UTC (permalink / raw) To: Richard Henderson; +Cc: Aldy Hernandez, gcc-patches, jakub, jason Richard Henderson <rth@redhat.com> writes: | 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? I would like to express my concerns also (already stated by Stan and Matt). Before this patch goes in, it would be highly helpful to see discussions about the problem, and the proposed solution. I think this is such a dramatic addition that it wouldn't be wise to let it go it just as if it were a basic improvement to the compiler. -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 4:20 ` Gabriel Dos Reis @ 2002-11-06 9:05 ` Aldy Hernandez 2002-11-06 9:11 ` Matt Austern 0 siblings, 1 reply; 128+ messages in thread From: Aldy Hernandez @ 2002-11-06 9:05 UTC (permalink / raw) To: Gabriel Dos Reis; +Cc: Richard Henderson, gcc-patches, jakub, jason, drepper >>>>> "Gabriel" == Gabriel Dos Reis <gdr@integrable-solutions.net> writes: > Richard Henderson <rth@redhat.com> writes: > | 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? > I would like to express my concerns also (already stated by Stan and > Matt). Before this patch goes in, it would be highly helpful to see > discussions about the problem, and the proposed solution. I think > this is such a dramatic addition that it wouldn't be wise to let it go > it just as if it were a basic improvement to the compiler. I'mna let y'all discuss this. I was just the hacker, nothing else. Ulrich Drepper and rth asked me to work on this for Uli's libpthread rewrite for glibc. (Not that this is a valid argument, but a few other compilers have try/finally for C :-)). Meanwhile I'll keep iteracting with Joseph Myers, rth, etc over documentation changes ;-). Aldy ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 9:05 ` Aldy Hernandez @ 2002-11-06 9:11 ` Matt Austern 2002-11-06 9:25 ` Gabriel Dos Reis 2002-11-06 11:15 ` Richard Henderson 0 siblings, 2 replies; 128+ messages in thread From: Matt Austern @ 2002-11-06 9:11 UTC (permalink / raw) To: Aldy Hernandez Cc: Gabriel Dos Reis, Richard Henderson, gcc-patches, jakub, jason, drepper On Wednesday, November 6, 2002, at 09:08 AM, Aldy Hernandez wrote: > I'mna let y'all discuss this. I was just the hacker, nothing else. > Ulrich Drepper and rth asked me to work on this for Uli's libpthread > rewrite for glibc. (Not that this is a valid argument, but a few > other compilers have try/finally for C :-)). > > Meanwhile I'll keep iteracting with Joseph Myers, rth, etc over > documentation changes ;-). I hope the documentation will include a rationale, not just for exceptions in general, but for the specific design decisions you made. There are an awful lot of ways in which a language can support exceptions, after all: why this way instead of one of all the others? I'm not necessarily opposed to this change, but mostly I want us to recognize that what we're doing is language design and that it ought to be treated as such. It's a much more drastic thing than just adding a new optimization pass. --Matt ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 9:11 ` Matt Austern @ 2002-11-06 9:25 ` Gabriel Dos Reis 2002-11-06 11:15 ` Richard Henderson 1 sibling, 0 replies; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-06 9:25 UTC (permalink / raw) To: Matt Austern Cc: Aldy Hernandez, Richard Henderson, gcc-patches, jakub, jason, drepper Matt Austern <austern@apple.com> writes: | I'm not necessarily opposed to this change, but mostly I want us | to recognize that what we're doing is language design and that it | ought to be treated as such. Same here. -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 9:11 ` Matt Austern 2002-11-06 9:25 ` Gabriel Dos Reis @ 2002-11-06 11:15 ` Richard Henderson 2002-11-07 0:09 ` Kai Henningsen 1 sibling, 1 reply; 128+ messages in thread From: Richard Henderson @ 2002-11-06 11:15 UTC (permalink / raw) To: Matt Austern Cc: Aldy Hernandez, Gabriel Dos Reis, gcc-patches, jakub, jason, drepper On Wed, Nov 06, 2002 at 09:12:15AM -0800, Matt Austern wrote: > There are an awful lot of ways in which a language can > support exceptions, after all: why this way instead of one of all > the others? In my opinion, this is the most minimal way in which exceptions can be supported in a language. The worst problem we have with generic exception handling is the problem of type correspondence across language boundaries. This is of course related to the type of the exception object. If we added the ability to throw or catch exceptions in C, the average user would expect the "right" thing to happen with mixed C and C++ code. This without any clear description of what the "right" thing is. How, for example can C even talk about a template type? Of course, we have the same problem with mixing Ada <-> C++, and C++ -> Java (note that Java -> C++ is handled via gcj's CNI), but as yet no one has either complained or attempted to address the issue. With this extension, we have no facilities either for throwing or catching exceptions; only the running of a bit of code while an exception propagates through the call chain. Thus we are able to avoid all issues related to the type of the exception object. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 11:15 ` Richard Henderson @ 2002-11-07 0:09 ` Kai Henningsen 2002-11-07 12:56 ` Richard Henderson 0 siblings, 1 reply; 128+ messages in thread From: Kai Henningsen @ 2002-11-07 0:09 UTC (permalink / raw) To: gcc-patches rth@redhat.com (Richard Henderson) wrote on 06.11.02 in <20021106191509.GH22066@redhat.com>: > In my opinion, this is the most minimal way in which exceptions > can be supported in a language. As a user, I'd say this is too minimal. > The worst problem we have with generic exception handling is the > problem of type correspondence across language boundaries. This > is of course related to the type of the exception object. If we > added the ability to throw or catch exceptions in C, the average > user would expect the "right" thing to happen with mixed C and C++ > code. This without any clear description of what the "right" > thing is. How, for example can C even talk about a template type? Does it *need* to? Could C not simply define an interface which deals in opaque values? True, that is not worth much when throwing or catching across language boundaries, but it should do enough to make this usable from inside C, no? > Of course, we have the same problem with mixing Ada <-> C++, and > C++ -> Java (note that Java -> C++ is handled via gcj's CNI), but > as yet no one has either complained or attempted to address the > issue. Indicating that the inter-language case does not need to do this part. > With this extension, we have no facilities either for throwing or > catching exceptions; only the running of a bit of code while an > exception propagates through the call chain. Thus we are able to > avoid all issues related to the type of the exception object. And that is why this is not useful enough to normal C use. I've wanted exceptions for C for a long time; this isn't it - neither for a C programmer, nor for compiling into C. MfG Kai ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-07 0:09 ` Kai Henningsen @ 2002-11-07 12:56 ` Richard Henderson 0 siblings, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-07 12:56 UTC (permalink / raw) To: Kai Henningsen; +Cc: gcc-patches On Thu, Nov 07, 2002 at 08:54:00AM +0200, Kai Henningsen wrote: > > Of course, we have the same problem with mixing Ada <-> C++, and > > C++ -> Java (note that Java -> C++ is handled via gcj's CNI), but > > as yet no one has either complained or attempted to address the > > issue. > > Indicating that the inter-language case does not need to do this part. Indicating that no one mixes C++ and Ada, actaully, since at the moment Ada has not been updated to use the generic mechanisms. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 15:57 ` Richard Henderson 2002-11-05 23:03 ` Aldy Hernandez 2002-11-06 4:20 ` Gabriel Dos Reis @ 2002-11-06 6:05 ` Jason Merrill 2002-11-06 10:56 ` Richard Henderson 2 siblings, 1 reply; 128+ messages in thread From: Jason Merrill @ 2002-11-06 6:05 UTC (permalink / raw) To: Richard Henderson; +Cc: Aldy Hernandez, gcc-patches, jakub On Tue, 5 Nov 2002 15:57:18 -0800, Richard Henderson <rth@redhat.com> wrote: > 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? The code in the finally block is run on exit from the try block, except that exiting a try block with a corresponding finally block via longjmp or computed goto has undefined behavior. Jason ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 6:05 ` Jason Merrill @ 2002-11-06 10:56 ` Richard Henderson 2002-11-06 12:14 ` Jason Merrill 0 siblings, 1 reply; 128+ messages in thread From: Richard Henderson @ 2002-11-06 10:56 UTC (permalink / raw) To: Jason Merrill; +Cc: Aldy Hernandez, gcc-patches, jakub On Wed, Nov 06, 2002 at 09:03:45AM -0500, Jason Merrill wrote: > > 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? > > The code in the finally block is run on exit from the try block, except > that exiting a try block with a corresponding finally block via longjmp or > computed goto has undefined behavior. Yes, clearly, but how to integrate this statement cleanly with the ISO document? That is why I think we need to piggyback on the existing destructor language. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-06 10:56 ` Richard Henderson @ 2002-11-06 12:14 ` Jason Merrill 0 siblings, 0 replies; 128+ messages in thread From: Jason Merrill @ 2002-11-06 12:14 UTC (permalink / raw) To: Richard Henderson; +Cc: Aldy Hernandez, gcc-patches, jakub On Wed, 6 Nov 2002 10:56:30 -0800, Richard Henderson <rth@redhat.com> wrote: > On Wed, Nov 06, 2002 at 09:03:45AM -0500, Jason Merrill wrote: >> > 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? >> >> The code in the finally block is run on exit from the try block, except >> that exiting a try block with a corresponding finally block via longjmp or >> computed goto has undefined behavior. > > Yes, clearly, but how to integrate this statement cleanly with > the ISO document? That is why I think we need to piggyback on > the existing destructor language. The above is proposed wording. :) For destructors, the C++ standard just says (in stmt.dcl) Variables with automatic storage duration declared in the block are destroyed on exit from the block (_stmt.jump_). I think trying to word it in terms of a destructor would be too complicated; it's easier to express cleanups in terms of try/finally. Jason ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 15:16 [basic-improvements] try/finally support for c/c++ Aldy Hernandez 2002-11-05 15:57 ` Richard Henderson @ 2002-11-05 16:40 ` Stan Shebs 2002-11-05 16:48 ` Matt Austern 2002-11-06 9:43 ` [basic-improvements] try/finally support for c/c++ - more tests Jakub Jelinek 2 siblings, 1 reply; 128+ messages in thread From: Stan Shebs @ 2002-11-05 16:40 UTC (permalink / raw) To: Aldy Hernandez; +Cc: rth, gcc-patches, jakub, jason Aldy Hernandez wrote: >As promised. Here are the try/finally patches for C and C++. > So, uh, did I miss the part where we discussed whether this was a good extension to add? Stan ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 16:40 ` Stan Shebs @ 2002-11-05 16:48 ` Matt Austern 2002-11-05 17:21 ` Jason Merrill 2002-11-05 21:20 ` Aldy Hernandez 0 siblings, 2 replies; 128+ messages in thread From: Matt Austern @ 2002-11-05 16:48 UTC (permalink / raw) To: Stan Shebs; +Cc: Aldy Hernandez, rth, gcc-patches, jakub, jason On Tuesday, November 5, 2002, at 04:38 PM, Stan Shebs wrote: > Aldy Hernandez wrote: > >> As promised. Here are the try/finally patches for C and C++. >> > So, uh, did I miss the part where we discussed whether this > was a good extension to add? I'm a bit concerned about that too. I hate to see major language design decisions get made without a lot of thought given to the overall direction of the language. One big question is whether the intention is for this to be part of the GNU C dialect only, or whether there's to be an attempt to make it part of standard C. --Matt ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 16:48 ` Matt Austern @ 2002-11-05 17:21 ` Jason Merrill 2002-11-05 19:25 ` Matt Austern 2002-11-05 21:20 ` Aldy Hernandez 1 sibling, 1 reply; 128+ messages in thread From: Jason Merrill @ 2002-11-05 17:21 UTC (permalink / raw) To: Matt Austern; +Cc: Stan Shebs, Aldy Hernandez, rth, gcc-patches, jakub On Tue, 5 Nov 2002 16:48:33 -0800, Matt Austern <austern@apple.com> wrote: > On Tuesday, November 5, 2002, at 04:38 PM, Stan Shebs wrote: > >> Aldy Hernandez wrote: >> >>> As promised. Here are the try/finally patches for C and C++. >>> >> So, uh, did I miss the part where we discussed whether this >> was a good extension to add? > > I'm a bit concerned about that too. I hate to see major > language design decisions get made without a lot of thought > given to the overall direction of the language. I believe that the purpose of this stuff is to handle pthread cleanups using EH so that we can implement thread cancellation using EH. Matt, you may remember discussing this strategy at the ABI meetings (it gave rise to the forced_unwind stuff). Jason ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 17:21 ` Jason Merrill @ 2002-11-05 19:25 ` Matt Austern 2002-11-06 10:25 ` Richard Henderson 2002-11-06 11:05 ` Mike Stump 0 siblings, 2 replies; 128+ messages in thread From: Matt Austern @ 2002-11-05 19:25 UTC (permalink / raw) To: Jason Merrill; +Cc: Stan Shebs, Aldy Hernandez, rth, gcc-patches, jakub On Tuesday, November 5, 2002, at 05:19 PM, Jason Merrill wrote: > I believe that the purpose of this stuff is to handle pthread cleanups > using EH so that we can implement thread cancellation using EH. Matt, > you > may remember discussing this strategy at the ABI meetings (it gave > rise to > the forced_unwind stuff). Thanks for the explanation, Jason. Yes, I can see that motivation. I'm still not 100% sure that I find it completely compelling, though. Yes, I do remember the forced unwind stuff, but that started from the question of how thread cancellation would interact with automatic variables' destructors, which is, um, less of a concern for C. I also have to wonder if there's a less drastic solution for implementing thread cancellation than making a major language extension. After all, pthreads was designed and implemented with standard C90 in mind; do we really need this sort of language change either to implement pthread_cancel or for programmers to be able to use it effectively? If this is the motivation, I think there may be a mismatch between the scope of the problem and the scope of the solution. (One thing I've learned since the ABI discussions, by the way, is that asynchronous cancelation with pthread_cancel was only designed for some extremely specialized cases; pthreads experts advise against using it in general. Take a look at what Dave Butenhof writes, for example.) --Matt ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 19:25 ` Matt Austern @ 2002-11-06 10:25 ` Richard Henderson 2002-11-06 11:05 ` Mike Stump 1 sibling, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-06 10:25 UTC (permalink / raw) To: Matt Austern Cc: Jason Merrill, Stan Shebs, Aldy Hernandez, gcc-patches, jakub On Tue, Nov 05, 2002 at 07:25:18PM -0800, Matt Austern wrote: > I'm still not 100% sure that I find it completely compelling, > though. Yes, I do remember the forced unwind stuff, but that > started from the question of how thread cancellation would > interact with automatic variables' destructors, which is, um, > less of a concern for C. Actually, it is a concern for libc itself. Thread cancelation is required to release various locks acquired within stdio. > After all, pthreads was designed and implemented > with standard C90 in mind; do we really need this sort of > language change either to implement pthread_cancel or for > programmers to be able to use it effectively? We have two choices: One, libpthread and libc can continue to use a setjmp/longjmp based solution, which _does_ work within the framework of C90. This, however, ignores the many many (somewhat misinformed) bug reports that complain about C++ destructors not being run at thread cancelation. Despite the fact that POSIX does not mention C++ at all, one must agree that having destructors run at thread cancelation is a highly desireable feature. Two, we can add just enough EH support in C such that we can drop the setjmp/longjmp solution and use EH alone for thread cancelation. (Apparently the glibc folk consider building libc with a C++ compiler to be an abomination. Given the sometimes subtle differences between the two languages, I can't really fault this point of view.) > (One thing I've learned since the ABI discussions, by the way, > is that asynchronous cancelation with pthread_cancel was only > designed for some extremely specialized cases... I'm talking about synchronous cancelation only. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 19:25 ` Matt Austern 2002-11-06 10:25 ` Richard Henderson @ 2002-11-06 11:05 ` Mike Stump 1 sibling, 0 replies; 128+ messages in thread From: Mike Stump @ 2002-11-06 11:05 UTC (permalink / raw) To: Matt Austern Cc: Jason Merrill, Stan Shebs, Aldy Hernandez, rth, gcc-patches, jakub On Tuesday, November 5, 2002, at 07:25 PM, Matt Austern wrote: > On Tuesday, November 5, 2002, at 05:19 PM, Jason Merrill wrote: > >> I believe that the purpose of this stuff is to handle pthread cleanups >> using EH so that we can implement thread cancellation using EH. >> Matt, you >> may remember discussing this strategy at the ABI meetings (it gave >> rise to >> the forced_unwind stuff). > > Thanks for the explanation, Jason. Yes, I can see that > motivation. > > I'm still not 100% sure that I find it completely compelling, > though. As I recall... the problem is that in a C only world, existing pthreads implementations are fine, and in a C++ only world, EH is fine. If one wants to combine those two features pthreads and C++, there is a slight semantic rubbing that happens. One wants the stack cleanup actions of threads and the stack cleanup actions of C++ to interleave normally. From the C++ perspective, the way that we insist that this work, is if the EH mechanism, throw, is used. If you accept that design point, then you come to the conclusion that pthreads wants to throw an object to cleanup, so that the C++ actions run. And from there, we then need to use a more EH style mechanism to register the C cleanups, so that they interleave nicely with C++. We can avoid this by either mandating that pthreads and C++ should not be used at the same time, or by mandating non-exceptional overhead to track the entering and leaving of regions for C++, or by removing cleanups from pthreads or removing EH from C++. So, the question isn't, do you oppose it, it is rather, which solution to the problem do you prefer, and why? A design goal of the gcc family of languages has always been interoperability between the languages, or at least as much as possible. This is one of the motivations behind wanting pthreads from the C world and cleanups actions from the C++ world to interoperate nicely. Then both features can be used to their fullest, even in a complex system when C/pthreads and C++ are mixed. The C++ world is used to the zero-overhead EH chanting, and are loath to give it up. We could, but, I suspect we'd not be C++ abi compliant with the existing C++ abi standard. These two points, not wanting to give up C++ abi, and not wanting overhead I think constrain the C world to need to access the EH data the C++ world creates. From there, the wanting of C++ to run the cleanup actions from pthreads, means the C++ EH mechanism has to be able to read the data the C/pthreads implementation produces. In the end, you can think about it anyway you want, but in reality you've just unified C/pthreads and C++ EH. And once you've done that, __try/__finally or whatever you want to call it is just syntactic sugar on __builtin_pthread_register_cleanup or some other such nonsense. Also, this isn't new or out of thin air. It was designed and planned around many years years ago (5, 8?). I think that discussion mostly happened on the eh list, though, some of it did happen in smaller email groups. I could be mistaken, and maybe the discussions were just seeded off the eh list. In that timeframe and after thinking about it, I don't think we found anything we like better, and apparently the `problem' hasn't just gone away. I tried to recount the history of this, with a little luck it is close. If I got it any of it wrong, I'm sure other will chime in and correct it. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ 2002-11-05 16:48 ` Matt Austern 2002-11-05 17:21 ` Jason Merrill @ 2002-11-05 21:20 ` Aldy Hernandez 1 sibling, 0 replies; 128+ messages in thread From: Aldy Hernandez @ 2002-11-05 21:20 UTC (permalink / raw) To: Matt Austern; +Cc: Stan Shebs, rth, gcc-patches, jakub, jason, drepper > >So, uh, did I miss the part where we discussed whether this > >was a good extension to add? > > I'm a bit concerned about that too. I hate to see major > language design decisions get made without a lot of thought > given to the overall direction of the language. Matt, Stan: see Jason's followup email. > One big question is whether the intention is for this to be > part of the GNU C dialect only, or whether there's to be an > attempt to make it part of standard C. GNU C dialect for now. This was needed for glibc's rewrite of threads. I'm hoping Uli will chime in here. Aldy ^ permalink raw reply [flat|nested] 128+ messages in thread
* [basic-improvements] try/finally support for c/c++ - more tests 2002-11-05 15:16 [basic-improvements] try/finally support for c/c++ Aldy Hernandez 2002-11-05 15:57 ` Richard Henderson 2002-11-05 16:40 ` Stan Shebs @ 2002-11-06 9:43 ` Jakub Jelinek 2002-11-06 11:04 ` Joseph S. Myers 2002-11-06 15:34 ` Mark Mitchell 2 siblings, 2 replies; 128+ messages in thread From: Jakub Jelinek @ 2002-11-06 9:43 UTC (permalink / raw) To: Aldy Hernandez; +Cc: rth, gcc-patches, jason Hi! On Tue, Nov 05, 2002 at 03:19:02PM -0800, Aldy Hernandez wrote: > 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? :) Attached. One test for throwing from C++ through C code with __try/__finally, one test showing what approximately could libpthread do (well, there is still a problem if some function in the backtrace from the point of cancellation to __libc_start_main resp. pthread_start_thread is compiled with -fno-exceptions, _Unwind_Resume will abort. I think a callback is needed for that (e.g. calling the stop callback with some special arguments). 2002-11-06 Jakub Jelinek <jakub@redhat.com> * Makefile.in (USER_H): Install unwind.h. * libgcc-std.ver (__gcc_personality_v0, __gcc_personality_sj0): Export @GCC_3.4. * lib/g++-dg.exp (g++-dg-test): Add g++-dg-aux-sources to additional flags. (dg-aux-sources): New subroutine. * g++.dg/ext/try-finally-1.C: New test. * g++.dg/ext/try-finally-1-aux.c: New auxiliary file for the test. * gcc.dg/try-finally-1.c: New test. --- gcc/Makefile.in.jj 2002-10-25 14:12:50.000000000 +0200 +++ gcc/Makefile.in 2002-11-06 18:44:16.000000000 +0100 @@ -157,7 +157,7 @@ INSTALL_HEADERS_DIR = @build_install_hea USER_H = $(srcdir)/ginclude/stdarg.h $(srcdir)/ginclude/stddef.h \ $(srcdir)/ginclude/varargs.h \ $(srcdir)/ginclude/stdbool.h $(srcdir)/ginclude/iso646.h \ - $(EXTRA_HEADERS) + $(srcdir)/unwind.h $(EXTRA_HEADERS) # The GCC to use for compiling libgcc.a, enquire, and crt*.o. # Usually the one we just built. --- gcc/libgcc-std.ver.jj 2001-07-22 21:34:05.000000000 +0200 +++ gcc/libgcc-std.ver 2002-11-05 14:11:03.000000000 +0100 @@ -175,3 +175,7 @@ GCC_3.0 { _Unwind_SjLj_ForcedUnwind _Unwind_SjLj_Resume } +GCC_3.4 { + __gcc_personality_v0 + __gcc_personality_sj0 +} --- gcc/testsuite/lib/g++-dg.exp.jj 2002-01-23 16:29:52.000000000 +0100 +++ gcc/testsuite/lib/g++-dg.exp 2002-11-05 13:57:13.000000000 +0100 @@ -23,6 +23,7 @@ load_lib scanasm.exp proc g++-dg-test { prog do_what extra_tool_flags } { # Set up the compiler flags, based on what we're going to do. + global g++-dg-aux-sources switch $do_what { "preprocess" { @@ -59,6 +60,10 @@ proc g++-dg-test { prog do_what extra_to } } set options "" + if { ${g++-dg-aux-sources} != "" } { + append extra_tool_flags "${g++-dg-aux-sources}" + set g++-dg-aux-sources "" + } if { $extra_tool_flags != "" } { lappend options "additional_flags=$extra_tool_flags" } @@ -82,3 +87,22 @@ proc g++-dg-prune { system text } { return $text } + + +# +# Add additional sources to compile together with the main source file +# + +proc dg-aux-sources { args } { + global g++-dg-aux-sources + upvar prog myprog + + foreach arg [lrange $args 1 [llength $args]] { + set filename "[file dirname $myprog]/$arg" + if { [file extension $arg] == ".c" } { + append g++-dg-aux-sources " -xc $filename -xnone" + } else { + append g++-dg-aux-sources " $filename" + } + } +} --- gcc/testsuite/g++.dg/ext/try-finally-1.C.jj 2002-11-05 14:13:46.000000000 +0100 +++ gcc/testsuite/g++.dg/ext/try-finally-1.C 2002-11-05 12:47:17.000000000 +0100 @@ -0,0 +1,31 @@ +// { dg-do run } +// { dg-options "-O2 -fexceptions" } +// { dg-aux-sources try-finally-1-aux.c } + +extern int caught; +extern "C" void test (void); +extern "C" void do_throw (void); +extern "C" void abort (void); + +void +do_throw (void) +{ + caught |= 4; + throw 1; +} + +int +main () +{ + try + { + test (); + } + catch(...) + { + caught |= 8; + } + if (caught != 15) + abort (); + return 0; +} --- gcc/testsuite/g++.dg/ext/try-finally-1-aux.c.jj 2002-11-05 14:13:48.000000000 +0100 +++ gcc/testsuite/g++.dg/ext/try-finally-1-aux.c 2002-11-05 12:43:30.000000000 +0100 @@ -0,0 +1,23 @@ +int caught; +extern void do_throw (void); +extern void abort (void); + +void +test (void) +{ + caught |= 1; + __try + { + do_throw (); + } + __finally + { + finally (); + } + abort (); +} + +finally() +{ + caught |= 2; +} --- gcc/testsuite/gcc.dg/try-finally-1.c.jj 2002-07-23 20:50:16.000000000 +0200 +++ gcc/testsuite/gcc.dg/try-finally-1.c 2002-11-06 18:46:39.000000000 +0100 @@ -0,0 +1,94 @@ +/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* sparc*-*-linux* } } */ +/* { dg-options "-O2 -fexceptions" } */ + +#include <unwind.h> + +int caught; + +void finally (void); +void do_throw (void); +extern void abort (void); +extern void exit (int); + +void +test1 (void) +{ + caught |= 1; + __try + { + do_throw (); + abort (); + } + __finally + { + finally (); + } + abort (); +} + +void +test2 (void) +{ + caught |= 2; + __try + { + test1 (); + abort (); + } + __finally + { + caught |= 4; + } + abort (); +} + +void +test3 (void) +{ + test2 (); + caught = 0; +} + +void +finally (void) +{ + caught |= 8; +} + +void +exception_cleanup (_Unwind_Reason_Code code, + struct _Unwind_Exception *exc) +{ +} + +_Unwind_Reason_Code +stop_fn (int x, _Unwind_Action action, _Unwind_Exception_Class class, + struct _Unwind_Exception *exc, struct _Unwind_Context *ctx, void *arg) +{ + /* This would actually check for __libc_start_main or + pthread_start_thread. */ + if ((void *) _Unwind_GetRegionStart (ctx) == (void *) test3) + { + if (caught != 15) + abort (); + exit (0); + } + return _URC_NO_REASON; +} + +struct _Unwind_Exception ue; + +void +do_throw (void) +{ + ue.exception_class = 1; + ue.exception_cleanup = exception_cleanup; + _Unwind_ForcedUnwind (&ue, stop_fn, 0); +} + +int +main (void) +{ + test3 (); + abort (); +} Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 9:43 ` [basic-improvements] try/finally support for c/c++ - more tests Jakub Jelinek @ 2002-11-06 11:04 ` Joseph S. Myers 2002-11-06 15:34 ` Mark Mitchell 1 sibling, 0 replies; 128+ messages in thread From: Joseph S. Myers @ 2002-11-06 11:04 UTC (permalink / raw) To: Jakub Jelinek; +Cc: Aldy Hernandez, rth, gcc-patches, jason On Wed, 6 Nov 2002, Jakub Jelinek wrote: > * Makefile.in (USER_H): Install unwind.h. Installed header files are documented in sourcebuild.texi. -- Joseph S. Myers jsm28@cam.ac.uk ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 9:43 ` [basic-improvements] try/finally support for c/c++ - more tests Jakub Jelinek 2002-11-06 11:04 ` Joseph S. Myers @ 2002-11-06 15:34 ` Mark Mitchell 2002-11-06 16:03 ` Richard Henderson 1 sibling, 1 reply; 128+ messages in thread From: Mark Mitchell @ 2002-11-06 15:34 UTC (permalink / raw) To: Jakub Jelinek, Aldy Hernandez; +Cc: rth, gcc-patches, jason --On Wednesday, November 06, 2002 12:43:04 PM -0500 Jakub Jelinek <jakub@redhat.com> wrote: > Hi! > > On Tue, Nov 05, 2002 at 03:19:02PM -0800, Aldy Hernandez wrote: >> As promised. Here are the try/finally patches for C and C++. I've been offline for a few days, and am trying to catch up on email, not to mention the release. So, I apologize for jumping in late. But, I do not approve of adding try/finally to C and/or C++ until and unless ISO adds it. There is nothing you can do with try/finally in C++ you can't already do: try { X } finally { Y } can always be replaced with either of: (1) try { X } catch (...) { Y; throw; } Y; or: (2) { struct S { ~S() { Y } } s; X } depending on your stylistic preference. These examples show that Richard's point about needing to deal with unknown exception types is moot; the use of ... already allows you to avoid knowing the type. I do not think we should add exception support of any kind to GNU C; use C++ if you want exceptions. Please do not check in these patches until we've had a chance to hash this out more fully. If we do want to check these patches in, the semantics should be given in terms of translation to (1) above. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 15:34 ` Mark Mitchell @ 2002-11-06 16:03 ` Richard Henderson 2002-11-06 16:10 ` Gabriel Dos Reis ` (3 more replies) 0 siblings, 4 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-06 16:03 UTC (permalink / raw) To: Mark Mitchell; +Cc: Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Wed, Nov 06, 2002 at 03:32:20PM -0800, Mark Mitchell wrote: > There is nothing you can do with try/finally in C++ you can't already > do: > > try { X } finally { Y } > > can always be replaced with either of: > > (1) try { X } catch (...) { Y; throw; } Y; > > or: > > (2) { struct S { ~S() { Y } } s; X } > > depending on your stylistic preference. True. I was simply trying to make things easier for the thread library in having one macro work for both languages. > I do not think we should add exception support of any kind to GNU C; use > C++ if you want exceptions. See elsewhere about resistance compiling libc with a c++ compiler. The main problem is that you simply cannot implement cleanups with a few calls to a runtime library. There are data structures that the compiler must set up related to how it generated code. > If we do want to check these patches in, the semantics should be given > in terms of translation to (1) above. I don't agree with this. The EH ABI clearly distingishes between cleanups and catches. Thus the semantics are exactly those of (2), and not those of (1) at all. Indeed, even ISO C++ makes this distinction with std::uncaught_exception. Further, try/catch/rethrow does not express what happens when you use goto/break/continue/return to leave the try block. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:03 ` Richard Henderson @ 2002-11-06 16:10 ` Gabriel Dos Reis 2002-11-06 16:12 ` Richard Henderson 2002-11-06 16:47 ` Mark Mitchell ` (2 subsequent siblings) 3 siblings, 1 reply; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-06 16:10 UTC (permalink / raw) To: Richard Henderson Cc: Mark Mitchell, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason Richard Henderson <rth@redhat.com> writes: | Further, try/catch/rethrow does not express what happens when | you use goto/break/continue/return to leave the try block. Leaving a scope always implies destructors being run for local objects. -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:10 ` Gabriel Dos Reis @ 2002-11-06 16:12 ` Richard Henderson 2002-11-06 16:20 ` Gabriel Dos Reis 0 siblings, 1 reply; 128+ messages in thread From: Richard Henderson @ 2002-11-06 16:12 UTC (permalink / raw) To: Gabriel Dos Reis Cc: Mark Mitchell, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 01:10:57AM +0100, Gabriel Dos Reis wrote: > | Further, try/catch/rethrow does not express what happens when > | you use goto/break/continue/return to leave the try block. > > Leaving a scope always implies destructors being run for local > objects. Correct. But it doesn't imply running Y in Mark's example. Which is exactly my point. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:12 ` Richard Henderson @ 2002-11-06 16:20 ` Gabriel Dos Reis 2002-11-06 17:02 ` Per Bothner 0 siblings, 1 reply; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-06 16:20 UTC (permalink / raw) To: Richard Henderson Cc: Mark Mitchell, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason Richard Henderson <rth@redhat.com> writes: | On Thu, Nov 07, 2002 at 01:10:57AM +0100, Gabriel Dos Reis wrote: | > | Further, try/catch/rethrow does not express what happens when | > | you use goto/break/continue/return to leave the try block. | > | > Leaving a scope always implies destructors being run for local | > objects. | | Correct. But it doesn't imply running Y in Mark's example. | Which is exactly my point. Let me see if I'm not lost. I assume you're talking of try { X } finally { Y } being translated into (1) try { X } catch (...) { Y; throw; } Y; Right? Maybe I got the same (mis)understanding as Mark that Y should always be run. Am I wrong? -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:20 ` Gabriel Dos Reis @ 2002-11-06 17:02 ` Per Bothner 2002-11-06 17:14 ` Gabriel Dos Reis 0 siblings, 1 reply; 128+ messages in thread From: Per Bothner @ 2002-11-06 17:02 UTC (permalink / raw) To: Gabriel Dos Reis; +Cc: gcc-patches Gabriel Dos Reis wrote: > I assume you're talking of > > try { X } finally { Y } > > being translated into > > (1) try { X } catch (...) { Y; throw; } Y; > > Right? > > Maybe I got the same (mis)understanding as Mark that Y should always > be run. Am I wrong? What about: for {;;} { try { break; } finally { Y } } which runs Y, while: for (;;) { try { break; } catch (...) { Y; throw; } Y; } doesn't, if I understand things correctly. -- --Per Bothner per@bothner.com http://www.bothner.com/per/ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 17:02 ` Per Bothner @ 2002-11-06 17:14 ` Gabriel Dos Reis 0 siblings, 0 replies; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-06 17:14 UTC (permalink / raw) To: Per Bothner; +Cc: gcc-patches Per Bothner <per@bothner.com> writes: | Gabriel Dos Reis wrote: | | > I assume you're talking of | > | > try { X } finally { Y } | > | > being translated into | > | > (1) try { X } catch (...) { Y; throw; } Y; | > | > Right? | > | > Maybe I got the same (mis)understanding as Mark that Y should always | > be run. Am I wrong? | | What about: | | for {;;} { try { break; } finally { Y } } | | which runs Y, while: | | for (;;) { try { break; } catch (...) { Y; throw; } Y; } | | doesn't, if I understand things correctly. Thanks for the clarification! Then I think I would lean toward the "Resource Acquisition Is Initialization" approach i.e. option (2) offered by Mark in his message. -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:03 ` Richard Henderson 2002-11-06 16:10 ` Gabriel Dos Reis @ 2002-11-06 16:47 ` Mark Mitchell 2002-11-06 16:54 ` Matt Austern 2002-11-06 18:00 ` Zack Weinberg 2002-11-06 17:58 ` Fergus Henderson 2002-11-06 18:34 ` Geoff Keating 3 siblings, 2 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-06 16:47 UTC (permalink / raw) To: Richard Henderson; +Cc: Jakub Jelinek, Aldy Hernandez, gcc-patches, jason > See elsewhere about resistance compiling libc with a c++ compiler. I know there's resistance, but frankly I think that's just predjudice. Compile the bits you need C++ features for in C++. Avoid stuff that seems fragile, like virtual bases/virtual functions etc; just use try/catch and/or destructors if that's all you want. The functionality you need has been stable for ages and ages. I feel strongly that we should not try to bring C++ features into C, just to avoid having to compile some stuff in libc with G++. Especially as similar features may eventually go into ISO C with subtly different semantics. > The main problem is that you simply cannot implement cleanups with > a few calls to a runtime library. There are data structures that > the compiler must set up related to how it generated code. > >> If we do want to check these patches in, the semantics should be given >> in terms of translation to (1) above. I should have said (1) or (2). I'm comfortable with either formulation, and you're right that they are subtly different. If we do (2), we have to word it cleverly; a literal substitution wouldn't work because local variables wouldn't be available in S::~S. > Further, try/catch/rethrow does not express what happens when > you use goto/break/continue/return to leave the try block. True. I don't want to distract us by getting into that; I'm happy to go with the translation (2) which seems to be what you prefer, if we decide we absolutely must introduce this feature. I, however, am far from convinced. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:47 ` Mark Mitchell @ 2002-11-06 16:54 ` Matt Austern 2002-11-06 18:00 ` Zack Weinberg 1 sibling, 0 replies; 128+ messages in thread From: Matt Austern @ 2002-11-06 16:54 UTC (permalink / raw) To: Mark Mitchell Cc: Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Wednesday, November 6, 2002, at 04:44 PM, Mark Mitchell wrote: > I feel strongly that we should not try to bring C++ features into C, > just to avoid having to compile some stuff in libc with G++. > Especially > as similar features may eventually go into ISO C with subtly different > semantics. I have the same concerns as Mark. I'm nervous about the possibility that adding a major new language feature to our C compiler now, just to meet the needs of a single project, may conflict with future work on more general exception handling. I'd feel a lot better about this either if (1) it could be hidden behind builtins that looked like function calls, so that it didn't do anything like introducing new keywords or new kinds of scope into the language; or (2) it was done in the context of explicit consultation with WG14 and we could be pretty sure that we were headed in the same direction as standard C. --Matt ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:47 ` Mark Mitchell 2002-11-06 16:54 ` Matt Austern @ 2002-11-06 18:00 ` Zack Weinberg 2002-11-06 18:14 ` Gabriel Dos Reis ` (3 more replies) 1 sibling, 4 replies; 128+ messages in thread From: Zack Weinberg @ 2002-11-06 18:00 UTC (permalink / raw) To: Mark Mitchell Cc: Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Wed, Nov 06, 2002 at 04:44:49PM -0800, Mark Mitchell wrote: > >See elsewhere about resistance compiling libc with a c++ compiler. > > I know there's resistance, but frankly I think that's just predjudice. > > Compile the bits you need C++ features for in C++. Avoid stuff that > seems fragile, like virtual bases/virtual functions etc; just use > try/catch and/or destructors if that's all you want. The functionality > you need has been stable for ages and ages. > > I feel strongly that we should not try to bring C++ features into C, > just to avoid having to compile some stuff in libc with G++. Especially > as similar features may eventually go into ISO C with subtly different > semantics. To clarify, this is about pthread_cleanup_push/pop, right? Which are used in code that _uses_ libc, not just inside libc itself. I got the impression that the idea here was to be able to do #define pthread_cleanup_push(routine_, arg_) { \ __pthread_cleanup_t __cleanup_info; \ __cleanup_info.routine = routine_; \ __cleanup_info.arg = arg_; \ __cleanup_info.doit = 1; \ __try { #define pthread_cleanup_pop(doit_) \ __cleanup_info.doit = doit_; \ } __finally { \ if (__cleanup_info.doit) \ __cleanup_info.routine(__cleanup_info.arg); \ } } And the point of doing this is to get pthread_cancel handlers to be run when a C++ exception is thrown, and vice versa to get destructors to be run when pthread_cancel() happens. (pthread_cancel itself will presumably call _Unwind_RaiseException directly, in this scheme.) This is actually an important correctness issue for threading in C++. Currently, you can be reliable in the face of pthread_cancel, or you can be reliable in the face of exceptions being thrown, but not both at the same time. It is also, obviously, desirable not to have to maintain separate versions of these macros for C and C++. And I sympathize somewhat with the desire to create a generic extension rather than one specific to this precise situation. However. The code I sketched above has a number of correctness issues -- mostly due to the unhygenic nature of C preprocessor macros rather than to the try/finally construct itself. It is difficult to make them go away while still using the present proposal, but it would be very easy to get rid of them using a narrowly tailored one: #define pthread_cleanup_push(routine_, arg_) \ __builtin_cleanup_block(routine_, arg_) { #define pthread_cleanup_pop(doit_) \ __builtin_toggle_do_cleanup(doit_); } These are equivalent to this C++: struct cleanup { void (*routine)(void *); void *arg; int doit; cleanup(void (*R)(void *), void *A) : routine(R), arg(A), doit(1) { }; ~cleanup() { if(doit) routine(arg); } }; #define pthread_cleanup_push(R, A) { cleanup C(R, A); #define pthread_cleanup_pop(DOIT) C.doit = DOIT; } except that (a) the local variable is anonymous, (b) they work in C as well as C++, and (d) no declaration of struct cleanup is visible. Are there other uses of __try/__finally which y'all have in mind that wouldn't be covered by this? zw p.s. It would be nifty if setjmp/longjmp could be defined in terms of exception handling. Anyone put thought into that? ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 18:00 ` Zack Weinberg @ 2002-11-06 18:14 ` Gabriel Dos Reis 2002-11-06 18:58 ` Zack Weinberg 2002-11-06 22:37 ` Mark Mitchell ` (2 subsequent siblings) 3 siblings, 1 reply; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-06 18:14 UTC (permalink / raw) To: Zack Weinberg Cc: Mark Mitchell, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason Zack Weinberg <zack@codesourcery.com> writes: | p.s. It would be nifty if setjmp/longjmp could be defined in terms of | exception handling. Anyone put thought into that? EH in C++ sense essentially makes control flow flows one direction whereas setjmp/longjmp transfers control virtually anywhere. -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 18:14 ` Gabriel Dos Reis @ 2002-11-06 18:58 ` Zack Weinberg 2002-11-06 19:33 ` Gabriel Dos Reis 0 siblings, 1 reply; 128+ messages in thread From: Zack Weinberg @ 2002-11-06 18:58 UTC (permalink / raw) To: Gabriel Dos Reis Cc: Mark Mitchell, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 03:14:25AM +0100, Gabriel Dos Reis wrote: > Zack Weinberg <zack@codesourcery.com> writes: > > | p.s. It would be nifty if setjmp/longjmp could be defined in terms of > | exception handling. Anyone put thought into that? > > EH in C++ sense essentially makes control flow flows one direction > whereas setjmp/longjmp transfers control virtually anywhere. Imagine a setup like this: class jmp_buf { int setjmp_return_value; } __attribute__ ((always_passed_by_reference)); void calls_longjmp(jmp_buf env) { env.setjmp_return_value = 1; throw env; } void calls_setjmp(void) { try { jmp_buf env; env.setjmp_return_value = 0; control_transfers_here_twice: if (env.setjmp_return_value == 0) { puts("first call to setjmp()"); calls_longjmp(env); } else { puts("second call to setjmp()"); } } catch (jmp_buf E) { if (&E != &env) throw; goto control_transfers_here_twice; } } The "always_passed_by_reference" bit ensures that when control transfers to the catch clause, &E == &env if and only if it was 'env' that got longjmped to. This is not possible to achieve with macros, of course -- imagine this as a compact representation of the tree structure generated when __builtin_setjmp and __builtin_longjmp are used. (Which builtins should not be confused with the existing ones of the same names.) I claim that any use of setjmp/longjmp that won't work with this implementation is already invoking undefined behavior. Code that calls longjmp from a signal handler would have to be compiled with -fasynchronous-exceptions, and we wouldn't want to do this on a platform that couldn't unwind through a signal handler frame. (I'm assuming it is okay to perform that goto. I think such is the case, but I could be wrong.) zw ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 18:58 ` Zack Weinberg @ 2002-11-06 19:33 ` Gabriel Dos Reis 2002-11-06 22:15 ` Zack Weinberg 0 siblings, 1 reply; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-06 19:33 UTC (permalink / raw) To: Zack Weinberg Cc: Mark Mitchell, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason Zack Weinberg <zack@codesourcery.com> writes: | On Thu, Nov 07, 2002 at 03:14:25AM +0100, Gabriel Dos Reis wrote: | > Zack Weinberg <zack@codesourcery.com> writes: | > | > | p.s. It would be nifty if setjmp/longjmp could be defined in terms of | > | exception handling. Anyone put thought into that? | > | > EH in C++ sense essentially makes control flow flows one direction | > whereas setjmp/longjmp transfers control virtually anywhere. | | Imagine a setup like this: | | class jmp_buf { | int setjmp_return_value; | } __attribute__ ((always_passed_by_reference)); | | void calls_longjmp(jmp_buf env) | { | env.setjmp_return_value = 1; | throw env; | } | | void calls_setjmp(void) | { | try { | jmp_buf env; | env.setjmp_return_value = 0; | | control_transfers_here_twice: | if (env.setjmp_return_value == 0) { | puts("first call to setjmp()"); | calls_longjmp(env); | } else { | puts("second call to setjmp()"); | } | | } catch (jmp_buf E) { | if (&E != &env) | throw; | goto control_transfers_here_twice; | } | } | | The "always_passed_by_reference" bit ensures that when control | transfers to the catch clause, &E == &env if and only if it was | 'env' that got longjmped to. I'm not sure that extra linguistic facility is really in accordance with C++ rules (I'm not sure 12.8/15 applies here). Furthermore after call to calls_longjmp(), the object env ceases existing -- it isn't even visible in the catch block so I assume you wanted jmp_buf env; try { env.setjmp_return_value = 0; // ... [...] | I claim that any use of setjmp/longjmp that won't work with this | implementation is already invoking undefined behavior. Well, let's first address the case of situations that "work" with the above scheme before addressing the validity of the claim. What is supposed to happen for the rethrow case? -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 19:33 ` Gabriel Dos Reis @ 2002-11-06 22:15 ` Zack Weinberg 0 siblings, 0 replies; 128+ messages in thread From: Zack Weinberg @ 2002-11-06 22:15 UTC (permalink / raw) To: Gabriel Dos Reis Cc: Mark Mitchell, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 04:34:06AM +0100, Gabriel Dos Reis wrote: > | The "always_passed_by_reference" bit ensures that when control > | transfers to the catch clause, &E == &env if and only if it was > | 'env' that got longjmped to. > > I'm not sure that extra linguistic facility is really in accordance > with C++ rules (I'm not sure 12.8/15 applies here). I couldn't think of a clearer way to express the necessary effect. Each longjmp (throw) needs to transfer control to one specific setjmp (catch block); leveraging the uniqueness of objects seemed like the obvious way to do it. Unfortunately, jmp_buf objects are passed around by value, so I couldn't see any way to avoid some sort of internal hack. > Furthermore after call to calls_longjmp(), the object env ceases > existing -- it isn't even visible in the catch block so I assume you > wanted > > jmp_buf env; > try { > env.setjmp_return_value = 0; > // ... Yes. Oops. You can tell I've done more Python than C++, eh? That's actually good; we could then restructure it as jmp_buf env; env.setjmp_return_value = 0; for (;;) { try { ... break; } catch (jmp_buf E) { if (E is env) continue; throw; } } and avoid the dubious goto. Read "E is env" as whatever has to be done to check the identity constraint. > | I claim that any use of setjmp/longjmp that won't work with this > | implementation is already invoking undefined behavior. > > Well, let's first address the case of situations that "work" with the > above scheme before addressing the validity of the claim. What is > supposed to happen for the rethrow case? If control reaches "throw;" you mean? That happens when the jmp_buf that was jumped to, isn't the jmp_buf that was initialized in this stack frame, so we should keep unwinding. Presumably, higher up the stack, there is a jmp_buf that we do want to jump to. If not, do whatever is normally done for an unhandled exception (call std::terminate, isn't it? Come to think, if we're doing exceptions in C, we need a C equivalent of that...) zw ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 18:00 ` Zack Weinberg 2002-11-06 18:14 ` Gabriel Dos Reis @ 2002-11-06 22:37 ` Mark Mitchell 2002-11-06 23:30 ` Aldy Hernandez ` (2 more replies) 2002-11-07 10:06 ` Richard Henderson 2002-11-07 12:57 ` Hans-Peter Nilsson 3 siblings, 3 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-06 22:37 UTC (permalink / raw) To: Zack Weinberg Cc: Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason > #define pthread_cleanup_push(routine_, arg_) \ > __builtin_cleanup_block(routine_, arg_) { > > #define pthread_cleanup_pop(doit_) \ > __builtin_toggle_do_cleanup(doit_); } Something like this is a much, much closer to what I think we should do. Thanks for working this through. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 22:37 ` Mark Mitchell @ 2002-11-06 23:30 ` Aldy Hernandez 2002-11-07 1:03 ` Gabriel Dos Reis 2002-11-07 5:34 ` Michael Matz 2002-11-07 9:38 ` Mike Stump 2 siblings, 1 reply; 128+ messages in thread From: Aldy Hernandez @ 2002-11-06 23:30 UTC (permalink / raw) To: Mark Mitchell Cc: Zack Weinberg, Richard Henderson, Jakub Jelinek, gcc-patches, jason >>>>> "Mark" == Mark Mitchell <mark@codesourcery.com> writes: >> #define pthread_cleanup_push(routine_, arg_) \ >> __builtin_cleanup_block(routine_, arg_) { >> >> #define pthread_cleanup_pop(doit_) \ >> __builtin_toggle_do_cleanup(doit_); } > Something like this is a much, much closer to what I think we should > do. You know, I ain't gonna comment much on this because I was just an innocent bystander who just got told what to do, but... It seems we sometimes, in an effort to be purists, bend over backwards to avoid adding front end extensions and end up with rather ugly interfaces. It's not like try/finally isn't available in other compilers, and it's not like the __builtin_cleanup_block() stuff is aesthetically pleasing either. Just think, if any of the nifty features presently available as extensions in GCC (inline, nested functions, labels as values, inline assembly, etc) were to be brought up now, I'm 99% sure they'd be shot down, purely because they were front end extensions. I think we're loosing the GNU's Not Unix spirit. Be that as it may, my point is purely a philosophical one. I will not argue for either standpoint. Exception handling is not my thing. > Thanks for working this through. > -- > Mark Mitchell mark@codesourcery.com > CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 23:30 ` Aldy Hernandez @ 2002-11-07 1:03 ` Gabriel Dos Reis 0 siblings, 0 replies; 128+ messages in thread From: Gabriel Dos Reis @ 2002-11-07 1:03 UTC (permalink / raw) To: Aldy Hernandez Cc: Mark Mitchell, Zack Weinberg, Richard Henderson, Jakub Jelinek, gcc-patches, jason Aldy Hernandez <aldyh@redhat.com> writes: [...] | Just think, if any of the nifty features presently available as | extensions in GCC (inline, nested functions, labels as values, inline | assembly, etc) were to be brought up now, I'm 99% sure they'd be shot | down, purely because they were front end extensions. I think we're | loosing the GNU's Not Unix spirit. I don't understand how you came to that conclusion. Anyway, if you were to track, understand and fix the zillions of bugs caused by extensions that were put there with no in-depth understanding of its implications and interactions with the language and explorations of alternatives (and sometimes with conflicting semantics) I'm sure you would have a different stance. [ I did a tiny part of bug tracking; that wasn't picnic and I certainly don't like *some* extensions there in the language. I do find other useful. ] The issue isn't to shot down every extension. The issue is, given current experience with extensions (in the broad sense), given current C++ (resp. C) semantics and facilities, given current front-end complexities, bugs and plans, given a *clear* statement of the problem what points of the solutions space should we consider. The proposed patch is such a dramatic change that I can not imagine that it would be checked in with no discussion. -- Gaby ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 22:37 ` Mark Mitchell 2002-11-06 23:30 ` Aldy Hernandez @ 2002-11-07 5:34 ` Michael Matz 2002-11-07 8:14 ` Mark Mitchell 2002-11-07 11:38 ` Zack Weinberg 2002-11-07 9:38 ` Mike Stump 2 siblings, 2 replies; 128+ messages in thread From: Michael Matz @ 2002-11-07 5:34 UTC (permalink / raw) To: Mark Mitchell Cc: Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason Hi, On Wed, 6 Nov 2002, Mark Mitchell wrote: > > #define pthread_cleanup_push(routine_, arg_) \ > > __builtin_cleanup_block(routine_, arg_) { > > > > #define pthread_cleanup_pop(doit_) \ > > __builtin_toggle_do_cleanup(doit_); } > > Something like this is a much, much closer to what I think we should > do. > > Thanks for working this through. Uhh, that's exceedingly ugly. Try to think of the proposed semantic and then try to come up with syntax implementing that semantic. The special property of this extension is, that it changes control flow in a very non-trivial (but well defined) way. Every control flow related construct in C (except calls) are done by "top-level" keywords and syntactic structure (if, while, for, goto ...). Therefore I'm totally and strictly against implementing cleanups with the help of builtins, which have function-call like syntax. Now let's look at the wanted semantic of cleanups: "Do something (A), and if A is done, no matter what, do B". This means, we at least have the notion of two different statement sets, i.e. two blocks. Then we need at least one syntactic element to bind them together and give them that semantic. A keyword is the natural choice. The best choice of the placement of that keyword seems to be in front of the whole construct. That leads to: keyword { A } { B } This is esthetically unpleasant, because now it isn't very easy to see, that both blocks belong to the same construct, and are on the same level, i.e. it could be confused (structure-wise) with 'if (...) { A } { B }'. Therefore we do a similar thing like in if-else (it's not "if-else (...) { A } { B }" for a reason), which leads to keyword1 { A } keyword2 { B } Now you only need to choose how to call both keywords, and __finally seems to be good enough for the second. __try for the first is not optimal, because we not only "try" A, but really do it completely, but looking at other compilers having such constructs and C++ exception handling, it also isn't the worst choice. That some people here consider the lack of ability to pass around exception objects to be a deficiency stems from the fact, that sometimes in this thread exception handling and cleanups were confused. The proposed language extension has next to nothing to do with exceptions, but just with cleanups. That cleanups can happen while unwinding the stack for throwing an exceptions is the only connection. Regarding semantic again: block A shall only be entered by fall-through from the syntactically preceding statements, and shall be left only by return, break, fallthrough, goto to label (_not_ computed), by throwing an exception (maybe from a called function) or by exiting the program (in which case the cleanup needs not to be run). The same for B, except the language about the cleanup. I'm of course not sure, but I can't think of many variations how to design cleanups, ergo I think if ISO C once includes it, it will be very similar to what we would have now. I really think, that this is one of the more well-designed and unproblematic extensions. And contrary to some people here I don't even think it's such a invasive language change at all. It's quite orthogonal to the rest of the language by introducing a new toplevel construct. Contrary to statement expressions for instance. If people have problems with this extension they should name them so they can be fixed, instead of just being "sceptic" or "nervous", or generally just against it until some standard standardizes it (which by the way is anyway the wrong direction. Standards fixate existing practice, they don't establish it.) Ciao, Michael. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 5:34 ` Michael Matz @ 2002-11-07 8:14 ` Mark Mitchell 2002-11-07 8:37 ` Daniel Jacobowitz ` (2 more replies) 2002-11-07 11:38 ` Zack Weinberg 1 sibling, 3 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 8:14 UTC (permalink / raw) To: Michael Matz Cc: Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason > Standards fixate existing practice, they don't establish it. We've already got a standard that's relevant here. In particular, we have the C++ programming language, which provides the functionality needed. If you need that functionality, use that language, or another language (like Java, Ada, etc.) that provides that functionality. Now, I'm not fully understanding how this is going to be used, which is perhaps coloring my thinking. I'm getting the impression that this functionality is going to get buried in C headers that are going to get seen in *user* C code. Is that true? If it is true, it makes my above remark irrelevant; we need something that works in C. The question, of course, is *what* do we need. Let me try to see if I've got right what it is we're trying to accomplish. If I don't have it right, I'll not be intelligent in the discussion, so please correct me. We're trying to implement one particular piece of functionality required by the POSIX threads interface; namely "pthread_cleanup_push" and friends. (I know that any feature might get used more widely, but this is the motivation, as I understand it.) Furthermore, we're trying to make the POSIX threads cleanups play nice with exception-handling. Or are we trying to use EH mechanisms to make things go faster? Anyhow, if I write: try { pthread_cleanup_push (...); throw 3; } catch (...) { } and the system arranges to run the cleanup when the exception is thrown, the system is badly broken. So, I think I'm not getting the point. What interface is it that we think we need this functionality to implement? -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 8:14 ` Mark Mitchell @ 2002-11-07 8:37 ` Daniel Jacobowitz 2002-11-07 9:09 ` Mark Mitchell 2002-11-07 8:44 ` Jakub Jelinek 2002-11-07 12:18 ` Geoff Keating 2 siblings, 1 reply; 128+ messages in thread From: Daniel Jacobowitz @ 2002-11-07 8:37 UTC (permalink / raw) To: Mark Mitchell Cc: Michael Matz, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 08:12:05AM -0800, Mark Mitchell wrote: > >Standards fixate existing practice, they don't establish it. > > We've already got a standard that's relevant here. In particular, > we have the C++ programming language, which provides the functionality > needed. If you need that functionality, use that language, or another > language (like Java, Ada, etc.) that provides that functionality. > > Now, I'm not fully understanding how this is going to be used, which > is perhaps coloring my thinking. I'm getting the impression that this > functionality is going to get buried in C headers that are going to > get seen in *user* C code. Is that true? > > If it is true, it makes my above remark irrelevant; we need something > that works in C. The question, of course, is *what* do we need. That's right. pthread_cleanup_push/pop are user-accessible macros/functions. > Let me try to see if I've got right what it is we're trying to > accomplish. If I don't have it right, I'll not be intelligent in the > discussion, so please correct me. > > We're trying to implement one particular piece of functionality required > by the POSIX threads interface; namely "pthread_cleanup_push" and friends. > (I know that any feature might get used more widely, but this is the > motivation, as I understand it.) Furthermore, we're trying to make the Before people fixate on this any further, it's worth remembering that we've had requests for this feature in C before. I see one in September: From: "Michael Lovett" <mlovett@morpace.com> Subject: GCC Feature question I'm pretty sure there have been others. That's not any kind of overwhelming consideration, but it is something to keep this in perspective. > POSIX threads cleanups play nice with exception-handling. Or are we > trying to use EH mechanisms to make things go faster? The former. The discussion about try/finally being faster is in comparision to some of the other suggestions which involve nested functions or calling into C++. > Anyhow, if I write: > > try { pthread_cleanup_push (...); > throw 3; } > catch (...) { } > > and the system arranges to run the cleanup when the exception is thrown, > the system is badly broken. > > So, I think I'm not getting the point. > > What interface is it that we think we need this functionality to > implement? On the contrary, these are for cleanups that _would_ have to be run when that "throw 3" was triggered. It would have to be: try { pthread_cleanup_push (...); throw 3; pthread_cleanup_pop (...); } catch (...) { } though. For instance, if a thread is cancelled while holding stdio locks, the cleanups must be run in order to restore the state of the stdio structures and release the lock. Otherwise stdio becomes unusable after cancellation. (malloc has the same problem but doesn't use the cleanup handlers at present, I think...) -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 8:37 ` Daniel Jacobowitz @ 2002-11-07 9:09 ` Mark Mitchell 2002-11-07 9:19 ` Daniel Jacobowitz 0 siblings, 1 reply; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 9:09 UTC (permalink / raw) To: Daniel Jacobowitz Cc: Michael Matz, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason > On the contrary, these are for cleanups that _would_ have to be run > when that "throw 3" was triggered. It would have to be: > try { > pthread_cleanup_push (...); > throw 3; > pthread_cleanup_pop (...); > } catch (...) { } > > though. I did not understand the requirement that pthread_cleanup_push and pthread_cleanup_pop be within the same lexical scope. It's still arguable whether or not you should be calling the cleanup at this point. I don't see anything in the pthreads spec that says what happens if you do a "goto" out of the block, for example. I agree that, without my language lawyer hat on, doing the cleanup on any block exit seems like a good thing. You will, however, break code that presently does: try { pthread_cleanup_push (...); throw 3; pthread_cleanup_pop (...); } catch (...) { // Do the cleanup by hand; I know it will not have been run. } Well, let's not argue that. Our goals, then, seem to be: (1) Make life easier for C++ programmers by calling cleanups as exceptions propagate. (This can already be managed explicitly, with try/catch, but if we can fold it into the library, that's a good QOI thing. We do have to be very careful to document it;) (2) Shield GNU libc developers from having to write the few bits of the library that they want to be exception-safe in C++. The second bit carries no weight with me at all. It's no big deal to write a few source files in the C++ almost-superset of C. The first bit is, however, a good, user-focused idea. But why not just do that at the source level? In pthread.h: #ifdef __cplusplus #define pthread_cleanup_push(routine, arg) \ { struct pthread_cleanup c(routine, arg); #define pthread_cleanup_pop(execute) \ c.run(execute); } #endif with something like: struct pthread_cleanup { pthread_cleanup (void (*r)(void*), void *a) : r_(r), a_(a) {} ~pthread_cleanup () { if (r_) r_(a); } void run(int execute) { if (execute) { _r(_a); } _r = 0; } }; I'm sure there are subtleties I got wrong, but that's the idea. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 9:09 ` Mark Mitchell @ 2002-11-07 9:19 ` Daniel Jacobowitz 2002-11-07 9:53 ` Mark Mitchell 0 siblings, 1 reply; 128+ messages in thread From: Daniel Jacobowitz @ 2002-11-07 9:19 UTC (permalink / raw) To: Mark Mitchell Cc: Michael Matz, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 09:07:02AM -0800, Mark Mitchell wrote: > Our goals, then, seem to be: > > (1) Make life easier for C++ programmers by calling cleanups as > exceptions propagate. (This can already be managed explicitly, > with try/catch, but if we can fold it into the library, that's > a good QOI thing. We do have to be very careful to document it;) > > (2) Shield GNU libc developers from having to write the few bits of > the library that they want to be exception-safe in C++. > > The second bit carries no weight with me at all. It's no big deal to > write a few source files in the C++ almost-superset of C. It is when they're written in gnu99. It's also a royal pain to require a C++ compiler when building glibc; bootstrapping gets harder every day... > The first bit is, however, a good, user-focused idea. > > But why not just do that at the source level? In pthread.h: Then you require that all pthread_cleanup_push's which need to be unwound properly be written in C++ source files. In other words, using these in a library now requires that part of the library to be converted to C++ in order to be used from C++ safely. Not just talking the implementation of GNU libc here; all libraries which use pthreads cleanups. I'm sure there are other reasons but I've started to lose track of them in this discussion, so I'll step back now. I also approve of the extension on its own... -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 9:19 ` Daniel Jacobowitz @ 2002-11-07 9:53 ` Mark Mitchell 2002-11-07 9:57 ` Matt Austern 2002-11-07 10:43 ` Jason Merrill 0 siblings, 2 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 9:53 UTC (permalink / raw) To: Daniel Jacobowitz Cc: Michael Matz, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason > It is when they're written in gnu99. It's also a royal pain to require > a C++ compiler when building glibc; bootstrapping gets harder every > day... Well, you want C++ features, you need a C++ compiler. :-) I'd rather see ISO C99 extensions getting added to G++ than features that don't even exist in C++ getting added to GCC. > Then you require that all pthread_cleanup_push's which need to > be unwound properly be written in C++ source files. Precisely. I think that if you want exception-handling, you should use a language that has that feature. (Otherwise, I want to add Prolog unification and ML type inference to GNU C. :-)) And, if we really, really want exceptions in C, we should pick an existing, standardized model from the C family of languages -- namely the model in C++. Add try/catch, not try/finally. Or, perhaps better, and taking into account RTH's comments, add destructors. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 9:53 ` Mark Mitchell @ 2002-11-07 9:57 ` Matt Austern 2002-11-07 10:43 ` Jason Merrill 1 sibling, 0 replies; 128+ messages in thread From: Matt Austern @ 2002-11-07 9:57 UTC (permalink / raw) To: Mark Mitchell Cc: Daniel Jacobowitz, Michael Matz, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thursday, November 7, 2002, at 09:51 AM, Mark Mitchell wrote: > >> It is when they're written in gnu99. It's also a royal pain to >> require >> a C++ compiler when building glibc; bootstrapping gets harder every >> day... > > Well, you want C++ features, you need a C++ compiler. :-) > > I'd rather see ISO C99 extensions getting added to G++ than features > that don't even exist in C++ getting added to GCC. I suspect that most C99 features will be added to a future version of the C++ Standard in any case. There are a few that I think the C++ Standards Committee will be skeptical of, but only a few. I certainly wouldn't mind making some guesses about where C++ is going and anticipating the standard by a couple years. (Obviously C++ will get long long, for example.) --Matt ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 9:53 ` Mark Mitchell 2002-11-07 9:57 ` Matt Austern @ 2002-11-07 10:43 ` Jason Merrill 1 sibling, 0 replies; 128+ messages in thread From: Jason Merrill @ 2002-11-07 10:43 UTC (permalink / raw) To: Mark Mitchell Cc: Daniel Jacobowitz, Michael Matz, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches On Thu, 07 Nov 2002 09:51:03 -0800, Mark Mitchell <mark@codesourcery.com> wrote: > I think that if you want exception-handling, you should use a language > that has that feature. (Otherwise, I want to add Prolog unification and > ML type inference to GNU C. :-)) This isn't about exception handling, it's about exception-safe cleanups, a somewhat smaller target. > And, if we really, really want exceptions in C, we should pick an > existing, standardized model from the C family of languages -- namely > the model in C++. Add try/catch, not try/finally. try/catch is handling. Using a catch(...) for cleanups is horrible style, as you have to duplicate the code. And the EH runtime treats them differently. > Or, perhaps better, and taking into account RTH's comments, add > destructors. How would you do that? try/finally is a much simpler notion than destructors--it makes more sense to express destructors using try/finally than the other way around--and the explicit syntax seems more appropriate to the spirit of C. And there's lots of prior art for it, in Java, other C compilers, and many macro-based C exception handling implementations. It might be feasible to use something more specifically tailored to pthread cleanups, such as Zack's builtins, but if we want a more generally useful mechanism, this is it. Jason ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 8:14 ` Mark Mitchell 2002-11-07 8:37 ` Daniel Jacobowitz @ 2002-11-07 8:44 ` Jakub Jelinek 2002-11-07 12:18 ` Geoff Keating 2 siblings, 0 replies; 128+ messages in thread From: Jakub Jelinek @ 2002-11-07 8:44 UTC (permalink / raw) To: Mark Mitchell Cc: Michael Matz, Zack Weinberg, Richard Henderson, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 08:12:05AM -0800, Mark Mitchell wrote: > > Standards fixate existing practice, they don't establish it. > > We've already got a standard that's relevant here. In particular, > we have the C++ programming language, which provides the functionality > needed. If you need that functionality, use that language, or another > language (like Java, Ada, etc.) that provides that functionality. As has been mentioned previously, compiling GNU libc as C++ is hard, since it is a heavy user of -std=gnu99 features and extensions which are not in C++. > Now, I'm not fully understanding how this is going to be used, which > is perhaps coloring my thinking. I'm getting the impression that this > functionality is going to get buried in C headers that are going to > get seen in *user* C code. Is that true? Yes, among other places. > We're trying to implement one particular piece of functionality required > by the POSIX threads interface; namely "pthread_cleanup_push" and friends. > (I know that any feature might get used more widely, but this is the > motivation, as I understand it.) Furthermore, we're trying to make the > POSIX threads cleanups play nice with exception-handling. Or are we > trying to use EH mechanisms to make things go faster? Both. One goal is to make sure C++ destructors are run when cancelling a thread, properly interleaved with C cleanups. Of course the smaller overhead the mechanism has in the normal (ie. thread is not being cancelled) case, the better. > Anyhow, if I write: > > try { pthread_cleanup_push (...); > throw 3; pthread_cleanup_pop (doit); > } > catch (...) { } > > and the system arranges to run the cleanup when the exception is thrown, > the system is badly broken. Implementation of pthread_cleanup_pop using __try/__finally would have to do if ((doit) || __pthread_cancelling()) at the beginning of the __finally block, so if you do pthread_cleanup_pop (0), the cleanup will not be run when the exception is thrown, just when cancellation happens. __pthread_cancelling may be just a simple TLS variable access. Though if C has something like __try/__finally, then the programmer can as well use it directly and not through the horrible pthread_cleanup_* interface, while if pthread_cleanup_{push,pop} is implemented using builtins which match exactly what pthread_cleanup_{push,pop} is doing (as has been already suggested), then all the code is stuck in using it. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 8:14 ` Mark Mitchell 2002-11-07 8:37 ` Daniel Jacobowitz 2002-11-07 8:44 ` Jakub Jelinek @ 2002-11-07 12:18 ` Geoff Keating 2002-11-07 12:24 ` Daniel Jacobowitz 2002-11-07 12:32 ` Mark Mitchell 2 siblings, 2 replies; 128+ messages in thread From: Geoff Keating @ 2002-11-07 12:18 UTC (permalink / raw) To: Mark Mitchell Cc: Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason Mark Mitchell <mark@codesourcery.com> writes: > We're trying to implement one particular piece of functionality required > by the POSIX threads interface; namely "pthread_cleanup_push" and friends. > (I know that any feature might get used more widely, but this is the > motivation, as I understand it.) Furthermore, we're trying to make the > POSIX threads cleanups play nice with exception-handling. Yes, this is right, but your example is not the case we really care about. What we particularly want to make work is this C++ code: struct A { ~A() { ... } }; { A foo; sigpause (); // cancellation point, I hope } Here, if 'sigpause' gets cancelled, we want A's destructor to not be run. At present, cancellation is implemented using setjmp/longjmp, and so knows nothing about C++ destructors, and so this doesn't work. If we made C++ use setjmp/longjmp for destructors, that would be very expensive for all C++ code. Instead, we want to make cancellation use the C++ exception mechanism, because that's already there and so wouldn't impose any extra overhead on C++ code. The problem is that then we can't implement pthread_cleanup_push in C, because C can't interact with the exception mechanism. -- - Geoffrey Keating <geoffk@geoffk.org> ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 12:18 ` Geoff Keating @ 2002-11-07 12:24 ` Daniel Jacobowitz 2002-11-07 12:32 ` Mark Mitchell 1 sibling, 0 replies; 128+ messages in thread From: Daniel Jacobowitz @ 2002-11-07 12:24 UTC (permalink / raw) To: Geoff Keating Cc: Mark Mitchell, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 12:18:33PM -0800, Geoff Keating wrote: > Mark Mitchell <mark@codesourcery.com> writes: > > > We're trying to implement one particular piece of functionality required > > by the POSIX threads interface; namely "pthread_cleanup_push" and friends. > > (I know that any feature might get used more widely, but this is the > > motivation, as I understand it.) Furthermore, we're trying to make the > > POSIX threads cleanups play nice with exception-handling. > > Yes, this is right, but your example is not the case we really care > about. What we particularly want to make work is this C++ code: > > struct A { ~A() { ... } }; > > { > A foo; > sigpause (); // cancellation point, I hope > } > > Here, if 'sigpause' gets cancelled, we want A's destructor to not be > run. At present, cancellation is implemented using setjmp/longjmp, Don't you mean, "to be run"? > and so knows nothing about C++ destructors, and so this doesn't work. > If we made C++ use setjmp/longjmp for destructors, that would be very > expensive for all C++ code. Instead, we want to make cancellation use > the C++ exception mechanism, because that's already there and so > wouldn't impose any extra overhead on C++ code. The problem is that > then we can't implement pthread_cleanup_push in C, because C can't > interact with the exception mechanism. > > -- > - Geoffrey Keating <geoffk@geoffk.org> > -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 12:18 ` Geoff Keating 2002-11-07 12:24 ` Daniel Jacobowitz @ 2002-11-07 12:32 ` Mark Mitchell 2002-11-07 13:41 ` Geoff Keating 1 sibling, 1 reply; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 12:32 UTC (permalink / raw) To: Geoff Keating Cc: Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason --On Thursday, November 07, 2002 12:18:33 PM -0800 Geoff Keating <geoffk@geoffk.org> wrote: > Mark Mitchell <mark@codesourcery.com> writes: > >> We're trying to implement one particular piece of functionality required >> by the POSIX threads interface; namely "pthread_cleanup_push" and >> friends. (I know that any feature might get used more widely, but this >> is the motivation, as I understand it.) Furthermore, we're trying to >> make the POSIX threads cleanups play nice with exception-handling. > > Yes, this is right, but your example is not the case we really care > about. What we particularly want to make work is this C++ code: > > struct A { ~A() { ... } }; > > { > A foo; > sigpause (); // cancellation point, I hope > } > Here, if 'sigpause' gets cancelled, we want A's destructor to not be > run. I think you mean you want it *to* be run? These kinds of cases are easily handled by my #ifdef __cplusplus idea for the pthread_cleanup_push definition. As far as I can tell, the only reason to add anything to the compiler (whether it be try/finally or __builtin_pthread_cleanup_push, or whatever) is to make it possible to write C code that is linked with C++ programs, and have exceptions unwinding through the C code run the cleanups. Note that this can only happen if the C code calls C++ code, either explicitly or through a function pointer. In which case it has to worry about exceptions already, whether they come from cancellation or an exlicit throw. I'm confused. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 12:32 ` Mark Mitchell @ 2002-11-07 13:41 ` Geoff Keating 2002-11-07 14:06 ` Mark Mitchell 0 siblings, 1 reply; 128+ messages in thread From: Geoff Keating @ 2002-11-07 13:41 UTC (permalink / raw) To: mark; +Cc: zack, rth, jakub, aldyh, gcc-patches, jason > Date: Thu, 07 Nov 2002 12:29:46 -0800 > From: Mark Mitchell <mark@codesourcery.com> > > --On Thursday, November 07, 2002 12:18:33 PM -0800 Geoff Keating > <geoffk@geoffk.org> wrote: > > > Mark Mitchell <mark@codesourcery.com> writes: > > > >> We're trying to implement one particular piece of functionality required > >> by the POSIX threads interface; namely "pthread_cleanup_push" and > >> friends. (I know that any feature might get used more widely, but this > >> is the motivation, as I understand it.) Furthermore, we're trying to > >> make the POSIX threads cleanups play nice with exception-handling. > > > > Yes, this is right, but your example is not the case we really care > > about. What we particularly want to make work is this C++ code: > > > > struct A { ~A() { ... } }; > > > > { > > A foo; > > sigpause (); // cancellation point, I hope > > } > > > Here, if 'sigpause' gets cancelled, we want A's destructor to not be > > run. > > I think you mean you want it *to* be run? Yes. > These kinds of cases are easily handled by my #ifdef __cplusplus idea > for the pthread_cleanup_push definition. How? There aren't any pthread_cleanup_push calls in the example. You'd have to have sigpause (and the other cancellable calls) conditionalised on __cplusplus, and then to permit users to write programs in a mix of C and C++ you'd have to define some way to convert the exceptions thrown in C++ to the sj/lj calls in C. -- - Geoffrey Keating <geoffk@geoffk.org> ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 13:41 ` Geoff Keating @ 2002-11-07 14:06 ` Mark Mitchell 2002-11-07 14:39 ` Richard Henderson 0 siblings, 1 reply; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 14:06 UTC (permalink / raw) To: Geoff Keating; +Cc: zack, rth, jakub, aldyh, gcc-patches, jason > You'd have to have sigpause (and the other cancellable calls) > conditionalised on __cplusplus, and then to permit users to write > programs in a mix of C and C++ you'd have to define some way to > convert the exceptions thrown in C++ to the sj/lj calls in C. OK, I think I see the problem. Suppose the dynamic stack of your code looks like: C++ -> C -> C++ -> sigpause When cancellation occurs, you want to have sigpause throw an exception, run cleanups in C++, then run the pthread_cleanup_push stuff in C, the outer C++ cleanups agagin, etc. If the -> transitions are shared library boundaries, you have no problem; you can have your personality routines do the right thing. In fact, you can do that anyhow, if you mark your .o's as being C or C++. In C, you have pthread_cleanup_push keep a stack of cleanups. When unwinding through a a C .o, you run the stack. In C++, you use my pthread_cleanup_push class so that it just happens by itself. You have sigpause throw an exception, and you have a handler at the top of the stack, to finish the thread exit. (This last bit is what was going to happen with try/finally anyhow, I assume.) -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 14:06 ` Mark Mitchell @ 2002-11-07 14:39 ` Richard Henderson 2002-11-07 14:53 ` Mark Mitchell 0 siblings, 1 reply; 128+ messages in thread From: Richard Henderson @ 2002-11-07 14:39 UTC (permalink / raw) To: Mark Mitchell; +Cc: Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Thu, Nov 07, 2002 at 02:03:55PM -0800, Mark Mitchell wrote: > Suppose the dynamic stack of your code looks like: > > C++ -> C -> C++ -> sigpause > > When cancellation occurs, you want to have sigpause throw an exception, > run cleanups in C++, then run the pthread_cleanup_push stuff in C, > the outer C++ cleanups agagin, etc. Yes. > In C++, you use > my pthread_cleanup_push class so that it just happens by itself. Agreed. > In C, you have pthread_cleanup_push keep a stack of cleanups. > When unwinding through a a C .o, you run the stack. How, exactly, do you do that without having C use EH? Or, more specifically, how do you interleave the C stack and the C++ EH? This is the *exactly* the problem that suggested try/finally be used in the first place. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 14:39 ` Richard Henderson @ 2002-11-07 14:53 ` Mark Mitchell 2002-11-07 15:14 ` Geoff Keating 2002-11-07 15:45 ` Richard Henderson 0 siblings, 2 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 14:53 UTC (permalink / raw) To: Richard Henderson; +Cc: Geoff Keating, zack, jakub, aldyh, gcc-patches, jason --On Thursday, November 07, 2002 02:39:02 PM -0800 Richard Henderson <rth@redhat.com> wrote: > On Thu, Nov 07, 2002 at 02:03:55PM -0800, Mark Mitchell wrote: >> Suppose the dynamic stack of your code looks like: >> >> C++ -> C -> C++ -> sigpause >> >> When cancellation occurs, you want to have sigpause throw an exception, >> run cleanups in C++, then run the pthread_cleanup_push stuff in C, >> the outer C++ cleanups agagin, etc. > > Yes. Well, I'm catching up, and nobody is throwing up. We're all trying. Finally. > How, exactly, do you do that without having C use EH? Or, > more specifically, how do you interleave the C stack and > the C++ EH? When in C code, and you hit pthread_cleanup_push, call into the runtime passing the address of the start and end of the function you're in, and the frame pointer. When unwinding, notice that you're in that PC range with that frame pointer, and run the cleanups that correspond to that range. You're guaranteed to be getting these in the right order; as you unwind you'll always be pulling stuff off the front of the list. The call to register the handler needn't be a call; it could be inlined. You need is to hook a record on the front of a piece of thread-specific data. I bet the idea of using the frame pointer to tell function instances apart doesn't quite work, but I bet some modification of that idea could work. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 14:53 ` Mark Mitchell @ 2002-11-07 15:14 ` Geoff Keating 2002-11-07 15:37 ` Mark Mitchell 2002-11-07 15:45 ` Richard Henderson 1 sibling, 1 reply; 128+ messages in thread From: Geoff Keating @ 2002-11-07 15:14 UTC (permalink / raw) To: Mark Mitchell; +Cc: zack, jakub, aldyh, gcc-patches, jason Mark Mitchell <mark@codesourcery.com> writes: > --On Thursday, November 07, 2002 02:39:02 PM -0800 Richard Henderson > <rth@redhat.com> wrote: > > How, exactly, do you do that without having C use EH? Or, > > more specifically, how do you interleave the C stack and > > the C++ EH? > > When in C code, and you hit pthread_cleanup_push, call into the runtime > passing the address of the start and end of the function you're in, and > the frame pointer. When unwinding, notice that you're in that PC range > with that frame pointer, and run the cleanups that correspond to that > range. You're guaranteed to be getting these in the right order; as > you unwind you'll always be pulling stuff off the front of the list. Wouldn't that: (a) slow down normal C++ unwinding, because you have to keep looking for runtime-installed cleanups? and (b) still require unwinding data for the C code? -- - Geoffrey Keating <geoffk@geoffk.org> ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 15:14 ` Geoff Keating @ 2002-11-07 15:37 ` Mark Mitchell 2002-11-08 11:30 ` Geoff Keating 0 siblings, 1 reply; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 15:37 UTC (permalink / raw) To: Geoff Keating; +Cc: zack, jakub, aldyh, gcc-patches, jason > (a) slow down normal C++ unwinding, because you have to keep looking > for runtime-installed cleanups? and That's pretty much a total non-issue, but it's true. It would be a quick check, and exceptions are expensive anyhow; as a percentage of EH-handling cost, let alone as a precentage of program time, this would be free. > (b) still require unwinding data for the C code? Only a very ittle. I'm not sure you'd even need the typical data; just enough to figure out what function invocation you're in. You certainly wouldn't need per-block-including-cleanup information, which is what would happen with try-finally. The key difference from try/finally in this respect is that the pthread_cleanup_push interface takes a function pointer and an argument; there's noting in there to allow you to access local variables, etc. So, you don't need to really unwind the frame; you just need to know that you need to call the function. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 15:37 ` Mark Mitchell @ 2002-11-08 11:30 ` Geoff Keating 0 siblings, 0 replies; 128+ messages in thread From: Geoff Keating @ 2002-11-08 11:30 UTC (permalink / raw) To: mark; +Cc: zack, jakub, aldyh, gcc-patches, jason > Date: Thu, 07 Nov 2002 15:34:53 -0800 > From: Mark Mitchell <mark@codesourcery.com> > > (a) slow down normal C++ unwinding, because you have to keep looking > > for runtime-installed cleanups? and > > That's pretty much a total non-issue, but it's true. It would be a > quick check, and exceptions are expensive anyhow; as a percentage of > EH-handling cost, let alone as a precentage of program time, this > would be free. This would need to be measured... There would also be ABI issues, of course, since this is a global list shared by everything. > > (b) still require unwinding data for the C code? > > Only a very ittle. I'm not sure you'd even need the typical > data; just enough to figure out what function invocation you're in. > You certainly wouldn't need per-block-including-cleanup information, > which is what would happen with try-finally. > > The key difference from try/finally in this respect is that the > pthread_cleanup_push interface takes a function pointer and an argument; > there's noting in there to allow you to access local variables, etc. > > So, you don't need to really unwind the frame; you just need to know > that you need to call the function. How do you handle the case of C++ (with destructor) -> C -> C++ -> cancellable function if the C frame never calls pthread_cleanup_push? No, you have to have unwinding information for all stack frames. In fact, you might want to think about what the code is going to have to do for C++ (with destructor) -> C (with cleanup) -> cancellable function after the cleanup in the C code, there'll need to be some way to `rethrow' an exception which may never have been thrown in the first place. It's worth pointing out that DWARF2-based cleanup information is likely to be smaller than each entry in this global list (let alone the code to add to the global list), and is allocated statically per-function at compile-time rather than dynamically per-function-invocation at runtime. -- - Geoffrey Keating <geoffk@geoffk.org> ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 14:53 ` Mark Mitchell 2002-11-07 15:14 ` Geoff Keating @ 2002-11-07 15:45 ` Richard Henderson 2002-11-07 16:21 ` Mark Mitchell 1 sibling, 1 reply; 128+ messages in thread From: Richard Henderson @ 2002-11-07 15:45 UTC (permalink / raw) To: Mark Mitchell; +Cc: Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Thu, Nov 07, 2002 at 02:50:47PM -0800, Mark Mitchell wrote: > When in C code, and you hit pthread_cleanup_push, call into the runtime > passing the address of the start and end of the function you're in, and > the frame pointer. When unwinding, notice that you're in that PC range > with that frame pointer, and run the cleanups that correspond to that > range. You're guaranteed to be getting these in the right order; as > you unwind you'll always be pulling stuff off the front of the list. I don't like the idea of registering such information at runtime. It is a fact that to unwind through functions at all you have to compile with -fexceptions, otherwise the data in .eh_frame does not exist. And if .eh_frame does not exist, we don't have enough information to find the next call frame. What you're asking for is that we have .eh_frame data, but that we go look somewhere else when it comes time to decide if the frame wants to handle exceptions. This look-aside will have to happen for each and every call frame, because we don't know which frames are written in C and which aren't. (And before you mention the personality routine, you should note that any frame that does not actually use EH constructs does not have a personality routine and is thus not an indicator of language.) Whereas if we add some sort of EH block primitive to C, the compiler marks which regions need cleanups statically, in read-only data structures, which are examined as normal during the unwind phase. I think your option slows down EH for C++ and Java for no good reason. --- I don't really comprehend the resistance to adding try/finally to C. I never would have guessed that it would have been greeted with anything but "hey that's cool". I apologize to Aldy for getting him into this mess. I really can't think of any solution to the thread cancelation problem that works as cleanly and correctly as try/finally. Yes, I can think of a few hacks that might could be made to work, but that's all they are -- hacks. It's not like we're even breaking new ground on the language front. Microsoft has supported try/finally in their C compiler for years. I can't imagine WG14 being so bull-headed as to define a similar construct that is wildly incompatible with prior art. Of course, Microsoft fails to define their extension in anything even approaching standards legaleese, but I think that we're on safe ground with the basic concept, and if we make all the horrible corner cases undefined we'll still be ok if the future standard does something different. If you continue to be rock solid dead-set against this extension, I guess I'll honor that and think of something else (probably with something akin to longjmp_unwind). That won't happen until I get back from vacation late next week though. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 15:45 ` Richard Henderson @ 2002-11-07 16:21 ` Mark Mitchell 2002-11-07 16:44 ` aldyh ` (4 more replies) 0 siblings, 5 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 16:21 UTC (permalink / raw) To: Richard Henderson; +Cc: Geoff Keating, zack, jakub, aldyh, gcc-patches, jason > What you're asking for is that we have .eh_frame data, but that > we go look somewhere else when it comes time to decide if the > frame wants to handle exceptions. This look-aside will have to > happen for each and every call frame, because we don't know which > frames are written in C and which aren't. Couldn't it get a bit in its frame info to say whether or not it calls pthread_cleanup_push? That would make the check pretty cheap. (I'm not nearly as familiar as you with the format of that data; it might well be that there's no place to put that bit.) > It's not like we're even breaking new ground on the language front. > Microsoft has supported try/finally in their C compiler for years. Yes -- I wrote a pile of code that used it heavily. :-) It has somewhat fancy semantics. For example, you can catch floating-point exceptions this way and other things that would be signals in UNIX. They have a "__leave" keyword; they have exception handling (as well as cleanups) and they have ways to say whether you keep unwinding, or stop where you are, when you hit the handler. The aysnchronous exception aspect of their stuff is particularly interesting. It's partly because of Microsoft's stuff that I'm so nervous about this feature. Their semantics are not always what people expect, but ours probably won't match theirs, and the next thing that will happen will be that people will want to port "structured exception-handling" code to GCC, and then we'll be in trouble. > I don't really comprehend the resistance to adding try/finally to C. > I never would have guessed that it would have been greeted with > anything but "hey that's cool". You won't make that mistake again. :-) We ought to be talking about new language features before we implement them, so we can have the arguments up front. I apologize to Aldy too -- the patches are technically sound, and the goal of improving interactions between threads and C++ is a good one. I appreciate the effort, and apologize if I've come across otherwise. > If you continue to be rock solid dead-set against this extension, > I guess I'll honor that and think of something else (probably with > something akin to longjmp_unwind). That won't happen until I get > back from vacation late next week though. I promise not to be a complete jerk. :-) If everyone else wants to do this, I'll go along. I would prefer longjmp_unwind; that's something we're supposed to have anyhow, and it would be very useful in making existing C libraries play more nicely with C++, so implementing that would be a definite win. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 16:21 ` Mark Mitchell @ 2002-11-07 16:44 ` aldyh 2002-11-07 17:06 ` Richard Henderson ` (3 subsequent siblings) 4 siblings, 0 replies; 128+ messages in thread From: aldyh @ 2002-11-07 16:44 UTC (permalink / raw) To: Mark Mitchell Cc: Richard Henderson, Geoff Keating, zack, jakub, gcc-patches, jason > I apologize to Aldy too -- the patches are technically sound, and the > goal of improving interactions between threads and C++ is a good one. > I appreciate the effort, and apologize if I've come across otherwise. Just wake me up when all the apolgizing is done and y'all decide what's going to be implemented. Of course I'm hoping it'll be try/finally, cuz I *think* I already have a patch for that and I really don't have many cycles left to work on this ;-))). Aldy ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 16:21 ` Mark Mitchell 2002-11-07 16:44 ` aldyh @ 2002-11-07 17:06 ` Richard Henderson 2002-11-07 17:10 ` Jakub Jelinek ` (2 subsequent siblings) 4 siblings, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-07 17:06 UTC (permalink / raw) To: Mark Mitchell; +Cc: Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Thu, Nov 07, 2002 at 04:19:03PM -0800, Mark Mitchell wrote: > It has somewhat fancy semantics... Well, the __finally part of Microsoft's extensions are fairly normal. It's the __except part of their extensions that are fancy. That's the one I *don't* want to implement. ;-) > I would prefer longjmp_unwind; that's something we're supposed to > have anyhow, and it would be very useful in making existing C > libraries play more nicely with C++, so implementing that would be > a definite win. I'll play with this week after next and see how it goes. If it can be made to interoperate correctly across c/c++, as well as not absolutely requiring C to be compiled with -fexceptions, then we'll go ahead with that. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 16:21 ` Mark Mitchell 2002-11-07 16:44 ` aldyh 2002-11-07 17:06 ` Richard Henderson @ 2002-11-07 17:10 ` Jakub Jelinek 2002-11-07 17:29 ` Mark Mitchell 2002-11-07 22:07 ` Alexandre Oliva 2002-11-08 9:31 ` Michael Matz 4 siblings, 1 reply; 128+ messages in thread From: Jakub Jelinek @ 2002-11-07 17:10 UTC (permalink / raw) To: Mark Mitchell Cc: Richard Henderson, Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Thu, Nov 07, 2002 at 04:19:03PM -0800, Mark Mitchell wrote: > > What you're asking for is that we have .eh_frame data, but that > > we go look somewhere else when it comes time to decide if the > > frame wants to handle exceptions. This look-aside will have to > > happen for each and every call frame, because we don't know which > > frames are written in C and which aren't. > > Couldn't it get a bit in its frame info to say whether or not it calls > pthread_cleanup_push? That would make the check pretty cheap. (I'm > not nearly as familiar as you with the format of that data; it might > well be that there's no place to put that bit.) You mean statically into .gcc_except_table, or dynamically? Statically could be doable through some builtin and some hacks, dynamically would be way harder. > It has somewhat fancy semantics. For example, you can catch > floating-point exceptions this way and other things that would be > signals in UNIX. They have a "__leave" keyword; they have exception > handling (as well as cleanups) and they have ways to say whether you > keep unwinding, or stop where you are, when you hit the handler. > > The aysnchronous exception aspect of their stuff is particularly > interesting. > > It's partly because of Microsoft's stuff that I'm so nervous about > this feature. Their semantics are not always what people expect, but > ours probably won't match theirs, and the next thing that will happen > will be that people will want to port "structured exception-handling" > code to GCC, and then we'll be in trouble. That's why the proposal is about __try/__finally only, not __except where it is e.g. not clear at all what happens if you throw in C++ and __except control expression returns -1. At least from what I read in MSFT docs on the web, their __try/__finally matches Aldy's patch. > I would prefer longjmp_unwind; that's something we're supposed to > have anyhow, and it would be very useful in making existing C > libraries play more nicely with C++, so implementing that would be > a definite win. longjmp_unwind would be good to have. But __builtin_setjmp has higher runtime overhead than __try/__finally for pthread_cleanups (especially on some architectures __builtin_setjmp is really expensive), plus unless I misunderstood how longjmp_unwind is supposed to work, longjmp_unwind needs to be passed address to the youngest jmp_buf on the stack, which means maintaining a chain of nested jmp_buf's on the stack with the head of the chain in some TLS variable (Richard, please correct me if you have a better idea). __try/__finally can well interact with longjmp_unwind - longjmp_unwind would just call all the __finally blocks while unwinding to the longjmp_unwind target. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 17:10 ` Jakub Jelinek @ 2002-11-07 17:29 ` Mark Mitchell 2002-11-07 17:43 ` Richard Henderson 2002-11-07 17:52 ` Jason Merrill 0 siblings, 2 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 17:29 UTC (permalink / raw) To: Jakub Jelinek Cc: Richard Henderson, Geoff Keating, zack, aldyh, gcc-patches, jason > You mean statically into .gcc_except_table, or dynamically? > Statically could be doable through some builtin and some hacks, > dynamically would be way harder. I meant statically -- a "you have to check to see if I might have registered anything" bit. > That's why the proposal is about __try/__finally only, not __except > where it is e.g. not clear at all what happens if you throw in C++ > and __except control expression returns -1. > At least from what I read in MSFT docs on the web, their __try/__finally > matches Aldy's patch. Except that it also handles asynchronous exceptions, which ours doesn't. Where we'd get a SIGFPE you get a structured exception in Microsoft's stuff. >> I would prefer longjmp_unwind; that's something we're supposed to >> have anyhow, and it would be very useful in making existing C >> libraries play more nicely with C++, so implementing that would be >> a definite win. > > longjmp_unwind would be good to have. Well, we all seem to agree on that. So, if we can do it that way, we get a definitively useful feature required by the ABI, and we don't open a can of worms on the language side. If it's really too dang slow, we can do something different. On the other hand, you'll have avoided adding frame information to every C program, which is a big win on space, and something our C users have told us they don't want in the past. And you can avoid the setjmps if you write your code in C++; there you can use the resource-acquisition-as-initialization idiom. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 17:29 ` Mark Mitchell @ 2002-11-07 17:43 ` Richard Henderson 2002-11-07 17:55 ` Mark Mitchell 2002-11-07 17:52 ` Jason Merrill 1 sibling, 1 reply; 128+ messages in thread From: Richard Henderson @ 2002-11-07 17:43 UTC (permalink / raw) To: Mark Mitchell Cc: Jakub Jelinek, Geoff Keating, zack, aldyh, gcc-patches, jason On Thu, Nov 07, 2002 at 05:26:38PM -0800, Mark Mitchell wrote: > Except that it also handles asynchronous exceptions, which ours doesn't. Heh. Not that I've tried, but I bet theirs doesn't *really* handle asynchronous exceptions any more than ours does. I bet the best they can actually handle properly are synchronous exceptions -- which we can also do with -fnon-call-exceptions. The difference between SIGFPE and SIGALRM is very significant. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 17:43 ` Richard Henderson @ 2002-11-07 17:55 ` Mark Mitchell 0 siblings, 0 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 17:55 UTC (permalink / raw) To: Richard Henderson Cc: Jakub Jelinek, Geoff Keating, zack, aldyh, gcc-patches, jason --On Thursday, November 07, 2002 05:43:28 PM -0800 Richard Henderson <rth@redhat.com> wrote: > On Thu, Nov 07, 2002 at 05:26:38PM -0800, Mark Mitchell wrote: >> Except that it also handles asynchronous exceptions, which ours doesn't. > > Heh. Not that I've tried, but I bet theirs doesn't *really* handle > asynchronous exceptions any more than ours does. I bet the best they > can actually handle properly are synchronous exceptions -- which we > can also do with -fnon-call-exceptions. > > The difference between SIGFPE and SIGALRM is very significant. You're probably correct. They handle the SIGFPE, SIGSEGV, etc., kind of stuff -- probably not SIGALRM. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 17:29 ` Mark Mitchell 2002-11-07 17:43 ` Richard Henderson @ 2002-11-07 17:52 ` Jason Merrill 2002-11-07 17:57 ` Mark Mitchell 1 sibling, 1 reply; 128+ messages in thread From: Jason Merrill @ 2002-11-07 17:52 UTC (permalink / raw) To: Mark Mitchell Cc: Jakub Jelinek, Richard Henderson, Geoff Keating, zack, aldyh, gcc-patches On Thu, 07 Nov 2002 17:26:38 -0800, Mark Mitchell <mark@codesourcery.com> wrote: >> That's why the proposal is about __try/__finally only, not __except >> where it is e.g. not clear at all what happens if you throw in C++ >> and __except control expression returns -1. >> At least from what I read in MSFT docs on the web, their __try/__finally >> matches Aldy's patch. > > Except that it also handles asynchronous exceptions, which ours doesn't. > Where we'd get a SIGFPE you get a structured exception in Microsoft's > stuff. That has nothing to do with the semantics of try/finally, which just deals with cleaning up after whatever exceptions do happen to be thrown. Jason ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 17:52 ` Jason Merrill @ 2002-11-07 17:57 ` Mark Mitchell 2002-11-07 18:17 ` Zack Weinberg 2002-11-07 19:28 ` Daniel Jacobowitz 0 siblings, 2 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 17:57 UTC (permalink / raw) To: Jason Merrill Cc: Jakub Jelinek, Richard Henderson, Geoff Keating, zack, aldyh, gcc-patches --On Thursday, November 07, 2002 08:52:37 PM -0500 Jason Merrill <jason@redhat.com> wrote: > On Thu, 07 Nov 2002 17:26:38 -0800, Mark Mitchell <mark@codesourcery.com> > wrote: > >>> That's why the proposal is about __try/__finally only, not __except >>> where it is e.g. not clear at all what happens if you throw in C++ >>> and __except control expression returns -1. >>> At least from what I read in MSFT docs on the web, their __try/__finally >>> matches Aldy's patch. >> >> Except that it also handles asynchronous exceptions, which ours doesn't. >> Where we'd get a SIGFPE you get a structured exception in Microsoft's >> stuff. > > That has nothing to do with the semantics of try/finally, which just deals > with cleaning up after whatever exceptions do happen to be thrown. This horse is pretty dang dead, but the point is that people will *expect* that the construct behaves the same way as Microsoft's "structured exception handling" stuff -- in every way. Part of that is handling SIGFPE type events. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 17:57 ` Mark Mitchell @ 2002-11-07 18:17 ` Zack Weinberg 2002-11-07 18:29 ` Mark Mitchell 2002-11-07 19:28 ` Daniel Jacobowitz 1 sibling, 1 reply; 128+ messages in thread From: Zack Weinberg @ 2002-11-07 18:17 UTC (permalink / raw) To: Mark Mitchell; +Cc: gcc-patches On Thu, Nov 07, 2002 at 05:55:21PM -0800, Mark Mitchell wrote: > --On Thursday, November 07, 2002 08:52:37 PM -0500 Jason Merrill > <jason@redhat.com> wrote: > >On Thu, 07 Nov 2002 17:26:38 -0800, Mark Mitchell <mark@codesourcery.com> > >wrote: > >>Except that it also handles asynchronous exceptions, which ours doesn't. > >>Where we'd get a SIGFPE you get a structured exception in Microsoft's > >>stuff. > > > >That has nothing to do with the semantics of try/finally, which just deals > >with cleaning up after whatever exceptions do happen to be thrown. > > This horse is pretty dang dead, but the point is that people will *expect* > that the construct behaves the same way as Microsoft's "structured > exception handling" stuff -- in every way. Part of that is handling > SIGFPE type events. Y'know, I don't see why people would think that. It doesn't have __except or __catch or whatever Microsoft calls it, and we say explicitly that this is only for pthread_cancel() and for exceptions thrown by other language runtimes... zw ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 18:17 ` Zack Weinberg @ 2002-11-07 18:29 ` Mark Mitchell 2002-11-07 21:23 ` Robert Lipe ` (2 more replies) 0 siblings, 3 replies; 128+ messages in thread From: Mark Mitchell @ 2002-11-07 18:29 UTC (permalink / raw) To: Zack Weinberg; +Cc: gcc-patches > Y'know, I don't see why people would think that. It doesn't have > __except or __catch or whatever Microsoft calls it, and we say > explicitly that this is only for pthread_cancel() and for exceptions > thrown by other language runtimes... Maybe I have been so often burned by these language extensions that I am overly paranoid. It's certainly possible, and Matt Austern has stopped commenting, so he is perhaps convinced, leaving me as a lone voice of insane conservatism. In contrast to Alexandre, I always thought GCC's C front end philosophy of having basically every feature in any language was just plain nuts. It's certainly lead to some major oddness over the years. In the last several weeks, I've fixed probably twenty or so bugs; of those about half have to do with language extensions. These included zero-sized structure problems, implicit typename problems, strange brace-enclosed initializer extensions, the zero-sized array extension, and probably a few more. Several of the fixes required not just a simple "oops, forgot that could be that way" kind of change, but a "hmm -- now what should this mean?" kind of change. There's way too much bugginess associated with extensions. We try to take credit for introducing extensions that are now part of C99 -- but some of them are in C99 with rather different syntax, with the result that it's now even harder for us. VLAs are a good example; our VLAs aren't C99 VLAs. I agree that try/finally is a lot better than, say, nested functions, though. Maybe we could horse-trade; we pull out zero-sized structures or nested functions, and replace them with try/finally. :-) -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 18:29 ` Mark Mitchell @ 2002-11-07 21:23 ` Robert Lipe 2002-11-07 21:32 ` Jason Merrill 2002-11-08 4:48 ` Nicola Pero 2002-11-08 10:02 ` Matt Austern 2 siblings, 1 reply; 128+ messages in thread From: Robert Lipe @ 2002-11-07 21:23 UTC (permalink / raw) To: gcc-patches Mark Mitchell wrote: > There's way too much bugginess associated with extensions. Language design is really hard. History has proven that GCC isn't _that_ good at it. (I can hear the "boo"s already. Sorry.) > We try to take credit for introducing extensions that are now part of > C99 -- but some of them are in C99 with rather different syntax, with > the result that it's now even harder for us. VLAs are a good example; > our VLAs aren't C99 VLAs. Working now with other compilers that correctly implement C99 'inline', people are mystified that it isn't the same as GNU C's definition of 'inline'. VLAs, zero length arrays, and math library extensions have often turned into similar head-screws once officially standardized becuase they've crept into the GNU C/libc vernacular without clear markings that they are extensions to the pertinent specs. Free software folks that like to complain about evil vendor extensions to standards then run off and define their own mystify me. At the very least, please consider naming the reserved tokens "gnuc_try" or "_try" or something to make people realize that it isn't part of the official language/library that is portable C. RJL ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 21:23 ` Robert Lipe @ 2002-11-07 21:32 ` Jason Merrill 0 siblings, 0 replies; 128+ messages in thread From: Jason Merrill @ 2002-11-07 21:32 UTC (permalink / raw) To: gcc-patches On Thu, 7 Nov 2002 23:23:55 -0600, Robert Lipe <robertlipe@usa.net> wrote: > At the very least, please consider naming the reserved tokens "gnuc_try" > or "_try" or something to make people realize that it isn't part of the > official language/library that is portable C. They're named __try and __finally in the patch. Jason ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 18:29 ` Mark Mitchell 2002-11-07 21:23 ` Robert Lipe @ 2002-11-08 4:48 ` Nicola Pero 2002-11-08 5:47 ` Jakub Jelinek 2002-11-08 10:02 ` Matt Austern 2 siblings, 1 reply; 128+ messages in thread From: Nicola Pero @ 2002-11-08 4:48 UTC (permalink / raw) To: Mark Mitchell; +Cc: Zack Weinberg, gcc-patches > > Y'know, I don't see why people would think that. It doesn't have > > __except or __catch or whatever Microsoft calls it, and we say > > explicitly that this is only for pthread_cancel() and for exceptions > > thrown by other language runtimes... > > Maybe I have been so often burned by these language extensions that I > am overly paranoid. It's certainly possible, and Matt Austern has > stopped commenting, so he is perhaps convinced, leaving me as a lone > voice of insane conservatism. Well you're not a lone voice of insance conservatism, I actually think you are quite well giving voices to the puzzled C users, like me. :-) In all this discussion, I didn't quite find discussed how it would work in C/ObjC, from a pure C/ObjC perspective. Which IMO is essential to have the C extension approved. The suggestion that this change is good because "it makes C look more like C++ so that it's easier to integrate C and C++" might be good for C++ hackers and lovers, but it's definitely unconvincing for C/ObjC users with no interest in C++. Shall we "finally try" to talk a bit about this C language extension from a C user perspective, without jumping into C++ every sentence ? I've got a lot of doubts that this extension is good for C, at least as it is. In C there is no exception handling, so it's common for C libraries to implement some sort of exception handling using setjmp/longjmp. As far as I understand, the proposed feature wouldn't be enough powerful to replace the existing setjmp/longjmp based exception handling. Actually, the proposed feature would actually not work with the existing setjmp/longjmp based exception handling ... either you use the new feature (which is not enough powerful to provide exception handling), or you use setjmp/longjmp. As a C/ObjC user, I don't find this solution very satisfactorily. We've been long waiting for "real" exception handling in C/ObjC ... and this is *not* it. I'd like to see the thing discussed more in details from a pure C point of view, ignoring C++. It's an extension to C, not to C++. This thread was full of explanations such as "the real purpose of try/finally is that if an exception is thrown in try, the code in finally is executed", which is not particularly convincing for C/ObjC users, since we can't throw any exceptions in C/ObjC! :-) (the patch does not provide support for it), except possibly some custom/hackish setjmp based exceptions, which finally can't catch. As far as I understand from the explanations on this thread, try/finally in C would only be used to cleanup before returning from a function, such as try { char *stringA = NULL; char *stringB = NULL; char *stringC = NULL; stringA = malloc (sizeof (char) * 20); if (stringA == NULL) return; ... stringB = malloc (sizeof (char) * 20); if (stringB == NULL) return; ... stringC = malloc (sizeof (char) * 20); if (stringC == NULL) return; ... return; } finally { if (stringA != NULL) free (stringA); if (stringB != NULL) free (stringB); if (stringC != NULL) free (stringC); } It's nice as an example, except I can trivially do it already without any need for a C extension: char *stringA = NULL; char *stringB = NULL; char *stringC = NULL; stringA = malloc (sizeof (char) * 20); if (stringA == NULL) goto finally; ... stringB = malloc (sizeof (char) * 20); goto finally; ... stringC = malloc (sizeof (char) * 20); if (stringC == NULL) goto finally; ... finally: { if (stringA != NULL) free (stringA); if (stringB != NULL) free (stringB); if (stringC != NULL) free (stringC); return; } (please pardon me for any syntax error, it's just a rough example, you get the idea). So I'm unconvinced by this C extension, which provides nothing new to the language - at least in this thread I've not been given any example of things you can do with it in C/ObjC which you couldn't already do by using a trivial label/goto construct (and please note that, in the example, the code without try/finally is portable, and only uses basic C constructs, while the example with try/finally is non portable, and requires you to know the semantics and syntax of GNU C extensions, so it's harder to read for non-GNU C programmers). Adding extensions with no use (except "making C more similar to C++") is quite like taking up lot more work without any actual compensation for it. I personally don't think that pthread_cleanup_* in C++ has much relevance to this discussion - it's a C/C++ interaction problem and we should not be changing the C language so deeply just to work around a C/C++ interaction problem. There must be other ways. Maybe changing C++. ;-) Having said all this, I'd really love to see real exception handling in C, so please pursue /real/ exception handling further! :-) But the whole point is that language extensions should be designed for the language users - to provide carefully designed useful facilities for the users of that language, not for the benefit of the users of another language. Else, try/finally should be renamed to something obscure such as __builtin_cplusplus_try and __builtin_cplusplus_finally (since it's only useful when C++ exceptions come into play), and deprecated in the doc for use from user code, and pthread_cleanup_* would be the only user of this extension - so that it's not really a generally available extension, but just for pthread_cleanup_* (and other C/C++ interaction stuff), and it's easy to drop the extension in the future whenever a better solution is there ... this might be ok, unless, well of course unless adding this thing would bloat all C files compiled with -lpthread with exception handling information tables [so that in C we get the bloating overhead in the object file, but not the actual exception handling features - very kind of you :-)] as someone seems to suggest - because if that's the case, no matter how you rename it, it's obviously not going to make C/ObjC users very happy. Sorry for providing criticism to the patch - I hope I've been able to concentrate on actual practical 'end-user' issues and problems which might lead to more explanations and useful discussions. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 4:48 ` Nicola Pero @ 2002-11-08 5:47 ` Jakub Jelinek 2002-11-08 10:02 ` Fergus Henderson 2002-11-08 11:24 ` Kai Henningsen 0 siblings, 2 replies; 128+ messages in thread From: Jakub Jelinek @ 2002-11-08 5:47 UTC (permalink / raw) To: Nicola Pero; +Cc: Mark Mitchell, Zack Weinberg, gcc-patches On Fri, Nov 08, 2002 at 12:48:49PM +0000, Nicola Pero wrote: > Well you're not a lone voice of insance conservatism, I actually think you > are quite well giving voices to the puzzled C users, like me. :-) > > In all this discussion, I didn't quite find discussed how it would work in > C/ObjC, from a pure C/ObjC perspective. Which IMO is essential to have > the C extension approved. > > The suggestion that this change is good because "it makes C look more like > C++ so that it's easier to integrate C and C++" might be good for C++ > hackers and lovers, but it's definitely unconvincing for C/ObjC users with > no interest in C++. If you look at a typical system nowadays, C and C++ has to easily integrate together, as C++ code often calls C routines (starting from libstdc++ using C library functions where C library is most often written in C) and a lot of C programs/libraries are using C++ libraries too. > Shall we "finally try" to talk a bit about this C language extension from > a C user perspective, without jumping into C++ every sentence ? > > I've got a lot of doubts that this extension is good for C, at least as it > is. > > In C there is no exception handling, so it's common for C libraries to > implement some sort of exception handling using setjmp/longjmp. > > As far as I understand, the proposed feature wouldn't be enough powerful > to replace the existing setjmp/longjmp based exception handling. It has no intent to replace it, it is about cleanups when exception is thrown, not the exception handling mechanism itself. > Actually, the proposed feature would actually not work with the existing > setjmp/longjmp based exception handling ... either you use the new feature > (which is not enough powerful to provide exception handling), or you use > setjmp/longjmp. But it plays nicely with setjmp/longjmp_unwind. Code using pure setjmp/longjmp nowadays cannot use any cleanups locally, all buffers you allocate or locks you acquire have to be global, so that when setjmp returns non-zero you can free them or release them. At least with current glibc pthread_cleanup_* implementation, it even cannot use pthread_cleanup_*, because libpthread will be seriously confused (usually segfault) after you try longjmp for the first time skipping some frame which did pthread_cleanup_push. > As a C/ObjC user, I don't find this solution very satisfactorily. We've > been long waiting for "real" exception handling in C/ObjC ... and this is > *not* it. See the above. If you do: jmp_buf b; void foo (void) { if (setjmp (b)) { exception was raised; } bar (); } void bar (void) { void *x = malloc (1024); __try { do_something_with_x baz (); do_something_else_with_x } __finally { free (x); } } void baz (void) { if (some_weird_condition) longjmp_unwind (b); } then you IMHO have all you need for satisfactory pure C exception handling with minimal overhead. With __thread variables you can put any data you want into them at longjmp_unwind time (ie. throw someobject in C) and check it at setjmp time. Without __try/__finally but with longjmp_unwind you can still do this, but see my other mail what needs to be done instead of that, making the code quite unreadable. > As far as I understand from the explanations on this thread, try/finally > in C would only be used to cleanup before returning from a function, such > as > > try > { > char *stringA = NULL; > char *stringB = NULL; > char *stringC = NULL; > > stringA = malloc (sizeof (char) * 20); > if (stringA == NULL) > return; > > ... > > stringB = malloc (sizeof (char) * 20); > if (stringB == NULL) > return; > > ... > > stringC = malloc (sizeof (char) * 20); > if (stringC == NULL) > return; > > ... > > return; > } > finally > { > if (stringA != NULL) > free (stringA); > > if (stringB != NULL) > free (stringB); > > if (stringC != NULL) > free (stringC); > } > > It's nice as an example, except I can trivially do it already without any > need for a C extension: > > char *stringA = NULL; > char *stringB = NULL; > char *stringC = NULL; > > stringA = malloc (sizeof (char) * 20); > if (stringA == NULL) > goto finally; > > ... > > stringB = malloc (sizeof (char) * 20); > goto finally; > > ... > > stringC = malloc (sizeof (char) * 20); > if (stringC == NULL) > goto finally; > > ... > > finally: > { > if (stringA != NULL) > free (stringA); > > if (stringB != NULL) > free (stringB); > > if (stringC != NULL) > free (stringC); > > return; > } Sure, but: a) typically in such functions they are not returning void, but some value, with __try/__finally you can leave the code as above, just add the return value to each return statement. With goto gem you need some function scope variable and set it first, then return, so if (stringC == NULL) return 134; becomes if (stringC == NULL) { ret = 134; goto finally; } which is less readable b) if not all variables are function scope, the code gets much uglier c) with __try/__finally, you get the cleanups with pthread cancellation or C++ exceptions thrown or longjmp_unwind for free. You don't have to worry about storing stringA, stringB, stringC not in separate variables, but into some local structure, doing pthread_cleanup_push at the beginning with address of that local structure and either having the finally block just do pthread_cleanup_pop(1) or pthread_cleanup_pop(0) with duplication of all the free calls into the code after finally label and in a separate function. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 5:47 ` Jakub Jelinek @ 2002-11-08 10:02 ` Fergus Henderson 2002-11-08 11:24 ` Kai Henningsen 1 sibling, 0 replies; 128+ messages in thread From: Fergus Henderson @ 2002-11-08 10:02 UTC (permalink / raw) To: Jakub Jelinek; +Cc: Nicola Pero, Mark Mitchell, Zack Weinberg, gcc-patches On 08-Nov-2002, Jakub Jelinek <jakub@redhat.com> wrote: > On Fri, Nov 08, 2002 at 12:48:49PM +0000, Nicola Pero wrote: > > The suggestion that this change is good because "it makes C look more like > > C++ so that it's easier to integrate C and C++" might be good for C++ > > hackers and lovers, but it's definitely unconvincing for C/ObjC users with > > no interest in C++. > > If you look at a typical system nowadays, C and C++ has to easily integrate > together, as C++ code often calls C routines (starting from libstdc++ using > C library functions where C library is most often written in C) and a lot of > C programs/libraries are using C++ libraries too. C++ calling C is very common, but C calling C++ is a lot less so. Furthermore, for C calling C++ you need some `extern "C"' glue code anyway, and this glue code can catch C++ exceptions and convert them to something suitable for C. > > Actually, the proposed feature would actually not work with the existing > > setjmp/longjmp based exception handling ... either you use the new feature > > (which is not enough powerful to provide exception handling), or you use > > setjmp/longjmp. > > But it plays nicely with setjmp/longjmp_unwind. That's all very well, but we don't have setjmp_unwind/longjmp_wind yet! Also, these routines might be slower than setjmp/longjmp. -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 5:47 ` Jakub Jelinek 2002-11-08 10:02 ` Fergus Henderson @ 2002-11-08 11:24 ` Kai Henningsen 2002-11-08 11:44 ` Jakub Jelinek 2002-11-08 11:46 ` Mike Stump 1 sibling, 2 replies; 128+ messages in thread From: Kai Henningsen @ 2002-11-08 11:24 UTC (permalink / raw) To: gcc-patches jakub@redhat.com (Jakub Jelinek) wrote on 08.11.02 in <20021108084659.A10988@devserv.devel.redhat.com>: > On Fri, Nov 08, 2002 at 12:48:49PM +0000, Nicola Pero wrote: > > Well you're not a lone voice of insance conservatism, I actually think you > > are quite well giving voices to the puzzled C users, like me. :-) > > > > In all this discussion, I didn't quite find discussed how it would work in > > C/ObjC, from a pure C/ObjC perspective. Which IMO is essential to have > > the C extension approved. > > > > The suggestion that this change is good because "it makes C look more like > > C++ so that it's easier to integrate C and C++" might be good for C++ > > hackers and lovers, but it's definitely unconvincing for C/ObjC users with > > no interest in C++. > > If you look at a typical system nowadays, C and C++ has to easily integrate > together, as C++ code often calls C routines (starting from libstdc++ using > C library functions where C library is most often written in C) and a lot of > C programs/libraries are using C++ libraries too. But, just like Nicola, I don't care about that part because I don't use C++ myself. Let this be solved by C++, not by C! I *really* want *real* exception handling for C - doing this with setjmp/ longjmp (a.k.a. NS_DURING and friends) is just too ugly for words. Besides, it is dog slow - but this isn't it. > then you IMHO have all you need for satisfactory pure C exception handling > with minimal overhead. Minimal overhead? Your definition of minimal is certainly not mine. Setjmp/ longjmp based exceptions in C are *SLOW* even for code which doesn't raise exceptions. Besides, I'm sick and tired of "... may be clobbered by longjmp" because gcc cannot know how those jmp_buf's will be used. > a) typically in such functions they are not returning void, but some value, > with __try/__finally you can leave the code as above, just add the > return value to each return statement. With goto gem you need some > function scope variable and set it first, then return, > so if (stringC == NULL) return 134; becomes > if (stringC == NULL) { ret = 134; goto finally; } > which is less readable Look up NS_DURING and friends. It's not that it can't be hidden away in macrosm, because it can. It's that macros which expand with unbalanced braces are *extremely* easy to get wrong. And, of course, setjmp is no speed demon, and putting chaining on top of that doesn't help. MfG Kai ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 11:24 ` Kai Henningsen @ 2002-11-08 11:44 ` Jakub Jelinek 2002-11-09 0:11 ` Fergus Henderson 2002-11-08 11:46 ` Mike Stump 1 sibling, 1 reply; 128+ messages in thread From: Jakub Jelinek @ 2002-11-08 11:44 UTC (permalink / raw) To: Kai Henningsen; +Cc: gcc-patches On Fri, Nov 08, 2002 at 07:58:00PM +0200, Kai Henningsen wrote: > Minimal overhead? Your definition of minimal is certainly not mine. Setjmp/ > longjmp based exceptions in C are *SLOW* even for code which doesn't raise > exceptions. Minimal runtime overhead primarily for the functions which don't catch nor throw, just contain cleanups (ie. just use __try/__finally, not setjmp nor longjmp_unwind). Compare that to setjmp in every function which has cleanups (that is as far as I understand the proposed solution if __try/__finally gets shot down). Actually, for use with longjmp_unwind as far as I understand it is enough to just save frame pointer if -fexceptions are everywhere, the rest can be taken care by the unwind. As for speed of longjmp, speed of longjmp_unwind is certainly lower than of plain longjmp, because of all the .eh_frame processing and unwinding, as slow as is C++ throw. But IMHO exceptions are for exceptional cases, not common cases. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 11:44 ` Jakub Jelinek @ 2002-11-09 0:11 ` Fergus Henderson 0 siblings, 0 replies; 128+ messages in thread From: Fergus Henderson @ 2002-11-09 0:11 UTC (permalink / raw) To: Jakub Jelinek; +Cc: Kai Henningsen, gcc-patches On 08-Nov-2002, Jakub Jelinek <jakub@redhat.com> wrote: > As for speed of longjmp, speed of longjmp_unwind is certainly lower than of > plain longjmp, because of all the .eh_frame processing and unwinding, as > slow as is C++ throw. But IMHO exceptions are for exceptional cases, not > common cases. longjmp() can be used for things that are not exceptional. IMHO it is reasonable to use it that way. For example, when the Mercury compiler converts programs with backtracking to C using a continuation passing style, it generates a longjmp() for every commit (which in Prolog would correspond to cut). Commits can be common. -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 11:24 ` Kai Henningsen 2002-11-08 11:44 ` Jakub Jelinek @ 2002-11-08 11:46 ` Mike Stump 1 sibling, 0 replies; 128+ messages in thread From: Mike Stump @ 2002-11-08 11:46 UTC (permalink / raw) To: Kai Henningsen; +Cc: gcc-patches On Friday, November 8, 2002, at 09:58 AM, Kai Henningsen wrote: > Besides, I'm sick and tired of "... may be clobbered by longjmp" > because > gcc cannot know how those jmp_buf's will be used. This only applies to setjmp, not to __builtin_setjmp, nor sjlj EH. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 18:29 ` Mark Mitchell 2002-11-07 21:23 ` Robert Lipe 2002-11-08 4:48 ` Nicola Pero @ 2002-11-08 10:02 ` Matt Austern 2002-11-11 5:38 ` Michael Matz 2 siblings, 1 reply; 128+ messages in thread From: Matt Austern @ 2002-11-08 10:02 UTC (permalink / raw) To: Mark Mitchell; +Cc: Zack Weinberg, gcc-patches On Thursday, November 7, 2002, at 06:27 PM, Mark Mitchell wrote: >> Y'know, I don't see why people would think that. It doesn't have >> __except or __catch or whatever Microsoft calls it, and we say >> explicitly that this is only for pthread_cancel() and for exceptions >> thrown by other language runtimes... > > Maybe I have been so often burned by these language extensions that I > am overly paranoid. It's certainly possible, and Matt Austern has > stopped commenting, so he is perhaps convinced, leaving me as a lone > voice of insane conservatism. > > In contrast to Alexandre, I always thought GCC's C front end philosophy > of having basically every feature in any language was just plain nuts. > It's certainly lead to some major oddness over the years. Nope. I've been staying quiet mainly because I've agreed with what Mark has been saying. I have a lot less experience as a gcc maintainer than he does, but I already have enough experience to have felt burned by language extensions. There have been an awful lot of cases where users report problems with one extension or another, or worse, with some combination of them, and I have to go through the steps of wondering: what is this extension supposed to do? was this particular corner case ever considered? what does the documentation say, and it is right? has this extension gone stale? This sort of confusion is a burden for users and implementors. Partly the reason I lean toward conservatism is my experience on standards bodies. (I know I'm not the only person on this list with such experience.) I've learned that language design is hard. I've learned also that adding a major new language feature, and specifying it adequately, is always harder than it looks. It's rarely good enough to give a short writeup describing the feature: what's more common is pervasive changes throughout the specification, as you describe, one by one, how this feature interacts with what's already there. Especially hard for us, since we've got so many extensions already. Language extensions are sometimes necessary, but there should be a high standard of proof. Finally, I'm concerned about the idea of putting in a language extension just to meet the needs of a single project. That's the way to get language evolution without direction. One compromise suggestion I've seen that might be reasonable, if the glibc/pthreads argument is considered compelling: give the primitives ugly names, warn users against putting them in their own code (and by "warn" I mean both a note in the documentation and a compiler warning), and use them solely as primitives for glibc implementation. That way we give ourselves more freedom to change or remove them in the future if appropriate. I'm still not 100% sure I understand the glibc/pthreads discussion, though. There was some speculation that, with this change, all users who want to use pthread cancelation in their code will have to explicitly add -fexceptions to their command lines. What was the outcome of that discussion? If there was an outcome, I missed it. --Matt ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 10:02 ` Matt Austern @ 2002-11-11 5:38 ` Michael Matz 2002-11-11 12:59 ` Matt Austern 0 siblings, 1 reply; 128+ messages in thread From: Michael Matz @ 2002-11-11 5:38 UTC (permalink / raw) To: Matt Austern; +Cc: Mark Mitchell, Zack Weinberg, gcc-patches Hi, On Fri, 8 Nov 2002, Matt Austern wrote: > I have a lot less experience as a gcc maintainer than he does, but > I already have enough experience to have felt burned by language > extensions. There have been an awful lot of cases where users > report problems with one extension or another, or worse, with some > combination of them, and I have to go through the steps of wondering: > what is this extension supposed to do? was this particular corner > case ever considered? what does the documentation say, and it is > right? has this extension gone stale? This sort of confusion is a > burden for users and implementors. > > Partly the reason I lean toward conservatism is my experience on > standards bodies. (I know I'm not the only person on this > list with such experience.) I've learned that language design is > hard. I've learned also that adding a major new language feature, > and specifying it adequately, is always harder than it looks. It's > rarely good enough to give a short writeup describing the feature: > what's more common is pervasive changes throughout the specification, > as you describe, one by one, how this feature interacts with what's > already there. Now all that being said, do you have any concrete issues with this particular extension than with extensions in general? Being conservative just for being conservative is not very usefull IMO. We right now _are_ in the discussion of that extension, so this is your chance. > Finally, I'm concerned about the idea of putting in a language > extension just to meet the needs of a single project. That's the > way to get language evolution without direction. Again a general remark. First: the extension has other uses (I'm not sure how often that needs to be repeated), second: try/finally has quite similar implementations in other languages, and even an implementation in C, so IMHO the fear of undirected evolution isn't justified here. > One compromise suggestion I've seen that might be reasonable, if the > glibc/pthreads argument is considered compelling: give the primitives > ugly names, warn users against putting them in their own code (and > by "warn" I mean both a note in the documentation and a compiler > warning), and use them solely as primitives for glibc implementation. Well, you see, if it looks like a dog, smells like a dog, and barks like a dog, then most probably it is a dog. There is no need to call it "four-legged-waging-tailed-barking-mammal-with-fur". On the contrary. An artificial language should have some well defined constructs and they should reflect in the syntax somehow. In an imperative language control flow (instead of data flow) is made explicit by different language means, and hence also a flow resembling try/finally should be made such. Sure, we could call it __gcc_try {} __gcc_finally {}. But I really think if at all, we want the extension in this syntactic form. Ciao, Michael. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-11 5:38 ` Michael Matz @ 2002-11-11 12:59 ` Matt Austern 2002-11-12 1:01 ` Michael Matz 0 siblings, 1 reply; 128+ messages in thread From: Matt Austern @ 2002-11-11 12:59 UTC (permalink / raw) To: Michael Matz; +Cc: Mark Mitchell, Zack Weinberg, gcc-patches On Monday, November 11, 2002, at 05:38 AM, Michael Matz wrote: > On Fri, 8 Nov 2002, Matt Austern wrote: > >> I have a lot less experience as a gcc maintainer than he does, but >> I already have enough experience to have felt burned by language >> extensions. There have been an awful lot of cases where users >> report problems with one extension or another, or worse, with some >> combination of them, and I have to go through the steps of wondering: >> what is this extension supposed to do? was this particular corner >> case ever considered? what does the documentation say, and it is >> right? has this extension gone stale? This sort of confusion is a >> burden for users and implementors. >> >> Partly the reason I lean toward conservatism is my experience on >> standards bodies. (I know I'm not the only person on this >> list with such experience.) I've learned that language design is >> hard. I've learned also that adding a major new language feature, >> and specifying it adequately, is always harder than it looks. It's >> rarely good enough to give a short writeup describing the feature: >> what's more common is pervasive changes throughout the specification, >> as you describe, one by one, how this feature interacts with what's >> already there. > > Now all that being said, do you have any concrete issues with this > particular extension than with extensions in general? Being > conservative > just for being conservative is not very usefull IMO. Whereas my opinion is that an attitude toward extensions other than being conservative is very dangerous. These are general comments because they have to be. If you look at a single extension in isolation, it'll always seem like a good idea. The answer will always be: sure, we can get this to work, and it'll be useful to someone or other. The reason to be scared of uncontrolled extension isn't that any one extension is terrible, it's the overall accumulation of one extension after another. (See Bjarne Stroustrup's _The Design and Evolution of C++_ for a more complete discussion.) So for me, the question isn't whether an extension might be useful for someone, but whether it's so very useful to enough people that it can overcome a strong bias against adding extensions. Some extensions pass that test; I'm not yet convinced that this one does. --Matt ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-11 12:59 ` Matt Austern @ 2002-11-12 1:01 ` Michael Matz 2002-11-12 8:20 ` Mark Mitchell 0 siblings, 1 reply; 128+ messages in thread From: Michael Matz @ 2002-11-12 1:01 UTC (permalink / raw) To: Matt Austern; +Cc: Mark Mitchell, Zack Weinberg, gcc-patches Hi, On Mon, 11 Nov 2002, Matt Austern wrote: > Whereas my opinion is that an attitude toward extensions other than > being conservative is very dangerous. I agree to a certain degree. But that doesn't relieve one from also thinking about any extension on its own, its implications and issues. > So for me, the question isn't whether an extension might be useful > for someone, but whether it's so very useful to enough people that it > can overcome a strong bias against adding extensions. Some extensions > pass that test; I'm not yet convinced that this one does. Yes, and I ask for specific reasons why this wouldn't pass. Ciao, Michael. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-12 1:01 ` Michael Matz @ 2002-11-12 8:20 ` Mark Mitchell 2002-11-12 8:58 ` Michael Matz 0 siblings, 1 reply; 128+ messages in thread From: Mark Mitchell @ 2002-11-12 8:20 UTC (permalink / raw) To: Michael Matz, Matt Austern; +Cc: Zack Weinberg, gcc-patches >> So for me, the question isn't whether an extension might be useful >> for someone, but whether it's so very useful to enough people that it >> can overcome a strong bias against adding extensions. Some extensions >> pass that test; I'm not yet convinced that this one does. > > Yes, and I ask for specific reasons why this wouldn't pass. I (and probably Matt) are going to argue that the burden is not on us to provide a specific reason *not to* have an extension; the burden is on you *to* provide a specific reason to have the extension. The reason that I would find compelling is that there is no way to achieve some vital piece of functionality without the extension. Richard's recent TLS extension met that criteria to me; that gives you a portable way of writing code that takes advantage of the TLS support in the linker. I couldn't think of any other good way to do that, so I didn't object. Introducing a new control-flow construct into a language that has been used for decades without that control-flow construct is a much more radical change. There's no question the extension would be useful; the question is whether it is essential. Anyhow, I think you're beating a dead horse. :-) Richard has agreed to try to implement and use longjmp_unwind. There's no question that function would be useful to people in other situations, and it doesn't require any language extension. If Richard's attempt fails for some reason, we can reconsider. -- Mark Mitchell mark@codesourcery.com CodeSourcery, LLC http://www.codesourcery.com ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-12 8:20 ` Mark Mitchell @ 2002-11-12 8:58 ` Michael Matz 0 siblings, 0 replies; 128+ messages in thread From: Michael Matz @ 2002-11-12 8:58 UTC (permalink / raw) To: Mark Mitchell; +Cc: Matt Austern, Zack Weinberg, gcc-patches Hi, On Tue, 12 Nov 2002, Mark Mitchell wrote: > I (and probably Matt) are going to argue that the burden is not on us > to provide a specific reason *not to* have an extension; the burden is > on you *to* provide a specific reason to have the extension. I feared that argument chain ;-) But I think I (and others) did provide some arguments, one of them being elegance (and by that possibility to write more constructs in a non so error-prone style). > Anyhow, I think you're beating a dead horse. :-) > > Richard has agreed to try to implement and use longjmp_unwind. There's > no question that function would be useful to people in other situations, > and it doesn't require any language extension. If Richard's attempt > fails for some reason, we can reconsider. And this is what I feared too. That Richards offer to implement a very narrow case with not nearly the usability and elegance of the original proposal implicitely removed the extension from any consideration, although there's precedent for it in other C dialects. I mean people who think longjmp and friends are elegant can't be helped (sorry to whoever I described with this ;-) ). Unfortunately I also think that Richard will of course succeed :) , so I think I know what will happen with the proposal. Then we will have the compiler without that extension for the next decade or so and no standard body will consider its inclusion into C, because the only widespread compilers supporting it are for one platform, and those compilers also implement questionable extensions to that extension (erhh, well you know what I mean ;-) exceptions and such). I.e. all in all I think we miss a chance, but well, so be it. There's nothing more to say for me on this topic. Ciao, Michael. P.S.: Ok, a last attempt: I just saw, that even EDG does support __try/__finally. Ok, only in Microsoft mode, but still ;-) If that doesn't make GCC one of a very limited set of compilers _not_ accepting it, I don't know ;-) ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 17:57 ` Mark Mitchell 2002-11-07 18:17 ` Zack Weinberg @ 2002-11-07 19:28 ` Daniel Jacobowitz 1 sibling, 0 replies; 128+ messages in thread From: Daniel Jacobowitz @ 2002-11-07 19:28 UTC (permalink / raw) To: Mark Mitchell Cc: Jason Merrill, Jakub Jelinek, Richard Henderson, Geoff Keating, zack, aldyh, gcc-patches On Thu, Nov 07, 2002 at 05:55:21PM -0800, Mark Mitchell wrote: > > > --On Thursday, November 07, 2002 08:52:37 PM -0500 Jason Merrill > <jason@redhat.com> wrote: > > >On Thu, 07 Nov 2002 17:26:38 -0800, Mark Mitchell <mark@codesourcery.com> > >wrote: > > > >>>That's why the proposal is about __try/__finally only, not __except > >>>where it is e.g. not clear at all what happens if you throw in C++ > >>>and __except control expression returns -1. > >>>At least from what I read in MSFT docs on the web, their __try/__finally > >>>matches Aldy's patch. > >> > >>Except that it also handles asynchronous exceptions, which ours doesn't. > >>Where we'd get a SIGFPE you get a structured exception in Microsoft's > >>stuff. > > > >That has nothing to do with the semantics of try/finally, which just deals > >with cleaning up after whatever exceptions do happen to be thrown. > > This horse is pretty dang dead, but the point is that people will *expect* > that the construct behaves the same way as Microsoft's "structured > exception handling" stuff -- in every way. Part of that is handling > SIGFPE type events. If you look through the list archives, you'll see that people _already_ expect that; we get a "why doesn't C++ catch{} block catch SIGFPE" every couple of months. I don't think this would make it any worse. And adding platform-specific code to catch SIGFPE's and unwind is not all that hard. -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 16:21 ` Mark Mitchell ` (2 preceding siblings ...) 2002-11-07 17:10 ` Jakub Jelinek @ 2002-11-07 22:07 ` Alexandre Oliva 2002-11-08 4:27 ` Richard Henderson 2002-11-08 9:31 ` Michael Matz 4 siblings, 1 reply; 128+ messages in thread From: Alexandre Oliva @ 2002-11-07 22:07 UTC (permalink / raw) To: Mark Mitchell Cc: Richard Henderson, Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Nov 7, 2002, Mark Mitchell <mark@codesourcery.com> wrote: > I would prefer longjmp_unwind; that's something we're supposed to > have anyhow, and it would be very useful in making existing C > libraries play more nicely with C++, so implementing that would be > a definite win. I fail to see how longjmp_unwind could possibly be implemented without EH frame information for all frames, C ones included. I mean, if all you have is a chain of jmp_bufs that link together some call frames, but you can't get from them to other call frames that have actual cleanups, I don't see how longjmp_unwind could get to the cleanups in order to run them. But then, this thread was the first time I heard of longjmp_unwind, so perhaps I'm missing some magic about it. Or it's just that the need for EH call frames in C for it to work is so obvious that nobody brought it up, and it was stupid of me to even consider it might not be the case :-) -- Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/ Red Hat GCC Developer aoliva@{redhat.com, gcc.gnu.org} CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org} Free Software Evangelist Professional serial bug killer ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 22:07 ` Alexandre Oliva @ 2002-11-08 4:27 ` Richard Henderson 2002-11-08 4:54 ` Jakub Jelinek 2002-11-08 11:25 ` Mike Stump 0 siblings, 2 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-08 4:27 UTC (permalink / raw) To: Alexandre Oliva Cc: Mark Mitchell, Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Fri, Nov 08, 2002 at 04:07:09AM -0200, Alexandre Oliva wrote: > I fail to see how longjmp_unwind could possibly be implemented without > EH frame information for all frames, C ones included. The idea I has was that it unwound frames until (1) we arrive at the destination frame or (2) we don't find any more EH information, at which point it falls back to just longjmp. This does require that all EH-bearing frames appear at the bottom of the call chain, but I think it does handle the common case of an all-C++ or all-C pthreads application. It's only people who mix C and C++ that have to be more careful about using -fexceptions with their C code. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 4:27 ` Richard Henderson @ 2002-11-08 4:54 ` Jakub Jelinek 2002-11-08 6:01 ` Jakub Jelinek 2002-11-08 11:38 ` Mike Stump 2002-11-08 11:25 ` Mike Stump 1 sibling, 2 replies; 128+ messages in thread From: Jakub Jelinek @ 2002-11-08 4:54 UTC (permalink / raw) To: Richard Henderson, Alexandre Oliva, Mark Mitchell, Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Fri, Nov 08, 2002 at 04:26:58AM -0800, Richard Henderson wrote: > On Fri, Nov 08, 2002 at 04:07:09AM -0200, Alexandre Oliva wrote: > > I fail to see how longjmp_unwind could possibly be implemented without > > EH frame information for all frames, C ones included. > > The idea I has was that it unwound frames until (1) we arrive at > the destination frame or (2) we don't find any more EH information, > at which point it falls back to just longjmp. But that's the same what would be needed for __try/__finally based thread cancellation, there is no difference if libpthread cancellation calls _Unwind_ForcedUnwind directly with a stop_fn which checks for __libc_start_main resp. pthread_start_thread, or if pthread cancellation calls longjmp_unwind with a jmp_buf set up in __libc_start_main resp. pthread_start_thread. Even there we don't want to abort() in: if (exc->private_1 == 0) code = _Unwind_RaiseException_Phase2 (exc, &cur_context); else code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); if (code != _URC_INSTALL_CONTEXT) abort (); but to let either the stop_fn, or some other hook decide what to do, such as do the longjmp. The question is more what will each function having cleanups have to do: Is it something like: ... extern __thread jmp_buf *__youngest_jmp_buf; ... { jmp_buf __buf; jmp_buf *__previous = __youngest_jmp_buf; int __cleanup; __youngest_jmp_buf = &__buf; __cleanup = setjmp (__buf); if (!__cleanup) { try block; } { finally block; } __youngest_jmp_buf = __previous; if (__cleanup) longjmp_unwind (__youngest_jmp_buf); } ? If __thread is not supported on particular target, it would have to do a call to pthread library to find address of (resp. get and set) __youngest_jmp_buf instead. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 4:54 ` Jakub Jelinek @ 2002-11-08 6:01 ` Jakub Jelinek 2002-11-08 11:38 ` Mike Stump 1 sibling, 0 replies; 128+ messages in thread From: Jakub Jelinek @ 2002-11-08 6:01 UTC (permalink / raw) To: Richard Henderson Cc: Alexandre Oliva, Mark Mitchell, Geoff Keating, zack, aldyh, gcc-patches, jason On Fri, Nov 08, 2002 at 07:54:04AM -0500, Jakub Jelinek wrote: > Is it something like: > ... > extern __thread jmp_buf *__youngest_jmp_buf; > ... > { > jmp_buf __buf; > jmp_buf *__previous = __youngest_jmp_buf; > int __cleanup; > __youngest_jmp_buf = &__buf; > __cleanup = setjmp (__buf); > if (!__cleanup) > { > try block; > } > { > finally block; > } > __youngest_jmp_buf = __previous; > if (__cleanup) > longjmp_unwind (__youngest_jmp_buf); > } > > ? > If __thread is not supported on particular target, it would have to > do a call to pthread library to find address of (resp. get and set) > __youngest_jmp_buf instead. Note that if something like this is necessary for longjmp_unwind pthread_cleanup_{push,pop} without __try/__finally, then it will not work when setjmp/longjmp (expected; the same as __try/__finally based implementation), but neither with setjmp/longjmp_unwind (because the jmp_buf pointer chain will be corrupted and of course the cleanups won't be run) nor C++ exception throwing. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 4:54 ` Jakub Jelinek 2002-11-08 6:01 ` Jakub Jelinek @ 2002-11-08 11:38 ` Mike Stump 1 sibling, 0 replies; 128+ messages in thread From: Mike Stump @ 2002-11-08 11:38 UTC (permalink / raw) To: Jakub Jelinek Cc: Richard Henderson, Alexandre Oliva, Mark Mitchell, Geoff Keating, zack, aldyh, gcc-patches, jason On Friday, November 8, 2002, at 04:54 AM, Jakub Jelinek wrote: > Is it something like: > ... > extern __thread jmp_buf *__youngest_jmp_buf; > ... > { > jmp_buf __buf; > jmp_buf *__previous = __youngest_jmp_buf; > int __cleanup; > __youngest_jmp_buf = &__buf; > __cleanup = setjmp (__buf); > if (!__cleanup) > { > try block; > } > { > finally block; > } > __youngest_jmp_buf = __previous; > if (__cleanup) > longjmp_unwind (__youngest_jmp_buf); > } > > ? > If __thread is not supported on particular target, it would have to > do a call to pthread library to find address of (resp. get and set) > __youngest_jmp_buf instead. Congratulations, you just re-invented sjlj expcetions. :-) It is possible to reuse the code that is already written and implemented and make it interoperate with dwarf EH, see my other email. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 4:27 ` Richard Henderson 2002-11-08 4:54 ` Jakub Jelinek @ 2002-11-08 11:25 ` Mike Stump 1 sibling, 0 replies; 128+ messages in thread From: Mike Stump @ 2002-11-08 11:25 UTC (permalink / raw) To: Richard Henderson Cc: Alexandre Oliva, Mark Mitchell, Geoff Keating, zack, jakub, aldyh, gcc-patches, jason On Friday, November 8, 2002, at 04:26 AM, Richard Henderson wrote: > This does require that all EH-bearing frames appear at the bottom > of the call chain, but I think it does handle the common case of > an all-C++ or all-C pthreads application. > > It's only people who mix C and C++ that have to be more careful > about using -fexceptions with their C code. I think this case can be handled by checking out the frame address, if any, and use the one that is closest. In __builtin_setjmp, grabbing this value is easy enough. With dwarf, its a bit harder. This would also enable one to intermix sjlj EH and dwarf EH seemlessly. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 16:21 ` Mark Mitchell ` (3 preceding siblings ...) 2002-11-07 22:07 ` Alexandre Oliva @ 2002-11-08 9:31 ` Michael Matz 2002-11-08 11:26 ` Hans-Peter Nilsson 4 siblings, 1 reply; 128+ messages in thread From: Michael Matz @ 2002-11-08 9:31 UTC (permalink / raw) To: Mark Mitchell Cc: Richard Henderson, Geoff Keating, zack, jakub, aldyh, gcc-patches, jason Hi, On Thu, 7 Nov 2002, Mark Mitchell wrote: > > It's not like we're even breaking new ground on the language front. > > Microsoft has supported try/finally in their C compiler for years. > > It has somewhat fancy semantics. For example, you can catch > floating-point exceptions this way We don't. > and other things that would be > signals in UNIX. They have a "__leave" keyword; We don't. > they have exception handling (as well as cleanups) dito. > and they have ways to say whether you keep unwinding, or stop where > you are, when you hit the handler. the same. > It's partly because of Microsoft's stuff that I'm so nervous about > this feature. Then you are nervous not about the current proposal, but about a theoretical possibilitywhat you think might also be implemented with it. > We ought to be talking about new language features before we implement > them, so we can have the arguments up front. That would have been good indeed. But I too do not understand at all the resistance about this special extension, in the limited way in which it is implemented. It's not hard to think about it, it's not complicated, and it's not difficult to see, that it _does_ fit well into C (and C++) and doesn't make problems. So from me it's a "hey that is cool" ;-) > I apologize to Aldy too -- the patches are technically sound, and the > goal of improving interactions between threads and C++ is a good one. You still seem to concentrate on just the threading issue in glibc. While that may have been the original reason to implement it, as already demonstrated repeatedly it has other uses. In fact I don't care a little bit about threading, I'm not interested in how cancellation is implemented. In fact I think, once it is implemented in whichever way, most users of GCC will not care about that. But they will care about expressive power of the language they use, and if they choose to use GNU C, and we can provide them with an easy and esthetically appealing way of doing cleanups, I can't find arguments against that. In that respect it even doesn't really matter (to me) if those cleanups are now run when unwinding or not. I find the possibility to reformulate goto gems (or cascading cleanup-before-return blocks) already appealing enough. If they additionally also cleanup while unwinding, well, then all the better, but it's not the main feature to me. Using builtins, with function-call like syntax, but with funny semantics resembling the cursed setjmp/longjmp approach is _not_ pretty. This also means, that all the other hacks^Wsolutions for the threading problem to not have to integrate try/finally don't apply at all. They all wouldn't satisfy the above need. The suggestion that I should use C++ isn't usefull, because right now that language also hasn't cleanups in this way, therefore I would be forced to implement them also with a hack, like a block local struct with a destructor. It's a hack because I don't want a destructor, I want a cleanup. > I promise not to be a complete jerk. :-) > > If everyone else wants to do this, I'll go along. Of course I would also be fine with a different thing which implements cleanups. But as I pointed out in my first mail, from the need for cleanups it's a failry direct way to the try/finally syntax, and currently I can't think of a better way. Ciao, Michael. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 9:31 ` Michael Matz @ 2002-11-08 11:26 ` Hans-Peter Nilsson 2002-11-08 11:48 ` Mike Stump 0 siblings, 1 reply; 128+ messages in thread From: Hans-Peter Nilsson @ 2002-11-08 11:26 UTC (permalink / raw) To: Michael Matz; +Cc: Mark Mitchell, gcc-patches On Fri, 8 Nov 2002, Michael Matz wrote: > > I apologize to Aldy too -- the patches are technically sound, and the > > goal of improving interactions between threads and C++ is a good one. > > You still seem to concentrate on just the threading issue in glibc. > While that may have been the original reason to implement it, as already > demonstrated repeatedly it has other uses. In fact I don't care a little > bit about threading, I'm not interested in how cancellation is > implemented. In fact I think, once it is implemented in whichever way, > most users of GCC will not care about that. They will care about the bloat from the frame info, necessary on the execution path from the "exception" to the "finally" point. Right, compile code in-between with -fexceptions. Problem is, how do I know what code is in-between on the execution path so I can compile only that with -fexceptions? Won't *somebody* think of the children^Wlittle executables? (Proactively: Yes I *know* that stuff isn't mapped in until exception time, but that's not the point.) brgds, H-P ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-08 11:26 ` Hans-Peter Nilsson @ 2002-11-08 11:48 ` Mike Stump 0 siblings, 0 replies; 128+ messages in thread From: Mike Stump @ 2002-11-08 11:48 UTC (permalink / raw) To: Hans-Peter Nilsson; +Cc: Michael Matz, Mark Mitchell, gcc-patches On Friday, November 8, 2002, at 11:26 AM, Hans-Peter Nilsson wrote: > They will care about the bloat from the frame info, necessary on > the execution path from the "exception" to the "finally" point. I don't think it is necessary. See my other email about fp <? ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 5:34 ` Michael Matz 2002-11-07 8:14 ` Mark Mitchell @ 2002-11-07 11:38 ` Zack Weinberg 1 sibling, 0 replies; 128+ messages in thread From: Zack Weinberg @ 2002-11-07 11:38 UTC (permalink / raw) To: Michael Matz Cc: Mark Mitchell, Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 02:34:38PM +0100, Michael Matz wrote: > Hi, > > On Wed, 6 Nov 2002, Mark Mitchell wrote: > > > > #define pthread_cleanup_push(routine_, arg_) \ > > > __builtin_cleanup_block(routine_, arg_) { > > > > > > #define pthread_cleanup_pop(doit_) \ > > > __builtin_toggle_do_cleanup(doit_); } > > > > Something like this is a much, much closer to what I think we should > > do. > > > > Thanks for working this through. > > Uhh, that's exceedingly ugly. Try to think of the proposed semantic and > then try to come up with syntax implementing that semantic. The special > property of this extension is, that it changes control flow in a very > non-trivial (but well defined) way. Every control flow related construct > in C (except calls) are done by "top-level" keywords and syntactic > structure (if, while, for, goto ...). Therefore I'm totally and strictly > against implementing cleanups with the help of builtins, which have > function-call like syntax. I have to say here that I actually _like_ the idea of adding a try/finally construct to C. It has a lot of interesting uses independent of the pthreads cancellation problem. Java and Python have it already, so there's plenty of experience with the idiom. Jakub posted some examples of how it makes code more readable and less error prone. It's explicit, which fits C better than destructors. Using it directly leads to a more natural coding style than pthread_cleanup_* do, since the cleanup doesn't have to be broken out to a callback function. I made up __builtin_cleanup_block and __builtin_toggle_do_cleanup to address a specific difficulty with implementing pthread_cleanup_push/pop in terms of try/finally, which is: when you write out the macros as they would need to appear, you discover that they're asking to be broken by user code playing around with the preprocessor. Also it is impossible to write them in a way that won't produce unavoidable -Wshadow warnings if you have nested pthread_cleanup_push/pop blocks. Please note that __builtin_cleanup_block is _not_ a builtin function, despite the name; it's a control flow keyword with the rough semantic of 'establish a cleanup for the block immediately following, which calls ROUTINE with sole argument ARG if (the cleanup was reached because an exception was thrown || the DOIT flag is true). __builtin_toggle_do_cleanup is a builtin function, but it doesn't affect control flow; it just writes the value of its sole argument into the DOIT flag, which is an invisible variable. zw ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 22:37 ` Mark Mitchell 2002-11-06 23:30 ` Aldy Hernandez 2002-11-07 5:34 ` Michael Matz @ 2002-11-07 9:38 ` Mike Stump 2 siblings, 0 replies; 128+ messages in thread From: Mike Stump @ 2002-11-07 9:38 UTC (permalink / raw) To: Mark Mitchell Cc: Zack Weinberg, Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Wednesday, November 6, 2002, at 10:34 PM, Mark Mitchell wrote: >> #define pthread_cleanup_push(routine_, arg_) \ >> __builtin_cleanup_block(routine_, arg_) { >> >> #define pthread_cleanup_pop(doit_) \ >> __builtin_toggle_do_cleanup(doit_); } > > Something like this is a much, much closer to what I think we should > do. The added benefit is that no changes need to be made to programs that understand and process C source code. Plus, if one doesn't care about C++ interoperability, those can be implemented in normal C on non-gcc platforms. This is useful in being able to port code from one platform to another. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 18:00 ` Zack Weinberg 2002-11-06 18:14 ` Gabriel Dos Reis 2002-11-06 22:37 ` Mark Mitchell @ 2002-11-07 10:06 ` Richard Henderson 2002-11-07 12:57 ` Hans-Peter Nilsson 3 siblings, 0 replies; 128+ messages in thread From: Richard Henderson @ 2002-11-07 10:06 UTC (permalink / raw) To: Zack Weinberg Cc: Mark Mitchell, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On Wed, Nov 06, 2002 at 05:59:59PM -0800, Zack Weinberg wrote: > Are there other uses of __try/__finally which y'all have in mind that > wouldn't be covered by this? Not at present. > p.s. It would be nifty if setjmp/longjmp could be defined in terms of > exception handling. Anyone put thought into that? See the description of longjmp_unwind in the ia64 eh abi. r~ ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 18:00 ` Zack Weinberg ` (2 preceding siblings ...) 2002-11-07 10:06 ` Richard Henderson @ 2002-11-07 12:57 ` Hans-Peter Nilsson 3 siblings, 0 replies; 128+ messages in thread From: Hans-Peter Nilsson @ 2002-11-07 12:57 UTC (permalink / raw) To: Zack Weinberg; +Cc: gcc-patches On Wed, 6 Nov 2002, Zack Weinberg wrote: > To clarify, this is about pthread_cleanup_push/pop, right? Which are > used in code that _uses_ libc, not just inside libc itself. So then you need all -pthread code compiled with -fexceptions, right? All user code? Perhaps *make it the default for C?* Argh! Bloat! .eh_frame and friends everywhere! brgds, H-P ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:03 ` Richard Henderson 2002-11-06 16:10 ` Gabriel Dos Reis 2002-11-06 16:47 ` Mark Mitchell @ 2002-11-06 17:58 ` Fergus Henderson 2002-11-06 18:09 ` Fergus Henderson 2002-11-07 0:30 ` Jakub Jelinek 2002-11-06 18:34 ` Geoff Keating 3 siblings, 2 replies; 128+ messages in thread From: Fergus Henderson @ 2002-11-06 17:58 UTC (permalink / raw) To: Richard Henderson, Mark Mitchell, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On 06-Nov-2002, Richard Henderson <rth@redhat.com> wrote: > The main problem is that you simply cannot implement cleanups with > a few calls to a runtime library. This is not true. Cleanups *can* be implemented via a runtime library. It's just that you need to use callbacks, and this makes the code harder to read and less efficient. How performance-critical are the sections of glibc which are affected? -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 17:58 ` Fergus Henderson @ 2002-11-06 18:09 ` Fergus Henderson 2002-11-07 0:30 ` Jakub Jelinek 1 sibling, 0 replies; 128+ messages in thread From: Fergus Henderson @ 2002-11-06 18:09 UTC (permalink / raw) To: Richard Henderson, Mark Mitchell, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On 07-Nov-2002, Fergus Henderson <fjh@cs.mu.OZ.AU> wrote: > On 06-Nov-2002, Richard Henderson <rth@redhat.com> wrote: > > The main problem is that you simply cannot implement cleanups with > > a few calls to a runtime library. > > This is not true. Cleanups *can* be implemented via a runtime library. > It's just that you need to use callbacks, and this makes the code > harder to read and less efficient. Actually, if you use GNU C nested functions, it's only very slightly harder to read: instead of void foo() { __try { do_some_stuff(); } __finally { do_some_cleanup(); } } you have void foo() { void stuff(void) { do_some_stuff(); } void cleanup(void) { do_some_cleanup(); } try_finally(stuff, cleanup); } Anyway my guess is that glibc would probably end up using macros for this, void foo() { TRY_FINALLY({ do_some_stuff(); },{ do_some_cleanup(); }) } and the important thing is the readability of the code using the macro, not the readability of the code which defines the macro. So in that case, it's just an efficiency issue. -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 17:58 ` Fergus Henderson 2002-11-06 18:09 ` Fergus Henderson @ 2002-11-07 0:30 ` Jakub Jelinek 1 sibling, 0 replies; 128+ messages in thread From: Jakub Jelinek @ 2002-11-07 0:30 UTC (permalink / raw) To: Fergus Henderson Cc: Richard Henderson, Mark Mitchell, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 12:57:57PM +1100, Fergus Henderson wrote: > On 06-Nov-2002, Richard Henderson <rth@redhat.com> wrote: > > The main problem is that you simply cannot implement cleanups with > > a few calls to a runtime library. > > This is not true. Cleanups *can* be implemented via a runtime library. > It's just that you need to use callbacks, and this makes the code > harder to read and less efficient. > > How performance-critical are the sections of glibc which are affected? Very. The sections are e.g. stdio, fast paths in threading library, etc. Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 16:03 ` Richard Henderson ` (2 preceding siblings ...) 2002-11-06 17:58 ` Fergus Henderson @ 2002-11-06 18:34 ` Geoff Keating 2002-11-07 3:29 ` Fergus Henderson 3 siblings, 1 reply; 128+ messages in thread From: Geoff Keating @ 2002-11-06 18:34 UTC (permalink / raw) To: Richard Henderson; +Cc: Jakub Jelinek, Aldy Hernandez, gcc-patches, jason Richard Henderson <rth@redhat.com> writes: > On Wed, Nov 06, 2002 at 03:32:20PM -0800, Mark Mitchell wrote: > > I do not think we should add exception support of any kind to GNU C; use > > C++ if you want exceptions. > > See elsewhere about resistance compiling libc with a c++ compiler. It wouldn't work, anyway. User programs can also use pthread_cleanup_push/pthread_cleanup_pop, in C, so whatever mechanism is used for that must be accessible to C. -- - Geoffrey Keating <geoffk@geoffk.org> ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-06 18:34 ` Geoff Keating @ 2002-11-07 3:29 ` Fergus Henderson 2002-11-07 4:22 ` Jakub Jelinek 0 siblings, 1 reply; 128+ messages in thread From: Fergus Henderson @ 2002-11-07 3:29 UTC (permalink / raw) To: Geoff Keating Cc: Richard Henderson, Jakub Jelinek, Aldy Hernandez, gcc-patches, jason On 06-Nov-2002, Geoff Keating <geoffk@geoffk.org> wrote: > Richard Henderson <rth@redhat.com> writes: > > > On Wed, Nov 06, 2002 at 03:32:20PM -0800, Mark Mitchell wrote: > > > I do not think we should add exception support of any kind to GNU C; use > > > C++ if you want exceptions. > > > > See elsewhere about resistance compiling libc with a c++ compiler. > > It wouldn't work, anyway. User programs can also use > pthread_cleanup_push/pthread_cleanup_pop, in C, so whatever mechanism > is used for that must be accessible to C. How about the following? This uses the C++ compiler's exception support, and is accessible from C. It makes use of the GNU C nested function extension. The main drawback that I can see is that it is not as efficient as possible. /* pthread.h */ void __pthread_try_finally(void (*)(void), void (*)(void *), void *, int); #define pthread_cleanup_push(__routine,__arg) \ { \ void (*__cleanup_routine)(void *) = __routine; \ void *__cleanup_arg = __arg; \ void __body(void) { #define pthread_cleanup_pop(__call_cleanup) \ } \ __pthread_try_finally(__body, __cleanup_routine, __cleanup_arg, \ __call_cleanup); \ } /* pthread_try_finally.cpp */ extern "C" { void __pthread_try_finally( void (*body)(void), void (*cleanup_routine)(void *), void (*cleanup_arg)(void), int call_cleanup) { class S { void (*cleanup_routine)(void *); void (*cleanup_arg)(void); int call_cleanup; public: S(void (*cleanup_routine)(void *), void (*cleanup_arg)(void), int call_cleanup) { this->cleanup_routine = cleanup_routine; this->cleanup_arg = cleanup_arg; this->call_cleanup = call_cleanup; } ~S() { if (call_cleanup) (*cleanup_routine)(cleanup_arg); } } s(cleanup_routine, cleanup_arg, call_cleanup); (*body)(); } } -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 3:29 ` Fergus Henderson @ 2002-11-07 4:22 ` Jakub Jelinek 2002-11-07 5:13 ` Fergus Henderson 0 siblings, 1 reply; 128+ messages in thread From: Jakub Jelinek @ 2002-11-07 4:22 UTC (permalink / raw) To: Fergus Henderson Cc: Geoff Keating, Richard Henderson, Aldy Hernandez, gcc-patches, jason On Thu, Nov 07, 2002 at 10:29:21PM +1100, Fergus Henderson wrote: > On 06-Nov-2002, Geoff Keating <geoffk@geoffk.org> wrote: > > Richard Henderson <rth@redhat.com> writes: > > > > > On Wed, Nov 06, 2002 at 03:32:20PM -0800, Mark Mitchell wrote: > > > > I do not think we should add exception support of any kind to GNU C; use > > > > C++ if you want exceptions. > > > > > > See elsewhere about resistance compiling libc with a c++ compiler. > > > > It wouldn't work, anyway. User programs can also use > > pthread_cleanup_push/pthread_cleanup_pop, in C, so whatever mechanism > > is used for that must be accessible to C. > > How about the following? > This uses the C++ compiler's exception support, and is accessible from C. > It makes use of the GNU C nested function extension. > The main drawback that I can see is that it is not as efficient as possible. s/not efficient as possible/completely inefficient/. Plus it is incorrect too as pthread_cleanup_p{ush,op} implementation - the cleanup is to be run if cancellation happens no matter whether __call_cleanup is zero or non-zero. This would slow e.g. stdio a lot. ATM if libpthread is not linked in, __libc_cleanup_region_start and __libc_cleanup_region_end make no function calls at all, if it is linked in, it makes functions calls but certainly the body is not forced to be a separate function, forcing all parent's variables to stack and accessing them through static chain pointers. With __try/__finally, there would be no calls at all and no need to duplicate the cleanup once in a separate function for the unwinder, once when exiting the block (__libc_cleanup_region_end). Furthemore, even when no exceptions are used, __try/__finally is a nice way how to avoid very common goto gem: x = malloc (somesize); if (x == NULL) { ret = ENOMEM; goto out_exit; } if (fstat (fd, &st) < 0) { ret = errno; goto out_exit; } ... out_exit: free (y); free (x); return ret; One just writes: __try { x = malloc (somesize); if (x == NULL) return ENOMEM; if (fstat (fd, &st) < 0) return errno; ... return 0; } __finally { free (y); free (x); } and magically the code is pthread cancellation aware. > > /* pthread.h */ > > void __pthread_try_finally(void (*)(void), void (*)(void *), void *, int); > > #define pthread_cleanup_push(__routine,__arg) \ > { \ > void (*__cleanup_routine)(void *) = __routine; \ > void *__cleanup_arg = __arg; \ > void __body(void) { > > #define pthread_cleanup_pop(__call_cleanup) \ > } \ > __pthread_try_finally(__body, __cleanup_routine, __cleanup_arg, \ > __call_cleanup); \ > } > > /* pthread_try_finally.cpp */ > > extern "C" { > > void > __pthread_try_finally( > void (*body)(void), > void (*cleanup_routine)(void *), > void (*cleanup_arg)(void), > int call_cleanup) > { > class S { > void (*cleanup_routine)(void *); > void (*cleanup_arg)(void); > int call_cleanup; > public: > S(void (*cleanup_routine)(void *), > void (*cleanup_arg)(void), > int call_cleanup) > { > this->cleanup_routine = cleanup_routine; > this->cleanup_arg = cleanup_arg; > this->call_cleanup = call_cleanup; > } > ~S() > { > if (call_cleanup) > (*cleanup_routine)(cleanup_arg); > } > } s(cleanup_routine, cleanup_arg, call_cleanup); > > (*body)(); > } > > } Jakub ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 4:22 ` Jakub Jelinek @ 2002-11-07 5:13 ` Fergus Henderson 2002-11-07 5:47 ` Michael Matz 2002-11-07 8:52 ` Aldy Hernandez 0 siblings, 2 replies; 128+ messages in thread From: Fergus Henderson @ 2002-11-07 5:13 UTC (permalink / raw) To: Jakub Jelinek Cc: Geoff Keating, Richard Henderson, Aldy Hernandez, gcc-patches, jason On 07-Nov-2002, Jakub Jelinek <jakub@redhat.com> wrote: > On Thu, Nov 07, 2002 at 10:29:21PM +1100, Fergus Henderson wrote: > > On 06-Nov-2002, Geoff Keating <geoffk@geoffk.org> wrote: > > > Richard Henderson <rth@redhat.com> writes: > > > > > > > On Wed, Nov 06, 2002 at 03:32:20PM -0800, Mark Mitchell wrote: > > > > > I do not think we should add exception support of any kind to GNU C; use > > > > > C++ if you want exceptions. > > > > > > > > See elsewhere about resistance compiling libc with a c++ compiler. > > > > > > It wouldn't work, anyway. User programs can also use > > > pthread_cleanup_push/pthread_cleanup_pop, in C, so whatever mechanism > > > is used for that must be accessible to C. > > > > How about the following? > > This uses the C++ compiler's exception support, and is accessible from C. > > It makes use of the GNU C nested function extension. > > The main drawback that I can see is that it is not as efficient as possible. > > s/not efficient as possible/completely inefficient/. I agree that this approach is not efficient. Describing it as "completely inefficient" is going a bit too far, IMHO. Cleanups are most often used to protect code which acquires locks or makes system calls, aren't they? Isn't acquiring a lock or making a system call a fairly expensive operation anyway? The worst cause of inefficiency for this approach is probably the icache flush needed for the trampoline creation when you take the address of a GNU C nested function. (I would like to see a different extension to fix that: one that allowed you to take the address of a nested function in a way that gave you two pointers -- a code pointer and a data pointer -- rather than a single pointer to a trampoline.) > This would slow e.g. stdio a lot. I was not saying that this code should be used for stdio. I was just refuting the claim that "it wouldn't work". Stdio (and other performance-critical routines that need cleanups) could be implemented in C++. These macros could be implemented differently (more efficiently) for C++. Now, all that said, I would like to see support for exception handling in GNU C (and for glibc to continue to be written in C rather than C++). But I would like the support for exception handling to include support for throwing and catching exceptions, not just try/finally. The current proposal seems too limited to be useful for much else than glibc, IMHO. > Plus it is incorrect too as pthread_cleanup_p{ush,op} implementation - the > cleanup is to be run if cancellation happens no matter whether __call_cleanup > is zero or non-zero. Details, details ;-) Sorry, I misread the spec for pthread_cleanup_{push,pop}. But this point can easily be remedied. The code I posted was just proof of concept, really. "Designing grand concepts is fun, finding nitty little bugs is just work" -- Brooks, in "The Mythical Man-Month". -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 5:13 ` Fergus Henderson @ 2002-11-07 5:47 ` Michael Matz 2002-11-07 8:52 ` Aldy Hernandez 1 sibling, 0 replies; 128+ messages in thread From: Michael Matz @ 2002-11-07 5:47 UTC (permalink / raw) To: Fergus Henderson Cc: Jakub Jelinek, Geoff Keating, Richard Henderson, Aldy Hernandez, gcc-patches, jason Hi, On Fri, 8 Nov 2002, Fergus Henderson wrote: > Describing it as "completely inefficient" is going a bit too far, IMHO. > Cleanups are most often used to protect code which acquires locks or > makes system calls, aren't they? Isn't acquiring a lock No it isn't. spinlocks e.g. can be implemented with inline asm, and have no call in the fast path (which only takes some cycles) at all. > or making a system call a fairly expensive operation anyway? > > The worst cause of inefficiency for this approach is probably the icache > flush needed for the trampoline creation when you take the address of a > GNU C nested function. > > (I would like to see a different extension to fix that: one that > allowed you to take the address of a nested function in a way that > gave you two pointers -- a code pointer and a data pointer -- rather > than a single pointer to a trampoline.) So instead of having an extension designed for doing what we want, you want a) use another extension (which is neither designed, nor implemented that well) to implement what we want, and b) add another not yet specified extension to fix one problem with a) ? > Now, all that said, I would like to see support for exception handling > in GNU C Although the extension only does cleanups not exceptions. > (and for glibc to continue to be written in C rather than C++). > But I would like the support for exception handling to include support > for throwing and catching exceptions, not just try/finally. The current > proposal seems too limited to be useful for much else than glibc, IMHO. Please? A try/finally would be usefull nearly everywhere in C which deals with resources. E.g. for something like this: char *buf; char *name; FILE *f; name = (char *) malloc (size); if (!name) return ERROR; buf = (char *) malloc (size2); if (!buf) { free (name); return ERROR; } f = fopen (name, "r"); if (!f) { free (name); free (buf); return ERROR; } if (fread (buf, size2, 1, f) < 0) { fclose (f); free (name); free (buf); return ERROR; } ... Well, you get the idea. Ciao, Michael. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 5:13 ` Fergus Henderson 2002-11-07 5:47 ` Michael Matz @ 2002-11-07 8:52 ` Aldy Hernandez 2002-11-07 10:00 ` Mike Stump 2002-11-07 12:36 ` Alexandre Oliva 1 sibling, 2 replies; 128+ messages in thread From: Aldy Hernandez @ 2002-11-07 8:52 UTC (permalink / raw) To: Fergus Henderson Cc: Jakub Jelinek, Geoff Keating, Richard Henderson, gcc-patches, jason > But I would like the support for exception handling to include support > for throwing and catching exceptions, not just try/finally. The current > proposal seems too limited to be useful for much else than glibc, IMHO. How are you going to handle catching exceptions, given that we have no way to recognize certain types in C (templates, classes, etc)? See rth's post about catching exceptions in C. Besides, this is just a first step. What other compilers have done (m$oft) is provide a try/finally/__except. Where the __except can catch exceptions. But they've hand waived over the issue as well and __except catches *any* exceptions (ala catch(...)) because they've obviously run into the same problem of type interoperability between languages. try/finally is a way to run cleanups, not to implement a full fledged EH mechanism for C. If you want that, you should be using C++. Aldy ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 8:52 ` Aldy Hernandez @ 2002-11-07 10:00 ` Mike Stump 2002-11-07 12:36 ` Alexandre Oliva 1 sibling, 0 replies; 128+ messages in thread From: Mike Stump @ 2002-11-07 10:00 UTC (permalink / raw) To: Aldy Hernandez Cc: Fergus Henderson, Jakub Jelinek, Geoff Keating, Richard Henderson, gcc-patches, jason On Thursday, November 7, 2002, at 08:55 AM, Aldy Hernandez wrote: >> But I would like the support for exception handling to include support >> for throwing and catching exceptions, not just try/finally. The >> current >> proposal seems too limited to be useful for much else than glibc, >> IMHO. > > How are you going to handle catching exceptions, given that we have no > way to recognize certain types in C (templates, classes, etc)? See > rth's post about catching exceptions in C. This is easy. You conform to the C++ rtti system. Another way to view that, is as the definition of the language independent runtime type information. Once you do that, you can catch and throw any C++ compatible type. There are many in gcc, for example, int. Another example: struct exception { int why; char *description; }; the possibilities are endless. The fact there might exist an example of a type that doesn't work in C land isn't that interesting. If we add the ability to throw and catch to C, we should of course just do it correctly, the first time. ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 8:52 ` Aldy Hernandez 2002-11-07 10:00 ` Mike Stump @ 2002-11-07 12:36 ` Alexandre Oliva 2002-11-07 13:06 ` Aldy Hernandez 1 sibling, 1 reply; 128+ messages in thread From: Alexandre Oliva @ 2002-11-07 12:36 UTC (permalink / raw) To: Aldy Hernandez Cc: Fergus Henderson, Jakub Jelinek, Geoff Keating, Richard Henderson, gcc-patches, jason On Nov 7, 2002, Aldy Hernandez <aldyh@redhat.com> wrote: >> But I would like the support for exception handling to include support >> for throwing and catching exceptions, not just try/finally. The current >> proposal seems too limited to be useful for much else than glibc, IMHO. > How are you going to handle catching exceptions, given that we have no > way to recognize certain types in C (templates, classes, etc)? You don't recognize types. You just catch everything. Which sounds perfectly reasonable from a C standpoint. One of the things I liked about the C front-end of GCC was that it could pretty much exercise any of the features available to all other languages: nested functions, so that you could do the same as Pascal; extended inline assembly, such that you didn't have to fallback to assembly for everything; variable-sized types, like some other languages support; expression statements, etc, etc. The nice thing was that C could really be used as a high-level assembly, exercising most (if not all) of the internal features the back-end would have to implement for other languages anyway. This broke down when Ada and C++ introduced exceptions as language-specific extensions, and then, even though C++ exceptions were later integrated into the generic back end framework, they were still unavailable in C. I personally think cleanups are a step in the right direction of restoring the ability to exercise all features of the compiler in a single front end. I don't really care if it's C, C++, treelang or something else, but clearly to me C++ is not a good candidate since it fails to support a number of other gcc extensions that the C front end supports. So I'm all for bringing back-end-supported exception handling support features into our higher-level assembly. I wouldn't go as far as supporting catches and throws right now, given that we don't have a clean design for this feature, but try/finally looks terrifically simple, and it's not like it's a new idea: as many others have pointed out, other compilers already support it, so it's likely to gain acceptance in the next round of C standardization. Even more so if we choose to support it exactly like other compilers do. The other advantage I see in offering not only clean-ups, but actual exception catching and throwing in our high-level assembly, is that we can then write glue code to convert exceptions from one language to another. Currently, there's really no simple way to do it, to the best of my knowledge. I'm not saying writing such glue code would be simple, but at least someone wouldn't have to write such glue as a number of functions that call one-another, each one implemented in a separate exception-supporting language. Being able to unify the EH framework and expose it to the user would even enable us to implement EH supporting routines for languages in our higher-level assembly. But then, again, for actual exception handling, we still need more discussion and design, but for clean ups, there's really not much possibility for variation in the design and syntax, and following existing practice in other compilers and languages is clearly a plus. -- Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/ Red Hat GCC Developer aoliva@{redhat.com, gcc.gnu.org} CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org} Free Software Evangelist Professional serial bug killer ^ permalink raw reply [flat|nested] 128+ messages in thread
* Re: [basic-improvements] try/finally support for c/c++ - more tests 2002-11-07 12:36 ` Alexandre Oliva @ 2002-11-07 13:06 ` Aldy Hernandez 0 siblings, 0 replies; 128+ messages in thread From: Aldy Hernandez @ 2002-11-07 13:06 UTC (permalink / raw) To: Alexandre Oliva Cc: Fergus Henderson, Jakub Jelinek, Geoff Keating, Richard Henderson, gcc-patches, jason > > How are you going to handle catching exceptions, given that we have no > > way to recognize certain types in C (templates, classes, etc)? > > You don't recognize types. You just catch everything. Which sounds > perfectly reasonable from a C standpoint. Which is what try/finally/__except does, and which other C compilers do. I can implement that. I'm just waiting for all the dust to settle, and if this an acceptable construct. > acceptance in the next round of C standardization. Even more so if we > choose to support it exactly like other compilers do. Which is exactly what I did ;-). Aldy ^ permalink raw reply [flat|nested] 128+ messages in thread
end of thread, other threads:[~2002-11-12 16:58 UTC | newest] Thread overview: 128+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2002-11-05 15:16 [basic-improvements] try/finally support for c/c++ Aldy Hernandez 2002-11-05 15:57 ` Richard Henderson 2002-11-05 23:03 ` Aldy Hernandez 2002-11-06 0:44 ` Joseph S. Myers 2002-11-06 0:52 ` Jakub Jelinek 2002-11-06 3:02 ` Michael Matz 2002-11-06 3:11 ` Jakub Jelinek 2002-11-06 4:16 ` Michael Matz 2002-11-06 10:29 ` Aldy Hernandez 2002-11-06 10:53 ` Richard Henderson 2002-11-06 10:56 ` Aldy Hernandez 2002-11-06 11:24 ` Joseph S. Myers 2002-11-06 13:49 ` Richard Henderson 2002-11-06 17:45 ` Fergus Henderson 2002-11-07 9:54 ` Richard Henderson 2002-11-06 17:48 ` Fergus Henderson 2002-11-07 9:58 ` Richard Henderson 2002-11-06 11:22 ` Joseph S. Myers 2002-11-06 14:00 ` Richard Henderson 2002-11-06 17:21 ` Fergus Henderson 2002-11-06 4:20 ` Gabriel Dos Reis 2002-11-06 9:05 ` Aldy Hernandez 2002-11-06 9:11 ` Matt Austern 2002-11-06 9:25 ` Gabriel Dos Reis 2002-11-06 11:15 ` Richard Henderson 2002-11-07 0:09 ` Kai Henningsen 2002-11-07 12:56 ` Richard Henderson 2002-11-06 6:05 ` Jason Merrill 2002-11-06 10:56 ` Richard Henderson 2002-11-06 12:14 ` Jason Merrill 2002-11-05 16:40 ` Stan Shebs 2002-11-05 16:48 ` Matt Austern 2002-11-05 17:21 ` Jason Merrill 2002-11-05 19:25 ` Matt Austern 2002-11-06 10:25 ` Richard Henderson 2002-11-06 11:05 ` Mike Stump 2002-11-05 21:20 ` Aldy Hernandez 2002-11-06 9:43 ` [basic-improvements] try/finally support for c/c++ - more tests Jakub Jelinek 2002-11-06 11:04 ` Joseph S. Myers 2002-11-06 15:34 ` Mark Mitchell 2002-11-06 16:03 ` Richard Henderson 2002-11-06 16:10 ` Gabriel Dos Reis 2002-11-06 16:12 ` Richard Henderson 2002-11-06 16:20 ` Gabriel Dos Reis 2002-11-06 17:02 ` Per Bothner 2002-11-06 17:14 ` Gabriel Dos Reis 2002-11-06 16:47 ` Mark Mitchell 2002-11-06 16:54 ` Matt Austern 2002-11-06 18:00 ` Zack Weinberg 2002-11-06 18:14 ` Gabriel Dos Reis 2002-11-06 18:58 ` Zack Weinberg 2002-11-06 19:33 ` Gabriel Dos Reis 2002-11-06 22:15 ` Zack Weinberg 2002-11-06 22:37 ` Mark Mitchell 2002-11-06 23:30 ` Aldy Hernandez 2002-11-07 1:03 ` Gabriel Dos Reis 2002-11-07 5:34 ` Michael Matz 2002-11-07 8:14 ` Mark Mitchell 2002-11-07 8:37 ` Daniel Jacobowitz 2002-11-07 9:09 ` Mark Mitchell 2002-11-07 9:19 ` Daniel Jacobowitz 2002-11-07 9:53 ` Mark Mitchell 2002-11-07 9:57 ` Matt Austern 2002-11-07 10:43 ` Jason Merrill 2002-11-07 8:44 ` Jakub Jelinek 2002-11-07 12:18 ` Geoff Keating 2002-11-07 12:24 ` Daniel Jacobowitz 2002-11-07 12:32 ` Mark Mitchell 2002-11-07 13:41 ` Geoff Keating 2002-11-07 14:06 ` Mark Mitchell 2002-11-07 14:39 ` Richard Henderson 2002-11-07 14:53 ` Mark Mitchell 2002-11-07 15:14 ` Geoff Keating 2002-11-07 15:37 ` Mark Mitchell 2002-11-08 11:30 ` Geoff Keating 2002-11-07 15:45 ` Richard Henderson 2002-11-07 16:21 ` Mark Mitchell 2002-11-07 16:44 ` aldyh 2002-11-07 17:06 ` Richard Henderson 2002-11-07 17:10 ` Jakub Jelinek 2002-11-07 17:29 ` Mark Mitchell 2002-11-07 17:43 ` Richard Henderson 2002-11-07 17:55 ` Mark Mitchell 2002-11-07 17:52 ` Jason Merrill 2002-11-07 17:57 ` Mark Mitchell 2002-11-07 18:17 ` Zack Weinberg 2002-11-07 18:29 ` Mark Mitchell 2002-11-07 21:23 ` Robert Lipe 2002-11-07 21:32 ` Jason Merrill 2002-11-08 4:48 ` Nicola Pero 2002-11-08 5:47 ` Jakub Jelinek 2002-11-08 10:02 ` Fergus Henderson 2002-11-08 11:24 ` Kai Henningsen 2002-11-08 11:44 ` Jakub Jelinek 2002-11-09 0:11 ` Fergus Henderson 2002-11-08 11:46 ` Mike Stump 2002-11-08 10:02 ` Matt Austern 2002-11-11 5:38 ` Michael Matz 2002-11-11 12:59 ` Matt Austern 2002-11-12 1:01 ` Michael Matz 2002-11-12 8:20 ` Mark Mitchell 2002-11-12 8:58 ` Michael Matz 2002-11-07 19:28 ` Daniel Jacobowitz 2002-11-07 22:07 ` Alexandre Oliva 2002-11-08 4:27 ` Richard Henderson 2002-11-08 4:54 ` Jakub Jelinek 2002-11-08 6:01 ` Jakub Jelinek 2002-11-08 11:38 ` Mike Stump 2002-11-08 11:25 ` Mike Stump 2002-11-08 9:31 ` Michael Matz 2002-11-08 11:26 ` Hans-Peter Nilsson 2002-11-08 11:48 ` Mike Stump 2002-11-07 11:38 ` Zack Weinberg 2002-11-07 9:38 ` Mike Stump 2002-11-07 10:06 ` Richard Henderson 2002-11-07 12:57 ` Hans-Peter Nilsson 2002-11-06 17:58 ` Fergus Henderson 2002-11-06 18:09 ` Fergus Henderson 2002-11-07 0:30 ` Jakub Jelinek 2002-11-06 18:34 ` Geoff Keating 2002-11-07 3:29 ` Fergus Henderson 2002-11-07 4:22 ` Jakub Jelinek 2002-11-07 5:13 ` Fergus Henderson 2002-11-07 5:47 ` Michael Matz 2002-11-07 8:52 ` Aldy Hernandez 2002-11-07 10:00 ` Mike Stump 2002-11-07 12:36 ` Alexandre Oliva 2002-11-07 13:06 ` Aldy Hernandez
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).