* [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: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 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
* 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-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-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 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
* [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++
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-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 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++ - 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++
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-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 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 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 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-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 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++ - 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: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: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++
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-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 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++ - 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 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 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 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 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: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++
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++ - 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 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 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-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: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: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: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 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: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-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-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++
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++ - 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++
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++ - 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-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-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 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-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 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++
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++ - 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-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
* 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 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: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: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: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 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 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 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-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: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: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 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-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 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-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 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 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-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-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-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 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: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-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-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 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
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).