Index: doc/theses/andrew_beach_MMath/code/.gitignore
===================================================================
--- doc/theses/andrew_beach_MMath/code/.gitignore	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/.gitignore	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,7 @@
+# Ignore everything that doesn't have a dot in its name.
+# (These are the generated executables.)
+/*
+!/*.*
+
+# Java Executables:
+*.class
Index: doc/theses/andrew_beach_MMath/code/cond-catch.cpp
===================================================================
--- doc/theses/andrew_beach_MMath/code/cond-catch.cpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ doc/theses/andrew_beach_MMath/code/cond-catch.cpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -19,5 +19,5 @@
 		throw_exception();
 	} catch (EmptyException & exc) {
-		if (should_catch) {
+		if (!should_catch) {
 			throw;
 		}
Index: doc/theses/andrew_beach_MMath/code/cond-fixup.cfa
===================================================================
--- doc/theses/andrew_beach_MMath/code/cond-fixup.cfa	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ doc/theses/andrew_beach_MMath/code/cond-fixup.cfa	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -12,5 +12,5 @@
 
 void throw_exception() {
-	throw (empty_exception){&empty_vt};
+	throwResume (empty_exception){&empty_vt};
 }
 
@@ -18,5 +18,5 @@
 	try {
 		throw_exception();
-	} catch (empty_exception * exc ; should_catch) {
+	} catchResume (empty_exception * exc ; should_catch) {
 		// ...
 	}
@@ -36,5 +36,5 @@
 		try {
 			cond_catch();
-		} catch (empty_exception * exc) {
+		} catchResume (empty_exception * exc) {
 			// ...
 		}
Index: doc/theses/andrew_beach_MMath/code/cond_catch.py
===================================================================
--- doc/theses/andrew_beach_MMath/code/cond_catch.py	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/cond_catch.py	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+
+# Conditional Match (or Re-Raise)
+
+from time import thread_time_ns
+
+
+class EmptyException(Exception):
+    pass
+
+
+should_catch = False
+
+
+def throw_exception():
+    raise EmptyException()
+
+
+def cond_catch():
+    try:
+        throw_exception()
+    except EmptyException as exc:
+        if not should_catch:
+            raise
+
+
+def main(argv):
+    times = 1
+    if 1 < len(argv):
+        times = int(argv[1])
+    if 2 < len(argv):
+        should_catch = 0 < int(argv[2])
+
+    start_time = thread_time_ns()
+    for count in range(times):
+        try:
+            cond_catch();
+        except EmptyException:
+            pass
+
+    end_time = thread_time_ns()
+    print('Run-Time (ns):', end_time - start_time)
+
+
+if '__main__' == __name__:
+    import sys
+    main(sys.argv)
Index: doc/theses/andrew_beach_MMath/code/cross_catch.py
===================================================================
--- doc/theses/andrew_beach_MMath/code/cross_catch.py	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/cross_catch.py	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+# Cross a Try Statement with a Termination Handler
+
+from time import thread_time_ns
+
+
+class NotRaisedException(Exception):
+    pass
+
+
+def main(argv):
+    times = 1;
+    if 1 < len(argv):
+        times = int(argv[1])
+
+    start_time = thread_time_ns()
+    for count in range(times):
+        try:
+            pass
+        except NotRaisedException:
+            pass
+
+    end_time = thread_time_ns()
+    print('Run-Time (ns):', end_time - start_time)
+
+
+if '__main__' == __name__:
+    import sys
+    main(sys.argv)
Index: doc/theses/andrew_beach_MMath/code/cross_finally.py
===================================================================
--- doc/theses/andrew_beach_MMath/code/cross_finally.py	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/cross_finally.py	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+
+# Cross a Try Statement With Finally Clause
+
+from time import thread_time_ns
+
+
+def main(argv):
+    times = 1;
+    total_frames = 1;
+    if 1 < len(argv):
+        times = int(argv[1])
+    if 2 < len(argv):
+        total_frames = int(argv[2])
+
+    start_time = thread_time_ns()
+    for count in range(times):
+        try:
+            pass
+        finally:
+            pass
+
+    end_time = thread_time_ns()
+    print('Run-Time (ns):', end_time - start_time)
+
+
+if '__main__' == __name__:
+    import sys
+    main(sys.argv)
Index: doc/theses/andrew_beach_MMath/code/resume-empty.cfa
===================================================================
--- doc/theses/andrew_beach_MMath/code/resume-empty.cfa	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ doc/theses/andrew_beach_MMath/code/resume-empty.cfa	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -13,5 +13,5 @@
 		unwind_empty(frames - 1);
 	} else {
-		throw (empty_exception){&empty_vt};
+		throwResume (empty_exception){&empty_vt};
 	}
 }
@@ -31,5 +31,5 @@
 		try {
 			unwind_empty(total_frames);
-		} catch (empty_exception *) {
+		} catchResume (empty_exception *) {
 			// ...
 		}
Index: doc/theses/andrew_beach_MMath/code/test.sh
===================================================================
--- doc/theses/andrew_beach_MMath/code/test.sh	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ doc/theses/andrew_beach_MMath/code/test.sh	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -18,8 +18,8 @@
 	*.cfa)
 		# Requires a symbolic link.
-		mmake "${1%.cfa}" "$1" ./cfa "$1" -o "${1%.cfa}"
+		mmake "${1%.cfa}" "$1" ./cfa -DNDEBUG -nodebug -O3 "$1" -o "${1%.cfa}"
 		;;
 	*.cpp)
-		mmake "${1%.cpp}-cpp" "$1" g++ "$1" -o "${1%.cpp}-cpp"
+		mmake "${1%.cpp}-cpp" "$1" g++ -DNDEBUG -O3 "$1" -o "${1%.cpp}-cpp"
 		;;
 	*.java)
@@ -39,9 +39,9 @@
 	exit 0
 elif [ 2 -eq "$#" ]; then
-    TEST_LANG="$1"
-    TEST_CASE="$2"
+	TEST_LANG="$1"
+	TEST_CASE="$2"
 else
-    echo "Unknown call pattern." >&2
-    exit 2
+	echo "Unknown call pattern." >&2
+	exit 2
 fi
 
@@ -58,4 +58,5 @@
 	CPP="./cond-catch-cpp $ITERATIONS 1"
 	JAVA="java CondCatch $ITERATIONS 1"
+	PYTHON="./cond_catch.py $ITERATIONS 1"
 	;;
 cond-match-none)
@@ -64,4 +65,5 @@
 	CPP="./cond-catch-cpp $ITERATIONS 0"
 	JAVA="java CondCatch $ITERATIONS 0"
+	PYTHON="./cond_catch.py $ITERATIONS 0"
 	;;
 cross-catch)
@@ -70,4 +72,5 @@
 	CPP="./cross-catch-cpp $ITERATIONS"
 	JAVA="java CrossCatch $ITERATIONS"
+	PYTHON="./cross_catch.py $ITERATIONS"
 	;;
 cross-finally)
@@ -76,4 +79,5 @@
 	CPP=unsupported
 	JAVA="java CrossFinally $ITERATIONS"
+	PYTHON="./cross_finally.py $ITERATIONS"
 	;;
 raise-detor)
@@ -82,4 +86,5 @@
 	CPP="./throw-detor-cpp $ITERATIONS $STACK_HEIGHT"
 	JAVA=unsupported
+	PYTHON=unsupported
 	;;
 raise-empty)
@@ -88,4 +93,5 @@
 	CPP="./throw-empty-cpp $ITERATIONS $STACK_HEIGHT"
 	JAVA="java ThrowEmpty $ITERATIONS $STACK_HEIGHT"
+	PYTHON="./throw_empty.py $ITERATIONS $STACK_HEIGHT"
 	;;
 raise-finally)
@@ -94,4 +100,5 @@
 	CPP=unsupported
 	JAVA="java ThrowFinally $ITERATIONS $STACK_HEIGHT"
+	PYTHON="./throw_finally.py $ITERATIONS $STACK_HEIGHT"
 	;;
 raise-other)
@@ -100,4 +107,5 @@
 	CPP="./throw-other-cpp $ITERATIONS $STACK_HEIGHT"
 	JAVA="java ThrowOther $ITERATIONS $STACK_HEIGHT"
+	PYTHON="./throw_other.py $ITERATIONS $STACK_HEIGHT"
 	;;
 *)
@@ -112,6 +120,8 @@
 cpp) echo $CPP; $CPP;;
 java) echo $JAVA; $JAVA;;
+python) echo $PYTHON; $PYTHON;;
 *)
 	echo "No such language: $TEST_LANG" >&2
 	exit 2
+	;;
 esac
Index: doc/theses/andrew_beach_MMath/code/throw_empty.py
===================================================================
--- doc/theses/andrew_beach_MMath/code/throw_empty.py	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/throw_empty.py	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+
+# Throw Across Empty Function
+
+from time import thread_time_ns
+
+
+class EmptyException(Exception):
+    pass
+
+
+def unwind_empty(frames):
+    if 0 < frames:
+        unwind_empty(frames - 1)
+    else:
+        raise EmptyException()
+
+
+def main(argv):
+    times = 1
+    total_frames = 1
+    if 1 < len(argv):
+        times = int(argv[1])
+    if 2 < len(argv):
+        total_frames = int(argv[2])
+
+    start_time = thread_time_ns()
+    for count in range(times):
+        try:
+            unwind_empty(total_frames)
+        except EmptyException:
+            pass
+
+    end_time = thread_time_ns()
+    print('Run-Time (ns):', end_time - start_time)
+
+
+if '__main__' == __name__:
+    import sys
+    main(sys.argv)
Index: doc/theses/andrew_beach_MMath/code/throw_finally.py
===================================================================
--- doc/theses/andrew_beach_MMath/code/throw_finally.py	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/throw_finally.py	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+# Throw Across Finally
+
+from time import thread_time_ns
+
+
+class EmptyException(Exception):
+    pass
+
+
+def unwind_finally(frames):
+    if 0 < frames:
+        try:
+            unwind_finally(frames - 1)
+        finally:
+            pass
+    else:
+        raise EmptyException()
+
+
+def main(argv):
+    times = 1
+    total_frames = 1
+    if 1 < len(argv):
+        times = int(argv[1])
+    if 2 < len(argv):
+        total_frames = int(argv[2])
+
+    start_time = thread_time_ns()
+    for count in range(times):
+        try:
+            unwind_finally(total_frames)
+        except EmptyException:
+            pass
+
+    end_time = thread_time_ns()
+    print('Run-Time (ns):', end_time - start_time)
+
+
+if '__main__' == __name__:
+    import sys
+    main(sys.argv)
Index: doc/theses/andrew_beach_MMath/code/throw_other.py
===================================================================
--- doc/theses/andrew_beach_MMath/code/throw_other.py	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/throw_other.py	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+
+# Throw Across Other Handler
+
+from time import thread_time_ns
+
+
+class EmptyException(Exception):
+    pass
+
+
+class NotRaisedException(Exception):
+    pass
+
+
+def unwind_other(frames):
+    if 0 < frames:
+        try:
+            unwind_other(frames - 1)
+        except NotRaisedException:
+            pass
+    else:
+        raise EmptyException()
+
+
+def main(argv):
+    times = 1
+    total_frames = 1
+    if 1 < len(argv):
+        times = int(argv[1])
+    if 2 < len(argv):
+        total_frames = int(argv[2])
+
+    start_time = thread_time_ns()
+    for count in range(times):
+        try:
+            unwind_other(total_frames)
+        except EmptyException:
+            pass
+
+    end_time = thread_time_ns()
+    print('Run-Time (ns):', end_time - start_time)
+
+
+if '__main__' == __name__:
+    import sys
+    main(sys.argv)
Index: doc/theses/andrew_beach_MMath/code/throw_with.py
===================================================================
--- doc/theses/andrew_beach_MMath/code/throw_with.py	(revision 63bde810176345a17a52622fedf64439891234a2)
+++ doc/theses/andrew_beach_MMath/code/throw_with.py	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+
+# Throw Across With Statement (closest thing Python has to a destructor)
+
+from time import thread_time_ns
+
+
+class EmptyException(Exception):
+    pass
+
+
+class EmptyContextManager:
+
+    def __enter__(self):
+        pass
+
+    def __exit__(self, exception_type, exception_value, traceback):
+        pass
+
+
+def unwind_with(frames):
+    if 0 < frames:
+        with EmptyContextManager():
+            unwind_with(frames - 1)
+    else:
+        raise EmptyException()
+
+
+def main(argv):
+    times = 1
+    total_frames = 1
+    if 1 < len(argv):
+        times = int(argv[1])
+    if 2 < len(argv):
+        total_frames = int(argv[2])
+
+    start_time = thread_time_ns()
+    for count in range(times):
+        try:
+            unwind_with(total_frames)
+        except EmptyException:
+            pass
+
+    end_time = thread_time_ns()
+    print('Run-Time (ns):', end_time - start_time)
+
+
+if '__main__' == __name__:
+    import sys
+    main(sys.argv)
Index: doc/theses/andrew_beach_MMath/intro.tex
===================================================================
--- doc/theses/andrew_beach_MMath/intro.tex	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ doc/theses/andrew_beach_MMath/intro.tex	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -107,13 +107,28 @@
 
 Exception handling is not a new concept,
-with papers on the subject dating back 70s.
-
-Their were popularised by \Cpp,
+with papers on the subject dating back 70s.\cite{Goodenough}
+
+Early exceptions were often treated as signals. They carried no information
+except their identity. Ada still uses this system.
+
+The modern flag-ship for termination exceptions is \Cpp,
 which added them in its first major wave of non-object-orientated features
 in 1990.
 % https://en.cppreference.com/w/cpp/language/history
-
-Java was the next popular language to use exceptions. It is also the most
-popular language with checked exceptions.
+\Cpp has the ability to use any value of any type as an exception.
+However that seems to immediately pushed aside for classes inherited from
+\code{C++}{std::exception}.
+Although there is a special catch-all syntax it does not allow anything to
+be done with the caught value becuase nothing is known about it.
+So instead a base type is defined with some common functionality (such as
+the ability to describe the reason the exception was raised) and all
+exceptions have that functionality.
+This seems to be the standard now, as the garentied functionality is worth
+any lost flexibility from limiting it to a single type.
+
+Java was the next popular language to use exceptions.
+Its exception system largely reflects that of \Cpp, except that requires
+you throw a child type of \code{Java}{java.lang.Throwable}
+and it uses checked exceptions.
 Checked exceptions are part of the function interface they are raised from.
 This includes functions they propogate through, until a handler for that
@@ -131,35 +146,44 @@
 Resumption exceptions have been much less popular.
 Although resumption has a history as old as termination's, very few
-programming languages have implement them.
+programming languages have implemented them.
 % http://bitsavers.informatik.uni-stuttgart.de/pdf/xerox/parc/techReports/
 %   CSL-79-3_Mesa_Language_Manual_Version_5.0.pdf
-Mesa is one programming languages that did and experiance with that
-languages is quoted as being one of the reasons resumptions were not
+Mesa is one programming languages that did. Experiance with Mesa
+is quoted as being one of the reasons resumptions were not
 included in the \Cpp standard.
 % https://en.wikipedia.org/wiki/Exception_handling
-\todo{A comment about why we did include them when they are so unpopular
-might be approprate.}
-
-%\subsection
-Functional languages, tend to use solutions like the return union, but some
-exception-like constructs still appear.
-
-For instance Haskell's built in error mechanism can make the result of any
-expression, including function calls. Any expression that examines an
-error value will in-turn produce an error. This continues until the main
-function produces an error or until it is handled by one of the catch
-functions.
+Since then resumptions have been ignored in the main-stream.
+
+All of this does call into question the use of resumptions, is
+something largely rejected decades ago worth revisiting now?
+Yes, even if it was the right call at the time there have been decades
+of other developments in computer science that have changed the situation
+since then.
+Some of these developments, such as in functional programming's resumption
+equivalent: algebraic effects\cite{Zhang19}, are directly related to
+resumptions as well.
+A complete rexamination of resumptions is beyond a single paper, but it is
+enough to try them again in \CFA.
+% Especially considering how much easier they are to implement than
+% termination exceptions.
+
+%\subsection
+Functional languages tend to use other solutions for their primary error
+handling mechanism, exception-like constructs still appear.
+Termination appears in error construct, which marks the result of an
+expression as an error, the result of any expression that tries to use it as
+an error, and so on until an approprate handler is reached.
+Resumption appears in algebric effects, where a function dispatches its
+side-effects to its caller for handling.
 
 %\subsection
 More recently exceptions seem to be vanishing from newer programming
-languages.
-Rust and Go reduce this feature to panics.
-Panicing is somewhere between a termination exception and a program abort.
-Notably in Rust a panic can trigger either, a panic may unwind the stack or
-simply kill the process.
+languages, replaced by ``panic".
+In Rust a panic is just a program level abort that may be implemented by
+unwinding the stack like in termination exception handling.
 % https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
-Go's panic is much more similar to a termination exception but there is
-only a catch-all function with \code{Go}{recover()}.
-So exceptions still are appearing, just in reduced forms.
+Go's panic through is very similar to a termination except it only supports
+a catch-all by calling \code{Go}{recover()}, simplifying the interface at
+the cost of flexability.
 
 %\subsection
Index: driver/cc1.cc
===================================================================
--- driver/cc1.cc	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ driver/cc1.cc	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Fri Aug 26 14:23:51 2005
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Jun  1 23:07:21 2021
-// Update Count     : 415
+// Last Modified On : Wed Jul 14 15:42:08 2021
+// Update Count     : 418
 //
 
@@ -372,7 +372,7 @@
 			if ( prefix( arg, "-fdiagnostics-color=" ) ) {
 				string choice = arg.substr(20);
-				     if(choice == "always") color_arg = Color_Always;
-				else if(choice == "never" ) color_arg = Color_Never;
-				else if(choice == "auto"  ) color_arg = Color_Auto;
+				if ( choice == "always" ) color_arg = Color_Always;
+				else if ( choice == "never" ) color_arg = Color_Never;
+				else if ( choice == "auto" ) color_arg = Color_Auto;
 			} else if ( arg == "-fno-diagnostics-color" ) {
 				color_arg = Color_Auto;
Index: driver/cfa.cc
===================================================================
--- driver/cfa.cc	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ driver/cfa.cc	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Tue Aug 20 13:44:49 2002
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jan 16 07:30:19 2021
-// Update Count     : 442
+// Last Modified On : Wed Jul 14 21:55:12 2021
+// Update Count     : 467
 //
 
@@ -94,9 +94,9 @@
 	// get executable path from /proc/self/exe
 	ssize_t size = readlink("/proc/self/exe", const_cast<char*>(abspath.c_str()), abspath.size());
-	if(size <= 0) {
+	if ( size <= 0 ) {
 		std::cerr << "Error could not evaluate absolute path from /proc/self/exe" << std::endl;
 		std::cerr << "Failed with " << std::strerror(errno) << std::endl;
 		std::exit(1);
-	}
+	} // if
 
 	// Trim extra characters
@@ -104,11 +104,11 @@
 
 	// Are we installed
-	if(abspath.rfind(CFA_BINDIR  , 0) == 0) { return Installed; }
+	if ( abspath.rfind(CFA_BINDIR, 0) == 0 ) { return Installed; }
 
 	// Is this the build tree
-	if(abspath.rfind(TOP_BUILDDIR, 0) == 0) { return BuildTree; }
+	if ( abspath.rfind(TOP_BUILDDIR, 0 ) == 0 ) { return BuildTree; }
 
 	// Does this look like distcc
-	if(abspath.find("/.cfadistcc/") != std::string::npos) { return Distributed; }
+	if ( abspath.find( "/.cfadistcc/" ) != std::string::npos ) { return Distributed; }
 
 	// None of the above? Give up since we don't know where the prelude or include directories are
@@ -188,8 +188,16 @@
 					i += 1;
 					if ( i == argc ) continue;			// next argument available ?
-					Putenv( argv, argv[i] );
+					Putenv( argv, argv[i] );			// make available for cc1
 				} else if ( arg[5] == ',' ) {			// CFA specific arguments
-					Putenv( argv, argv[i] + 6 );
+					string xcfargs = arg.substr( 6 ) + ","; // add sentinel
+					for ( ;; ) {
+						size_t posn = xcfargs.find_first_of( "," ); // find separator
+					  if ( posn == string::npos ) break; // any characters left ?
+						string xcfarg = xcfargs.substr( 0, posn ); // remove XCFA argument
+						Putenv( argv, xcfarg );			// make available for cc1
+						xcfargs.erase( 0, posn + 1 );	// remove first argument and comma
+					} // for
 				} else {								// CFA specific arguments
+					assert( false );					// this does not make sense
 					args[nargs++] = argv[i];
 				} // if
@@ -364,5 +372,5 @@
 	args[nargs++] = "stdbool.h";
 
-	if( compiling_libs ) {
+	if ( compiling_libs ) {
 		Putenv( argv, "-t" );
 	} // if
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/AST/Convert.cpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -9,7 +9,7 @@
 // Author           : Thierry Delisle
 // Created On       : Thu May 09 15::37::05 2019
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Mar 12 18:43:51 2021
-// Update Count     : 36
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jul 14 16:15:00 2021
+// Update Count     : 37
 //
 
@@ -1356,4 +1356,11 @@
 	}
 
+	const ast::Type * visit( const ast::VTableType * node ) override final {
+		return visitType( node, new VTableType{
+			cv( node ),
+			get<Type>().accept1( node->base )
+		} );
+	}
+
 	const ast::Type * visit( const ast::VarArgsType * node ) override final {
 		return visitType( node, new VarArgsType{ cv( node ) } );
@@ -2799,4 +2806,11 @@
 	}
 
+	virtual void visit( const VTableType * old ) override final {
+		visitType( old, new ast::VTableType{
+			GET_ACCEPT_1( base, Type ),
+			cv( old )
+		} );
+	}
+
 	virtual void visit( const AttrType * ) override final {
 		assertf( false, "AttrType deprecated in new AST." );
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/AST/Fwd.hpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -117,4 +117,5 @@
 class TupleType;
 class TypeofType;
+class VTableType;
 class VarArgsType;
 class ZeroType;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/AST/Pass.hpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -213,4 +213,5 @@
 	const ast::Type *             visit( const ast::TupleType            * ) override final;
 	const ast::Type *             visit( const ast::TypeofType           * ) override final;
+	const ast::Type *             visit( const ast::VTableType           * ) override final;
 	const ast::Type *             visit( const ast::VarArgsType          * ) override final;
 	const ast::Type *             visit( const ast::ZeroType             * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/AST/Pass.impl.hpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -1873,4 +1873,17 @@
 
 //--------------------------------------------------------------------------
+// VTableType
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::VTableType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &VTableType::base );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
 // VarArgsType
 template< typename core_t >
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/AST/Print.cpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -1416,4 +1416,12 @@
 	}
 
+	virtual const ast::Type * visit( const ast::VTableType * node ) override final {
+		preprint( node );
+		os << "vtable for ";
+		safe_print( node->base );
+
+		return node;
+	}
+
 	virtual const ast::Type * visit( const ast::VarArgsType * node ) override final {
 		preprint( node );
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/AST/Type.hpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Thu May 9 10:00:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Thu Jul 23 14:15:00 2020
-// Update Count     : 6
+// Last Modified On : Wed Jul 14 15:54:00 2021
+// Update Count     : 7
 //
 
@@ -491,4 +491,17 @@
 };
 
+/// Virtual Table Type `vtable(T)`
+class VTableType final : public Type {
+public:
+	ptr<Type> base;
+
+	VTableType( const Type * b, CV::Qualifiers q = {} ) : Type(q), base(b) {}
+
+	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	VTableType * clone() const override { return new VTableType{ *this }; }
+	MUTATE_FRIEND
+};
+
 /// GCC built-in varargs type
 class VarArgsType final : public Type {
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/AST/Visitor.hpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -105,4 +105,5 @@
     virtual const ast::Type *             visit( const ast::TupleType            * ) = 0;
     virtual const ast::Type *             visit( const ast::TypeofType           * ) = 0;
+    virtual const ast::Type *             visit( const ast::VTableType           * ) = 0;
     virtual const ast::Type *             visit( const ast::VarArgsType          * ) = 0;
     virtual const ast::Type *             visit( const ast::ZeroType             * ) = 0;
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Common/CodeLocationTools.cpp	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -176,4 +176,5 @@
     macro(TupleType, Type) \
     macro(TypeofType, Type) \
+    macro(VTableType, Type) \
     macro(VarArgsType, Type) \
     macro(ZeroType, Type) \
Index: src/Common/PassVisitor.h
===================================================================
--- src/Common/PassVisitor.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Common/PassVisitor.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -230,4 +230,6 @@
 	virtual void visit( TypeofType * typeofType ) override final;
 	virtual void visit( const TypeofType * typeofType ) override final;
+	virtual void visit( VTableType * vtableType ) override final;
+	virtual void visit( const VTableType * vtableType ) override final;
 	virtual void visit( AttrType * attrType ) override final;
 	virtual void visit( const AttrType * attrType ) override final;
@@ -343,4 +345,5 @@
 	virtual Type * mutate( TupleType * tupleType ) override final;
 	virtual Type * mutate( TypeofType * typeofType ) override final;
+	virtual Type * mutate( VTableType * vtableType ) override final;
 	virtual Type * mutate( AttrType * attrType ) override final;
 	virtual Type * mutate( VarArgsType * varArgsType ) override final;
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Common/PassVisitor.impl.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -3610,4 +3610,39 @@
 
 //--------------------------------------------------------------------------
+// VTableType
+template< typename pass_type >
+void PassVisitor< pass_type >::visit( VTableType * node ) {
+	VISIT_START( node );
+
+	// Forall qualifiers should be on base type, not here
+	// maybeAccept_impl( node->forall, *this );
+	maybeAccept_impl( node->base, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+void PassVisitor< pass_type >::visit( const VTableType * node ) {
+	VISIT_START( node );
+
+	// Forall qualifiers should be on base type, not here
+	// maybeAccept_impl( node->forall, *this );
+	maybeAccept_impl( node->base, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Type * PassVisitor< pass_type >::mutate( VTableType * node ) {
+	MUTATE_START( node );
+
+	// Forall qualifiers should be on base type, not here
+	// maybeMutate_impl( node->forall, *this );
+	maybeMutate_impl( node->base, *this );
+
+	MUTATE_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
 // AttrType
 template< typename pass_type >
Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/GenPoly/Box.cc	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -1546,11 +1546,28 @@
 			long i = 0;
 			for(std::list< Declaration* >::const_iterator decl = baseDecls.begin(); decl != baseDecls.end(); ++decl, ++i ) {
-				if ( memberDecl->get_name() != (*decl)->get_name() ) continue;
-
-				if ( DeclarationWithType *declWithType = dynamic_cast< DeclarationWithType* >( *decl ) ) {
-					if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty()
-					     || memberDecl->get_mangleName() == declWithType->get_mangleName() ) return i;
-					else continue;
-				} else return i;
+				if ( memberDecl->get_name() != (*decl)->get_name() )
+					continue;
+
+				if ( memberDecl->get_name().empty() ) {
+					// plan-9 field: match on unique_id
+					if ( memberDecl->get_uniqueId() == (*decl)->get_uniqueId() )
+						return i;
+					else
+						continue;
+				}
+
+				DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( *decl );
+
+				if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) {
+					// tuple-element field: expect neither had mangled name; accept match on simple name (like field_2) only
+					assert( memberDecl->get_mangleName().empty() && declWithType->get_mangleName().empty() );
+					return i;
+				}
+
+				// ordinary field: use full name to accommodate overloading
+				if ( memberDecl->get_mangleName() == declWithType->get_mangleName() )
+					return i;
+				else
+					continue;
 			}
 			return -1;
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Parser/DeclarationNode.cc	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 12:34:05 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Mar 23 08:44:08 2021
-// Update Count     : 1149
+// Last Modified On : Wed Jul 14 17:36:57 2021
+// Update Count     : 1154
 //
 
@@ -385,4 +385,11 @@
 	newnode->type = new TypeData( basetypeof ? TypeData::Basetypeof : TypeData::Typeof );
 	newnode->type->typeexpr = expr;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newVtableType( DeclarationNode * decl ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Vtable );
+	newnode->setBase( decl->type );
 	return newnode;
 }
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Parser/ParseNode.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 13:28:16 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Mar 12 15:19:04 2021
-// Update Count     : 897
+// Last Modified On : Wed Jul 14 17:28:53 2021
+// Update Count     : 900
 //
 
@@ -249,4 +249,5 @@
 	static DeclarationNode * newTuple( DeclarationNode * members );
 	static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
+	static DeclarationNode * newVtableType( DeclarationNode * expr );
 	static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
 	static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Parser/TypeData.cc	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:12:51 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Dec 16 07:56:46 2019
-// Update Count     : 662
+// Last Modified On : Wed Jul 14 18:57:31 2021
+// Update Count     : 672
 //
 
@@ -100,4 +100,6 @@
 		typeexpr = nullptr;
 		break;
+	  case Vtable:
+		break;
 	  case Builtin:
 		// builtin = new Builtin_t;
@@ -170,4 +172,6 @@
 		// delete typeexpr->expr;
 		delete typeexpr;
+		break;
+	  case Vtable:
 		break;
 	  case Builtin:
@@ -249,4 +253,6 @@
 	  case Basetypeof:
 		newtype->typeexpr = maybeClone( typeexpr );
+		break;
+	  case Vtable:
 		break;
 	  case Builtin:
@@ -467,4 +473,5 @@
 	  case Basetypeof:
 	  case Builtin:
+	  case Vtable:
 		assertf(false, "Tried to get leaf name from kind without a name: %d", kind);
 		break;
@@ -546,4 +553,6 @@
 	  case TypeData::Basetypeof:
 		return buildTypeof( td );
+	  case TypeData::Vtable:
+		return buildVtable( td );
 	  case TypeData::Builtin:
 		switch ( td->builtintype ) {
@@ -945,7 +954,12 @@
 	assert( td->typeexpr );
 	// assert( td->typeexpr->expr );
-	return new TypeofType{
-		buildQualifiers( td ), td->typeexpr->build(), td->kind == TypeData::Basetypeof };
+	return new TypeofType{ buildQualifiers( td ), td->typeexpr->build(), td->kind == TypeData::Basetypeof };
 } // buildTypeof
+
+
+VTableType * buildVtable( const TypeData * td ) {
+	assert( td->base );
+	return new VTableType{ buildQualifiers( td ), typebuild( td->base ) };
+} // buildVtable
 
 
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Parser/TypeData.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:18:36 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Mar 27 09:05:35 2021
-// Update Count     : 200
+// Last Modified On : Wed Jul 14 17:44:05 2021
+// Update Count     : 202
 //
 
@@ -27,5 +27,5 @@
 struct TypeData {
 	enum Kind { Basic, Pointer, Reference, Array, Function, Aggregate, AggregateInst, Enum, EnumConstant, Symbolic,
-				SymbolicInst, Tuple, Typeof, Basetypeof, Builtin, GlobalScope, Qualified, Unknown };
+				SymbolicInst, Tuple, Typeof, Basetypeof, Vtable, Builtin, GlobalScope, Qualified, Unknown };
 
 	struct Aggregate_t {
@@ -128,4 +128,5 @@
 TupleType * buildTuple( const TypeData * );
 TypeofType * buildTypeof( const TypeData * );
+VTableType * buildVtable( const TypeData * );
 Declaration * buildDecl( const TypeData *, const std::string &, Type::StorageClasses, Expression *, Type::FuncSpecifiers funcSpec, LinkageSpec::Spec, Expression * asmName,
 						 Initializer * init = nullptr, std::list< class Attribute * > attributes = std::list< class Attribute * >() );
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/Parser/parser.yy	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Jun 29 09:12:47 2021
-// Update Count     : 5027
+// Last Modified On : Wed Jul 14 17:27:54 2021
+// Update Count     : 5030
 //
 
@@ -1923,6 +1923,7 @@
 
 vtable:
-	VTABLE '(' type_list ')' default_opt
-		{ SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; }
+	VTABLE '(' typedef_name ')' default_opt
+		{ $$ = DeclarationNode::newVtableType( $3 ); }
+		// { SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; }
 	;
 
Index: src/SynTree/Mutator.h
===================================================================
--- src/SynTree/Mutator.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/SynTree/Mutator.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -112,4 +112,5 @@
 	virtual Type * mutate( TupleType * tupleType ) = 0;
 	virtual Type * mutate( TypeofType * typeofType ) = 0;
+	virtual Type * mutate( VTableType * vtableType ) = 0;
 	virtual Type * mutate( AttrType * attrType ) = 0;
 	virtual Type * mutate( VarArgsType * varArgsType ) = 0;
Index: src/SynTree/SynTree.h
===================================================================
--- src/SynTree/SynTree.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/SynTree/SynTree.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -119,4 +119,5 @@
 class TupleType;
 class TypeofType;
+class VTableType;
 class AttrType;
 class VarArgsType;
Index: src/SynTree/Type.cc
===================================================================
--- src/SynTree/Type.cc	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/SynTree/Type.cc	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Dec 15 16:52:37 2019
-// Update Count     : 49
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jul 14 15:47:00 2021
+// Update Count     : 50
 //
 #include "Type.h"
@@ -178,4 +178,25 @@
 }
 
+VTableType::VTableType( const Type::Qualifiers &tq, Type *base, const std::list< Attribute * > & attributes )
+		: Type( tq, attributes ), base( base ) {
+	assertf( base, "VTableType with a null base created." );
+}
+
+VTableType::VTableType( const VTableType &other )
+		: Type( other ), base( other.base->clone() ) {
+}
+
+VTableType::~VTableType() {
+	delete base;
+}
+
+void VTableType::print( std::ostream &os, Indenter indent ) const {
+	Type::print( os, indent );
+	os << "get virtual-table type of ";
+	if ( base ) {
+		base->print( os, indent );
+	} // if
+}
+
 // Local Variables: //
 // tab-width: 4 //
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/SynTree/Type.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep  4 09:58:00 2019
-// Update Count     : 170
+// Last Modified On : Wed Jul 14 15:40:00 2021
+// Update Count     : 171
 //
 
@@ -651,4 +651,23 @@
 };
 
+class VTableType : public Type {
+public:
+	Type *base;
+
+	VTableType( const Type::Qualifiers & tq, Type *base,
+		const std::list< Attribute * > & attributes = std::list< Attribute * >() );
+	VTableType( const VTableType & );
+	virtual ~VTableType();
+
+	Type *get_base() { return base; }
+	void set_base( Type *newValue ) { base = newValue; }
+
+	virtual VTableType *clone() const override { return new VTableType( *this ); }
+	virtual void accept( Visitor & v ) override { v.visit( this ); }
+	virtual void accept( Visitor & v ) const override { v.visit( this ); }
+	virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
+	virtual void print( std::ostream & os, Indenter indent = {} ) const override;
+};
+
 class AttrType : public Type {
   public:
Index: src/SynTree/Visitor.h
===================================================================
--- src/SynTree/Visitor.h	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ src/SynTree/Visitor.h	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -198,4 +198,6 @@
 	virtual void visit( TypeofType * node ) { visit( const_cast<const TypeofType *>(node) ); }
 	virtual void visit( const TypeofType * typeofType ) = 0;
+	virtual void visit( VTableType * node ) { visit( const_cast<const VTableType *>(node) ); }
+	virtual void visit( const VTableType * vtableType ) = 0;
 	virtual void visit( AttrType * node ) { visit( const_cast<const AttrType *>(node) ); }
 	virtual void visit( const AttrType * attrType ) = 0;
Index: tests/.expect/polymorphism.txt
===================================================================
--- tests/.expect/polymorphism.txt	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ tests/.expect/polymorphism.txt	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -1,2 +1,9 @@
 123 456 456
 5 5
+=== checkPlan9offsets
+static:
+  offset of inner double: 8
+  offset of inner float:  16
+dynamic:
+  offset of inner double: 8
+  offset of inner float:  16
Index: tests/polymorphism.cfa
===================================================================
--- tests/polymorphism.cfa	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ tests/polymorphism.cfa	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -54,4 +54,38 @@
 	b.i = s.i;
 	return b.j;
+}
+
+void checkPlan9offsets() {
+
+	forall( T )
+	struct thing {
+		T q;                // variable-sized padding
+		inline double;
+		inline float;
+	};
+
+	#define SHOW_OFFSETS \
+		double & x_inner_double = x; \
+		float  & x_inner_float  = x; \
+		printf("  offset of inner double: %ld\n", ((char *) & x_inner_double) - ((char *) & x) ); \
+		printf("  offset of inner float:  %ld\n", ((char *) & x_inner_float ) - ((char *) & x) );
+
+	void showStatic( thing(int) & x ) {
+		printf("static:\n");
+		SHOW_OFFSETS
+	}
+
+	forall( T )
+	void showDynamic( thing(T) & x ) {
+		printf("dynamic:\n");
+		SHOW_OFFSETS
+	}
+
+	#undef SHOW_OFFSETS
+
+	printf("=== checkPlan9offsets\n");
+	thing(int) x;
+	showStatic(x);
+	showDynamic(x);
 }
 
@@ -114,4 +148,6 @@
 		assertf(ret == u.f2, "union operation fails in polymorphic context.");
 	}
+
+	checkPlan9offsets();
 }
 
Index: tests/unified_locking/mutex_test.hfa
===================================================================
--- tests/unified_locking/mutex_test.hfa	(revision 12a10131f66f049235ccb6e2e4929285cd0e9139)
+++ tests/unified_locking/mutex_test.hfa	(revision 63bde810176345a17a52622fedf64439891234a2)
@@ -8,5 +8,5 @@
 struct MutexObj {
 	LOCK l;
-	$thread * id;
+	thread$ * id;
 	uint32_t sum;
 };
@@ -22,5 +22,5 @@
 
 uint32_t cs() {
-	$thread * me = active_thread();
+	thread$ * me = active_thread();
 	uint32_t value;
 	lock(mo.l);
