Index: doc/working/exception/impl/README
===================================================================
--- doc/working/exception/impl/README	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
+++ doc/working/exception/impl/README	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
@@ -0,0 +1,9 @@
+This folder contains a working prototype of how to implement exceptions in C.
+
+main.cfa	: Example user code
+main.c	: Example generated code
+except.c	: Implementation of the unwinding logic
+except.h	: header for except
+lsda.h	: stolen code from gcc that handles reading the exception table language specifica data
+
+to compile run : "gcc -fexceptions -Wall -Werror -g main.c except.c"
Index: doc/working/exception/impl/except.c
===================================================================
--- doc/working/exception/impl/except.c	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
+++ doc/working/exception/impl/except.c	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
@@ -0,0 +1,217 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unwind.h>
+
+#include "lsda.h"
+
+//Global which defines the current exception
+//Currently an int just to make matching easier
+int this_exception;
+
+//This is our personality routine
+//For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
+//This function will be called twice when unwinding
+//Once in the search phased and once in the cleanup phase
+_Unwind_Reason_Code __gcfa_personality_v0 (
+                     int version, _Unwind_Action actions, unsigned long long exceptionClass,
+                     struct _Unwind_Exception* unwind_exception, struct _Unwind_Context* context)
+{
+	//DEBUG
+	printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
+
+	//If we've reached the end of the stack then there is nothing much we can do...
+	if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
+	
+	//DEBUG
+	if (actions & _UA_SEARCH_PHASE) {
+		printf(" lookup phase");
+	} 
+	//DEBUG
+	else if (actions & _UA_CLEANUP_PHASE) {
+		printf(" cleanup phase");
+	}
+	//Just in case, probably can't actually happen
+	else {
+		printf(" error\n");
+		return _URC_FATAL_PHASE1_ERROR;
+	}
+	
+	//Get a pointer to the language specific data from which we will read what we need
+	const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
+
+	if( !lsd ) {	//Nothing to do, keep unwinding
+		printf(" no LSD");
+		goto UNWIND;
+	}
+
+	//Get the instuction pointer and a reading pointer into the exception table
+	lsda_header_info lsd_info;
+	const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
+	_Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
+
+	//Linearly search the table for stuff to do
+	while( cur_ptr < lsd_info.action_table ) {
+		_Unwind_Ptr callsite_start;
+		_Unwind_Ptr callsite_len;
+		_Unwind_Ptr callsite_landing_pad;
+		_uleb128_t  callsite_action;
+
+		//Decode the common stuff we have in here
+		cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
+		cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
+		cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
+		cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
+
+		//Have we reach the correct frame info yet?
+		if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
+			//DEBUG BEGIN
+			void * ls = (void*)lsd_info.Start;
+			void * cs = (void*)callsite_start;
+			void * cl = (void*)callsite_len;
+			void * bp = (void*)lsd_info.Start + callsite_start;
+			void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
+			void * ip = (void*)instruction_ptr;
+			printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
+			//DEBUG END
+			continue;
+		}
+		
+		//Have we gone too far
+		if( lsd_info.Start + callsite_start > instruction_ptr ) {
+			printf(" gone too far");
+			break;
+		}
+
+		//Something to do?
+		if( callsite_landing_pad ) {
+			//Which phase are we in
+			if (actions & _UA_SEARCH_PHASE) {
+				//Search phase, this means we probably found a potential handler and must check if it is a match
+
+				//If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
+				//This doesn't seem to conflict the gcc default behavior
+				if (callsite_action != 0) {
+					//Now we want to run some code to see if the handler matches
+					//This is the tricky part where we want to the power to run arbitrary code
+					//However, generating a new exception table entry and try routine every time 
+					//is way more expansive than we might like
+					//The information we have is :
+					//  - The GR (???)
+					//  - The instruction pointer
+					//  - The instruction pointer info (???)
+					//  - The CFA (???)
+					//  - The BSP (Probably the base stack pointer)
+
+
+					//The current apprach uses one exception table entry per try block
+					_uleb128_t imatcher;
+					//Get the relative offset to the 
+					cur_ptr = read_uleb128 (cur_ptr, &imatcher);
+
+					//Get a function pointer from the relative offset and call it
+					_Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;					
+					_Unwind_Reason_Code ret = matcher();
+
+					//Based on the return value, check if we matched the exception
+					if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");
+					else printf(" no handler\n");
+					return ret;
+				}
+
+				//This is only a cleanup handler, ignore it
+				printf(" no action");
+			} 
+			else if (actions & _UA_CLEANUP_PHASE) {
+
+				if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
+					//If this is a potential exception handler 
+					//but not the one that matched the exception in the seach phase,
+					//just ignore it
+					goto UNWIND;
+				}
+
+				//We need to run some clean-up or a handler
+				//These statment do the right thing but I don't know any specifics at all
+				_Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
+				_Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
+
+				//I assume this sets the instruction pointer to the adress of the landing pad
+				//It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
+				_Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
+
+				//DEBUG
+				printf(" action\n");
+
+				//Return have some action to run
+				return _URC_INSTALL_CONTEXT;
+			}
+		}
+
+		//Nothing to do, move along
+		printf(" no landing pad");
+	}
+	//No handling found
+	printf(" table end reached\n");
+
+	//DEBUG
+	UNWIND:
+	printf(" unwind\n");
+
+	//Keep unwinding the stack
+	return _URC_CONTINUE_UNWIND;
+}
+
+//We need a piece of storage to raise the exception
+struct _Unwind_Exception this_exception_storage;
+
+//Function needed by force unwind
+//It basically says to unwind the whole stack and then exit when we reach the end of the stack
+static _Unwind_Reason_Code _Stop_Fn(	
+	int version, 
+	_Unwind_Action actions, 
+	_Unwind_Exception_Class exceptionClass, 
+	struct _Unwind_Exception * unwind_exception, 
+	struct _Unwind_Context * context, 
+	void * some_param
+) {
+	if( actions & _UA_END_OF_STACK  ) exit(1);
+	if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
+
+	return _URC_FATAL_PHASE2_ERROR;
+}
+
+//Example throw routine
+void throw( int val ) {
+	//Store the current exception
+	this_exception = val;
+
+	//DEBUG
+	printf("Throwing exception %d\n", this_exception);
+
+	//Call stdlibc to raise the exception
+	_Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
+
+	//If we reach here it means something happened
+	//For resumption to work we need to find a way to return back to here
+	//Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.
+	//Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.
+	//If we just pretend no handler was found that would work but may be expensive for no reason since we will always
+	//search the whole stack
+
+	if( ret == _URC_END_OF_STACK ) {
+		//No proper handler was found
+		//This can be handled in several way
+		//C++ calls std::terminate
+		//Here we force unwind the stack, basically raising a cancellation
+		printf("Uncaught exception %p\n", &this_exception_storage);
+		
+		ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
+		printf("UNWIND ERROR %d after force unwind\n", ret);
+		abort();
+	}
+
+	//We did not simply reach the end of the stack without finding a handler,
+	//Something wen't wrong
+	printf("UNWIND ERROR %d after raise exception\n", ret);
+	abort();
+}
Index: doc/working/exception/impl/except.h
===================================================================
--- doc/working/exception/impl/except.h	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
+++ doc/working/exception/impl/except.h	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
@@ -0,0 +1,3 @@
+#include <unwind.h>
+
+void throw( int val );
Index: doc/working/exception/impl/lsda.h
===================================================================
--- doc/working/exception/impl/lsda.h	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
+++ doc/working/exception/impl/lsda.h	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
@@ -0,0 +1,262 @@
+//This code was stolen from gcc to read exception tables
+
+
+/* If using C++, references to abort have to be qualified with std::.  */
+#if __cplusplus
+#define __gxx_abort std::abort
+#else
+#define __gxx_abort abort
+#endif
+
+/* Pointer encodings, from dwarf2.h.  */
+#define DW_EH_PE_absptr         0x00
+#define DW_EH_PE_omit           0xff
+
+#define DW_EH_PE_uleb128        0x01
+#define DW_EH_PE_udata2         0x02
+#define DW_EH_PE_udata4         0x03
+#define DW_EH_PE_udata8         0x04
+#define DW_EH_PE_sleb128        0x09
+#define DW_EH_PE_sdata2         0x0A
+#define DW_EH_PE_sdata4         0x0B
+#define DW_EH_PE_sdata8         0x0C
+#define DW_EH_PE_signed         0x08
+
+#define DW_EH_PE_pcrel          0x10
+#define DW_EH_PE_textrel        0x20
+#define DW_EH_PE_datarel        0x30
+#define DW_EH_PE_funcrel        0x40
+#define DW_EH_PE_aligned        0x50
+
+#define DW_EH_PE_indirect	0x80
+
+
+
+int handler_found = 0;
+
+/* Given an encoding, return the number of bytes the format occupies.
+This is only defined for fixed-size encodings, and so does not
+include leb128.  */
+static unsigned int size_of_encoded_value (unsigned char encoding) __attribute__ ((unused));
+
+static unsigned int size_of_encoded_value (unsigned char encoding)
+{
+	if (encoding == DW_EH_PE_omit) return 0;
+
+	switch (encoding & 0x07) {
+		case DW_EH_PE_absptr: return sizeof (void *);
+		case DW_EH_PE_udata2: return 2;
+		case DW_EH_PE_udata4: return 4;
+		case DW_EH_PE_udata8: return 8;
+	}
+	__gxx_abort ();
+}
+
+/* Given an encoding and an _Unwind_Context, return the base to which
+the encoding is relative.  This base may then be passed to
+read_encoded_value_with_base for use when the _Unwind_Context is
+not available.  */
+static _Unwind_Ptr base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
+{
+	if (encoding == DW_EH_PE_omit) return 0;
+
+	switch (encoding & 0x70) {
+		case DW_EH_PE_absptr:
+		case DW_EH_PE_pcrel:
+		case DW_EH_PE_aligned:
+			return 0;
+		case DW_EH_PE_textrel:
+			return _Unwind_GetTextRelBase (context);
+		case DW_EH_PE_datarel:
+			return _Unwind_GetDataRelBase (context);
+		case DW_EH_PE_funcrel:
+			return _Unwind_GetRegionStart (context);
+	}
+	__gxx_abort ();
+}
+
+/* Read an unsigned leb128 value from P, store the value in VAL, return
+P incremented past the value.  We assume that a word is large enough to
+hold any value so encoded; if it is smaller than a pointer on some target,
+pointers should not be leb128 encoded on that target.  */
+static const unsigned char * read_uleb128 (const unsigned char *p, _uleb128_t *val)
+{
+	unsigned int shift = 0;
+	unsigned char byte;
+	_uleb128_t result;
+
+	result = 0;
+	do
+	{
+		byte = *p++;
+		result |= ((_uleb128_t)byte & 0x7f) << shift;
+		shift += 7;
+	}
+	while (byte & 0x80);
+
+	*val = result;
+	return p;
+}
+
+/* Similar, but read a signed leb128 value.  */
+static const unsigned char * read_sleb128 (const unsigned char *p, _sleb128_t *val)
+{
+	unsigned int shift = 0;
+	unsigned char byte;
+	_uleb128_t result;
+
+	result = 0;
+	do
+	{
+		byte = *p++;
+		result |= ((_uleb128_t)byte & 0x7f) << shift;
+		shift += 7;
+	}
+	while (byte & 0x80);
+
+	/* Sign-extend a negative value.  */
+	if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) result |= -(((_uleb128_t)1L) << shift);
+
+	*val = (_sleb128_t) result;
+	return p;
+}
+
+/* Load an encoded value from memory at P.  The value is returned in VAL;
+The function returns P incremented past the value.  BASE is as given
+by base_of_encoded_value for this encoding in the appropriate context.  */
+
+static const unsigned char * read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, const unsigned char *p, _Unwind_Ptr *val)
+{
+	union unaligned
+	{
+		void *ptr;
+		unsigned u2 __attribute__ ((mode (HI)));
+		unsigned u4 __attribute__ ((mode (SI)));
+		unsigned u8 __attribute__ ((mode (DI)));
+		signed s2 __attribute__ ((mode (HI)));
+		signed s4 __attribute__ ((mode (SI)));
+		signed s8 __attribute__ ((mode (DI)));
+	} __attribute__((__packed__));
+
+	const union unaligned *u = (const union unaligned *) p;
+	_Unwind_Internal_Ptr result;
+
+	if (encoding == DW_EH_PE_aligned)
+	{
+		_Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
+		a = (a + sizeof (void *) - 1) & - sizeof(void *);
+		result = *(_Unwind_Internal_Ptr *) a;
+		p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
+	}
+	else
+	{
+		switch (encoding & 0x0f)
+		{
+			case DW_EH_PE_absptr:
+				result = (_Unwind_Internal_Ptr) u->ptr;
+				p += sizeof (void *);
+				break;
+			case DW_EH_PE_uleb128:
+			{
+				_uleb128_t tmp;
+				p = read_uleb128 (p, &tmp);
+				result = (_Unwind_Internal_Ptr) tmp;
+			}
+			break;
+
+			case DW_EH_PE_sleb128:
+			{
+				_sleb128_t tmp;
+				p = read_sleb128 (p, &tmp);
+				result = (_Unwind_Internal_Ptr) tmp;
+			}
+			break;
+
+			case DW_EH_PE_udata2:
+				result = u->u2;
+				p += 2;
+				break;
+			case DW_EH_PE_udata4:
+				result = u->u4;
+				p += 4;
+				break;
+			case DW_EH_PE_udata8:
+				result = u->u8;
+				p += 8;
+				break;
+			case DW_EH_PE_sdata2:
+				result = u->s2;
+				p += 2;
+				break;
+			case DW_EH_PE_sdata4:
+				result = u->s4;
+				p += 4;
+				break;
+			case DW_EH_PE_sdata8:
+				result = u->s8;
+				p += 8;
+				break;
+			default:
+				__gxx_abort();
+		}
+
+		if (result != 0)
+		{
+			result += ((encoding & 0x70) == DW_EH_PE_pcrel ? (_Unwind_Internal_Ptr) u : base);
+			
+			if (encoding & DW_EH_PE_indirect) result = *(_Unwind_Internal_Ptr *) result;
+		}
+	}
+
+	*val = result;
+	return p;
+}
+
+/* Like read_encoded_value_with_base, but get the base from the context
+rather than providing it directly.  */
+static inline const unsigned char * read_encoded_value (struct _Unwind_Context *context, unsigned char encoding, const unsigned char *p, _Unwind_Ptr *val)
+{
+	return read_encoded_value_with_base (encoding, base_of_encoded_value (encoding, context), p, val);
+}
+
+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)
+{
+	_uleb128_t 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;
+}
Index: doc/working/exception/impl/main.c
===================================================================
--- doc/working/exception/impl/main.c	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
+++ doc/working/exception/impl/main.c	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include "except.h"
+
+#define EXCEPTION 2
+
+struct type_raii_t {
+	char * msg;
+};
+
+//Dtor function to test clean up routines
+void dtor( struct type_raii_t * this ) {
+	printf("%s\n", this->msg);
+}
+
+//Type macro use to make scope unwinding easier to see.
+#define raii_t __attribute__(( cleanup(dtor) )) struct type_raii_t
+
+//Leaf functions that raises exception
+void bar() {
+	raii_t a = { "Bar dtor" };
+
+	throw( EXCEPTION );
+}
+
+//Matcher function which will check if the exception was correctly caught
+extern int this_exception;
+_Unwind_Reason_Code foo_try_match() {
+	return this_exception == 3 ? _URC_HANDLER_FOUND : _URC_CONTINUE_UNWIND;
+}
+
+//Try statements are hoisted out see comments for details
+//With this could probably be unique and simply linked from
+//libcfa but there is one problem left, see the exception table 
+//for details
+void try( void (*try_block)(), void (*catch_block)() )
+{
+	//Setup statments
+	//These 2 statments won't actually result in any code,
+	//they only setup global tables.
+	//However, they clobber gcc cancellation support from gcc.
+	//We can replace the personality routine but replacing the exception
+	//table gcc generates is not really doable, it generates labels based
+	//on how the assembly works.
+	//Setup the personality routine
+	asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
+	//Setup the exception table
+	asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
+
+	//Label which defines the start of the area for which the handler is setup
+	asm volatile (".TRYSTART:");
+
+	//The actual statements of the try blocks
+	try_block();
+
+	//asm statement to prevent deadcode removal
+	asm volatile goto ("" : : : : CATCH );
+
+	//Normal return
+	return;
+
+	//Exceptionnal path
+	CATCH : __attribute__(( unused ));
+	//Label which defines the end of the area for which the handler is setup
+	asm volatile (".TRYEND:");
+	//Label which defines the start of the exception landing pad
+	//basically what will be called when the exception is caught
+	//Note, if multiple handlers are given, the multiplexing should be done
+	//by the generated code, not the exception runtime
+	asm volatile (".CATCH:");
+
+	//Exception handler
+	catch_block();
+}
+
+//Exception table data we need to generate
+//While this is almost generic, the custom data refers to
+//foo_try_match try match, which is no way generic
+//Some more works need to be done if we want to have a single 
+//call to the try routine
+asm (
+	//HEADER
+	".LFECFA1:\n"
+	"	.globl	__gcfa_personality_v0\n"
+	"	.section	.gcc_except_table,\"a\",@progbits\n"
+	".LLSDACFA2:\n"							//TABLE header
+	"	.byte	0xff\n"
+	"	.byte	0xff\n"
+	"	.byte	0x1\n"
+	"	.uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"		//BODY length
+	//Body uses language specific data and therefore could be modified arbitrarily
+	".LLSDACSBCFA2:\n"						//BODY start
+	"	.uleb128 .TRYSTART-try\n"				//Handled area start  (relative to start of function)
+	"	.uleb128 .TRYEND-.TRYSTART\n"				//Handled area length
+	"	.uleb128 .CATCH-try\n"				//Hanlder landing pad adress  (relative to start of function)
+	"	.uleb128 1\n"						//Action code, gcc seems to use always 0
+	//Beyond this point we don't match gcc data'
+	"	.uleb128 foo_try_match-try\n"			//Handler routine to check if the exception is matched
+	".LLSDACSECFA2:\n"						//BODY end
+	"	.text\n"							//TABLE footer
+	"	.size	try, .-try\n"
+	"	.ident	\"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
+	"	.section	.note.GNU-stack,\"x\",@progbits\n"
+);
+
+void foo() {
+	raii_t a = { "Foo dtor" };
+
+	//Since try will clobber the gcc exception table assembly,
+	//We need to nest this to have gcc regenerate the data
+	void foo_try_block() {
+		raii_t b = { "Foo try dtor" };
+
+		bar();
+
+		printf("Called bar successfully\n");
+	}
+
+	void foo_catch_block() {
+		printf("Exception caught\n");
+	}
+
+	//Actual call to the try block
+	try( foo_try_block, foo_catch_block );
+
+	printf( "Foo exited normally\n" );
+}
+
+int main() {
+	raii_t a = { "Main dtor" };
+
+	foo();
+
+	printf("End of program reached\n");
+}
Index: doc/working/exception/impl/main.cfa
===================================================================
--- doc/working/exception/impl/main.cfa	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
+++ doc/working/exception/impl/main.cfa	(revision 88e0080b90dabaf4c321cedeaab29b07bb4972a2)
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include "except.h"
+
+struct raii_t {
+	char * msg;
+};
+
+void ^?{}( type_raii_t * this ) {
+	printf("%s\n", this->msg);
+}
+
+void bar() {
+	raii_t a = { "Bar dtor" };
+
+	throw( 3 );
+}
+
+void foo() {
+	raii_t a = { "Foo dtor" };
+
+	try {
+		raii_t b = { "Foo try dtor" };
+
+		bar();
+
+		printf("Called bar successfully\n");
+	}
+	catch( 2 ) {
+		printf("Exception caught\n");
+	}
+
+	printf( "Foo exited normally\n" );
+}
+
+int main() {
+	raii_t a = { "Main dtor" };
+
+	foo();
+
+	printf("End of program reached\n");
+}
