Index: Jenkins/FullBuild
===================================================================
--- Jenkins/FullBuild	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ Jenkins/FullBuild	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -25,5 +25,8 @@
 					gcc_08_x64_new: { trigger_build( 'gcc-8',   'x64', false ) },
 					gcc_07_x64_new: { trigger_build( 'gcc-7',   'x64', false ) },
-					// gcc_06_x64_new: { trigger_build( 'gcc-6',   'x64', false ) },
+					gcc_11_arm64_new: { trigger_build( 'gcc-11',  'arm64', false ) },
+					gcc_10_arm64_new: { trigger_build( 'gcc-10',  'arm64', false ) },
+					gcc_09_arm64_new: { trigger_build( 'gcc-9',   'arm64', false ) },
+					// gcc_06_arm64_new: { trigger_build( 'gcc-6',   'arm64', false ) },
 					clang_x64_new:  { trigger_build( 'clang',   'x64', true  ) },
 				)
Index: Jenkins/TestRegen
===================================================================
--- Jenkins/TestRegen	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ Jenkins/TestRegen	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -24,4 +24,8 @@
 		stage('Building x64') {
 			regen_tests('x86_64')
+		}
+
+		stage('Building arm64') {
+			regen_tests('arm64')
 		}
 
Index: Jenkinsfile
===================================================================
--- Jenkinsfile	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ Jenkinsfile	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -327,4 +327,7 @@
 			case 'x86':
 				this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
+			break
+			case 'arm64':
+				this.Architecture = new Arch_Desc('arm64', '--host=aarch64', 'arm64')
 			break
 			default :
@@ -377,5 +380,5 @@
 					description: 'The target architecture',			\
 					name: 'Architecture',					\
-					choices: 'x64\nx86',					\
+					choices: 'x64\nx86\narm64',				\
 					defaultValue: 'x64',					\
 				],								\
Index: doc/LaTeXmacros/common.sty
===================================================================
--- doc/LaTeXmacros/common.sty	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ doc/LaTeXmacros/common.sty	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Sun Jul 16 08:28:52 2023
-%% Update Count     : 586
+%% Last Modified On : Fri Sep 29 16:48:59 2023
+%% Update Count     : 587
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -272,4 +272,5 @@
 \setlength{\gcolumnposn}{2.75in}
 \setlength{\columnposn}{\gcolumnposn}
+\newcommand{\setgcolumn}[1]{\global\gcolumnposn=#1\global\columnposn=\gcolumnposn}
 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}}
 \newcommand{\CRT}{\global\columnposn=\gcolumnposn}
@@ -302,5 +303,5 @@
 literate=
   {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
-  {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
+  {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
   {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1
   {`}{\ttfamily\upshape\hspace*{-0.3ex}`}1
Index: doc/LaTeXmacros/common.tex
===================================================================
--- doc/LaTeXmacros/common.tex	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ doc/LaTeXmacros/common.tex	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Fri Jul 21 09:02:00 2023
-%% Update Count     : 576
+%% Last Modified On : Fri Sep 29 16:49:02 2023
+%% Update Count     : 590
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -275,4 +275,5 @@
 \setlength{\gcolumnposn}{2.75in}
 \setlength{\columnposn}{\gcolumnposn}
+\newcommand{\setgcolumn}[1]{\global\gcolumnposn=#1\global\columnposn=\gcolumnposn}
 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}}
 \newcommand{\CRT}{\global\columnposn=\gcolumnposn}
@@ -301,10 +302,10 @@
 showlines=true,							% show blank lines at end of code
 aboveskip=4pt,							% spacing above/below code block
-belowskip=0pt,
+belowskip=2pt,
 numberstyle=\footnotesize\sf,			% numbering style
 % replace/adjust listing characters that look bad in sanserif
 literate=
   {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
-  {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
+  {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
   {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1
   {`}{\ttfamily\upshape\hspace*{-0.3ex}`}1
Index: doc/LaTeXmacros/lstlang.sty
===================================================================
--- doc/LaTeXmacros/lstlang.sty	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ doc/LaTeXmacros/lstlang.sty	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -8,6 +8,6 @@
 %% Created On       : Sat May 13 16:34:42 2017
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Tue May  2 08:52:35 2023
-%% Update Count     : 30
+%% Last Modified On : Thu Sep 21 08:40:05 2023
+%% Update Count     : 31
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -134,5 +134,5 @@
 	morekeywords={
 		_Accept, _AcceptReturn, _AcceptWait, _Actor, _At, _Catch, _CatchResume, _CorActor, _Cormonitor, _Coroutine,
-		_Disable, _Else, _Enable, _Event, _Finally, _Monitor, _Mutex, _Nomutex, _PeriodicTask, _RealTimeTask,
+		_Disable, _Else, _Enable, _Event, _Exception, _Finally, _Monitor, _Mutex, _Nomutex, _PeriodicTask, _RealTimeTask,
 		_Resume, _ResumeTop, _Select, _SporadicTask, _Task, _Timeout, _When, _With, _Throw},
 }
Index: doc/bibliography/pl.bib
===================================================================
--- doc/bibliography/pl.bib	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ doc/bibliography/pl.bib	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -4113,6 +4113,7 @@
     title	= {High-Performance Extended Actors},
     journal	= spe,
-    year	= 2022,
-    note	= {submitted July 2022},
+    year	= 2023,
+    month	= sep,
+    note	= {\url{https://onlinelibrary.wiley.com/doi/pdf/10.1002/spe.3262}}
 }
 
Index: doc/user/user.tex
===================================================================
--- doc/user/user.tex	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ doc/user/user.tex	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -11,6 +11,6 @@
 %% Created On       : Wed Apr  6 14:53:29 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Thu Aug 10 21:24:07 2023
-%% Update Count     : 5570
+%% Last Modified On : Sat Sep 30 22:46:19 2023
+%% Update Count     : 5658
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -65,6 +65,6 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-\setlength{\gcolumnposn}{3in}
 \CFAStyle												% use default CFA format-style
+\setgcolumn{2.25in}
 %\lstset{language=CFA}									% CFA default lnaguage
 \lstnewenvironment{C++}[1][]                            % use C++ style
@@ -224,9 +224,9 @@
 \setlength{\tabcolsep}{10pt}
 \begin{tabular}{@{}rcccccccc@{}}
-		& 2021	& 2016	& 2011	& 2006	& 2001	& 1996	& 1991	& 1986	\\ \hline
-\RB{C}	& \RB{1}& \RB{2}& \RB{2}& \RB{1}& \RB{1}& \RB{1}& \RB{1}& \RB{1}\\
-Java	& 2		& 1		& 1		& 2		& 3		& 28	& -		& -		\\
-Python	& 3		& 5		& 6		& 7		& 23	& 13	& -		& -		\\
-\CC		& 4		& 3		& 3		& 3		& 2		& 2		& 2		& 8		\\
+		& 2023	& 2018	& 2013	& 2008	& 2003	& 1998	& 1993	& 1988	\\ \hline
+Python	& 1		& 4		& 8		& 7		& 12	& 25	& 18	& -		\\
+\RB{C}	& \RB{2}& \RB{2}& \RB{1}& \RB{2}& \RB{2}& \RB{1}& \RB{1}& \RB{1}\\
+C++		& 3		& 3		& 4		& 4		& 3		& 2		& 2		& 4		\\
+Java	& 4		& 1		& 2		& 1		& 1		& 18	& -		& -		\\
 \end{tabular}
 \end{center}
@@ -465,4 +465,6 @@
 \Indexc{-h}\index{translator option!-h@{©-h©}}, \Indexc{--help}\index{translator option!--help@{©--help©}} \, print translator help message
 \item
+\Indexc{-i}\index{translator option!-i@{©-i©}}, \Indexc{--invariant}\index{translator option!--invariant@{©--invariant©}} \, invariant checking during AST passes
+\item
 \Indexc{-l}\index{translator option!-l@{©-l©}}, \Indexc{--libcfa}\index{translator option!--libcfa@{©--libcfa©}} \, generate ©libcfa.c©
 \item
@@ -482,11 +484,11 @@
 \begin{description}[topsep=0pt,itemsep=0pt,parsep=0pt]
 \item
-\Indexc{ascodegen}\index{translator option!-P@{©-P©}!©ascodegen©}\index{translator option!--print@{©-print©}!©ascodegen©} \, as codegen rather than AST
-\item
-\Indexc{asterr}\index{translator option!-P@{©-P©}!©asterr©}\index{translator option!--print@{©-print©}!©asterr©} \, AST on error
-\item
-\Indexc{declstats}\index{translator option!-P@{©-P©}!©declstats©}\index{translator option!--print@{©-print©}!©declstats©} \, code property statistics
-\item
-\Indexc{parse}\index{translator option!-P@{©-P©}!©parse©}\index{translator option!--print@{©-print©}!©parse©} \, yacc (parsing) debug information
+\Indexc{ascodegen}\index{translator option!-P@{©-P©}!©ascodegen©}\index{translator option!--print@{©-print©}!©ascodegen©} \, print AST as codegen rather than AST
+\item
+\Indexc{asterr}\index{translator option!-P@{©-P©}!©asterr©}\index{translator option!--print@{©-print©}!©asterr©} \, print AST on error
+\item
+\Indexc{declstats}\index{translator option!-P@{©-P©}!©declstats©}\index{translator option!--print@{©-print©}!©declstats©} \, print code property statistics
+\item
+\Indexc{parse}\index{translator option!-P@{©-P©}!©parse©}\index{translator option!--print@{©-print©}!©parse©} \, print yacc (parsing) debug information
 \item
 \Indexc{pretty}\index{translator option!-P@{©-P©}!©pretty©}\index{translator option!--print@{©-print©}!©pretty©} \, prettyprint for ©ascodegen© flag
@@ -494,29 +496,29 @@
 \Indexc{rproto}\index{translator option!-P@{©-P©}!©rproto©}\index{translator option!--print@{©-print©}!©rproto©} \, resolver-proto instance
 \item
-\Indexc{rsteps}\index{translator option!-P@{©-P©}!©rsteps©}\index{translator option!--print@{©-print©}!©rsteps©} \, resolver steps
-\item
-\Indexc{tree}\index{translator option!-P@{©-P©}!©tree©}\index{translator option!--print@{©-print©}!©tree©} \, parse tree
-\item
-\Indexc{ast}\index{translator option!-P@{©-P©}!©ast©}\index{translator option!--print@{©-print©}!©ast©} \, AST after parsing
-\item
-\Indexc{symevt}\index{translator option!-P@{©-P©}!©symevt©}\index{translator option!--print@{©-print©}!©symevt©} \, symbol table events
-\item
-\Indexc{altexpr}\index{translator option!-P@{©-P©}!©altexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, alternatives for expressions
-\item
-\Indexc{astdecl}\index{translator option!-P@{©-P©}!©astdecl©}\index{translator option!--print@{©-print©}!©astdecl©} \, AST after declaration validation pass
-\item
-\Indexc{resolver}\index{translator option!-P@{©-P©}!©resolver©}\index{translator option!--print@{©-print©}!©resolver©} \, before resolver step
-\item
-\Indexc{astexpr}\index{translator option!-P@{©-P©}!©astexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, AST after expression analysis
-\item
-\Indexc{ctordtor}\index{translator option!-P@{©-P©}!©ctordtor©}\index{translator option!--print@{©-print©}!©ctordtor©} \, after ctor/dtor are replaced
-\item
-\Indexc{tuple}\index{translator option!-P@{©-P©}!©tuple©}\index{translator option!--print@{©-print©}!©tuple©} \, after tuple expansion
-\item
-\Indexc{astgen}\index{translator option!-P@{©-P©}!©astgen©}\index{translator option!--print@{©-print©}!©astgen©} \, AST after instantiate generics
-\item
-\Indexc{box}\index{translator option!-P@{©-P©}!©box©}\index{translator option!--print@{©-print©}!©box©} \, before box step
-\item
-\Indexc{codegen}\index{translator option!-P@{©-P©}!©codegen©}\index{translator option!--print@{©-print©}!©codegen©} \, before code generation
+\Indexc{rsteps}\index{translator option!-P@{©-P©}!©rsteps©}\index{translator option!--print@{©-print©}!©rsteps©} \, print resolver steps
+\item
+\Indexc{ast}\index{translator option!-P@{©-P©}!©ast©}\index{translator option!--print@{©-print©}!©ast©} \, print AST after parsing
+\item
+\Indexc{excpdecl}\index{translator option!-P@{©-P©}!©excpdecl©}\index{translator option!--print@{©-print©}!©excpdecl©} \, print AST after translating exception decls
+\item
+\Indexc{symevt}\index{translator option!-P@{©-P©}!©symevt©}\index{translator option!--print@{©-print©}!©symevt©} \, print AST after symbol table events
+\item
+\Indexc{expralt}\index{translator option!-P@{©-P©}!©expralt©}\index{translator option!--print@{©-print©}!©expralt©} \, print AST after expressions alternatives
+\item
+\Indexc{valdecl}\index{translator option!-P@{©-P©}!©valdecl©}\index{translator option!--print@{©-print©}!©valdecl©} \, print AST after declaration validation pass
+\item
+\Indexc{bresolver}\index{translator option!-P@{©-P©}!©bresolver©}\index{translator option!--print@{©-print©}!©bresolver©} \, print AST before resolver step
+\item
+\Indexc{expranly}\index{translator option!-P@{©-P©}!©expranly©}\index{translator option!--print@{©-print©}!©expranly©} \, print AST after expression analysis
+\item
+\Indexc{ctordtor}\index{translator option!-P@{©-P©}!©ctordtor©}\index{translator option!--print@{©-print©}!©ctordtor©} \, print AST after ctor/dtor are replaced
+\item
+\Indexc{tuple}\index{translator option!-P@{©-P©}!©tuple©}\index{translator option!--print@{©-print©}!©tuple©} \, print AST after tuple expansion
+\item
+\Indexc{instgen}\index{translator option!-P@{©-P©}!©instgen©}\index{translator option!--print@{©-print©}!©instgen©} \, print AST after instantiate generics
+\item
+\Indexc{bbox}\index{translator option!-P@{©-P©}!©bbox©}\index{translator option!--print@{©-print©}!©bbox©} \, print AST before box pass
+\item
+\Indexc{bcodegen}\index{translator option!-P@{©-P©}!©bcodegen©}\index{translator option!--print@{©-print©}!©bcodegen©} \, print AST before code generation
 \end{description}
 \item
@@ -535,5 +537,5 @@
 Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
 \begin{cfa}
-int ®``®coroutine = 3; $\C{// make keyword an identifier}$
+int ®``®coroutine = 3;					$\C{// make keyword an identifier}$
 double ®``®forall = 3.5;
 \end{cfa}
@@ -545,9 +547,9 @@
 \begin{cfa}
 // include file uses the CFA keyword "with".
-#if ! defined( with )							$\C{// nesting ?}$
-#define with ®``®with							$\C{// make keyword an identifier}$
+#if ! defined( with )					$\C{// nesting ?}$
+#define with ®``®with					$\C{// make keyword an identifier}$
 #define __CFA_BFD_H__
 #endif
-$\R{\#include\_next} <bfdlink.h>$				$\C{// must have internal check for multiple expansion}$
+$\R{\#include\_next} <bfdlink.h>$		$\C{// must have internal check for multiple expansion}$
 #if defined( with ) && defined( __CFA_BFD_H__ )	$\C{// reset only if set}$
 #undef with
@@ -564,13 +566,13 @@
 Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore} as a separator, \eg:
 \begin{cfa}
-2®_®147®_®483®_®648; $\C{// decimal constant}$
-56®_®ul; $\C{// decimal unsigned long constant}$
-0®_®377; $\C{// octal constant}$
-0x®_®ff®_®ff; $\C{// hexadecimal constant}$
-0x®_®ef3d®_®aa5c; $\C{// hexadecimal constant}$
-3.141®_®592®_®654; $\C{// floating constant}$
-10®_®e®_®+1®_®00; $\C{// floating constant}$
-0x®_®ff®_®ff®_®p®_®3; $\C{// hexadecimal floating}$
-0x®_®1.ffff®_®ffff®_®p®_®128®_®l; $\C{// hexadecimal floating long constant}$
+2®_®147®_®483®_®648;					$\C{// decimal constant}$
+56®_®ul;								$\C{// decimal unsigned long constant}$
+0®_®377;								$\C{// octal constant}$
+0x®_®ff®_®ff;							$\C{// hexadecimal constant}$
+0x®_®ef3d®_®aa5c;						$\C{// hexadecimal constant}$
+3.141®_®592®_®654;						$\C{// floating constant}$
+10®_®e®_®+1®_®00;					 	$\C{// floating constant}$
+0x®_®ff®_®ff®_®p®_®3;					$\C{// hexadecimal floating}$
+0x®_®1.ffff®_®ffff®_®p®_®128®_®l;		$\C{// hexadecimal floating long constant}$
 L®_®$"\texttt{\textbackslash{x}}$®_®$\texttt{ff}$®_®$\texttt{ee}"$; $\C{// wide character constant}$
 \end{cfa}
@@ -602,10 +604,9 @@
 
 There are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
-Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the exponent is 2).
+Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication ($O(\log y)$ multiplies or shifting if the exponent is 2).
 Overflow for a large exponent or negative exponent returns zero.
 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
 \begin{cfa}
-sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1
-	   | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
+sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1 | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
 \end{cfa}
@@ -620,5 +621,5 @@
 T ?®\®?( T ep, unsigned long int y );
 \end{cfa}
-The user type ©T© must define multiplication, one (©1©), and ©*©.
+A user type ©T© must define multiplication, one (©1©), and ©*©.
 
 
@@ -634,10 +635,10 @@
 Declarations in the \Indexc{do}-©while© condition are not useful because they appear after the loop body.}
 \begin{cfa}
-if ( ®int x = f()® ) ... $\C{// x != 0}$
-if ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$
+if ( ®int x = f()® ) ...			$\C{// x != 0}$
+if ( ®int x = f(), y = g()® ) ...	$\C{// x != 0 \&\& y != 0}$
 if ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
 if ( ®struct S { int i; } x = { f() }; x.i < 4® ) $\C{// relational expression}$
 
-while ( ®int x = f()® ) ... $\C{// x != 0}$
+while ( ®int x = f()® ) ...			$\C{// x != 0}$
 while ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$
 while ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
@@ -653,11 +654,20 @@
 \label{s:caseClause}
 
-C restricts the \Indexc{case} clause of a \Indexc{switch} statement to a single value.
-For multiple ©case© clauses associated with the same statement, it is necessary to have multiple ©case© clauses rather than multiple values.
+C restricts a \Indexc{case} clause in \Indexc{switch} statement to a single value.
+For multiple ©case© clauses prefixing a statement within the ©switch© statement, it is necessary to have multiple ©case© clauses rather than multiple values.
 Requiring a ©case© clause for each value is not in the spirit of brevity normally associated with C.
 Therefore, the ©case© clause is extended with a list of values.
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CFA}}	\\
+\begin{cfa}
+switch ( i ) {
+  case 1: case 3 : case 5:
+	...
+  case 2: case 4 : case 6:
+	...
+}
+\end{cfa}
+&
 \begin{cfa}
 switch ( i ) {
@@ -670,13 +680,4 @@
 &
 \begin{cfa}
-switch ( i ) {
-  case 1: case 3 : case 5:
-	...
-  case 2: case 4 : case 6:
-	...
-}
-\end{cfa}
-&
-\begin{cfa}
 
 // odd values
@@ -688,15 +689,48 @@
 \end{tabular}
 \end{cquote}
-In addition, subranges are allowed to specify case values.\footnote{
-gcc has the same mechanism but awkward syntax, \lstinline{2 ...42}, because a space is required after a number, otherwise the period is a decimal point.}
+In addition, subranges are allowed to specify case values.
+\begin{cquote}
+\begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{\hspace{2em}}l@{}}
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CFA}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{©gcc©}}	\\
 \begin{cfa}
 switch ( i ) {
-  case ®1~5:® $\C{// 1, 2, 3, 4, 5}$
+  case 1: case 2: case 3: case 4:
 	...
-  case ®10~15:® $\C{// 10, 11, 12, 13, 14, 15}$
+  case 10: case 11: case 12: case 13:
 	...
 }
 \end{cfa}
-Lists of subranges are also allowed.
+&
+\begin{cfa}
+switch ( i ) {
+  case ®1~4:®
+	...
+  case ®10~13:®
+	...
+}
+\end{cfa}
+&
+\begin{cfa}
+switch ( i ) {
+  case 1$\R{\textvisiblespace}$®...®4:
+	...
+  case 10$\R{\textvisiblespace}$®...®13:
+	...
+}
+\end{cfa}
+&
+\begin{cfa}
+
+// 1, 2, 3, 4
+
+// 10, 11, 12, 13
+
+
+\end{cfa}
+\end{tabular}
+\end{cquote}
+While ©gcc© has the same range mechanism, it has an awkward syntax, ©2©\R{\textvisiblespace}©...42©, because a space is required after a number, otherwise the period is a decimal point.
+
+\CFA also allows lists of subranges.
 \begin{cfa}
 case ®1~5, 12~21, 35~42®:
@@ -769,5 +803,5 @@
 This situation is better handled by a list of case values \see{\VRef{s:caseClause}}.
 While fall-through itself is not a problem, the problem occurs when fall-through is the default, as this semantics is unintuitive to many programmers and is different from most programming languages with a ©switch© statement.
-Hence, default fall-through semantics results in a large number of programming errors as programmers often \emph{forget} the ©break© statement at the end of a ©case© clause, resulting in inadvertent fall-through.
+Hence, default fall-through semantics results in a many programming errors as programmers often \emph{forget} the ©break© statement at the end of a ©case© clause, resulting in inadvertent fall-through.
 
 \item
@@ -846,5 +880,5 @@
 and there is only a medium amount of fall-through from one ©case© clause to the next, and most of these result from a list of case values executing common code, rather than a sequence of case actions that compound.
 \end{itemize}
-These observations put into perspective the \CFA changes to the ©switch©.
+These observations put into perspective the \CFA changes to the ©switch© statement.
 \begin{enumerate}
 \item
@@ -888,13 +922,13 @@
 \begin{cfa}
 switch ( x ) {
-	®int i = 0;® $\C{// allowed only at start}$
+	®int i = 0;®						$\C{// allowed only at start}$
   case 0:
 	...
-	®int j = 0;® $\C{// disallowed}$
+	®int j = 0;®						$\C{// disallowed}$
   case 1:
 	{
-		®int k = 0;® $\C{// allowed at different nesting levels}$
+		®int k = 0;®					$\C{// allowed at different nesting levels}$
 		...
-	  ®case 2:® $\C{// disallow case in nested statements}$
+	  ®case 2:®							$\C{// disallow case in nested statements}$
 	}
   ...
@@ -907,5 +941,5 @@
 
 The \Indexc{fallthrough} clause may be non-terminating within a \Indexc{case} clause or have a target label to common code from multiple case clauses.
-\begin{center}
+\begin{cquote}
 \begin{tabular}{@{}lll@{}}
 \begin{cfa}
@@ -957,5 +991,5 @@
 \end{cfa}
 \end{tabular}
-\end{center}
+\end{cquote}
 The target label must be below the \Indexc{fallthrough} and may not be nested in a control structure, and
 the target label must be at the same or higher level as the containing \Indexc{case} clause and located at
@@ -964,6 +998,6 @@
 
 \begin{figure}
-\begin{tabular}{@{}l@{\hspace{40pt}}|l@{}}
-\multicolumn{1}{@{}c@{\hspace{40pt}}|}{loop control} & \multicolumn{1}{c@{}}{output} \\
+\begin{tabular}{@{}l@{\hspace{50pt}}|l@{}}
+\multicolumn{1}{@{}c@{\hspace{50pt}}|}{loop control} & \multicolumn{1}{c@{}}{output} \\
 \hline
 \begin{cfa}
@@ -1083,7 +1117,7 @@
 The \Indexc{for}, \Indexc{while}, and \Indexc{do} loop-control allow an empty conditional, which implies a comparison value of ©1© (true).
 \begin{cfa}
-while ( ®/*empty*/®  )			$\C{// while ( true )}$
-for ( ®/*empty*/®  )			$\C{// for ( ; true; )}$
-do ... while ( ®/*empty*/®  )	 $\C{// do ... while ( true )}$
+while ( ®/* empty */®  )				$\C{// while ( true )}$
+for ( ®/* empty */®  )					$\C{// for ( ; true; )}$
+do ... while ( ®/* empty */®  )			$\C{// do ... while ( true )}$
 \end{cfa}
 
@@ -1115,7 +1149,7 @@
 If no type is specified for the loop index, it is the type of the high value H (when the low value is implicit) or the low value L.
 \begin{cfa}
-for ( ®5® )						$\C{// typeof(5) anonymous-index; 5 is high value}$
-for ( i; ®1.5® ~ 5.5 )			$\C{// typeof(1.5) i; 1.5 is low value}$
-for ( ®int i®; 0 ~ 10 ~ 2 )		$\C{// int i; type is explicit}$
+for ( ®5® )								$\C{// typeof(5) anonymous-index; 5 is high value}$
+for ( i; ®1.5® ~ 5.5 )					$\C{// typeof(1.5) i; 1.5 is low value}$
+for ( ®int i®; 0 ~ 10 ~ 2 )				$\C{// int i; type is explicit}$
 \end{cfa}
 
@@ -1125,37 +1159,37 @@
 H is implicit up-to exclusive range [0,H\R{)}.
 \begin{cfa}
-for ( ®5® )						$\C{// for ( typeof(5) i; i < 5; i += 1 )}$
+for ( ®5® )								$\C{// for ( typeof(5) i; i < 5; i += 1 )}$
 \end{cfa}
 \item
 ©~=© H is implicit up-to inclusive range [0,H\R{]}.
 \begin{cfa}
-for ( ®~=® 5 )					$\C{// for ( typeof(5) i; i <= 5; i += 1 )}$
+for ( ®~=® 5 )							$\C{// for ( typeof(5) i; i <= 5; i += 1 )}$
 \end{cfa}
 \item
 L ©~©\index{~@©~©} H is explicit up-to exclusive range [L,H\R{)}.
 \begin{cfa}
-for ( 1 ®~® 5 )					$\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$
+for ( 1 ®~® 5 )							$\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$
 \end{cfa}
 \item
 L ©~=©\index{~=@©~=©} H is explicit up-to inclusive range [L,H\R{]}.
 \begin{cfa}
-for ( 1 ®~=® 5 )					$\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$
+for ( 1 ®~=® 5 )						$\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$
 \end{cfa}
 \item
 L ©-~©\index{-~@©-~©} H is explicit down-to exclusive range [H,L\R{)}, where L and H are implicitly interchanged to make the range down-to.
 \begin{cfa}
-for ( 1 ®-~® 5 )					$\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$
+for ( 1 ®-~® 5 )						$\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$
 \end{cfa}
 \item
 L ©-~=©\index{-~=@©-~=©} H is explicit down-to inclusive range [H,L\R{]}, where L and H are implicitly interchanged to make the range down-to.
 \begin{cfa}
-for ( 1 ®-~=® 5 )					$\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$
+for ( 1 ®-~=® 5 )						$\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$
 \end{cfa}
 \item
 ©@© means put nothing in this field.
 \begin{cfa}
-for ( i; 1 ~ ®@® ~ 2 )			$\C{// for ( typeof(1) i = 1; \R{/* empty */}; i += 2 )}$
-for ( i; 1 ~ 10 ~ ®@® )			$\C{// for ( typeof(1) i = 1; i < 10; \R{/* empty */} )}$
-for ( i; 1 ~ ®@® ~ ®@® )		$\C{// for ( typeof(1) i = 1; /*empty*/; \R{/* empty */} )}$
+for ( i; 1 ~ ®@® ~ 2 )					$\C{// for ( typeof(1) i = 1; \R{/* empty */}; i += 2 )}$
+for ( i; 1 ~ 10 ~ ®@® )					$\C{// for ( typeof(1) i = 1; i < 10; \R{/* empty */} )}$
+for ( i; 1 ~ ®@® ~ ®@® )				$\C{// for ( typeof(1) i = 1; /*empty*/; \R{/* empty */} )}$
 \end{cfa}
 L cannot be elided for the up-to range, \lstinline{@ ~ 5}, and H for the down-to range, \lstinline{1 -~ @}, because then the loop index is uninitialized.
@@ -1164,12 +1198,12 @@
 ©:© means low another index.
 \begin{cfa}
-for ( i; 5 ®:® j; 2 ~ 12 ~ 3 )		$\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}$
+for ( i; 5 ®:® j; 2 ~ 12 ~ 3 )			$\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}$
 \end{cfa}
 \end{itemize}
 \R{Warning}: specifying the down-to range maybe unexpected because the loop control \emph{implicitly} switches the L and H values (and toggles the increment/decrement for I):
 \begin{cfa}
-for ( i; 1 ~ 10 )	${\C[1.5in]{// up range}$
-for ( i; 1 -~ 10 )	${\C{// down range}$
-for ( i; ®10 -~ 1® )	${\C{// \R{WRONG down range!}}\CRT}$
+for ( i; 1 ~ 10 )						${\C{// up range}$
+for ( i; 1 -~ 10 )						${\C{// down range}$
+for ( i; ®10 -~ 1® )					${\C{// \R{WRONG down range!}}}$
 \end{cfa}
 The reason for this semantics is that the range direction can be toggled by adding/removing the minus, ©'-'©, versus interchanging the L and H expressions, which has a greater chance of introducing errors.
@@ -1188,7 +1222,6 @@
 
 \begin{figure}
-\centering
 \begin{lrbox}{\myboxA}
-\begin{cfa}[tabsize=3]
+\begin{cfa}[tabsize=4]
 ®Compound:® {
 	®Try:® try {
@@ -1220,5 +1253,5 @@
 
 \begin{lrbox}{\myboxB}
-\begin{cfa}[tabsize=3]
+\begin{cfa}[tabsize=4]
 {
 
@@ -1249,9 +1282,9 @@
 \end{lrbox}
 
-\subfloat[\CFA]{\label{f:CFibonacci}\usebox\myboxA}
+\subfloat[C]{\label{f:CFAFibonacciGen}\usebox\myboxB}
 \hspace{3pt}
 \vrule
 \hspace{3pt}
-\subfloat[C]{\label{f:CFAFibonacciGen}\usebox\myboxB}
+\subfloat[\CFA]{\label{f:CFibonacci}\usebox\myboxA}
 \caption{Multi-level Exit}
 \label{f:MultiLevelExit}
@@ -1287,5 +1320,5 @@
 int a[10];
 \end{cfa}
-\begin{tabular}{@{}lll@{}}
+\begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{3em}}l@{}}
 \begin{cfa}
 
@@ -1328,7 +1361,11 @@
 Grouping heterogeneous data into an \newterm{aggregate} (structure/union) is a common programming practice, and aggregates may be nested:
 \begin{cfa}
-struct Person {								$\C{// aggregate}$
-	struct Name { char first[20], last[20]; } name $\C{// nesting}$
-	struct Address { ... } address			$\C{// nesting}$
+struct Person {							$\C{// aggregate}$
+	struct Name {						$\C{// nesting}$
+		char first[20], last[20];
+	} name;
+	struct Address {					$\C{// nesting}$
+		...
+	} address;
 	int sex;
 };
@@ -1337,5 +1374,5 @@
 \begin{cfa}
 Person p
-®p.®name; ®p.®address; ®p.®sex; $\C{// access containing fields}$
+®p.®name; ®p.®address; ®p.®sex;			$\C{// access containing fields}$
 \end{cfa}
 which extends to multiple levels of qualification for nested aggregates and multiple aggregates.
@@ -1352,7 +1389,7 @@
 \begin{cfa}
 struct S {
-	struct $\R{\LstCommentStyle{/* unnamed */}}$ { int g,  h; } __attribute__(( aligned(64) ));
+	struct $\R{\LstCommentStyle{/* unnamed */}}$  { int g,  h; } __attribute__(( aligned(64) ));
 	int tag;
-	union $\R{\LstCommentStyle{/* unnamed */}}$ {
+	union $\R{\LstCommentStyle{/* unnamed */}}$  {
 		struct { char c1,  c2; } __attribute__(( aligned(128) ));
 		struct { int i1,  i2; };
@@ -1368,6 +1405,6 @@
 struct S {
 	char ®c®;   int ®i®;   double ®d®;
-	void f( /* S * this */ ) {				$\C{// implicit ``this'' parameter}$
-		®c®;   ®i®;   ®d®;					$\C{// this->c; this->i; this->d;}$
+	void f( /* S * this */ ) {			$\C{// implicit ``this'' parameter}$
+		®c®;   ®i®;   ®d®;				$\C{// this->c; this->i; this->d;}$
 	}
 }
@@ -1377,12 +1414,12 @@
 \begin{cfa}
 struct T {
-	char ®m®;   int ®i®;   double ®n®;		$\C{// derived class variables}$
+	char ®m®;   int ®i®;   double ®n®;	$\C{// derived class variables}$
 };
 struct S : public T {
-	char ®c®;   int ®i®;   double ®d®;		$\C{// class variables}$
+	char ®c®;   int ®i®;   double ®d®;	$\C{// class variables}$
 	void g( double ®d®, T & t ) {
-		d;   ®t®.m;   ®t®.i;   ®t®.n;		$\C{// function parameter}$
-		c;   i;   ®this->®d;   ®S::®d;		$\C{// class S variables}$
-		m;   ®T::®i;   n;					$\C{// class T variables}$
+		d;   ®t®.m;   ®t®.i;   ®t®.n;	$\C{// function parameter}$
+		c;   i;   ®this->®d;   ®S::®d;	$\C{// class S variables}$
+		m;   ®T::®i;   n;				$\C{// class T variables}$
 	}
 };
@@ -1394,13 +1431,13 @@
 Hence, the qualified fields become variables with the side-effect that it is simpler to write, easier to read, and optimize field references in a block.
 \begin{cfa}
-void f( S & this ) ®with ( this )® {		$\C{// with statement}$
-	®c®;   ®i®;   ®d®;						$\C{// this.c, this.i, this.d}$
+void f( S & this ) ®with ( this )® {	$\C{// with statement}$
+	®c®;   ®i®;   ®d®;					$\C{// this.c, this.i, this.d}$
 }
 \end{cfa}
 with the generality of opening multiple aggregate-parameters:
 \begin{cfa}
-void g( S & s, T & t ) ®with ( s, t )® {	$\C{// multiple aggregate parameters}$
-	c;   ®s.®i;   d;						$\C{// s.c, s.i, s.d}$
-	m;   ®t.®i;   n;						$\C{// t.m, t.i, t.n}$
+void g( S & s, T & t ) ®with ( s, t )® {$\C{// multiple aggregate parameters}$
+	c;   ®s.®i;   d;					$\C{// s.c, s.i, s.d}$
+	m;   ®t.®i;   n;					$\C{// t.m, t.i, t.n}$
 }
 \end{cfa}
@@ -1425,11 +1462,11 @@
 struct R { int ®i®; int j; double ®m®; } r, w;
 with ( r, q ) {
-	j + k;									$\C{// unambiguous, r.j + q.k}$
-	m = 5.0;								$\C{// unambiguous, q.m = 5.0}$
-	m = 1;									$\C{// unambiguous, r.m = 1}$
-	int a = m;								$\C{// unambiguous, a = r.i }$
-	double b = m;							$\C{// unambiguous, b = q.m}$
-	int c = r.i + q.i;						$\C{// disambiguate with qualification}$
-	(double)m;								$\C{// disambiguate with cast}$
+	j + k;								$\C{// unambiguous, r.j + q.k}$
+	m = 5.0;							$\C{// unambiguous, q.m = 5.0}$
+	m = 1;								$\C{// unambiguous, r.m = 1}$
+	int a = m;							$\C{// unambiguous, a = r.i }$
+	double b = m;						$\C{// unambiguous, b = q.m}$
+	int c = r.i + q.i;					$\C{// disambiguate with qualification}$
+	(double)m;							$\C{// disambiguate with cast}$
 }
 \end{cfa}
@@ -1439,7 +1476,7 @@
 \begin{cfa}
 with ( r ) {
-	i;										$\C{// unambiguous, r.i}$
+	i;									$\C{// unambiguous, r.i}$
 	with ( q ) {
-		i;									$\C{// unambiguous, q.i}$
+		i;								$\C{// unambiguous, q.i}$
 	}
 }
@@ -1448,6 +1485,6 @@
 A cast can also be used to disambiguate among overload variables in a ©with© \emph{expression}:
 \begin{cfa}
-with ( w ) { ... }							$\C{// ambiguous, same name and no context}$
-with ( (Q)w ) { ... }						$\C{// unambiguous, cast}$
+with ( w ) { ... }						$\C{// ambiguous, same name and no context}$
+with ( (Q)w ) { ... }					$\C{// unambiguous, cast}$
 \end{cfa}
 Because there is no left-side in the ©with© expression to implicitly disambiguate between the ©w© variables, it is necessary to explicitly disambiguate by casting ©w© to type ©Q© or ©R©.
@@ -1456,5 +1493,5 @@
 \begin{cfa}
 void f( S & s, char c ) with ( s ) {
-	®s.c = c;®  i = 3;  d = 5.5;			$\C{// initialize fields}$
+	®s.c = c;®  i = 3;  d = 5.5;		$\C{// initialize fields}$
 }
 \end{cfa}
@@ -1462,5 +1499,5 @@
 To solve this problem, parameters \emph{not} explicitly opened are treated like an initialized aggregate:
 \begin{cfa}
-struct Params {								$\C{// s explicitly opened so S \& s elided}$
+struct Params {							$\C{// s explicitly opened so S \& s elided}$
 	char c;
 } params;
@@ -1481,4 +1518,23 @@
 Transfer of control can be local, within a routine, or non-local, among routines.
 Non-local transfer can cause stack unwinding, \ie non-local routine termination, depending on the kind of raise.
+
+Currently, \CFA uses macros ©ExceptionDecl© and ©ExceptionInst© to declare and instantiate an exception.
+\begin{cfa}
+#include <Exception.hfa>
+®ExceptionDecl®( E,		// must be global scope
+	... // exception fields
+);
+try {
+	...
+	if ( ... ) ®throwResume® ®ExceptionInst®( E, /* intialization */ );
+	if ( ... ) ®throw® ®ExceptionInst®( E, /* intialization */ );
+	...
+} ®catchResume®( E * ) { // must be pointer
+	...
+} catch( E * ) {
+	...
+}
+\end{cfa}
+
 \begin{cfa}
 exception_t E {}; $\C{// exception type}$
@@ -1489,5 +1545,5 @@
 try {
 	f(...);
-} catch( E e ; $boolean-predicate$ ) {		$\C{// termination handler}$
+} catch( E e ; $boolean-predicate$ ) {	$\C{// termination handler}$
 	// recover and continue
 } catchResume( E e ; $boolean-predicate$ ) { $\C{// resumption handler}$
@@ -1501,4 +1557,21 @@
 The ©catch© and ©catchResume© handlers may appear in any oder.
 However, the ©finally© clause must appear at the end of the ©try© statement.
+
+
+\section{Non-local Exception}
+
+\begin{cfa}
+void main() {
+	try {
+		_Enable {
+			... resume(); ...
+		}
+	} ®catchResume®( E & ) { // should be reference
+		...
+	} catch( E & ) {
+		...
+	}
+}
+\end{cfa}
 
 
@@ -1566,15 +1639,15 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c}{\textbf{\CFA}}	\\
+\begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}]
+®int® #*# x1 #[5]#;
+®int® #(*#x2#)[5]#;
+#int (*#f®( int p )®#)[5]#;
+\end{cfa}
+&
 \begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}]
 #[5] *# ®int® x1;
 #* [5]# ®int® x2;
 #[* [5] int]# f®( int p )®;
-\end{cfa}
-&
-\begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}]
-®int® #*# x1 #[5]#;
-®int® #(*#x2#)[5]#;
-#int (*#f®( int p )®#)[5]#;
 \end{cfa}
 \end{tabular}
@@ -1586,11 +1659,11 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c}{\textbf{\CFA}}	\\
+\begin{cfa}
+int ®*®x, ®*®y;
+\end{cfa}
+&
 \begin{cfa}
 ®*® int x, y;
-\end{cfa}
-&
-\begin{cfa}
-int ®*®x, ®*®y;
 \end{cfa}
 \end{tabular}
@@ -1599,13 +1672,13 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c}{\textbf{\CFA}}	\\
+\begin{cfa}
+int ®*®x, y;
+
+\end{cfa}
+&
 \begin{cfa}
 ®*® int x;
 int y;
-\end{cfa}
-&
-\begin{cfa}
-int ®*®x, y;
-
 \end{cfa}
 \end{tabular}
@@ -1615,5 +1688,16 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CFA}}	\\
+\begin{cfa}
+int z[ 5 ];
+char * w[ 5 ];
+double (* v)[ 5 ];
+struct s {
+	int f0:3;
+	int * f1;
+	int * f2[ 5 ]
+};
+\end{cfa}
+&
 \begin{cfa}
 [ 5 ] int z;
@@ -1628,15 +1712,4 @@
 &
 \begin{cfa}
-int z[ 5 ];
-char * w[ 5 ];
-double (* v)[ 5 ];
-struct s {
-	int f0:3;
-	int * f1;
-	int * f2[ 5 ]
-};
-\end{cfa}
-&
-\begin{cfa}
 // array of 5 integers
 // array of 5 pointers to char
@@ -1654,13 +1727,13 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{1em}}l@{\hspace{1em}}l@{}}
-\multicolumn{1}{c@{\hspace{1em}}}{\textbf{\CFA}}	& \multicolumn{1}{c@{\hspace{1em}}}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{1em}}}{\textbf{C}}	& \multicolumn{1}{c@{\hspace{1em}}}{\textbf{\CFA}}	\\
+\begin{cfa}
+int const * const x;
+const int (* const y)[ 5 ]
+\end{cfa}
+&
 \begin{cfa}
 const * const int x;
 const * [ 5 ] const int y;
-\end{cfa}
-&
-\begin{cfa}
-int const * const x;
-const int (* const y)[ 5 ]
 \end{cfa}
 &
@@ -1675,13 +1748,13 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CFA}}	\\
+\begin{cfa}
+int extern x[ 5 ];
+const int static * y;
+\end{cfa}
+&
 \begin{cfa}
 extern [ 5 ] int x;
 static * const int y;
-\end{cfa}
-&
-\begin{cfa}
-int extern x[ 5 ];
-const int static * y;
 \end{cfa}
 &
@@ -1696,13 +1769,13 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c}{\textbf{\CFA}}	\\
+\begin{cfa}
+y = (int *)x;
+i = sizeof(int * [ 5 ]);
+\end{cfa}
+&
 \begin{cfa}
 y = (* int)x;
 i = sizeof([ 5 ] * int);
-\end{cfa}
-&
-\begin{cfa}
-y = (int *)x;
-i = sizeof(int * [ 5 ]);
 \end{cfa}
 \end{tabular}
@@ -1899,13 +1972,13 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}	& \multicolumn{1}{c}{\textbf{C}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{Cy}}	& \multicolumn{1}{c}{\textbf{\CFA}}	\\
+\begin{cfa}
+const int * ®const® * ®const® ccp;
+
+\end{cfa}
+&
 \begin{cfa}
 ®const® * ®const® * const int ccp;
 ®const® & ®const® & const int ccr;
-\end{cfa}
-&
-\begin{cfa}
-const int * ®const® * ®const® ccp;
-
 \end{cfa}
 \end{tabular}
@@ -2068,5 +2141,5 @@
 \begin{cfa}
 int x, &r = ®x®, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$
-f( ®x® ); $\C{// lvalue variable (int) convert to reference (int \&)}$
+f( ®x® ); $\C{// lvalue variable (int) convert to reference (int \&)}\CRT$
 \end{cfa}
 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.
@@ -4430,5 +4503,5 @@
 \end{cfa}
 To match a minus, put it as the first character, ©"-0-9"©.
-Note, other complex forms of regular-expression matching is not supported.
+Other complex forms of regular-expression matching are not supported.
 
 The following \Index{manipulator}s control scanning of input values (reading), and only affect the format of the argument.
@@ -8628,20 +8701,6 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
-\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}}	& \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}	\\
+\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{C}}	& \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{\CFA}}	\\
 \hline
-\begin{cfa}
-#include <gmp.hfa>$\indexc{gmp}$
-int main( void ) {
-	sout | "Factorial Numbers";
-	Int fact = 1;
-
-	sout | 0 | fact;
-	for ( i; 40 ) {
-		fact *= i;
-		sout | i | fact;
-	}
-}
-\end{cfa}
-&
 \begin{cfa}
 #include <gmp.h>$\indexc{gmp.h}$
@@ -8654,4 +8713,18 @@
 		®mpz_mul_ui®( fact, fact, i );
 		®gmp_printf®( "%d %Zd\n", i, fact );
+	}
+}
+\end{cfa}
+&
+\begin{cfa}
+#include <gmp.hfa>$\indexc{gmp}$
+int main( void ) {
+	sout | "Factorial Numbers";
+	Int fact = 1;
+
+	sout | 0 | fact;
+	for ( i; 40 ) {
+		fact *= i;
+		sout | i | fact;
 	}
 }
Index: driver/cc1.cc
===================================================================
--- driver/cc1.cc	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ driver/cc1.cc	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,16 +10,14 @@
 // Created On       : Fri Aug 26 14:23:51 2005
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jun  9 11:36:44 2023
-// Update Count     : 423
+// Last Modified On : Mon Sep 25 11:07:22 2023
+// Update Count     : 427
 //
 
 #include <iostream>
-using std::cerr;
-using std::endl;
 #include <string>
-using std::string;
 #include <algorithm>									// find
 #include <cstdio>										// stderr, stdout, perror, fprintf
 #include <cstdlib>										// getenv, exit, mkstemp
+using namespace std;
 #include <unistd.h>										// execvp, fork, unlink
 #include <sys/wait.h>									// wait
@@ -52,5 +50,5 @@
 	if ( dot == string::npos ) return;
 	const string * end = suffixes + NumSuffixes;
-	if ( std::find( suffixes, end, arg.substr( dot + 1 ) ) != end ) {
+	if ( find( suffixes, end, arg.substr( dot + 1 ) ) != end ) {
 		args[nargs++] = "-x";
 		args[nargs++] = "c";
@@ -153,11 +151,13 @@
 
 	#ifdef __DEBUG_H__
-	cerr << "Stage1" << endl;
+	cerr << "#########" << endl << "Stage1 " << string( 100, '#' ) << endl << "#########" << endl;
 	#endif // __DEBUG_H__
 	checkEnv1();										// arguments passed via environment variables
 	#ifdef __DEBUG_H__
+	cerr << string( 100, '*' ) << endl;
 	for ( int i = 1; i < argc; i += 1 ) {
 		cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
 	} // for
+	cerr << string( 100, '*' ) << endl;
 	#endif // __DEBUG_H__
 
@@ -260,5 +260,5 @@
 		} else {
 			args[nargs++] = "-x";
-			args[nargs++] = ( *new string( lang.c_str() ) ).c_str();
+			args[nargs++] = ( *new string( lang ) ).c_str();
 		} // if
 		args[nargs++] = cpp_in;
@@ -275,4 +275,5 @@
 		} // for
 		cerr << endl;
+		cerr << string( 100, '*' ) << endl;
 		#endif // __DEBUG_H__
 
@@ -298,5 +299,5 @@
 		} else {
 			args[nargs++] = "-x";
-			args[nargs++] = ( *new string( lang.c_str() ) ).c_str();
+			args[nargs++] = ( *new string( lang ) ).c_str();
 		} // if
 		args[nargs++] = cpp_in;							// input to cpp
@@ -346,11 +347,13 @@
 
 	#ifdef __DEBUG_H__
-	cerr << "Stage2" << endl;
+	cerr << "#########" << endl << "Stage2 " << string( 100, '#' ) << endl << "#########" << endl;
 	#endif // __DEBUG_H__
 	checkEnv2( cargs, ncargs );							// arguments passed via environment variables
 	#ifdef __DEBUG_H__
+	cerr << string( 100, '*' ) << endl;
 	for ( int i = 1; i < argc; i += 1 ) {
 		cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
 	} // for
+	cerr << string( 100, '*' ) << endl;
 	#endif // __DEBUG_H__
 
@@ -473,5 +476,5 @@
 		if ( CFA_flag ) {								// run cfa-cpp ?
 			if ( o_file.size() != 0 ) {					// location for output
-				cargs[ncargs++] = ( *new string( o_file.c_str() ) ).c_str();
+				cargs[ncargs++] = ( *new string( o_file ) ).c_str();
 			} // if
 		} else {
@@ -571,7 +574,5 @@
 int main( const int argc, const char * const argv[], __attribute__((unused)) const char * const env[] ) {
 	#ifdef __DEBUG_H__
-	for ( int i = 0; env[i] != nullptr; i += 1 ) {
-		cerr << env[i] << endl;
-	} // for
+	cerr << "#########" << endl << "main cc1 " << string( 100, '#' ) << endl << "#########" << endl;
 	#endif // __DEBUG_H__
 
Index: driver/cfa.cc
===================================================================
--- driver/cfa.cc	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ driver/cfa.cc	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Tue Aug 20 13:44:49 2002
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Aug 30 21:48:48 2023
-// Update Count     : 480
+// Last Modified On : Thu Sep 28 21:53:54 2023
+// Update Count     : 484
 //
 
@@ -20,4 +20,5 @@
 #include <string>										// STL version
 #include <algorithm>									// find
+using namespace std;
 
 #include <unistd.h>										// execvp
@@ -27,9 +28,4 @@
 #include "Common/SemanticError.h"
 #include "config.h"										// configure info
-
-using std::cerr;
-using std::endl;
-using std::string;
-using std::to_string;
 
 //#define __DEBUG_H__
Index: libcfa/src/collections/string_res.cfa
===================================================================
--- libcfa/src/collections/string_res.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/collections/string_res.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -218,5 +218,7 @@
     // Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
     // so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
-    for (;;) {
+    for (bool cont = true; cont; ) {
+        cont = false;
+
         // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
         // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
@@ -228,10 +230,14 @@
         temp.Handle.ulink->EndVbyte -= 2;
 
-        // rest of heap, less 1 byte for null terminator, is available to read into
-        int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte - 1;
-        assert (lenReadable >= 1);
+        // rest of heap is available to read into
+        int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
+        assert (lenReadable >= 2);
 
         // get bytes
-        in | wdi( lenReadable + 1, lenReadable, temp.Handle.ulink->EndVbyte );
+        try {
+            in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
+        } catch (cstring_length*) {
+            cont = true;
+        }
         int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
 
@@ -239,6 +245,4 @@
         temp.Handle.lnth += lenWasRead;
         temp.Handle.ulink->EndVbyte += lenWasRead;
-
-      if (lenWasRead < lenReadable) break;
     }
 
Index: libcfa/src/concurrency/channel.hfa
===================================================================
--- libcfa/src/concurrency/channel.hfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/concurrency/channel.hfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -130,4 +130,5 @@
 static inline void __cons_handoff( channel(T) & chan, T & elem ) with(chan) {
     memcpy( cons`first.extra, (void *)&elem, sizeof(T) ); // do waiting consumer work
+    __atomic_thread_fence( __ATOMIC_SEQ_CST );
     wake_one( cons );
 }
@@ -136,4 +137,5 @@
 static inline void __prods_handoff( channel(T) & chan, T & retval ) with(chan) {
     memcpy( (void *)&retval, prods`first.extra, sizeof(T) );
+    __atomic_thread_fence( __ATOMIC_SEQ_CST );
     wake_one( prods );
 }
Index: libcfa/src/concurrency/cofor.cfa
===================================================================
--- libcfa/src/concurrency/cofor.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/concurrency/cofor.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -4,10 +4,10 @@
 // cofor ( uC++ COFOR )
 
-thread co_runner {
+thread cofor_runner {
 	ssize_t low, high;
 	__cofor_body_t loop_body;
 };
 
-static void ?{}( co_runner & this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) {
+static void ?{}( cofor_runner & this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) {
 	this.low = low;
 	this.high = high;
@@ -15,10 +15,10 @@
 }
 
-void main( co_runner & this ) with( this ) {
+void main( cofor_runner & this ) with( this ) {
 	for ( ssize_t i = low; i < high; i++ )
 		loop_body(i);
 }
 
-void cofor( ssize_t low, ssize_t high, __cofor_body_t loop_body ) libcfa_public {
+void __Cofor__( ssize_t low, ssize_t high, __cofor_body_t loop_body ) libcfa_public {
 	ssize_t range = high - low;
   if ( range <= 0 ) return;
@@ -29,5 +29,5 @@
 	ssize_t i = 0;
 	ssize_t stride_iter = low;
-	co_runner * runners[ threads ];
+	cofor_runner * runners[ threads ];
 	for ( i; threads ) {
 		runners[i] = alloc();
@@ -45,25 +45,3 @@
 }
 
-//////////////////////////////////////////////////////////////////////////////////////////
-// parallel (COBEGIN/COEND)
 
-thread para_runner {
-	parallel_stmt_t body;
-	void * arg;
-};
-
-static void ?{}( para_runner & this, parallel_stmt_t body, void * arg ) { 
-	this.body = body;
-	this.arg = arg;
-}
-
-void main( para_runner & this ) with( this ) { body( arg ); }
-
-void parallel( parallel_stmt_t * stmts, void ** args, size_t num ) libcfa_public {
-	para_runner * runners[ num ];
-	for ( i; num )
-		(*(runners[i] = malloc())){ stmts[i], args[i] };
-	for ( i; num )
-		delete( runners[i] );
-}
-
Index: libcfa/src/concurrency/cofor.hfa
===================================================================
--- libcfa/src/concurrency/cofor.hfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/concurrency/cofor.hfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -5,5 +5,5 @@
 typedef void (*__cofor_body_t)( ssize_t );
 
-void cofor( ssize_t low, ssize_t high, __cofor_body_t loop_body );
+void __Cofor__( ssize_t low, ssize_t high, __cofor_body_t loop_body );
 
 #define COFOR( lidname, low, high, loopbody ) \
@@ -12,10 +12,33 @@
 			loopbody \
 		} \
-		cofor( low, high, __CFA_loopLambda__ ); \
+		__Cofor__( low, high, __CFA_loopLambda__ ); \
 	}
 
 //////////////////////////////////////////////////////////////////////////////////////////
-// parallel (COBEGIN/COEND)
-typedef void (*parallel_stmt_t)( void * );
+// corun
 
-void parallel( parallel_stmt_t * stmts, void ** args, size_t num );
+// 
+typedef void (*__CFA_corun_lambda_t)( void );
+
+// used to run a corun statement in parallel
+thread co_runner {
+	__CFA_corun_lambda_t body;
+};
+
+// wraps a co_runner to provide RAII deallocation
+struct runner_block {
+    co_runner * runner;
+};
+static inline void ?{}( co_runner & this, __CFA_corun_lambda_t body ) { this.body = body; }
+
+void main( co_runner & this ) with( this ) { body(); }
+
+static inline void ?{}( runner_block & this ) {}
+static inline void ?{}( runner_block & this, __CFA_corun_lambda_t body ) {
+    (*(this.runner = malloc())){ body };
+}
+
+static inline void ^?{}( runner_block & this ) {
+    delete( this.runner );
+}
+
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/concurrency/coroutine.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -343,4 +343,7 @@
 
 bool poll() libcfa_public { return poll( active_coroutine() ); }
+void enable_ehm() libcfa_public { active_coroutine()->ehm_state.ehm_enabled = true; }
+void disable_ehm() libcfa_public { active_coroutine()->ehm_state.ehm_enabled = false; }
+bool checked_poll() libcfa_public { return active_coroutine()->ehm_state.ehm_enabled ? poll( active_coroutine() ) : false; }
 coroutine$ * resumer() libcfa_public { return active_coroutine()->last; }
 coroutine$ * first_resumer() libcfa_public { return active_coroutine()->starter; }
Index: libcfa/src/concurrency/coroutine.hfa
===================================================================
--- libcfa/src/concurrency/coroutine.hfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/concurrency/coroutine.hfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -224,14 +224,17 @@
 
 // non local ehm and coroutine utility routines
+void enable_ehm();
+void disable_ehm();
 bool poll( coroutine$ * cor );
 bool poll();
+bool checked_poll();
 coroutine$ * resumer();
 coroutine$ * first_resumer();
 
 forall(T & | is_coroutine(T)) {
-    void enable_ehm( T & cor );
-    void disable_ehm( T & cor );
+    void enable_ehm( T & cor );         // enable checking non-local exceptions for cor via checked_poll
+    void disable_ehm( T & cor );        // disable checking non-local exceptions for cor via checked_poll
     bool poll( T & cor );
-    bool checked_poll( T & cor );
+    bool checked_poll( T & cor );       // check for non-local exceptions while respecting enable/disable
     coroutine$ * resumer( T & cor );
     coroutine$ * first_resumer( T & cor );
Index: libcfa/src/concurrency/kernel/fwd.hfa
===================================================================
--- libcfa/src/concurrency/kernel/fwd.hfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/concurrency/kernel/fwd.hfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -118,5 +118,5 @@
 		// Yield: yield N times
 		static inline void yield( size_t times ) {
-			for( times ) {
+			for ( times ) {
 				yield();
 			}
@@ -136,8 +136,8 @@
 
 			bool wait(single_sem & this) {
-				for() {
+				for () {
 					struct thread$ * expected = this.ptr;
-					if(expected == 1p) {
-						if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+					if (expected == 1p) {
+						if (__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
 							return false;
 						}
@@ -145,5 +145,5 @@
 					else {
 						/* paranoid */ verify( expected == 0p );
-						if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+						if (__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
 							park();
 							return true;
@@ -155,14 +155,14 @@
 
 			bool post(single_sem & this) {
-				for() {
+				for () {
 					struct thread$ * expected = this.ptr;
-					if(expected == 1p) return false;
-					if(expected == 0p) {
-						if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+					if (expected == 1p) return false;
+					if (expected == 0p) {
+						if (__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
 							return false;
 						}
 					}
 					else {
-						if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+						if (__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
 							unpark( expected );
 							return true;
@@ -195,8 +195,8 @@
 			// return true if the thread was parked
 			bool wait(oneshot & this) {
-				for() {
+				for () {
 					struct thread$ * expected = this.ptr;
-					if(expected == oneshot_FULFILLED) return false;
-					if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+					if (expected == oneshot_FULFILLED) return false;
+					if (__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
 						park();
 						/* paranoid */ verify( this.ptr == oneshot_FULFILLED );
@@ -210,6 +210,6 @@
 			thread$ * post(oneshot & this, bool do_unpark = true) {
 				struct thread$ * got = __atomic_exchange_n( &this.ptr, oneshot_FULFILLED, __ATOMIC_SEQ_CST);
-				if( got == oneshot_ARMED || got == oneshot_FULFILLED ) return 0p;
-				if(do_unpark) unpark( got );
+				if ( got == oneshot_ARMED || got == oneshot_FULFILLED ) return 0p;
+				if (do_unpark) unpark( got );
 				return got;
 			}
@@ -255,11 +255,11 @@
 				/* paranoid */ verify( wait_ctx.ptr == oneshot_ARMED || wait_ctx.ptr == oneshot_FULFILLED );
 				// The future needs to set the wait context
-				for() {
+				for () {
 					struct oneshot * expected = this.ptr;
 					// Is the future already fulfilled?
-					if(expected == future_FULFILLED) return false; // Yes, just return false (didn't block)
+					if (expected == future_FULFILLED) return false; // Yes, just return false (didn't block)
 
 					// The future is not fulfilled, try to setup the wait context
-					if(__atomic_compare_exchange_n(&this.ptr, &expected, &wait_ctx, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+					if (__atomic_compare_exchange_n(&this.ptr, &expected, &wait_ctx, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
 						return true;
 					}
@@ -276,5 +276,5 @@
 
 				// attempt to remove the context so it doesn't get consumed.
-				if(__atomic_compare_exchange_n( &this.ptr, &expected, future_ARMED, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+				if (__atomic_compare_exchange_n( &this.ptr, &expected, future_ARMED, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
 					// we still have the original context, then no one else saw it
 					return false;
@@ -282,14 +282,14 @@
 
 				// expected == ARMED: future was never actually setup, just return
-				if( expected == future_ARMED ) return false;
+				if ( expected == future_ARMED ) return false;
 
 				// expected == FULFILLED: the future is ready and the context was fully consumed
 				// the server won't use the pointer again
 				// It is safe to delete (which could happen after the return)
-				if( expected == future_FULFILLED ) return true;
+				if ( expected == future_FULFILLED ) return true;
 
 				// expected == PROGRESS: the future is ready but the context hasn't fully been consumed
 				// spin until it is safe to move on
-				if( expected == future_PROGRESS ) {
+				if ( expected == future_PROGRESS ) {
 					while( this.ptr != future_FULFILLED ) Pause();
 					/* paranoid */ verify( this.ptr == future_FULFILLED );
@@ -310,9 +310,9 @@
 
 				// If the future isn't already fulfilled, let the server delete it
-				if( got == future_ARMED ) return false;
+				if ( got == future_ARMED ) return false;
 
 				// got == PROGRESS: the future is ready but the context hasn't fully been consumed
 				// spin until it is safe to move on
-				if( got == future_PROGRESS ) {
+				if ( got == future_PROGRESS ) {
 					while( this.ptr != future_FULFILLED ) Pause();
 					got = future_FULFILLED;
@@ -327,15 +327,19 @@
 			// from the server side, mark the future as fulfilled
 			// delete it if needed
+
 			thread$ * fulfil( future_t & this, bool do_unpark = true  ) {
-				for() {
+				for () {
 					struct oneshot * expected = this.ptr;
-					// was this abandoned?
+
 					#if defined(__GNUC__) && __GNUC__ >= 7
-						#pragma GCC diagnostic push
-						#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+					// SKULLDUGGERY: gcc bug does not handle push/pop for -Wfree-nonheap-object
+					//#pragma GCC diagnostic push
+					#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
 					#endif
-						if( expected == future_ABANDONED ) { free( &this ); return 0p; }
+
+					if ( expected == future_ABANDONED ) { free( &this ); return 0p; }
+
 					#if defined(__GNUC__) && __GNUC__ >= 7
-						#pragma GCC diagnostic pop
+					//#pragma GCC diagnostic pop
 					#endif
 
@@ -346,6 +350,6 @@
 					// If there is no context then we can skip the in progress phase
 					struct oneshot * want = expected == future_ARMED ? future_FULFILLED : future_PROGRESS;
-					if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
-						if( expected == future_ARMED ) { return 0p; }
+					if (__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+						if ( expected == future_ARMED ) { return 0p; }
 						thread$ * ret = post( *expected, do_unpark );
 						__atomic_store_n( &this.ptr, future_FULFILLED, __ATOMIC_SEQ_CST);
@@ -359,5 +363,5 @@
 			bool wait( future_t & this ) {
 				oneshot temp;
-				if( !setup(this, temp) ) return false;
+				if ( !setup(this, temp) ) return false;
 
 				// Wait context is setup, just wait on it
@@ -387,5 +391,5 @@
 				// if any are already satisfied return
 				for ( i; num_futures ) {
-					if( !setup(futures[i], temp) ) return futures[i];
+					if ( !setup(futures[i], temp) ) return futures[i];
 				}
 
@@ -413,17 +417,17 @@
 
 			#define __STATS__(in_kernel, ...) { \
-				if( !(in_kernel) ) disable_interrupts(); \
-				with( *__tls_stats() ) { \
+				if ( !(in_kernel) ) disable_interrupts(); \
+				with ( *__tls_stats() ) { \
 					__VA_ARGS__ \
 				} \
-				if( !(in_kernel) ) enable_interrupts(); \
+				if ( !(in_kernel) ) enable_interrupts(); \
 			}
 			#if defined(CFA_HAVE_LINUX_IO_URING_H)
 				#define __IO_STATS__(in_kernel, ...) { \
-					if( !(in_kernel) ) disable_interrupts(); \
-					with( *__tls_stats() ) { \
+					if ( !(in_kernel) ) disable_interrupts(); \
+					with ( *__tls_stats() ) { \
 						__VA_ARGS__ \
 					} \
-					if( !(in_kernel) ) enable_interrupts(); \
+					if ( !(in_kernel) ) enable_interrupts(); \
 				}
 			#else
@@ -436,3 +440,3 @@
 	}
 }
-#endif
+#endif // #endif
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/heap.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Sep 11 11:21:10 2023
-// Update Count     : 1615
+// Last Modified On : Sat Sep 30 17:31:15 2023
+// Update Count     : 1617
 //
 
@@ -53,5 +53,5 @@
 #define TLSMODEL __attribute__(( tls_model("initial-exec") ))
 
-//#define __STATISTICS__
+#define __STATISTICS__
 
 enum {
@@ -681,5 +681,5 @@
 
 static HeapStatistics & collectStats( HeapStatistics & stats ) with( heapMaster ) {
-	lock( mgrLock );
+	lock( heapMaster.mgrLock );
 
 	stats += heapMaster.stats;
@@ -688,10 +688,10 @@
 	} // for
 
-	unlock( mgrLock );
+	unlock( heapMaster.mgrLock );
 	return stats;
 } // collectStats
 
 static inline void clearStats() {
-	lock( mgrLock );
+	lock( heapMaster.mgrLock );
 
 	// Zero the heap master and all active thread heaps.
@@ -701,5 +701,5 @@
 	} // for
 
-	unlock( mgrLock );
+	unlock( heapMaster.mgrLock );
 } // clearStats
 #endif // __STATISTICS__
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/iostream.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -11,6 +11,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Sep  2 14:42:01 2023
-// Update Count     : 1561
+// Last Modified On : Sun Oct  8 12:10:21 2023
+// Update Count     : 1564
 //
 
@@ -22,4 +22,5 @@
 #include <float.h>										// DBL_DIG, LDBL_DIG
 #include <complex.h>									// creal, cimag
+#include <ctype.h>										// isspace
 //#include <stdio.h>
 
@@ -29,4 +30,5 @@
 extern char *strcpy (char *__restrict __dest, const char *__restrict __src) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
+extern char *strchr(const char *str, int ch);
 } // extern "C"
 
@@ -649,5 +651,5 @@
 		exp10 = floor( exp10, 3 ); \
 		value *= pow( 10.0, -exp10 ); \
-		if ( pc <= 3 ) pc = 3; \
+		if ( pc < 0 ) pc = 3; \
 	} /* eng */ \
 \
@@ -960,5 +962,16 @@
 	istype & ?|?( istype & is, _Istream_Cskip f ) {
 		// printf( "skip %s %d\n", f.scanset, f.wd );
-		if ( f.scanset ) fmt( is, f.scanset, "" );		// no input arguments
+		if ( f.scanset ) {
+			int nscanset = strlen(f.scanset);
+			char fmtstr[ sizeof("%*[]") + nscanset ];
+			int pos = 0;
+			fmtstr[pos] = '%';                  pos += 1;
+			fmtstr[pos] = '*';                  pos += 1;
+			fmtstr[pos] = '[';                  pos += 1;
+			strcpy( &fmtstr[pos], f.scanset );  pos += nscanset;
+			fmtstr[pos] = ']';                  pos += 1;
+			fmtstr[pos] = '\0';
+			fmt( is, fmtstr, (void*)0 );  // last arg is dummy: suppress gcc warning
+		}
 		else for ( f.wd ) fmt( is, "%*c" );
 		return is;
@@ -980,5 +993,12 @@
 			// wd is buffer bytes available (for input chars + null terminator)
 			// rwd is count of input chars
-			int rwd = f.flags.rwd ? f.wd : (f.wd - 1);
+			int rwd;
+			if (f.flags.rwd) {
+				verify (f.wd >= 0);
+				rwd = f.wd;
+			} else {
+				verify (f.wd >= 1);
+				rwd = f.wd - 1;
+			} // if
 			start += sprintf( &fmtstr[start], "%d", rwd );
 		}
@@ -1000,10 +1020,29 @@
 
 		int check = f.wd - 2;
-		if ( ! f.flags.rwd ) f.s[check] = '\0';			// insert sentinel
+		if (! f.flags.ignore ) {
+			f.s[0] = '\0';
+			if ( ! f.flags.rwd ) f.s[check] = '\0';		// insert sentinel
+		}
 		len = fmt( is, fmtstr, f.s );
 		//fprintf( stderr, "KK %s %zd %d %c %s\n", fmtstr, len, check, f.s[check], f.s );
 
-		if ( ! f.flags.rwd && f.s[check] != '\0' )		// sentinel overwritten ?
-			throw (cstring_length){ &cstring_length_vt };
+		if ( ! f.flags.ignore && ! f.flags.rwd && f.s[check] != '\0' ) { // sentinel overwritten ?
+			// buffer filled, but would we have kept going?
+			if ( ! eof( is ) ) {
+				char peek;
+				fmt( is, "%c", &peek );
+				ungetc( is, peek );
+				bool hasMore;
+				if (f.flags.delimiter) { // getline
+					hasMore = (peek != f.delimiter[0]);
+				} else if (f.scanset) { // incl/excl
+					bool peekMatch = strchr(f.scanset, peek) != 0p;
+					hasMore = f.flags.inex ? (!peekMatch) : (peekMatch);
+				} else { // %s
+					hasMore = !isspace(peek);
+				}
+				if (hasMore) throw (cstring_length){ &cstring_length_vt };
+			} // if
+		} // if
 
 		if ( f.flags.delimiter ) {						// getline ?
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/iostream.hfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Sep  2 14:42:13 2023
-// Update Count     : 567
+// Last Modified On : Sun Oct  8 12:02:55 2023
+// Update Count     : 568
 //
 
@@ -243,5 +243,5 @@
 	_Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
 	_Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
-	_Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.eng : true } }; } \
+	_Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, -1, 'g', { .flags.eng : true } }; } \
 	_Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'g', { .all : 0 } }; } \
 	_Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
Index: libcfa/src/rational.cfa
===================================================================
--- libcfa/src/rational.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/rational.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Wed Apr  6 17:54:28 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Jul 18 11:07:10 2023
-// Update Count     : 197
+// Last Modified On : Fri Oct  6 07:52:13 2023
+// Update Count     : 198
 //
 
@@ -76,6 +76,6 @@
 	} // denominator
 
-	[ T, T ] ?=?( & [ T, T ] dest, rational(T) src ) {
-		return dest = src.[ numerator, denominator ];
+	[ T, T ] ?=?( & [ T, T ] dst, rational(T) src ) {
+		return dst = src.[ numerator, denominator ];
 	} // ?=?
 
Index: libcfa/src/rational.hfa
===================================================================
--- libcfa/src/rational.hfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/rational.hfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -12,6 +12,6 @@
 // Created On       : Wed Apr  6 17:56:25 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Jul 18 11:08:24 2023
-// Update Count     : 121
+// Last Modified On : Fri Oct  6 07:52:20 2023
+// Update Count     : 122
 //
 
@@ -40,5 +40,5 @@
 	T numerator( rational(T) r );
 	T denominator( rational(T) r );
-	[ T, T ] ?=?( & [ T, T ] dest, rational(T) src );
+	[ T, T ] ?=?( & [ T, T ] dst, rational(T) src );
 
 	// numerator/denominator setter
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ libcfa/src/stdlib.hfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:12:35 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Sep  2 18:29:35 2023
-// Update Count     : 780
+// Last Modified On : Sun Oct  8 09:18:28 2023
+// Update Count     : 789
 //
 
@@ -431,5 +431,5 @@
 	uint32_t seed;										// current seed
 	PRNG_STATE_32_T state;								// random state
-}; // PRNG
+}; // PRNG32
 
 static inline {
@@ -442,5 +442,8 @@
 	uint32_t prng( PRNG32 & prng, uint32_t l, uint32_t u ) __attribute__(( warn_unused_result )) { return prng( prng, u - l + 1 ) + l; } // [l,u]
 	uint32_t calls( PRNG32 & prng ) __attribute__(( warn_unused_result )) with( prng ) { return callcnt; }
-} // distribution
+	void copy( PRNG32 & dst, PRNG32 & src ) { dst = src; } // checkpoint PRNG state, use autogen assignment
+} // distribution
+void ?{}( PRNG32 &, PRNG32 & ) = void;					// no copy, remove autogen copy constructor
+PRNG32 & ?=?( PRNG32 &, const PRNG32 ) = void;			// no assignment, remove autogen assignment
 
 struct PRNG64 {
@@ -448,5 +451,5 @@
 	uint64_t seed;										// current seed
 	PRNG_STATE_64_T state;								// random state
-}; // PRNG
+}; // PRNG64
 
 static inline {
@@ -459,5 +462,8 @@
 	uint64_t prng( PRNG64 & prng, uint64_t l, uint64_t u ) __attribute__(( warn_unused_result )) { return prng( prng, u - l + 1 ) + l; } // [l,u]
 	uint64_t calls( PRNG64 & prng ) __attribute__(( warn_unused_result )) with( prng ) { return callcnt; }
-} // distribution
+	void copy( PRNG64 & dst, PRNG64 & src ) { dst = src; } // checkpoint PRNG state, use autogen assignment
+} // distribution
+void ?{}( PRNG64 &, PRNG64 & ) = void;					// no copy, remove autogen copy constructor
+PRNG64 & ?=?( PRNG64 &, const PRNG64 ) = void;			// no assignment, remove autogen assignment
 
 // Set default random-generator size.
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Convert.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -269,5 +269,5 @@
 			node->location,
 			Type::StorageClasses( node->storage.val ),
-            get<Type>().accept1( node->base ),
+			get<Type>().accept1( node->base ),
 			LinkageSpec::Spec( node->linkage.val )
 		);
@@ -567,5 +567,5 @@
 	}
 
-    const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
+	const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
 		// There is no old-AST WhenClause, so this should never be called.
 		assert( !node );
@@ -604,6 +604,6 @@
 	}
 
-    const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
-        // There is no old-AST WaitUntilStmt, so this should never be called.
+	const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
+		// There is no old-AST WaitUntilStmt, so this should never be called.
 		assert( !node );
 		return nullptr;
@@ -648,4 +648,10 @@
 		);
 		return stmtPostamble( stmt, node );
+	}
+
+	const ast::Stmt * visit( const ast::CorunStmt * node ) override final {
+		// There is no old-AST CorunStmt, so this should never be called.
+		assert( !node );
+		return nullptr;
 	}
 
@@ -853,5 +859,5 @@
 		// New workd:   one public type: node->result, plus node->underlyer only to support roundtrip conversion
 		//              preserving underlyer because the correct type for string literals is complicated to construct,
-	    //              and distinguishing a string from other literals using the type is hard to do accurately
+		//              and distinguishing a string from other literals using the type is hard to do accurately
 		// Both worlds: the outer, expression-level type can change during resolution
 		//              for a string, that's char[k] before-resolve and char * after
@@ -859,5 +865,5 @@
 		//              for a string, that's char[k] always
 		// Both worlds: the "rep" field of a constant is the C source file fragment that compiles to the desired value
-        //              for a string, that includes outer quotes, backslashes, et al cases from the Literals test
+		//              for a string, that includes outer quotes, backslashes, et al cases from the Literals test
 		ConstantExpr *rslt = new ConstantExpr(Constant(
 			get<Type>().accept1(node->underlyer),
@@ -1518,5 +1524,5 @@
 		return strict_dynamic_cast< ast::Decl * >( node );
 	}
-	
+
 	ConverterOldToNew() = default;
 	ConverterOldToNew(const ConverterOldToNew &) = delete;
@@ -1581,5 +1587,5 @@
 	ast::Label make_label(const Label* old) {
 		CodeLocation const & location =
-		    ( old->labelled ) ? old->labelled->location : CodeLocation();
+			( old->labelled ) ? old->labelled->location : CodeLocation();
 		return ast::Label(
 			location,
@@ -2240,5 +2246,4 @@
 	// TypeSubstitution shouldn't exist yet in old.
 	ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) {
-		
 		if (!old) return nullptr;
 		if (old->empty()) return nullptr;
@@ -2285,5 +2290,5 @@
 	ast::Expr * visitBaseExpr_SkipResultType( const Expression * old, ast::Expr * nw) {
 
-		nw->env    = convertTypeSubstitution(old->env);
+		nw->env = convertTypeSubstitution(old->env);
 
 		nw->extension = old->extension;
@@ -2856,5 +2861,5 @@
 
 	virtual void visit( const EnumInstType * old ) override final {
-		ast::EnumInstType * ty; 
+		ast::EnumInstType * ty;
 		if ( old->baseEnum ) {
 			ty = new ast::EnumInstType{
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Fwd.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -67,4 +67,5 @@
 class ImplicitCtorDtorStmt;
 class MutexStmt;
+class CorunStmt;
 
 class Expr;
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Node.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -192,4 +192,6 @@
 template class ast::ptr_base< ast::MutexStmt, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::MutexStmt, ast::Node::ref_type::strong >;
+template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::weak >;
+template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::strong >;
 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::strong >;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Pass.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -162,8 +162,8 @@
 	const ast::FinallyClause *    visit( const ast::FinallyClause        * ) override final;
 	const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
-    const ast::WhenClause *       visit( const ast::WhenClause           * ) override final;
+	const ast::WhenClause *       visit( const ast::WhenClause           * ) override final;
 	const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
 	const ast::WaitForClause *    visit( const ast::WaitForClause        * ) override final;
-    const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) override final;
+	const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) override final;
 	const ast::Decl *             visit( const ast::WithStmt             * ) override final;
 	const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
@@ -171,4 +171,5 @@
 	const ast::Stmt *             visit( const ast::ImplicitCtorDtorStmt * ) override final;
 	const ast::Stmt *             visit( const ast::MutexStmt            * ) override final;
+	const ast::Stmt *             visit( const ast::CorunStmt            * ) override final;
 	const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
 	const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Pass.impl.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1121,4 +1121,17 @@
 
 //--------------------------------------------------------------------------
+// CorunStmt
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::CorunStmt * node ) {
+	VISIT_START( node );
+
+	if ( __visit_children() ) {
+		maybe_accept( node, &CorunStmt::stmt );
+	}
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
 // ApplicationExpr
 template< typename core_t >
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Print.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -209,5 +209,5 @@
 	}
 
-    void print( const ast::WaitStmt * node ) {
+	void print( const ast::WaitStmt * node ) {
 		if ( node->timeout_time ) {
 			os << indent-1 << "timeout of:" << endl;
@@ -860,5 +860,5 @@
 	}
 
-    virtual const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
+	virtual const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
 		os << "Waituntil Statement" << endl;
 		indent += 2;
@@ -866,5 +866,6 @@
 			clause->accept( *this );
 		}
-        print(node);    // calls print( const ast::WaitStmt * node )
+		// calls print( const ast::WaitStmt * node )
+		print(node);
 		return node;
 	}
@@ -913,4 +914,15 @@
 		printAll( node->mutexObjs );
 		--indent;
+		os << indent << "... with Statement: ";
+		++indent;
+		safe_print( node->stmt );
+		--indent;
+		os << endl;
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::CorunStmt * node ) override final {
+		os << "Corun Statement" << endl;
 		os << indent << "... with Statement: ";
 		++indent;
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Stmt.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -532,4 +532,18 @@
 };
 
+// Corun Statement
+class CorunStmt final : public Stmt {
+  public:
+	ptr<Stmt> stmt;
+
+	CorunStmt( const CodeLocation & loc, const Stmt * stmt, const std::vector<Label> && labels = {} )
+		: Stmt(loc, std::move(labels)), stmt(stmt) {}
+
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+  private:
+	CorunStmt * clone() const override { return new CorunStmt{ *this }; }
+	MUTATE_FRIEND
+};
+
 } // namespace ast
 
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/AST/Visitor.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -59,4 +59,5 @@
     virtual const ast::Stmt *             visit( const ast::ImplicitCtorDtorStmt * ) = 0;
     virtual const ast::Stmt *             visit( const ast::MutexStmt            * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::CorunStmt            * ) = 0;
     virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) = 0;
     virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) = 0;
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/CodeGen/CodeGenerator.cc	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1157,9 +1157,9 @@
 
 	void CodeGenerator::postvisit( WithStmt * with ) {
-		if ( ! options.genC ) {
-			output << "with ( ";
-			genCommaList( with->exprs.begin(), with->exprs.end() );
-			output << " ) ";
-		}
+		assertf( ! options.genC, "WithStmts should not reach code generation." );
+
+		output << "with ( ";
+		genCommaList( with->exprs.begin(), with->exprs.end() );
+		output << " ) ";
 		with->stmt->accept( *visitor );
 	}
Index: src/CodeGen/LinkOnce.cc
===================================================================
--- src/CodeGen/LinkOnce.cc	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/CodeGen/LinkOnce.cc	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Thur May 13 10:10:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Thur May 13 14:39:00 2021
-// Update Count     : 0
+// Last Modified On : Wed Oct  4 10:52:00 2023
+// Update Count     : 1
 //
 
@@ -18,13 +18,19 @@
 #include <algorithm>
 
+#include "AST/Attribute.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Pass.hpp"
 #include "Common/PassVisitor.h"       // for PassVisitor, WithShortCircuiting
 
 namespace CodeGen {
 
-static bool is_cfa_linkonce( Attribute const * attr ) {
+namespace {
+
+bool is_cfa_linkonce_old( Attribute const * attr ) {
 	return std::string("cfa_linkonce") == attr->name;
 }
 
-static bool is_section_attribute( Attribute const * attr ) {
+bool is_section_attribute_old( Attribute const * attr ) {
 	return std::string("section") == attr->name;
 }
@@ -39,8 +45,8 @@
 		std::list< Attribute * > & attributes = decl->attributes;
 		// See if we can find the element:
-		auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce );
+		auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce_old );
 		if ( attributes.end() != found ) {
 			// Remove any other sections:
-			attributes.remove_if( is_section_attribute );
+			attributes.remove_if( is_section_attribute_old );
 			// Iterator to the cfa_linkonce attribute should still be valid.
 			Attribute * attribute = *found;
@@ -63,4 +69,57 @@
 };
 
+bool is_cfa_linkonce( ast::Attribute const * attr ) {
+	return "cfa_linkonce" == attr->name;
+}
+
+bool is_section_attribute( ast::Attribute const * attr ) {
+	return "section" == attr->name;
+}
+
+struct LinkOnceCore : public ast::WithShortCircuiting {
+	void previsit( ast::Decl const * ) {
+		visit_children = false;
+	}
+
+	ast::DeclWithType const * postvisit( ast::DeclWithType const * decl ) {
+		// Check to see if we have to mutate, because should be uncommon.
+		{
+			auto & attributes = decl->attributes;
+			auto found = std::find_if( attributes.begin(), attributes.end(),
+					is_cfa_linkonce );
+			if ( attributes.end() == found ) return decl;
+		}
+		auto mutDecl = mutate( decl );
+		auto & attributes = mutDecl->attributes;
+
+		// Remove all conflicting section attributes.
+		erase_if( attributes, is_section_attribute );
+
+		// Get the attribute, and overwrite it as a section attribute.
+		auto found = std::find_if( attributes.begin(), attributes.end(),
+				is_cfa_linkonce );
+		assert( attributes.end() != found );
+		ast::Attribute * attribute = found->get_and_mutate();
+		assert( attribute->params.empty() );
+		assert( !decl->mangleName.empty() );
+
+		attribute->name = "section";
+		attribute->params.push_back(
+			ast::ConstantExpr::from_string( mutDecl->location,
+				".gnu.linkonce." + decl->mangleName
+			)
+		);
+
+		// Unconditionnaly add "visibility(default)" to anything with
+		// .gnu.linkonce visibility is a mess otherwise.
+		attributes.push_back( new ast::Attribute( "visibility", {
+			ast::ConstantExpr::from_string( mutDecl->location, "default" )
+		} ) );
+		return mutDecl;
+	}
+};
+
+} // namespace
+
 void translateLinkOnce( std::list< Declaration *> & translationUnit ) {
 	PassVisitor<LinkOnceVisitorCore> translator;
@@ -68,3 +127,7 @@
 }
 
+void translateLinkOnce( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<LinkOnceCore>::run( translationUnit );
 }
+
+} // namespace CodeGen
Index: src/CodeGen/LinkOnce.h
===================================================================
--- src/CodeGen/LinkOnce.h	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/CodeGen/LinkOnce.h	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Thur May 13 10:06:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Thur May 13 14:38:00 2021
-// Update Count     : 0
+// Last Modified On : Wed Oct  4 10:52:00 2023
+// Update Count     : 1
 //
 
@@ -23,8 +23,12 @@
 
 class Declaration;
+namespace ast {
+	class TranslationUnit;
+}
 
 namespace CodeGen {
 
 void translateLinkOnce( std::list< Declaration *> & translationUnit );
+void translateLinkOnce( ast::TranslationUnit & translationUnit );
 /* Convert the cfa_linkonce attribute on top level declaration into
  * a special section declaration (.gnu.linkonce) so that it may be defined
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/Common/CodeLocationTools.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -137,4 +137,5 @@
     macro(ImplicitCtorDtorStmt, Stmt) \
     macro(MutexStmt, Stmt) \
+    macro(CorunStmt, Stmt) \
     macro(ApplicationExpr, Expr) \
     macro(UntypedExpr, Expr) \
Index: src/Concurrency/Corun.cpp
===================================================================
--- src/Concurrency/Corun.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ src/Concurrency/Corun.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,98 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Corun.cpp -- generate code needed by the actor system
+//
+// Author           : Colby Parsons
+// Created On       : Monday October 9 15:16:42 2023
+// Last Modified By : Colby Parsons
+// Last Modified On : Monday October 9 15:16:42 2023
+// Update Count     : 0
+//
+
+#include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Stmt.hpp"
+#include "AST/TranslationUnit.hpp"
+#include "Common/UniqueName.h"
+using namespace ast;
+using namespace std;
+
+namespace Concurrency {
+
+struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> {
+    UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
+    UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
+
+    const StructDecl * runnerBlockDecl = nullptr;
+
+    // Finds select_node decl
+    void previsit( const StructDecl * decl ) {
+        if ( !decl->body ) {
+            return;
+        } else if ( "runner_block" == decl->name ) {
+            assert( !runnerBlockDecl );
+            runnerBlockDecl = decl;
+        }
+    }
+
+    Stmt * postvisit( const CorunStmt * stmt ) {
+        if ( !runnerBlockDecl )
+            SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>\n" );
+
+        if ( !stmt->stmt )
+            return nullptr;
+
+        const CodeLocation & loc = stmt->location;
+        const string fnName = CorunFnNamer.newName();
+        const string objName = RunnerBlockNamer.newName();
+
+        // Generates:
+        // void __CFA_corun_lambda_() { ... stmt->stmt ... }
+        Stmt * runnerLambda = new DeclStmt( loc,
+            new FunctionDecl( loc,
+                fnName,                                             // name
+                {},                                                 // forall
+                {},                                                 // params
+                {},                                                 // return
+                new CompoundStmt( loc, { deepCopy(stmt->stmt) } )   // body
+            )
+        );
+
+        // Generates:
+        // runner_block __CFA_corun_block_;
+        Stmt * objDecl = new DeclStmt( loc,
+            new ObjectDecl( loc,
+                objName,
+                new StructInstType( runnerBlockDecl )
+            )
+        );
+
+        // Generates:
+        // __CFA_corun_block_{ __CFA_corun_lambda_ };
+        Stmt * threadStart = new ExprStmt( loc,
+            new UntypedExpr ( loc,
+                new NameExpr( loc, "?{}" ),
+                {
+                    new NameExpr( loc, objName ),
+                    new NameExpr( loc, fnName )
+                }
+            )
+        );
+
+        stmtsToAddBefore.push_back( runnerLambda );
+        stmtsToAddBefore.push_back( objDecl );
+
+        return threadStart;
+    }
+};
+
+void implementCorun( TranslationUnit & translationUnit ) {
+    Pass<CorunKeyword>::run( translationUnit );
+}
+
+} // namespace Concurrency
Index: src/Concurrency/Corun.hpp
===================================================================
--- src/Concurrency/Corun.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ src/Concurrency/Corun.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,30 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Corun.hpp -- Implement concurrency constructs from their keywords.
+//
+// Author           : Colby Parsons
+// Created On       : Monday October 9 15:16:42 2023
+// Last Modified By :
+// Last Modified On :
+// Update Count     : 1
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace Concurrency {
+	void implementCorun( ast::TranslationUnit & translationUnit );
+};
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Concurrency/module.mk
===================================================================
--- src/Concurrency/module.mk	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/Concurrency/module.mk	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -18,4 +18,6 @@
 	Concurrency/Actors.cpp \
 	Concurrency/Actors.hpp \
+	Concurrency/Corun.cpp \
+	Concurrency/Corun.hpp \
 	Concurrency/KeywordsNew.cpp \
 	Concurrency/Keywords.cc \
Index: src/GenPoly/Box.h
===================================================================
--- src/GenPoly/Box.h	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/GenPoly/Box.h	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -5,11 +5,11 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Box.h -- 
+// Box.h -- Implement polymorphic function calls and types.
 //
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:23:52 2017
-// Update Count     : 6
+// Last Modified By : Andrew Beach
+// Last Modified On : Thr Oct  6 13:37:00 2022
+// Update Count     : 7
 //
 
@@ -19,8 +19,12 @@
 
 class Declaration;
+namespace ast {
+	class TranslationUnit;
+}
 
 namespace GenPoly {
 	/// boxes polymorphic function calls
 	void box( std::list< Declaration* >& translationUnit );
+void box( ast::TranslationUnit & translationUnit );
 } // namespace GenPoly
 
Index: src/GenPoly/BoxNew.cpp
===================================================================
--- src/GenPoly/BoxNew.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ src/GenPoly/BoxNew.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,2496 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// BoxNew.cpp -- Implement polymorphic function calls and types.
+//
+// Author           : Andrew Beach
+// Created On       : Thr Oct  6 13:39:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Oct  2 17:00:00 2023
+// Update Count     : 0
+//
+
+#include "Box.h"
+
+#include "AST/Decl.hpp"                // for Decl, FunctionDecl, ...
+#include "AST/Expr.hpp"                // for AlignofExpr, ConstantExpr, ...
+#include "AST/Init.hpp"                // for Init, SingleInit
+#include "AST/Inspect.hpp"             // for getFunctionName
+#include "AST/Pass.hpp"                // for Pass, WithDeclsToAdd, ...
+#include "AST/Stmt.hpp"                // for CompoundStmt, ExprStmt, ...
+#include "AST/Vector.hpp"              // for vector
+#include "AST/GenericSubstitution.hpp" // for genericSubstitution
+#include "CodeGen/OperatorTable.h"     // for isAssignment
+#include "Common/ScopedMap.h"          // for ScopedMap
+#include "Common/UniqueName.h"         // for UniqueName
+#include "Common/utility.h"            // for toCString, group_iterate
+#include "GenPoly/FindFunction.h"      // for findFunction
+#include "GenPoly/GenPoly.h"           // for getFunctionType, ...
+#include "GenPoly/Lvalue.h"            // for generalizedLvalue
+#include "GenPoly/ScopedSet.h"         // for ScopedSet
+#include "GenPoly/ScrubTyVars.h"       // for scrubTypeVars, scrubAllTypeVars
+#include "ResolvExpr/Unify.h"          // for typesCompatible
+#include "SymTab/Mangler.h"            // for mangle, mangleType
+
+namespace GenPoly {
+
+namespace {
+
+/// Common field of several sub-passes of box.
+struct BoxPass {
+	TypeVarMap scopeTypeVars;
+	BoxPass() : scopeTypeVars( ast::TypeData() ) {}
+};
+
+// TODO: Could this be a common helper somewhere?
+ast::FunctionType * makeFunctionType( ast::FunctionDecl const * decl ) {
+	ast::FunctionType * type = new ast::FunctionType(
+		decl->type->isVarArgs, decl->type->qualifiers
+	);
+	for ( auto type_param : decl->type_params ) {
+		type->forall.emplace_back( new ast::TypeInstType( type_param ) );
+	}
+	for ( auto assertion : decl->assertions ) {
+		type->assertions.emplace_back( new ast::VariableExpr(
+			assertion->location, assertion ) );
+	}
+	for ( auto param : decl->params ) {
+		type->params.emplace_back( param->get_type() );
+	}
+	for ( auto retval : decl->returns ) {
+		type->returns.emplace_back( retval->get_type() );
+	}
+	return type;
+}
+
+// --------------------------------------------------------------------------
+/// Adds layout-generation functions to polymorphic types.
+struct LayoutFunctionBuilder final :
+		public ast::WithDeclsToAdd<>,
+		public ast::WithShortCircuiting,
+		public ast::WithVisitorRef<LayoutFunctionBuilder> {
+	void previsit( ast::StructDecl const * decl );
+	void previsit( ast::UnionDecl const * decl );
+};
+
+/// Get all sized type declarations; those that affect a layout function.
+ast::vector<ast::TypeDecl> takeSizedParams(
+		ast::vector<ast::TypeDecl> const & decls ) {
+	ast::vector<ast::TypeDecl> sizedParams;
+	for ( ast::ptr<ast::TypeDecl> const & decl : decls ) {
+		if ( decl->isComplete() ) {
+			sizedParams.emplace_back( decl );
+		}
+	}
+	return sizedParams;
+}
+
+ast::BasicType * makeSizeAlignType() {
+	return new ast::BasicType( ast::BasicType::LongUnsignedInt );
+}
+
+/// Adds parameters for otype size and alignment to a function type.
+void addSTypeParams(
+		ast::vector<ast::DeclWithType> & params,
+		ast::vector<ast::TypeDecl> const & sizedParams ) {
+	for ( ast::ptr<ast::TypeDecl> const & sizedParam : sizedParams ) {
+		ast::TypeInstType inst( sizedParam );
+		std::string paramName = Mangle::mangleType( &inst );
+		params.emplace_back( new ast::ObjectDecl(
+			sizedParam->location,
+			sizeofName( paramName ),
+			makeSizeAlignType()
+		) );
+		params.emplace_back( new ast::ObjectDecl(
+			sizedParam->location,
+			alignofName( paramName ),
+			makeSizeAlignType()
+		) );
+	}
+}
+
+ast::Type * makeSizeAlignOutType() {
+	return new ast::PointerType( makeSizeAlignType() );
+}
+
+struct LayoutData {
+	ast::FunctionDecl * function;
+	ast::ObjectDecl * sizeofParam;
+	ast::ObjectDecl * alignofParam;
+	ast::ObjectDecl * offsetofParam;
+};
+
+LayoutData buildLayoutFunction(
+		CodeLocation const & location, ast::AggregateDecl const * aggr,
+		ast::vector<ast::TypeDecl> const & sizedParams,
+		bool isInFunction, bool isStruct ) {
+	ast::ObjectDecl * sizeParam = new ast::ObjectDecl(
+		location,
+		sizeofName( aggr->name ),
+		makeSizeAlignOutType()
+	);
+	ast::ObjectDecl * alignParam = new ast::ObjectDecl(
+		location,
+		alignofName( aggr->name ),
+		makeSizeAlignOutType()
+	);
+	ast::ObjectDecl * offsetParam = nullptr;
+	ast::vector<ast::DeclWithType> params = { sizeParam, alignParam };
+	if ( isStruct ) {
+		offsetParam = new ast::ObjectDecl(
+			location,
+			offsetofName( aggr->name ),
+			makeSizeAlignOutType()
+		);
+		params.push_back( offsetParam );
+	}
+	addSTypeParams( params, sizedParams );
+
+	// Routines at global scope marked "static" to prevent multiple
+	// definitions is separate translation units because each unit generates
+	// copies of the default routines for each aggregate.
+	ast::FunctionDecl * layoutDecl = new ast::FunctionDecl(
+		location,
+		layoutofName( aggr ),
+		{}, // forall
+		{}, // assertions
+		std::move( params ),
+		{}, // returns
+		new ast::CompoundStmt( location ),
+		isInFunction ? ast::Storage::Classes() : ast::Storage::Static,
+		ast::Linkage::AutoGen,
+		{}, // attrs
+		ast::Function::Inline,
+		ast::FixedArgs
+	);
+	layoutDecl->fixUniqueId();
+	return LayoutData{ layoutDecl, sizeParam, alignParam, offsetParam };
+}
+
+/// Makes a binary operation.
+ast::Expr * makeOp( CodeLocation const & location, std::string const & name,
+		ast::Expr const * lhs, ast::Expr const * rhs ) {
+	return new ast::UntypedExpr( location,
+		new ast::NameExpr( location, name ), { lhs, rhs } );
+}
+
+/// Make a binary operation and wrap it in a statement.
+ast::Stmt * makeOpStmt( CodeLocation const & location, std::string const & name,
+		ast::Expr const * lhs, ast::Expr const * rhs ) {
+	return new ast::ExprStmt( location, makeOp( location, name, lhs, rhs ) );
+}
+
+/// Returns the dereference of a local pointer variable.
+ast::Expr * derefVar(
+		CodeLocation const & location, ast::ObjectDecl const * var ) {
+	return ast::UntypedExpr::createDeref( location,
+		new ast::VariableExpr( location, var ) );
+}
+
+/// Makes an if-statement with a single-expression then and no else.
+ast::Stmt * makeCond( CodeLocation const & location,
+		ast::Expr const * cond, ast::Expr const * thenPart ) {
+	return new ast::IfStmt( location,
+		cond, new ast::ExprStmt( location, thenPart ), nullptr );
+}
+
+/// Makes a statement that aligns lhs to rhs (rhs should be an integer
+/// power of two).
+ast::Stmt * makeAlignTo( CodeLocation const & location,
+		ast::Expr const * lhs, ast::Expr const * rhs ) {
+	// Check that the lhs is zeroed out to the level of rhs.
+	ast::Expr * ifCond = makeOp( location, "?&?", lhs,
+		makeOp( location, "?-?", rhs,
+				ast::ConstantExpr::from_ulong( location, 1 ) ) );
+	// If not aligned, increment to alignment.
+	ast::Expr * ifExpr = makeOp( location, "?+=?", ast::deepCopy( lhs ),
+		makeOp( location, "?-?", ast::deepCopy( rhs ),
+				ast::deepCopy( ifCond ) ) );
+	return makeCond( location, ifCond, ifExpr );
+}
+
+/// Makes a statement that assigns rhs to lhs if lhs < rhs.
+ast::Stmt * makeAssignMax( CodeLocation const & location,
+		ast::Expr const * lhs, ast::Expr const * rhs ) {
+	return makeCond( location,
+		makeOp( location, "?<?", ast::deepCopy( lhs ), ast::deepCopy( rhs ) ),
+		makeOp( location, "?=?", lhs, rhs ) );
+}
+
+void LayoutFunctionBuilder::previsit( ast::StructDecl const * decl ) {
+	// Do not generate layout function for empty tag structures.
+	visit_children = false;
+	if ( decl->members.empty() ) return;
+
+	// Get parameters that can change layout, exiting early if none.
+	ast::vector<ast::TypeDecl> sizedParams =
+		takeSizedParams( decl->params );
+	if ( sizedParams.empty() ) return;
+
+	CodeLocation const & location = decl->location;
+
+	// Build layout function signature.
+	LayoutData layout = buildLayoutFunction(
+		location, decl, sizedParams, isInFunction(), true );
+	ast::FunctionDecl * layoutDecl = layout.function;
+	// Also return these or extract them from the parameter list?
+	ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
+	ast::ObjectDecl const * alignofParam = layout.alignofParam;
+	ast::ObjectDecl const * offsetofParam = layout.offsetofParam;
+	assert( nullptr != layout.offsetofParam );
+
+	// Calculate structure layout in function body.
+	// Initialize size and alignment to 0 and 1
+	// (Will have at least one member to update size).
+	auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
+	kids.emplace_back( makeOpStmt( location, "?=?",
+		derefVar( location, sizeofParam ),
+		ast::ConstantExpr::from_ulong( location, 0 )
+	) );
+	kids.emplace_back( makeOpStmt( location, "?=?",
+		derefVar( location, alignofParam ),
+		ast::ConstantExpr::from_ulong( location, 1 )
+	) );
+	// TODO: Polymorphic types will be out of the struct declaration scope.
+	// Should be removed by PolyGenericCalculator.
+	for ( auto const & member : enumerate( decl->members ) ) {
+		auto dwt = member.val.strict_as<ast::DeclWithType>();
+		ast::Type const * memberType = dwt->get_type();
+
+		if ( 0 < member.idx ) {
+			// Make sure all later members have padding to align them.
+			kids.emplace_back( makeAlignTo( location,
+				derefVar( location, sizeofParam ),
+				new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
+			) );
+		}
+
+		// Place current size in the current offset index.
+		kids.emplace_back( makeOpStmt( location, "?=?",
+			makeOp( location, "?[?]",
+				new ast::VariableExpr( location, offsetofParam ),
+				ast::ConstantExpr::from_ulong( location, member.idx ) ),
+			derefVar( location, sizeofParam ) ) );
+
+		// Add member size to current size.
+		kids.emplace_back( makeOpStmt( location, "?+=?",
+			derefVar( location, sizeofParam ),
+			new ast::SizeofExpr( location, ast::deepCopy( memberType ) ) ) );
+
+		// Take max of member alignment and global alignment.
+		// (As align is always 2^n, this will always be a multiple of both.)
+		kids.emplace_back( makeAssignMax( location,
+			derefVar( location, alignofParam ),
+			new ast::AlignofExpr( location, ast::deepCopy( memberType ) ) ) );
+	}
+	// Make sure the type is end-padded to a multiple of its alignment.
+	kids.emplace_back( makeAlignTo( location,
+		derefVar( location, sizeofParam ),
+		derefVar( location, alignofParam ) ) );
+
+	declsToAddAfter.emplace_back( layoutDecl );
+}
+
+void LayoutFunctionBuilder::previsit( ast::UnionDecl const * decl ) {
+	visit_children = false;
+	// Do not generate layout function for empty tag unions.
+	if ( decl->members.empty() ) return;
+
+	// Get parameters that can change layout, exiting early if none.
+	ast::vector<ast::TypeDecl> sizedParams =
+		takeSizedParams( decl->params );
+	if ( sizedParams.empty() ) return;
+
+	CodeLocation const & location = decl->location;
+
+	// Build layout function signature.
+	LayoutData layout = buildLayoutFunction(
+		location, decl, sizedParams, isInFunction(), false );
+	ast::FunctionDecl * layoutDecl = layout.function;
+	// Also return these or extract them from the parameter list?
+	ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
+	ast::ObjectDecl const * alignofParam = layout.alignofParam;
+	assert( nullptr == layout.offsetofParam );
+
+	// Calculate union layout in function body.
+	// Both are simply the maximum for union (actually align is always the
+	// LCM, but with powers of two that is also the maximum).
+	auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
+	kids.emplace_back( makeOpStmt( location,
+		"?=?", derefVar( location, sizeofParam ),
+		ast::ConstantExpr::from_ulong( location, 1 )
+	) );
+	kids.emplace_back( makeOpStmt( location,
+		"?=?", derefVar( location, alignofParam ),
+		ast::ConstantExpr::from_ulong( location, 1 )
+	) );
+	// TODO: Polymorphic types will be out of the union declaration scope.
+	for ( auto const & member : decl->members ) {
+		auto dwt = member.strict_as<ast::DeclWithType>();
+		ast::Type const * memberType = dwt->get_type();
+
+		// Take max member size and global size.
+		kids.emplace_back( makeAssignMax( location,
+			derefVar( location, sizeofParam ),
+			new ast::SizeofExpr( location, ast::deepCopy( memberType ) )
+		) );
+
+		// Take max of member alignment and global alignment.
+		kids.emplace_back( makeAssignMax( location,
+			derefVar( location, alignofParam ),
+			new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
+		) );
+	}
+	kids.emplace_back( makeAlignTo( location,
+		derefVar( location, sizeofParam ),
+		derefVar( location, alignofParam ) ) );
+
+	declsToAddAfter.emplace_back( layoutDecl );
+}
+
+// --------------------------------------------------------------------------
+/// Application expression transformer.
+/// * Replaces polymorphic return types with out-parameters.
+/// * Replaces call to polymorphic functions with adapter calls which handles
+///   dynamic arguments and return values.
+/// * Adds appropriate type variables to the function calls.
+struct CallAdapter final :
+		public BoxPass,
+		public ast::WithConstTypeSubstitution,
+		public ast::WithGuards,
+		public ast::WithShortCircuiting,
+		public ast::WithStmtsToAdd<>,
+		public ast::WithVisitorRef<CallAdapter> {
+	CallAdapter();
+
+	void previsit( ast::Decl const * decl );
+	ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
+	void previsit( ast::TypeDecl const * decl );
+	void previsit( ast::CommaExpr const * expr );
+	ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
+	ast::Expr const * postvisit( ast::UntypedExpr const * expr );
+	void previsit( ast::AddressExpr const * expr );
+	ast::Expr const * postvisit( ast::AddressExpr const * expr );
+	ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
+	void previsit( ast::PointerType const * type );
+	void previsit( ast::FunctionType const * type );
+
+	void beginScope();
+	void endScope();
+private:
+	// Many helpers here use a mutable ApplicationExpr as an in/out parameter
+	// instead of using the return value, to save on mutates and free up the
+	// return value.
+
+	/// Pass the extra type parameters from polymorphic generic arguments or
+	/// return types into a function application.
+	ast::vector<ast::Expr>::iterator passArgTypeVars(
+		ast::ApplicationExpr * expr, ast::Type const * parmType,
+		ast::Type const * argBaseType, ast::vector<ast::Expr>::iterator arg,
+		const TypeVarMap & exprTyVars, std::set<std::string> & seenTypes );
+	/// Passes extra type parameters into a polymorphic function application.
+	ast::vector<ast::Expr>::iterator passTypeVars(
+		ast::ApplicationExpr * expr,
+		ast::Type const * polyRetType,
+		ast::FunctionType const * funcType,
+		const TypeVarMap & exprTyVars );
+	/// Wraps a function application with a new temporary for the
+	/// out-parameter return value.
+	ast::Expr const * addRetParam(
+		ast::ApplicationExpr * expr, ast::Type const * retType );
+	/// Wraps a function application returning a polymorphic type with a new
+	/// temporary for the out-parameter return value.
+	ast::Expr const * addDynRetParam(
+		ast::ApplicationExpr * expr, ast::Type const * polyType );
+	/// Modify a call so it passes the function through the correct adapter.
+	ast::Expr const * applyAdapter(
+		ast::ApplicationExpr * expr,
+		ast::FunctionType const * function );
+	/// Convert a single argument into its boxed form to pass the parameter.
+	void boxParam( ast::ptr<ast::Expr> & arg,
+		ast::Type const * formal, TypeVarMap const & exprTyVars );
+	/// Box every argument from arg forward, matching the functionType
+	/// parameter list. arg should point into expr's argument list.
+	void boxParams(
+		ast::ApplicationExpr const * expr,
+		ast::vector<ast::Expr>::iterator arg,
+		ast::FunctionType const * function,
+		const TypeVarMap & typeVars );
+	/// Adds the inferred parameters derived from the assertions of the
+	/// expression to the call.
+	void addInferredParams(
+		ast::ApplicationExpr * expr,
+		ast::vector<ast::Expr>::iterator arg,
+		ast::FunctionType const * functionType,
+		const TypeVarMap & typeVars );
+	/// Stores assignment operators from assertion list in
+	/// local map of assignment operations.
+	void passAdapters(
+		ast::ApplicationExpr * expr,
+		ast::FunctionType const * type,
+		const TypeVarMap & typeVars );
+	/// Create an adapter function based on the type of the adaptee and the
+	/// real type with the type substitutions applied.
+	ast::FunctionDecl * makeAdapter(
+		ast::FunctionType const * adaptee,
+		ast::FunctionType const * realType,
+		std::string const & mangleName,
+		TypeVarMap const & typeVars,
+		CodeLocation const & location ) const;
+	/// Replaces intrinsic operator functions with their arithmetic desugaring.
+	ast::Expr const * handleIntrinsics( ast::ApplicationExpr const * );
+	/// Inserts a new temporary variable into the current scope with an
+	/// auto-generated name.
+	ast::ObjectDecl * makeTemporary(
+		CodeLocation const & location, ast::Type const * type );
+
+	/// Set of adapter functions in the current scope.
+	ScopedMap< std::string, ast::DeclWithType const * > adapters;
+	std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
+	ast::DeclWithType const * retval;
+	UniqueName tmpNamer;
+};
+
+/// Replaces a polymorphic type with its concrete equivalant under the
+/// current environment (returns itself if concrete).
+/// If `doClone` is set to false, will not clone interior types
+ast::Type const * replaceWithConcrete(
+		ast::Type const * type,
+		ast::TypeSubstitution const & typeSubs,
+		bool doCopy = true );
+
+/// Replaces all the type parameters of a generic type with their
+/// concrete equivalents under the current environment.
+void replaceParametersWithConcrete(
+		ast::vector<ast::Expr> & params,
+		ast::TypeSubstitution const & typeSubs ) {
+	for ( ast::ptr<ast::Expr> & paramExpr : params ) {
+		ast::TypeExpr const * param = paramExpr.as<ast::TypeExpr>();
+		assertf( param, "Aggregate parameters should be type expressions." );
+		paramExpr = ast::mutate_field( param, &ast::TypeExpr::type,
+			replaceWithConcrete( param->type.get(), typeSubs, false ) );
+	}
+}
+
+ast::Type const * replaceWithConcrete(
+		ast::Type const * type,
+		ast::TypeSubstitution const & typeSubs,
+		bool doCopy ) {
+	if ( auto instType = dynamic_cast<ast::TypeInstType const *>( type ) ) {
+		ast::Type const * concrete = typeSubs.lookup( instType );
+		return ( nullptr != concrete ) ? concrete : instType;
+	} else if ( auto structType =
+			dynamic_cast<ast::StructInstType const *>( type ) ) {
+		ast::StructInstType * newType =
+			doCopy ? ast::deepCopy( structType ) : ast::mutate( structType );
+		replaceParametersWithConcrete( newType->params, typeSubs );
+		return newType;
+	} else if ( auto unionType =
+			dynamic_cast<ast::UnionInstType const *>( type ) ) {
+		ast::UnionInstType * newType =
+			doCopy ? ast::deepCopy( unionType ) : ast::mutate( unionType );
+		replaceParametersWithConcrete( newType->params, typeSubs );
+		return newType;
+	} else {
+		return type;
+	}
+}
+
+std::string makePolyMonoSuffix(
+		ast::FunctionType const * function,
+		TypeVarMap const & typeVars ) {
+	// If the return type or a parameter type involved polymorphic types,
+	// then the adapter will need to take those polymorphic types as pointers.
+	// Therefore, there can be two different functions with the same mangled
+	// name, so we need to further mangle the names.
+	std::stringstream name;
+	for ( auto ret : function->returns ) {
+		name << ( isPolyType( ret, typeVars ) ? 'P' : 'M' );
+	}
+	name << '_';
+	for ( auto arg : function->params ) {
+		name << ( isPolyType( arg, typeVars ) ? 'P' : 'M' );
+	}
+	return name.str();
+}
+
+std::string mangleAdapterName(
+		ast::FunctionType const * function,
+		TypeVarMap const & typeVars ) {
+	return Mangle::mangle( function, {} )
+		+ makePolyMonoSuffix( function, typeVars );
+}
+
+std::string makeAdapterName( std::string const & mangleName ) {
+	return "_adapter" + mangleName;
+}
+
+void makeRetParam( ast::FunctionType * type ) {
+	ast::ptr<ast::Type> & retParam = type->returns.front();
+
+	// Make a new parameter that is a pointer to the type of the old return value.
+	retParam = new ast::PointerType( retParam.get() );
+	type->params.emplace( type->params.begin(), retParam );
+
+	// We don't need the return value any more.
+	type->returns.clear();
+}
+
+ast::FunctionType * makeAdapterType(
+		ast::FunctionType const * adaptee,
+		TypeVarMap const & typeVars ) {
+	ast::FunctionType * adapter = ast::deepCopy( adaptee );
+	if ( isDynRet( adapter, typeVars ) ) {
+		makeRetParam( adapter );
+	}
+	adapter->params.emplace( adapter->params.begin(),
+		new ast::PointerType( new ast::FunctionType( ast::VariableArgs ) )
+	);
+	return adapter;
+}
+
+CallAdapter::CallAdapter() : tmpNamer( "_temp" ) {}
+
+void CallAdapter::previsit( ast::Decl const * ) {
+	// Prevent type declaration information from leaking out.
+	GuardScope( scopeTypeVars );
+}
+
+ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
+	if ( nullptr == decl->stmts ) {
+		// This may keep TypeDecls we don't ever want from sneaking in.
+		// Not visiting child nodes might just be faster.
+		GuardScope( scopeTypeVars );
+		return decl;
+	}
+
+	GuardScope( scopeTypeVars );
+	GuardValue( retval );
+
+	// Process polymorphic return value.
+	retval = nullptr;
+	ast::FunctionType const * type = decl->type;
+	if ( isDynRet( type ) && decl->linkage != ast::Linkage::C ) {
+		retval = decl->returns.front();
+
+		// Give names to unnamed return values.
+		if ( "" == retval->name ) {
+			auto mutRet = ast::mutate( retval );
+			mutRet->name = "_retparam";
+			mutRet->linkage = ast::Linkage::C;
+			retval = mutRet;
+			decl = ast::mutate_field_index( decl,
+				&ast::FunctionDecl::returns, 0, mutRet );
+		}
+	}
+
+	// The formal_usage/expr_id values may be off if we get them from the
+	// type, trying the declaration instead.
+	makeTypeVarMap( type, scopeTypeVars );
+
+	// Get all needed adapters from the call. We will forward them.
+	ast::vector<ast::FunctionType> functions;
+	for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
+		auto atype = assertion->result.get();
+		findFunction( atype, functions, scopeTypeVars, needsAdapter );
+	}
+
+	for ( ast::ptr<ast::Type> const & arg : type->params ) {
+		findFunction( arg, functions, scopeTypeVars, needsAdapter );
+	}
+
+	for ( auto funcType : functions ) {
+		std::string mangleName = mangleAdapterName( funcType, scopeTypeVars );
+		if ( adapters.contains( mangleName ) ) continue;
+		std::string adapterName = makeAdapterName( mangleName );
+		// TODO: The forwarding here is problematic because these
+		// declarations are not rooted anywhere in the translation unit.
+		adapters.insert(
+			mangleName,
+			new ast::ObjectDecl(
+				decl->location,
+				adapterName,
+				new ast::PointerType(
+					makeAdapterType( funcType, scopeTypeVars ) ),
+				nullptr, // init
+				ast::Storage::Classes(),
+				ast::Linkage::C
+			)
+		);
+	}
+
+	return decl;
+}
+
+void CallAdapter::previsit( ast::TypeDecl const * decl ) {
+	addToTypeVarMap( decl, scopeTypeVars );
+}
+
+void CallAdapter::previsit( ast::CommaExpr const * expr ) {
+	// Attempting to find application expressions that were mutated by the
+	// copy constructor passes to use an explicit return variable, so that
+	// the variable can be reused as a parameter to the call rather than
+	// creating a new temporary variable. Previously this step was an
+	// optimization, but with the introduction of tuples and UniqueExprs,
+	// it is necessary to ensure that they use the same variable.
+	// Essentially, looking for pattern:
+	// (x=f(...), x)
+	// To compound the issue, the right side can be *x, etc.
+	// because of lvalue-returning functions
+	if ( auto assign = expr->arg1.as<ast::UntypedExpr>() ) {
+		if ( CodeGen::isAssignment( ast::getFunctionName( assign ) ) ) {
+			assert( 2 == assign->args.size() );
+			if ( auto app = assign->args.back().as<ast::ApplicationExpr>() ) {
+				// First argument is assignable, so it must be an lvalue,
+				// so it should be legal to takes its address.
+				retVals.insert_or_assign( app, assign->args.front() );
+			}
+		}
+	}
+}
+
+ast::Expr const * CallAdapter::postvisit( ast::ApplicationExpr const * expr ) {
+	assert( expr->func->result );
+	ast::FunctionType const * function = getFunctionType( expr->func->result );
+	assertf( function, "ApplicationExpr has non-function type %s",
+			toCString( expr->func->result ) );
+
+	if ( auto newExpr = handleIntrinsics( expr ) ) {
+		return newExpr;
+	}
+
+	ast::ApplicationExpr * mutExpr = ast::mutate( expr );
+	ast::Expr const * ret = expr;
+
+	// TODO: This entire section should probably be refactored to do less
+	// pushing to the front/middle of a vector.
+	ptrdiff_t initArgCount = mutExpr->args.size();
+
+	TypeVarMap exprTypeVars = { ast::TypeData() };
+	// TODO: Should this take into account the variables already bound in
+	// scopeTypeVars ([ex] remove them from exprTypeVars)?
+	makeTypeVarMap( function, exprTypeVars );
+	auto dynRetType = isDynRet( function, exprTypeVars );
+
+	// NOTE: addDynRetParam needs to know the actual (generated) return type
+	// so it can make a temporary variable, so pass the result type form the
+	// `expr` `passTypeVars` needs to know the program-text return type ([ex]
+	// the distinction between _conc_T30 and T3(int)) concRetType may not be
+	// a good name in one or both of these places.
+	if ( dynRetType ) {
+		ast::Type const * result = mutExpr->result;
+		ast::Type const * concRetType = result->isVoid() ? nullptr : result;
+		// [Comment from before translation.]
+		// Used to use dynRetType instead of concRetType.
+		ret = addDynRetParam( mutExpr, concRetType );
+	} else if ( needsAdapter( function, scopeTypeVars )
+			&& !needsAdapter( function, exprTypeVars ) ) {
+		// Change the application so it calls the adapter rather than the
+		// passed function.
+		ret = applyAdapter( mutExpr, function );
+	}
+
+	assert( typeSubs );
+	ast::Type const * concRetType = replaceWithConcrete( dynRetType, *typeSubs );
+	// Used to use dynRetType instead of concRetType; this changed so that
+	// the correct type parameters are passed for return types (it should be
+	// the concrete type's parameters, not the formal type's).
+	ast::vector<ast::Expr>::iterator argIt =
+		passTypeVars( mutExpr, concRetType, function, exprTypeVars );
+	addInferredParams( mutExpr, argIt, function, exprTypeVars );
+
+	argIt = mutExpr->args.begin();
+	std::advance( argIt, ( mutExpr->args.size() - initArgCount ) );
+
+	boxParams( mutExpr, argIt, function, exprTypeVars );
+	passAdapters( mutExpr, function, exprTypeVars );
+
+	return ret;
+}
+
+bool isPolyDeref( ast::UntypedExpr const * expr,
+		TypeVarMap const & typeVars,
+		ast::TypeSubstitution const * typeSubs ) {
+	if ( expr->result && isPolyType( expr->result, typeVars, typeSubs ) ) {
+		if ( auto name = expr->func.as<ast::NameExpr>() ) {
+			if ( "*?" == name->name ) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+ast::Expr const * CallAdapter::postvisit( ast::UntypedExpr const * expr ) {
+	if ( isPolyDeref( expr, scopeTypeVars, typeSubs ) ) {
+		return expr->args.front();
+	}
+	return expr;
+}
+
+void CallAdapter::previsit( ast::AddressExpr const * ) {
+	visit_children = false;
+}
+
+ast::Expr const * CallAdapter::postvisit( ast::AddressExpr const * expr ) {
+	assert( expr->arg->result );
+	assert( !expr->arg->result->isVoid() );
+
+	bool doesNeedAdapter = false;
+	if ( auto un = expr->arg.as<ast::UntypedExpr>() ) {
+		if ( isPolyDeref( un, scopeTypeVars, typeSubs ) ) {
+			if ( auto app = un->args.front().as<ast::ApplicationExpr>() ) {
+				assert( app->func->result );
+				auto function = getFunctionType( app->func->result );
+				assert( function );
+				doesNeedAdapter = needsAdapter( function, scopeTypeVars );
+			}
+		}
+	}
+	// isPolyType check needs to happen before mutating expr arg,
+	// so pull it forward out of the if condition.
+	expr = ast::mutate_field( expr, &ast::AddressExpr::arg,
+			expr->arg->accept( *visitor ) );
+	// But must happen after mutate, since argument might change
+	// (ex. intrinsic *?, ?[?]) re-evaluate above comment.
+	bool polyType = isPolyType( expr->arg->result, scopeTypeVars, typeSubs );
+	if ( polyType || doesNeedAdapter ) {
+		ast::Expr * ret = ast::mutate( expr->arg.get() );
+		ret->result = ast::deepCopy( expr->result );
+		return ret;
+	} else {
+		return expr;
+	}
+}
+
+ast::ReturnStmt const * CallAdapter::previsit( ast::ReturnStmt const * stmt ) {
+	// Since retval is set when the return type is dynamic, this function
+	// should have been converted to void return & out parameter.
+	if ( retval && stmt->expr ) {
+		assert( stmt->expr->result );
+		assert( !stmt->expr->result->isVoid() );
+		return ast::mutate_field( stmt, &ast::ReturnStmt::expr, nullptr );
+	}
+	return stmt;
+}
+
+void CallAdapter::previsit( ast::PointerType const * type ) {
+	GuardScope( scopeTypeVars );
+	makeTypeVarMap( type, scopeTypeVars );
+}
+
+void CallAdapter::previsit( ast::FunctionType const * type ) {
+	GuardScope( scopeTypeVars );
+	makeTypeVarMap( type, scopeTypeVars );
+}
+
+void CallAdapter::beginScope() {
+	adapters.beginScope();
+}
+
+void CallAdapter::endScope() {
+	adapters.endScope();
+}
+
+/// Find instances of polymorphic type parameters.
+struct PolyFinder {
+	TypeVarMap const & typeVars;
+	bool result = false;
+	PolyFinder( TypeVarMap const & tvs ) : typeVars( tvs ) {}
+
+	void previsit( ast::TypeInstType const * type ) {
+		if ( isPolyType( type, typeVars ) ) result = true;
+	}
+};
+
+/// True if these is an instance of a polymorphic type parameter in the type.
+bool hasPolymorphism( ast::Type const * type, TypeVarMap const & typeVars ) {
+	return ast::Pass<PolyFinder>::read( type, typeVars );
+}
+
+// arg is an in/out parameter that matches the return value.
+ast::vector<ast::Expr>::iterator CallAdapter::passArgTypeVars(
+		ast::ApplicationExpr * expr, ast::Type const * paramType,
+		ast::Type const * argBaseType, ast::vector<ast::Expr>::iterator arg,
+		const TypeVarMap & exprTypeVars, std::set<std::string> & seenTypes ) {
+	ast::Type const * polyType = isPolyType( paramType, exprTypeVars );
+	if ( !polyType || dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
+		return arg;
+	}
+
+	std::string typeName = Mangle::mangleType( polyType );
+	if ( seenTypes.count( typeName ) ) return arg;
+
+	arg = expr->args.insert( arg,
+		new ast::SizeofExpr( expr->location, ast::deepCopy( argBaseType ) )
+	);
+	arg++;
+	arg = expr->args.insert( arg,
+		new ast::AlignofExpr( expr->location, ast::deepCopy( argBaseType ) )
+	);
+	arg++;
+	if ( dynamic_cast<ast::StructInstType const *>( polyType ) ) {
+		auto argBaseStructType =
+				dynamic_cast<ast::StructInstType const *>( argBaseType );
+		if ( nullptr == argBaseStructType ) {
+			SemanticError( expr,
+				"Cannot pass non-structure type for generic struct: " );
+		}
+
+		// Zero-length arrays are forbidden by C, so don't pass
+		// offset for empty structure.
+		if ( !argBaseStructType->base->members.empty() ) {
+			arg = expr->args.insert( arg,
+				new ast::OffsetPackExpr(
+					expr->location,
+					ast::deepCopy( argBaseStructType ) )
+			);
+			arg++;
+		}
+	}
+
+	seenTypes.insert( typeName );
+	return arg;
+}
+
+ast::vector<ast::Expr>::iterator CallAdapter::passTypeVars(
+		ast::ApplicationExpr * expr,
+		ast::Type const * polyRetType,
+		ast::FunctionType const * function,
+		const TypeVarMap & exprTypeVars ) {
+	assert( typeSubs );
+	ast::vector<ast::Expr>::iterator arg = expr->args.begin();
+	// Pass size/align for type variables.
+	for ( ast::ptr<ast::TypeInstType> const & typeVar : function->forall ) {
+		if ( !typeVar->base->isComplete() ) continue;
+		ast::Type const * concrete = typeSubs->lookup( typeVar );
+		if ( !concrete ) {
+			// Should this be an assertion?
+			SemanticError( expr, toString( typeSubs,
+				"\nunbound type variable: ", typeVar->typeString(),
+				" in application " ) );
+		}
+		arg = expr->args.insert( arg,
+			new ast::SizeofExpr( expr->location, ast::deepCopy( concrete ) ) );
+		arg++;
+		arg = expr->args.insert( arg,
+			new ast::AlignofExpr( expr->location, ast::deepCopy( concrete ) ) );
+		arg++;
+	}
+
+	// Add size/align for generic types to parameter list.
+	if ( !expr->func->result ) return arg;
+	ast::FunctionType const * funcType = getFunctionType( expr->func->result );
+	assert( funcType );
+
+	// This iterator points at first original argument.
+	ast::vector<ast::Expr>::const_iterator funcArg;
+	// Names for generic types we've seen.
+	std::set<std::string> seenTypes;
+
+	// A polymorphic return type may need to be added to the argument list.
+	if ( polyRetType ) {
+		assert( typeSubs );
+		auto concRetType = replaceWithConcrete( polyRetType, *typeSubs );
+		// TODO: This write-back may not be correct.
+		arg = passArgTypeVars( expr, polyRetType, concRetType,
+				arg, exprTypeVars, seenTypes );
+		// Skip the return parameter in the argument list.
+		funcArg = arg + 1;
+	} else {
+		funcArg = arg;
+	}
+
+	// TODO:
+	// I believe this is (starts as) the number of original arguments to the
+	// function with the args before funcArg all being inserted.
+	ptrdiff_t argsToPass = std::distance( funcArg, expr->args.cend() );
+
+	// Add type information args for presently unseen types in parameter list.
+	ast::vector<ast::Type>::const_iterator funcParam = funcType->params.begin();
+	// assert( funcType->params.size() == argsToPass );
+	for ( ; funcParam != funcType->params.end() && 0 < argsToPass
+			; ++funcParam, --argsToPass ) {
+		assert( 0 < argsToPass );
+		assert( argsToPass <= (ptrdiff_t)expr->args.size() );
+		ptrdiff_t index = expr->args.size() - argsToPass;
+		ast::Type const * argType = expr->args[index]->result;
+		if ( nullptr == argType ) continue;
+		arg = passArgTypeVars( expr, *funcParam, argType,
+				arg, exprTypeVars, seenTypes );
+	}
+	return arg;
+}
+
+ast::Expr const * CallAdapter::addRetParam(
+		ast::ApplicationExpr * expr, ast::Type const * retType ) {
+	// Create temporary to hold return value of polymorphic function and
+	// produce that temporary as a result using a comma expression.
+	assert( retType );
+
+	ast::Expr * paramExpr = nullptr;
+	// Try to use existing return value parameter if it exists,
+	// otherwise create a new temporary.
+	if ( retVals.count( expr ) ) {
+		paramExpr = ast::deepCopy( retVals[ expr ] );
+	} else {
+		auto newObj = makeTemporary( expr->location, ast::deepCopy( retType ) );
+		paramExpr = new ast::VariableExpr( expr->location, newObj );
+	}
+	ast::Expr * retExpr = ast::deepCopy( paramExpr );
+
+	// If the type of the temporary is not polpmorphic, box temporary by
+	// taking its address; otherwise the temporary is already boxed and can
+	// be used directly.
+	if ( !isPolyType( paramExpr->result, scopeTypeVars, typeSubs ) ) {
+		paramExpr = new ast::AddressExpr( paramExpr->location, paramExpr );
+	}
+	// Add argument to function call.
+	expr->args.insert( expr->args.begin(), paramExpr );
+	// Build a comma expression to call the function and return a value.
+	ast::CommaExpr * comma = new ast::CommaExpr(
+		expr->location, expr, retExpr );
+	comma->env = expr->env;
+	expr->env = nullptr;
+	return comma;
+}
+
+ast::Expr const * CallAdapter::addDynRetParam(
+		ast::ApplicationExpr * expr, ast::Type const * polyType ) {
+	assert( typeSubs );
+	ast::Type const * concrete = replaceWithConcrete( polyType, *typeSubs );
+	// Add out-parameter for return value.
+	return addRetParam( expr, concrete );
+}
+
+ast::Expr const * CallAdapter::applyAdapter(
+		ast::ApplicationExpr * expr,
+		ast::FunctionType const * function ) {
+	ast::Expr const * ret = expr;
+	if ( isDynRet( function, scopeTypeVars ) ) {
+		ret = addRetParam( expr, function->returns.front() );
+	}
+	std::string mangleName = mangleAdapterName( function, scopeTypeVars );
+	std::string adapterName = makeAdapterName( mangleName );
+
+	// Cast adaptee to `void (*)()`, since it may have any type inside a
+	// polymorphic function.
+	ast::Type const * adapteeType = new ast::PointerType(
+		new ast::FunctionType( ast::VariableArgs ) );
+	expr->args.insert( expr->args.begin(),
+		new ast::CastExpr( expr->location, expr->func, adapteeType ) );
+	// The result field is never set on NameExpr. / Now it is.
+	auto head = new ast::NameExpr( expr->location, adapterName );
+	head->result = ast::deepCopy( adapteeType );
+	expr->func = head;
+
+	return ret;
+}
+
+/// Cast parameters to polymorphic functions so that types are replaced with
+/// `void *` if they are type parameters in the formal type.
+/// This gets rid of warnings from gcc.
+void addCast(
+		ast::ptr<ast::Expr> & actual,
+		ast::Type const * formal,
+		TypeVarMap const & typeVars ) {
+	// Type contains polymorphism, but isn't exactly a polytype, in which
+	// case it has some real actual type (ex. unsigned int) and casting to
+	// `void *` is wrong.
+	if ( hasPolymorphism( formal, typeVars )
+			&& !isPolyType( formal, typeVars ) ) {
+		ast::Type const * newType = ast::deepCopy( formal );
+		newType = scrubTypeVars( newType, typeVars );
+		actual = new ast::CastExpr( actual->location, actual, newType );
+	}
+}
+
+void CallAdapter::boxParam( ast::ptr<ast::Expr> & arg,
+		ast::Type const * param, TypeVarMap const & exprTypeVars ) {
+	assertf( arg->result, "arg does not have result: %s", toCString( arg ) );
+	addCast( arg, param, exprTypeVars );
+	if ( !needsBoxing( param, arg->result, exprTypeVars, typeSubs ) ) {
+		return;
+	}
+	CodeLocation const & location = arg->location;
+
+	if ( arg->get_lvalue() ) {
+		// The argument expression may be CFA lvalue, but not C lvalue,
+		// so apply generalizedLvalue transformations.
+		// if ( auto var = dynamic_cast<ast::VariableExpr const *>( arg ) ) {
+		//  if ( dynamic_cast<ast::ArrayType const *>( varExpr->var->get_type() ) ){
+		//      // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
+		//      return;
+		//  }
+		// }
+		arg = generalizedLvalue( new ast::AddressExpr( arg->location, arg ) );
+		if ( !ResolvExpr::typesCompatible( param, arg->result ) ) {
+			// Silence warnings by casting boxed parameters when the actually
+			// type does not match up with the formal type.
+			arg = new ast::CastExpr( location, arg, ast::deepCopy( param ) );
+		}
+	} else {
+		// Use type computed in unification to declare boxed variables.
+		ast::ptr<ast::Type> newType = ast::deepCopy( param );
+		if ( typeSubs ) typeSubs->apply( newType );
+		ast::ObjectDecl * newObj = makeTemporary( location, newType );
+		auto assign = ast::UntypedExpr::createCall( location, "?=?", {
+			new ast::VariableExpr( location, newObj ),
+			arg,
+		} );
+		stmtsToAddBefore.push_back( new ast::ExprStmt( location, assign ) );
+		arg = new ast::AddressExpr(
+			new ast::VariableExpr( location, newObj ) );
+	}
+}
+
+void CallAdapter::boxParams(
+		ast::ApplicationExpr const * expr,
+		ast::vector<ast::Expr>::iterator arg,
+		ast::FunctionType const * function,
+		const TypeVarMap & typeVars ) {
+	for ( auto param : function->params ) {
+		assertf( arg != expr->args.end(),
+			"boxParams: missing argument for param %s to %s in %s",
+			toCString( param ), toCString( function ), toCString( expr ) );
+		boxParam( *arg, param, typeVars );
+		++arg;
+	}
+}
+
+void CallAdapter::addInferredParams(
+		ast::ApplicationExpr * expr,
+		ast::vector<ast::Expr>::iterator arg,
+		ast::FunctionType const * functionType,
+		TypeVarMap const & typeVars ) {
+	ast::vector<ast::Expr>::iterator cur = arg;
+	for ( auto assertion : functionType->assertions ) {
+		auto inferParam = expr->inferred.inferParams().find(
+			assertion->var->uniqueId );
+		assertf( inferParam != expr->inferred.inferParams().end(),
+			"addInferredParams missing inferred parameter: %s in: %s",
+			toCString( assertion ), toCString( expr ) );
+		ast::ptr<ast::Expr> newExpr = ast::deepCopy( inferParam->second.expr );
+		boxParam( newExpr, assertion->result, typeVars );
+		cur = expr->args.insert( cur, newExpr.release() );
+		++cur;
+	}
+}
+
+/// Modifies the ApplicationExpr to accept adapter functions for its
+/// assertion and parameters, declares the required adapters.
+void CallAdapter::passAdapters(
+		ast::ApplicationExpr * expr,
+		ast::FunctionType const * type,
+		const TypeVarMap & exprTypeVars ) {
+	// Collect a list of function types passed as parameters or implicit
+	// parameters (assertions).
+	ast::vector<ast::Type> const & paramList = type->params;
+	ast::vector<ast::FunctionType> functions;
+
+	for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
+		findFunction( assertion->result, functions, exprTypeVars, needsAdapter );
+	}
+	for ( ast::ptr<ast::Type> const & arg : paramList ) {
+		findFunction( arg, functions, exprTypeVars, needsAdapter );
+	}
+
+	// Parameter function types for which an appropriate adapter has been
+	// generated. We cannot use the types after applying substitutions,
+	// since two different parameter types may be unified to the same type.
+	std::set<std::string> adaptersDone;
+
+	CodeLocation const & location = expr->location;
+
+	for ( ast::ptr<ast::FunctionType> const & funcType : functions ) {
+		std::string mangleName = Mangle::mangle( funcType );
+
+		// Only attempt to create an adapter or pass one as a parameter if we
+		// haven't already done so for this pre-substitution parameter
+		// function type.
+		// The second part of the result if is if the element was inserted.
+		if ( !adaptersDone.insert( mangleName ).second ) continue;
+
+		// Apply substitution to type variables to figure out what the
+		// adapter's type should look like. (Copy to make the release safe.)
+		assert( typeSubs );
+		auto result = typeSubs->apply( ast::deepCopy( funcType ) );
+		ast::FunctionType * realType = ast::mutate( result.node.release() );
+		mangleName = Mangle::mangle( realType );
+		mangleName += makePolyMonoSuffix( funcType, exprTypeVars );
+
+		// Check if the adapter has already been created, or has to be.
+		using AdapterIter = decltype(adapters)::iterator;
+		AdapterIter adapter = adapters.find( mangleName );
+		if ( adapter == adapters.end() ) {
+			ast::FunctionDecl * newAdapter = makeAdapter(
+				funcType, realType, mangleName, exprTypeVars, location );
+			std::pair<AdapterIter, bool> answer =
+				adapters.insert( mangleName, newAdapter );
+			adapter = answer.first;
+			stmtsToAddBefore.push_back(
+				new ast::DeclStmt( location, newAdapter ) );
+		}
+		assert( adapter != adapters.end() );
+
+		// Add the approprate adapter as a parameter.
+		expr->args.insert( expr->args.begin(),
+			new ast::VariableExpr( location, adapter->second ) );
+	}
+}
+
+// Parameter and argument may be used wrong around here.
+ast::Expr * makeAdapterArg(
+		ast::DeclWithType const * param,
+		ast::Type const * arg,
+		ast::Type const * realParam,
+		TypeVarMap const & typeVars,
+		CodeLocation const & location ) {
+	assert( param );
+	assert( arg );
+	assert( realParam );
+	if ( isPolyType( realParam, typeVars ) && !isPolyType( arg ) ) {
+		ast::UntypedExpr * deref = ast::UntypedExpr::createDeref(
+			location,
+			new ast::CastExpr( location,
+				new ast::VariableExpr( location, param ),
+				new ast::PointerType( ast::deepCopy( arg ) )
+			)
+		);
+		deref->result = ast::deepCopy( arg );
+		return deref;
+	}
+	return new ast::VariableExpr( location, param );
+}
+
+// This seems to be one of the problematic functions.
+void addAdapterParams(
+		ast::ApplicationExpr * adaptee,
+		ast::vector<ast::Type>::const_iterator arg,
+		ast::vector<ast::DeclWithType>::iterator param,
+		ast::vector<ast::DeclWithType>::iterator paramEnd,
+		ast::vector<ast::Type>::const_iterator realParam,
+		TypeVarMap const & typeVars,
+		CodeLocation const & location ) {
+	UniqueName paramNamer( "_p" );
+	for ( ; param != paramEnd ; ++param, ++arg, ++realParam ) {
+		if ( "" == (*param)->name ) {
+			auto mutParam = (*param).get_and_mutate();
+			mutParam->name = paramNamer.newName();
+			mutParam->linkage = ast::Linkage::C;
+		}
+		adaptee->args.push_back(
+			makeAdapterArg( *param, *arg, *realParam, typeVars, location ) );
+	}
+}
+
+ast::FunctionDecl * CallAdapter::makeAdapter(
+		ast::FunctionType const * adaptee,
+		ast::FunctionType const * realType,
+		std::string const & mangleName,
+		TypeVarMap const & typeVars,
+		CodeLocation const & location ) const {
+	ast::FunctionType * adapterType = makeAdapterType( adaptee, typeVars );
+	adapterType = ast::mutate( scrubTypeVars( adapterType, typeVars ) );
+
+	// Some of these names will be overwritten, but it gives a default.
+	UniqueName pNamer( "_param" );
+	UniqueName rNamer( "_ret" );
+
+	bool first = true;
+
+	ast::FunctionDecl * adapterDecl = new ast::FunctionDecl( location,
+		makeAdapterName( mangleName ),
+		{}, // forall
+		{}, // assertions
+		map_range<ast::vector<ast::DeclWithType>>( adapterType->params,
+				[&pNamer, &location, &first]( ast::ptr<ast::Type> const & param ) {
+			// [Trying to make the generated code match exactly more often.]
+			if ( first ) {
+				first = false;
+				return new ast::ObjectDecl( location, "_adaptee", param );
+			}
+			return new ast::ObjectDecl( location, pNamer.newName(), param );
+		} ),
+		map_range<ast::vector<ast::DeclWithType>>( adapterType->returns,
+				[&rNamer, &location]( ast::ptr<ast::Type> const & retval ) {
+			return new ast::ObjectDecl( location, rNamer.newName(), retval );
+		} ),
+		nullptr, // stmts
+		{}, // storage
+		ast::Linkage::C
+	);
+
+	ast::DeclWithType * adapteeDecl =
+		adapterDecl->params.front().get_and_mutate();
+	adapteeDecl->name = "_adaptee";
+
+	// Do not carry over attributes to real type parameters/return values.
+	auto mutRealType = ast::mutate( realType );
+	for ( ast::ptr<ast::Type> & decl : mutRealType->params ) {
+		if ( decl->attributes.empty() ) continue;
+		auto mut = ast::mutate( decl.get() );
+		mut->attributes.clear();
+		decl = mut;
+	}
+	for ( ast::ptr<ast::Type> & decl : mutRealType->returns ) {
+		if ( decl->attributes.empty() ) continue;
+		auto mut = ast::mutate( decl.get() );
+		mut->attributes.clear();
+		decl = mut;
+	}
+	realType = mutRealType;
+
+	ast::ApplicationExpr * adapteeApp = new ast::ApplicationExpr( location,
+		new ast::CastExpr( location,
+			new ast::VariableExpr( location, adapteeDecl ),
+			new ast::PointerType( realType )
+		)
+	);
+
+	for ( auto group : group_iterate( realType->assertions,
+			adapterType->assertions, adaptee->assertions ) ) {
+		auto assertArg = std::get<0>( group );
+		auto assertParam = std::get<1>( group );
+		auto assertReal = std::get<2>( group );
+		adapteeApp->args.push_back( makeAdapterArg(
+			assertParam->var, assertArg->var->get_type(),
+			assertReal->var->get_type(), typeVars, location
+		) );
+	}
+
+	ast::vector<ast::Type>::const_iterator
+		arg = realType->params.begin(),
+		param = adapterType->params.begin(),
+		realParam = adaptee->params.begin();
+	ast::vector<ast::DeclWithType>::iterator
+		paramDecl = adapterDecl->params.begin();
+	// Skip adaptee parameter in the adapter type.
+	++param;
+	++paramDecl;
+
+	ast::Stmt * bodyStmt;
+	// Returns void/nothing.
+	if ( realType->returns.empty() ) {
+		addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
+			realParam, typeVars, location );
+		bodyStmt = new ast::ExprStmt( location, adapteeApp );
+	// Returns a polymorphic type.
+	} else if ( isDynType( adaptee->returns.front(), typeVars ) ) {
+		ast::UntypedExpr * assign = new ast::UntypedExpr( location,
+			new ast::NameExpr( location, "?=?" ) );
+		ast::UntypedExpr * deref = ast::UntypedExpr::createDeref( location,
+			new ast::CastExpr( location,
+				new ast::VariableExpr( location, *paramDecl++ ),
+				new ast::PointerType(
+					ast::deepCopy( realType->returns.front() ) ) ) );
+		assign->args.push_back( deref );
+		addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
+			realParam, typeVars, location );
+		assign->args.push_back( adapteeApp );
+		bodyStmt = new ast::ExprStmt( location, assign );
+	// Adapter for a function that returns a monomorphic value.
+	} else {
+		addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
+				realParam, typeVars, location );
+		bodyStmt = new ast::ReturnStmt( location, adapteeApp );
+	}
+
+	adapterDecl->stmts = new ast::CompoundStmt( location, { bodyStmt } );
+	return adapterDecl;
+}
+
+ast::Expr const * makeIncrDecrExpr(
+		CodeLocation const & location,
+		ast::ApplicationExpr const * expr,
+		ast::Type const * polyType,
+		bool isIncr ) {
+	ast::NameExpr * opExpr =
+			new ast::NameExpr( location, isIncr ? "?+=?" : "?-=?" );
+	ast::UntypedExpr * addAssign = new ast::UntypedExpr( location, opExpr );
+	if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
+		addAssign->args.push_back( address->arg );
+	} else {
+		addAssign->args.push_back( expr->args.front() );
+	}
+	addAssign->args.push_back( new ast::NameExpr( location,
+		sizeofName( Mangle::mangleType( polyType ) ) ) );
+	addAssign->result = ast::deepCopy( expr->result );
+	addAssign->env = expr->env ? expr->env : addAssign->env;
+	return addAssign;
+}
+
+/// Handles intrinsic functions for postvisit ApplicationExpr.
+ast::Expr const * CallAdapter::handleIntrinsics(
+		ast::ApplicationExpr const * expr ) {
+	auto varExpr = expr->func.as<ast::VariableExpr>();
+	if ( !varExpr || varExpr->var->linkage != ast::Linkage::Intrinsic ) {
+		return nullptr;
+	}
+	std::string const & varName = varExpr->var->name;
+
+	// Index Intrinsic:
+	if ( "?[?]" == varName ) {
+		assert( expr->result );
+		assert( 2 == expr->args.size() );
+
+		ast::Type const * baseType1 =
+			isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
+		ast::Type const * baseType2 =
+			isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
+		// If neither argument is a polymorphic pointer, do nothing.
+		if ( !baseType1 && !baseType2 ) {
+			return expr;
+		}
+		// The arguments cannot both be polymorphic pointers.
+		assert( !baseType1 || !baseType2 );
+		// (So exactly one of the arguments is a polymorphic pointer.)
+
+		CodeLocation const & location = expr->location;
+		CodeLocation const & location1 = expr->args.front()->location;
+		CodeLocation const & location2 = expr->args.back()->location;
+
+		ast::UntypedExpr * ret = new ast::UntypedExpr( location,
+				new ast::NameExpr( location, "?+?" ) );
+		if ( baseType1 ) {
+			auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
+				expr->args.back(),
+				new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
+			} );
+			ret->args.push_back( expr->args.front() );
+			ret->args.push_back( multiply );
+		} else {
+			assert( baseType2 );
+			auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
+				expr->args.front(),
+				new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
+			} );
+			ret->args.push_back( multiply );
+			ret->args.push_back( expr->args.back() );
+		}
+		ret->result = ast::deepCopy( expr->result );
+		ret->env = expr->env ? expr->env : ret->env;
+		return ret;
+	// Dereference Intrinsic:
+	} else if ( "*?" == varName ) {
+		assert( expr->result );
+		assert( 1 == expr->args.size() );
+
+		// If this isn't for a poly type, then do nothing.
+		if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
+			return expr;
+		}
+
+		// Remove dereference from polymorphic types since they are boxed.
+		ast::Expr * ret = ast::deepCopy( expr->args.front() );
+		// Fix expression type to remove pointer.
+		ret->result = expr->result;
+		ret->env = expr->env ? expr->env : ret->env;
+		return ret;
+	// Post-Increment/Decrement Intrinsics:
+	} else if ( "?++" == varName || "?--" == varName ) {
+		assert( expr->result );
+		assert( 1 == expr->args.size() );
+
+		ast::Type const * baseType =
+			isPolyType( expr->result, scopeTypeVars, typeSubs );
+		if ( nullptr == baseType ) {
+			return expr;
+		}
+		ast::Type * tempType = ast::deepCopy( expr->result );
+		if ( typeSubs ) {
+			auto result = typeSubs->apply( tempType );
+			tempType = ast::mutate( result.node.release() );
+		}
+		CodeLocation const & location = expr->location;
+		ast::ObjectDecl * newObj = makeTemporary( location, tempType );
+		ast::VariableExpr * tempExpr =
+			new ast::VariableExpr( location, newObj );
+		ast::UntypedExpr * assignExpr = new ast::UntypedExpr( location,
+			new ast::NameExpr( location, "?=?" ) );
+		assignExpr->args.push_back( ast::deepCopy( tempExpr ) );
+		if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
+			assignExpr->args.push_back( ast::deepCopy( address->arg ) );
+		} else {
+			assignExpr->args.push_back( ast::deepCopy( expr->args.front() ) );
+		}
+		return new ast::CommaExpr( location,
+			new ast::CommaExpr( location,
+				assignExpr,
+				makeIncrDecrExpr( location, expr, baseType, "?++" == varName )
+			),
+			tempExpr
+		);
+	// Pre-Increment/Decrement Intrinsics:
+	} else if ( "++?" == varName || "--?" == varName ) {
+		assert( expr->result );
+		assert( 1 == expr->args.size() );
+
+		ast::Type const * baseType =
+			isPolyType( expr->result, scopeTypeVars, typeSubs );
+		if ( nullptr == baseType ) {
+			return expr;
+		}
+		return makeIncrDecrExpr(
+			expr->location, expr, baseType, "++?" == varName );
+	// Addition and Subtration Intrinsics:
+	} else if ( "?+?" == varName || "?-?" == varName ) {
+		assert( expr->result );
+		assert( 2 == expr->args.size() );
+
+		auto baseType1 =
+			isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
+		auto baseType2 =
+			isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
+
+		CodeLocation const & location = expr->location;
+		CodeLocation const & location1 = expr->args.front()->location;
+		CodeLocation const & location2 = expr->args.back()->location;
+		// LHS op RHS -> (LHS op RHS) / sizeof(LHS)
+		if ( baseType1 && baseType2 ) {
+			auto divide = ast::UntypedExpr::createCall( location, "?/?", {
+				expr,
+				new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
+			} );
+			if ( expr->env ) divide->env = expr->env;
+			return divide;
+		// LHS op RHS -> LHS op (RHS * sizeof(LHS))
+		} else if ( baseType1 ) {
+			auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
+				expr->args.back(),
+				new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
+			} );
+			return ast::mutate_field_index(
+				expr, &ast::ApplicationExpr::args, 1, multiply );
+		// LHS op RHS -> (LHS * sizeof(RHS)) op RHS
+		} else if ( baseType2 ) {
+			auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
+				expr->args.front(),
+				new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
+			} );
+			return ast::mutate_field_index(
+				expr, &ast::ApplicationExpr::args, 0, multiply );
+		}
+	// Addition and Subtration Relative Assignment Intrinsics:
+	} else if ( "?+=?" == varName || "?-=?" == varName ) {
+		assert( expr->result );
+		assert( 2 == expr->args.size() );
+
+		CodeLocation const & location1 = expr->args.front()->location;
+		CodeLocation const & location2 = expr->args.back()->location;
+		auto baseType = isPolyPtr( expr->result, scopeTypeVars, typeSubs );
+		// LHS op RHS -> LHS op (RHS * sizeof(LHS))
+		if ( baseType ) {
+			auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
+				expr->args.back(),
+				new ast::SizeofExpr( location1, deepCopy( baseType ) ),
+			} );
+			return ast::mutate_field_index(
+				expr, &ast::ApplicationExpr::args, 1, multiply );
+		}
+	}
+	return expr;
+}
+
+ast::ObjectDecl * CallAdapter::makeTemporary(
+		CodeLocation const & location, ast::Type const * type ) {
+	auto newObj = new ast::ObjectDecl( location, tmpNamer.newName(), type );
+	stmtsToAddBefore.push_back( new ast::DeclStmt( location, newObj ) );
+	return newObj;
+}
+
+// --------------------------------------------------------------------------
+/// Modifies declarations to accept implicit parameters.
+/// * Move polymorphic returns in function types to pointer-type parameters.
+/// * Adds type size and assertion parameters to parameter lists.
+struct DeclAdapter final {
+	ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
+	ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
+private:
+	void addAdapters( ast::FunctionDecl * decl, TypeVarMap & localTypeVars );
+};
+
+// size/align/offset parameters may not be used, so add the unused attribute.
+ast::ObjectDecl * makeObj(
+		CodeLocation const & location, std::string const & name ) {
+	return new ast::ObjectDecl( location, name,
+		makeSizeAlignType(),
+		nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
+		{ new ast::Attribute( "unused" ) } );
+}
+
+ast::ObjectDecl * makePtr(
+		CodeLocation const & location, std::string const & name ) {
+	return new ast::ObjectDecl( location, name,
+		new ast::PointerType( makeSizeAlignType() ),
+		nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr );
+}
+
+ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
+	TypeVarMap localTypeVars = { ast::TypeData() };
+	makeTypeVarMap( decl, localTypeVars );
+
+	auto mutDecl = mutate( decl );
+
+	// Move polymorphic return type to parameter list.
+	if ( isDynRet( mutDecl->type ) ) {
+		auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
+			mutDecl->returns.front().get_and_mutate() );
+		ret->set_type( new ast::PointerType( ret->type ) );
+		mutDecl->params.insert( mutDecl->params.begin(), ret );
+		mutDecl->returns.erase( mutDecl->returns.begin() );
+		ret->init = nullptr;
+	}
+
+	// Add size/align and assertions for type parameters to parameter list.
+	ast::vector<ast::DeclWithType> inferredParams;
+	ast::vector<ast::DeclWithType> layoutParams;
+	for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
+		auto mutParam = mutate( typeParam.get() );
+		// Add all size and alignment parameters to parameter list.
+		if ( mutParam->isComplete() ) {
+			ast::TypeInstType paramType( mutParam );
+			std::string paramName = Mangle::mangleType( &paramType );
+
+			auto sizeParam = makeObj( typeParam->location, sizeofName( paramName ) );
+			layoutParams.emplace_back( sizeParam );
+
+			auto alignParam = makeObj( typeParam->location, alignofName( paramName ) );
+			layoutParams.emplace_back( alignParam );
+		}
+		// TODO: These should possibly all be gone.
+		// More all assertions into parameter list.
+		for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) {
+			// Assertion parameters may not be used in body,
+			// pass along with unused attribute.
+			assert.get_and_mutate()->attributes.push_back(
+				new ast::Attribute( "unused" ) );
+			inferredParams.push_back( assert );
+		}
+		mutParam->assertions.clear();
+		typeParam = mutParam;
+	}
+	// TODO: New version of inner loop.
+	for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
+		// Assertion parameters may not be used in body,
+		// pass along with unused attribute.
+		assert.get_and_mutate()->attributes.push_back(
+			new ast::Attribute( "unused" ) );
+		inferredParams.push_back( assert );
+	}
+	mutDecl->assertions.clear();
+
+	// Add size/align for generic parameter types to parameter list.
+	std::set<std::string> seenTypes;
+	ast::vector<ast::DeclWithType> otypeParams;
+	for ( ast::ptr<ast::DeclWithType> & funcParam : mutDecl->params ) {
+		ast::Type const * polyType = isPolyType( funcParam->get_type(), localTypeVars );
+		if ( !polyType || dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
+			continue;
+		}
+		std::string typeName = Mangle::mangleType( polyType );
+		if ( seenTypes.count( typeName ) ) continue;
+		seenTypes.insert( typeName );
+
+		auto sizeParam = makeObj( funcParam->location, sizeofName( typeName ) );
+		otypeParams.emplace_back( sizeParam );
+
+		auto alignParam = makeObj( funcParam->location, alignofName( typeName ) );
+		otypeParams.emplace_back( alignParam );
+
+		// Zero-length arrays are illegal in C, so empty structs have no
+		// offset array.
+		if ( auto * polyStruct =
+				dynamic_cast<ast::StructInstType const *>( polyType ) ;
+				polyStruct && !polyStruct->base->members.empty() ) {
+			auto offsetParam = makePtr( funcParam->location, offsetofName( typeName ) );
+			otypeParams.emplace_back( offsetParam );
+		}
+	}
+
+	// Prepend each argument group. From last group to first. addAdapters
+	// does do the same, it just does it itself and see all other parameters.
+	spliceBegin( mutDecl->params, inferredParams );
+	spliceBegin( mutDecl->params, otypeParams );
+	spliceBegin( mutDecl->params, layoutParams );
+	addAdapters( mutDecl, localTypeVars );
+
+	return mutDecl;
+}
+
+ast::FunctionDecl const * DeclAdapter::postvisit(
+		ast::FunctionDecl const * decl ) {
+	ast::FunctionDecl * mutDecl = mutate( decl );
+	if ( !mutDecl->returns.empty() && mutDecl->stmts
+			// Intrinsic functions won't be using the _retval so no need to
+			// generate it.
+			&& mutDecl->linkage != ast::Linkage::Intrinsic
+			// Remove check for prefix once thunks properly use ctor/dtors.
+			&& !isPrefix( mutDecl->name, "_thunk" )
+			&& !isPrefix( mutDecl->name, "_adapter" ) ) {
+		assert( 1 == mutDecl->returns.size() );
+		ast::DeclWithType const * retval = mutDecl->returns.front();
+		if ( "" == retval->name ) {
+			retval = ast::mutate_field(
+				retval, &ast::DeclWithType::name, "_retval" );
+			mutDecl->returns.front() = retval;
+		}
+		auto stmts = mutDecl->stmts.get_and_mutate();
+		stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
+		ast::DeclWithType * newRet = ast::deepCopy( retval );
+		mutDecl->returns.front() = newRet;
+	}
+	// Errors should have been caught by this point, remove initializers from
+	// parameters to allow correct codegen of default arguments.
+	for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
+		if ( auto obj = param.as<ast::ObjectDecl>() ) {
+			param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
+		}
+	}
+	// TODO: Can this be updated as we go along?
+	mutDecl->type = makeFunctionType( mutDecl );
+	return mutDecl;
+}
+
+void DeclAdapter::addAdapters(
+		ast::FunctionDecl * mutDecl, TypeVarMap & localTypeVars ) {
+	ast::vector<ast::FunctionType> functions;
+	for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
+		ast::Type const * type = arg->get_type();
+		type = findAndReplaceFunction( type, functions, localTypeVars, needsAdapter );
+		arg.get_and_mutate()->set_type( type );
+	}
+	std::set<std::string> adaptersDone;
+	for ( ast::ptr<ast::FunctionType> const & func : functions ) {
+		std::string mangleName = mangleAdapterName( func, localTypeVars );
+		if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
+			continue;
+		}
+		std::string adapterName = makeAdapterName( mangleName );
+		// The adapter may not actually be used, so make sure it has unused.
+		mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
+			mutDecl->location, adapterName,
+			new ast::PointerType( makeAdapterType( func, localTypeVars ) ),
+			nullptr, {}, {}, nullptr,
+			{ new ast::Attribute( "unused" ) } ) );
+		adaptersDone.insert( adaptersDone.begin(), mangleName );
+	}
+}
+
+// --------------------------------------------------------------------------
+// TODO: Ideally, there would be no floating nodes at all.
+/// Corrects the floating nodes created in CallAdapter.
+struct RewireAdapters final : public ast::WithGuards {
+	ScopedMap<std::string, ast::ObjectDecl const *> adapters;
+	void beginScope() { adapters.beginScope(); }
+	void endScope() { adapters.endScope(); }
+	void previsit( ast::FunctionDecl const * decl );
+	ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
+};
+
+void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
+	GuardScope( adapters );
+	for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
+		if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
+			adapters.insert( objectParam->name, objectParam );
+		}
+	}
+}
+
+ast::VariableExpr const * RewireAdapters::previsit(
+		ast::VariableExpr const * expr ) {
+	// If the node is not floating, we can skip.
+	if ( expr->var->isManaged() ) return expr;
+	auto it = adapters.find( expr->var->name );
+	assertf( it != adapters.end(), "Could not correct floating node." );
+	return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
+
+}
+
+// --------------------------------------------------------------------------
+/// Inserts code to access polymorphic layout inforation.
+/// * Replaces member and size/alignment/offsetof expressions on polymorphic
+///   generic types with calculated expressions.
+/// * Replaces member expressions for polymorphic types with calculated
+///   add-field-offset-and-dereference.
+/// * Calculates polymorphic offsetof expressions from offset array.
+/// * Inserts dynamic calculation of polymorphic type layouts where needed.
+struct PolyGenericCalculator final :
+		public BoxPass,
+		public ast::WithConstTypeSubstitution,
+		public ast::WithDeclsToAdd<>,
+		public ast::WithGuards,
+		public ast::WithStmtsToAdd<>,
+		public ast::WithVisitorRef<PolyGenericCalculator> {
+	PolyGenericCalculator();
+
+	void previsit( ast::ObjectDecl const * decl );
+	void previsit( ast::FunctionDecl const * decl );
+	void previsit( ast::TypedefDecl const * decl );
+	void previsit( ast::TypeDecl const * decl );
+	ast::Decl const * postvisit( ast::TypeDecl const * decl );
+	ast::StructDecl const * previsit( ast::StructDecl const * decl );
+	ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
+	void previsit( ast::PointerType const * type );
+	void previsit( ast::FunctionType const * type );
+	ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
+	ast::Expr const * postvisit( ast::MemberExpr const * expr );
+	void previsit( ast::AddressExpr const * expr );
+	ast::Expr const * postvisit( ast::AddressExpr const * expr );
+	ast::Expr const * postvisit( ast::SizeofExpr const * expr );
+	ast::Expr const * postvisit( ast::AlignofExpr const * expr );
+	ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
+	ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
+
+	void beginScope();
+	void endScope();
+private:
+	/// Makes a new variable in the current scope with the given name,
+	/// type and optional initializer.
+	ast::ObjectDecl * makeVar(
+			CodeLocation const & location, std::string const & name,
+			ast::Type const * type, ast::Init const * init = nullptr );
+	/// Returns true if the type has a dynamic layout;
+	/// such a layout will be stored in appropriately-named local variables
+	/// when the function returns.
+	bool findGeneric( CodeLocation const & location, ast::Type const * );
+	/// Adds type parameters to the layout call; will generate the
+	/// appropriate parameters if needed.
+	void addSTypeParamsToLayoutCall(
+		ast::UntypedExpr * layoutCall,
+		const ast::vector<ast::Type> & otypeParams );
+	/// Change the type of generic aggregate members to char[].
+	void mutateMembers( ast::AggregateDecl * aggr );
+	/// Returns the calculated sizeof expression for type, or nullptr for use
+	/// C sizeof().
+	ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
+
+	/// Enters a new scope for type-variables,
+	/// adding the type variables from the provided type.
+	void beginTypeScope( ast::Type const * );
+	/// Enters a new scope for known layouts and offsets, and queues exit calls.
+	void beginGenericScope();
+
+	/// Set of generic type layouts known in the current scope,
+	/// indexed by sizeofName.
+	ScopedSet<std::string> knownLayouts;
+	/// Set of non-generic types for which the offset array exists in the
+	/// current scope, indexed by offsetofName.
+	ScopedSet<std::string> knownOffsets;
+	/// Namer for VLA (variable length array) buffers.
+	UniqueName bufNamer;
+	/// If the argument of an AddressExpr is MemberExpr, it is stored here.
+	ast::MemberExpr const * addrMember = nullptr;
+	/// Used to avoid recursing too deep in type declarations.
+	bool expect_func_type = false;
+};
+
+PolyGenericCalculator::PolyGenericCalculator() :
+	knownLayouts(), knownOffsets(), bufNamer( "_buf" )
+{}
+
+/// Converts polymorphic type into a suitable monomorphic representation.
+/// Currently: __attribute__((aligned(8) )) char[size_T];
+ast::Type * polyToMonoType( CodeLocation const & location,
+		ast::Type const * declType ) {
+	auto charType = new ast::BasicType( ast::BasicType::Char );
+	auto size = new ast::NameExpr( location,
+		sizeofName( Mangle::mangleType( declType ) ) );
+	auto aligned = new ast::Attribute( "aligned",
+		{ ast::ConstantExpr::from_int( location, 8 ) } );
+	auto ret = new ast::ArrayType( charType, size,
+		ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
+	ret->attributes.push_back( aligned );
+	return ret;
+}
+
+void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
+	beginTypeScope( decl->type );
+}
+
+void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
+	beginGenericScope();
+	beginTypeScope( decl->type );
+
+	// TODO: Going though dec->params does not work for some reason.
+	for ( ast::ptr<ast::Type> const & funcParam : decl->type->params ) {
+		// Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
+		ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
+		if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
+			knownLayouts.insert( Mangle::mangleType( polyType ) );
+		}
+	}
+}
+
+void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
+	assertf( false, "All typedef declarations should be removed." );
+	beginTypeScope( decl->base );
+}
+
+void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
+	addToTypeVarMap( decl, scopeTypeVars );
+}
+
+ast::Decl const * PolyGenericCalculator::postvisit(
+		ast::TypeDecl const * decl ) {
+	ast::Type const * base = decl->base;
+	if ( nullptr == base) return decl;
+
+	// Add size/align variables for opaque type declarations.
+	ast::TypeInstType inst( decl->name, decl );
+	std::string typeName = Mangle::mangleType( &inst );
+	ast::Type * layoutType = new ast::BasicType(
+		ast::BasicType::LongUnsignedInt );
+
+	ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
+		sizeofName( typeName ), layoutType,
+		new ast::SingleInit( decl->location,
+			new ast::SizeofExpr( decl->location, deepCopy( base ) )
+		)
+	);
+	ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
+		alignofName( typeName ), layoutType,
+		new ast::SingleInit( decl->location,
+			new ast::AlignofExpr( decl->location, deepCopy( base ) )
+		)
+	);
+
+	// Ensure that the initializing sizeof/alignof exprs are properly mutated.
+	sizeDecl->accept( *visitor );
+	alignDecl->accept( *visitor );
+
+	// Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
+	// can occur at global scope.
+	declsToAddAfter.push_back( alignDecl );
+	// replace with sizeDecl.
+	return sizeDecl;
+}
+
+ast::StructDecl const * PolyGenericCalculator::previsit(
+		ast::StructDecl const * decl ) {
+	auto mutDecl = mutate( decl );
+	mutateMembers( mutDecl );
+	return mutDecl;
+}
+
+ast::UnionDecl const * PolyGenericCalculator::previsit(
+		ast::UnionDecl const * decl ) {
+	auto mutDecl = mutate( decl );
+	mutateMembers( mutDecl );
+	return mutDecl;
+}
+
+void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
+	beginTypeScope( type );
+}
+
+void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {
+	beginTypeScope( type );
+
+	GuardValue( expect_func_type );
+	GuardScope( *this );
+
+	// The other functions type we will see in this scope are probably
+	// function parameters they don't help us with the layout and offsets so
+	// don't mark them as known in this scope.
+	expect_func_type = false;
+
+	// Make sure that any type information passed into the function is
+	// accounted for.
+	for ( ast::ptr<ast::Type> const & funcParam : type->params ) {
+		// Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
+		ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
+		if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
+			knownLayouts.insert( Mangle::mangleType( polyType ) );
+		}
+	}
+}
+
+//void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
+ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
+	ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
+	if ( !decl || !findGeneric( decl->location, decl->type ) ) {
+		return stmt;
+	}
+
+	// Change initialization of a polymorphic value object to allocate via a
+	// variable-length-array (alloca was previouly used, but it cannot be
+	// safely used in loops).
+	ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
+		bufNamer.newName(),
+		polyToMonoType( decl->location, decl->type ),
+		nullptr, {}, ast::Linkage::C
+	);
+	stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
+
+	// If the object has a cleanup attribute, the clean-up should be on the
+	// buffer, not the pointer. [Perhaps this should be lifted?]
+	auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
+		if ( "cleanup" == attr->name ) {
+			newBuf->attributes.push_back( attr );
+			return true;
+		}
+		return false;
+	};
+
+	auto mutDecl = mutate( decl );
+
+	// Forally, side effects are not safe in this function. But it works.
+	erase_if( mutDecl->attributes, matchAndMove );
+
+	mutDecl->init = new ast::SingleInit( decl->location,
+		new ast::VariableExpr( decl->location, newBuf ) );
+
+	return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
+}
+
+/// Checks if memberDecl matches the decl from an aggregate.
+bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
+	// No matter the field, if the name is different it is not the same.
+	if ( memberDecl->name != decl->name ) {
+		return false;
+	}
+
+	if ( memberDecl->name.empty() ) {
+		// Plan-9 Field: Match on unique_id.
+		return ( memberDecl->uniqueId == decl->uniqueId );
+	}
+
+	ast::DeclWithType const * declWithType =
+		strict_dynamic_cast<ast::DeclWithType const *>( decl );
+
+	if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
+		// Tuple-Element Field: Expect neither had mangled name;
+		// accept match on simple name (like field_2) only.
+		assert( memberDecl->mangleName.empty() );
+		assert( declWithType->mangleName.empty() );
+		return true;
+	}
+
+	// Ordinary Field: Use full name to accommodate overloading.
+	return ( memberDecl->mangleName == declWithType->mangleName );
+}
+
+/// Finds the member in the base list that matches the given declaration;
+/// returns its index, or -1 if not present.
+long findMember( ast::DeclWithType const * memberDecl,
+		const ast::vector<ast::Decl> & baseDecls ) {
+	for ( auto pair : enumerate( baseDecls ) ) {
+		if ( isMember( memberDecl, pair.val.get() ) ) {
+			return pair.idx;
+		}
+	}
+	return -1;
+}
+
+/// Returns an index expression into the offset array for a type.
+ast::Expr * makeOffsetIndex( CodeLocation const & location,
+		ast::Type const * objectType, long i ) {
+	std::string name = offsetofName( Mangle::mangleType( objectType ) );
+	return ast::UntypedExpr::createCall( location, "?[?]", {
+		new ast::NameExpr( location, name ),
+		ast::ConstantExpr::from_ulong( location, i ),
+	} );
+}
+
+ast::Expr const * PolyGenericCalculator::postvisit(
+		ast::MemberExpr const * expr ) {
+	// Only mutate member expressions for polymorphic types.
+	ast::Type const * objectType = hasPolyBase(
+		expr->aggregate->result, scopeTypeVars
+	);
+	if ( !objectType ) return expr;
+	// Ensure layout for this type is available.
+	// The boolean result is ignored.
+	findGeneric( expr->location, objectType );
+
+	// Replace member expression with dynamically-computed layout expression.
+	ast::Expr * newMemberExpr = nullptr;
+	if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
+		long offsetIndex = findMember( expr->member, structType->base->members );
+		if ( -1 == offsetIndex ) return expr;
+
+		// Replace member expression with pointer to struct plus offset.
+		ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
+				new ast::NameExpr( expr->location, "?+?" ) );
+		ast::Expr * aggr = deepCopy( expr->aggregate );
+		aggr->env = nullptr;
+		fieldLoc->args.push_back( aggr );
+		fieldLoc->args.push_back(
+			makeOffsetIndex( expr->location, objectType, offsetIndex ) );
+		fieldLoc->result = deepCopy( expr->result );
+		newMemberExpr = fieldLoc;
+	// Union members are all at offset zero, so just use the aggregate expr.
+	} else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
+		ast::Expr * aggr = deepCopy( expr->aggregate );
+		aggr->env = nullptr;
+		aggr->result = deepCopy( expr->result );
+		newMemberExpr = aggr;
+	} else {
+		return expr;
+	}
+	assert( newMemberExpr );
+
+	// Must apply the generic substitution to the member type to handle cases
+	// where the member is a generic parameter subsituted by a known concrete
+	// type. [ex]
+	//	forall( T ) struct Box { T x; }
+	//	forall( T ) void f() {
+	//		Box( T * ) b; b.x;
+	//	}
+	// TODO: expr->result should be exactly expr->member->get_type() after
+	// substitution, so it doesn't seem like it should be necessary to apply
+	// the substitution manually. For some reason this is not currently the
+	// case. This requires more investigation.
+	ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
+	ast::TypeSubstitution sub = genericSubstitution( objectType );
+	sub.apply( memberType );
+
+	// Not all members of a polymorphic type are themselves of a polymorphic
+	// type; in this cas the member expression should be wrapped and
+	// dereferenced to form an lvalue.
+	if ( !isPolyType( memberType, scopeTypeVars ) ) {
+		auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
+			new ast::PointerType( memberType ) );
+		auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
+			ptrCastExpr );
+		newMemberExpr = derefExpr;
+	}
+
+	return newMemberExpr;
+}
+
+void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
+	GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
+}
+
+ast::Expr const * PolyGenericCalculator::postvisit(
+		ast::AddressExpr const * expr ) {
+	// arg has to have been a MemberExpr and has been mutated.
+	if ( nullptr == addrMember || expr->arg == addrMember ) {
+		return expr;
+	}
+	ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
+	if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
+		return expr;
+	}
+	// MemberExpr was converted to pointer + offset; and it is not valid C to
+	// take the address of an addition, so strip away the address-of.
+	// It also preserves the env value.
+	return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
+}
+
+ast::Expr const * PolyGenericCalculator::postvisit(
+		ast::SizeofExpr const * expr ) {
+	ast::Type const * type = expr->type ? expr->type : expr->expr->result;
+	ast::Expr const * gen = genSizeof( expr->location, type );
+	return ( gen ) ? gen : expr;
+}
+
+ast::Expr const * PolyGenericCalculator::postvisit(
+		ast::AlignofExpr const * expr ) {
+	ast::Type const * type = expr->type ? expr->type : expr->expr->result;
+	if ( findGeneric( expr->location, type ) ) {
+		return new ast::NameExpr( expr->location,
+			alignofName( Mangle::mangleType( type ) ) );
+	} else {
+		return expr;
+	}
+}
+
+ast::Expr const * PolyGenericCalculator::postvisit(
+		ast::OffsetofExpr const * expr ) {
+	ast::Type const * type = expr->type;
+	if ( !findGeneric( expr->location, type ) ) return expr;
+
+	// Structures replace offsetof expression with an index into offset array.
+	if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
+		long offsetIndex = findMember( expr->member, structType->base->members );
+		if ( -1 == offsetIndex ) return expr;
+
+		return makeOffsetIndex( expr->location, type, offsetIndex );
+	// All union members are at offset zero.
+	} else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
+		return ast::ConstantExpr::from_ulong( expr->location, 0 );
+	} else {
+		return expr;
+	}
+}
+
+ast::Expr const * PolyGenericCalculator::postvisit(
+		ast::OffsetPackExpr const * expr ) {
+	ast::StructInstType const * type = expr->type;
+
+	// Pull offset back from generated type information.
+	if ( findGeneric( expr->location, type ) ) {
+		return new ast::NameExpr( expr->location,
+			offsetofName( Mangle::mangleType( type ) ) );
+	}
+
+	std::string offsetName = offsetofName( Mangle::mangleType( type ) );
+	// Use the already generated offsets for this type.
+	if ( knownOffsets.contains( offsetName ) ) {
+		return new ast::NameExpr( expr->location, offsetName );
+	}
+
+	knownOffsets.insert( offsetName );
+
+	auto baseMembers = type->base->members;
+	ast::Type const * offsetType = new ast::BasicType(
+		ast::BasicType::LongUnsignedInt );
+
+	// Build initializer list for offset array.
+	ast::vector<ast::Init> inits;
+	for ( ast::ptr<ast::Decl> & member : baseMembers ) {
+		auto memberDecl = member.as<ast::DeclWithType>();
+		assertf( memberDecl, "Requesting offset of non-DWT member: %s",
+			toCString( member ) );
+		inits.push_back( new ast::SingleInit( expr->location,
+			new ast::OffsetofExpr( expr->location,
+				deepCopy( type ),
+				memberDecl
+			)
+		) );
+	}
+
+	auto offsetArray = makeVar( expr->location, offsetName,
+		new ast::ArrayType(
+			offsetType,
+			ast::ConstantExpr::from_ulong( expr->location, baseMembers.size() ),
+			ast::FixedLen,
+			ast::DynamicDim
+		),
+		new ast::ListInit( expr->location, std::move( inits ) )
+	);
+
+	return new ast::VariableExpr( expr->location, offsetArray );
+}
+
+void PolyGenericCalculator::beginScope() {
+	knownLayouts.beginScope();
+	knownOffsets.beginScope();
+}
+
+void PolyGenericCalculator::endScope() {
+	knownOffsets.endScope();
+	knownLayouts.endScope();
+}
+
+ast::ObjectDecl * PolyGenericCalculator::makeVar(
+		CodeLocation const & location, std::string const & name,
+		ast::Type const * type, ast::Init const * init ) {
+	ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
+	stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
+	return ret;
+}
+
+/// Returns true if any of the otype parameters have a dynamic layout; and
+/// puts all otype parameters in the output list.
+bool findGenericParams(
+		ast::vector<ast::Type> & out,
+		ast::vector<ast::TypeDecl> const & baseParams,
+		ast::vector<ast::Expr> const & typeParams ) {
+	bool hasDynamicLayout = false;
+
+	for ( auto pair : group_iterate( baseParams, typeParams ) ) {
+		auto baseParam = std::get<0>( pair );
+		auto typeParam = std::get<1>( pair );
+		if ( !baseParam->isComplete() ) continue;
+		ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
+		assertf( typeExpr, "All type parameters should be type expressions." );
+
+		ast::Type const * type = typeExpr->type.get();
+		out.push_back( type );
+		if ( isPolyType( type ) ) hasDynamicLayout = true;
+	}
+
+	return hasDynamicLayout;
+}
+
+bool PolyGenericCalculator::findGeneric(
+		CodeLocation const & location, ast::Type const * type ) {
+	type = replaceTypeInst( type, typeSubs );
+
+	if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
+		// Assumes that getting put in the scopeTypeVars includes having the
+		// layout variables set.
+		if ( scopeTypeVars.contains( *inst ) ) {
+			return true;
+		}
+	} else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
+		// Check if this type already has a layout generated for it.
+		std::string typeName = Mangle::mangleType( type );
+		if ( knownLayouts.contains( typeName ) ) return true;
+
+		// Check if any type parameters have dynamic layout;
+		// If none do, this type is (or will be) monomorphized.
+		ast::vector<ast::Type> sizedParams;
+		if ( !findGenericParams( sizedParams,
+				inst->base->params, inst->params ) ) {
+			return false;
+		}
+
+		// Insert local variables for layout and generate call to layout
+		// function.
+		// Done early so as not to interfere with the later addition of
+		// parameters to the layout call.
+		knownLayouts.insert( typeName );
+		ast::Type const * layoutType = makeSizeAlignType();
+
+		int memberCount = inst->base->members.size();
+		if ( 0 == memberCount ) {
+			// All empty structures have the same layout (size 1, align 1).
+			makeVar( location,
+				sizeofName( typeName ), layoutType,
+				new ast::SingleInit( location,
+						ast::ConstantExpr::from_ulong( location, 1 ) ) );
+			makeVar( location,
+				alignofName( typeName ), ast::deepCopy( layoutType ),
+				new ast::SingleInit( location,
+						ast::ConstantExpr::from_ulong( location, 1 ) ) );
+			// Since 0-length arrays are forbidden in C, skip the offset array.
+		} else {
+			ast::ObjectDecl const * sizeofVar = makeVar( location,
+				sizeofName( typeName ), deepCopy( layoutType ), nullptr );
+			ast::ObjectDecl const * alignofVar = makeVar( location,
+				alignofName( typeName ), deepCopy( layoutType ), nullptr );
+			ast::ObjectDecl const * offsetofVar = makeVar( location,
+				offsetofName( typeName ),
+				new ast::ArrayType(
+					layoutType,
+					ast::ConstantExpr::from_int( location, memberCount ),
+					ast::FixedLen,
+					ast::DynamicDim
+				),
+				nullptr
+			);
+
+			// Generate call to layout function.
+			ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
+				new ast::NameExpr( location, layoutofName( inst->base ) ),
+				{
+					new ast::AddressExpr(
+						new ast::VariableExpr( location, sizeofVar ) ),
+					new ast::AddressExpr(
+						new ast::VariableExpr( location, alignofVar ) ),
+					new ast::VariableExpr( location, offsetofVar ),
+				} );
+
+			addSTypeParamsToLayoutCall( layoutCall, sizedParams );
+
+			stmtsToAddBefore.emplace_back(
+				new ast::ExprStmt( location, layoutCall ) );
+		}
+
+		return true;
+	} else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
+		// Check if this type already has a layout generated for it.
+		std::string typeName = Mangle::mangleType( type );
+		if ( knownLayouts.contains( typeName ) ) return true;
+
+		// Check if any type parameters have dynamic layout;
+		// If none do, this type is (or will be) monomorphized.
+		ast::vector<ast::Type> sizedParams;
+		if ( !findGenericParams( sizedParams,
+				inst->base->params, inst->params ) ) {
+			return false;
+		}
+
+		// Insert local variables for layout and generate call to layout
+		// function.
+		// Done early so as not to interfere with the later addition of
+		// parameters to the layout call.
+		knownLayouts.insert( typeName );
+		ast::Type const * layoutType = makeSizeAlignType();
+
+		ast::ObjectDecl * sizeofVar = makeVar( location,
+			sizeofName( typeName ), layoutType );
+		ast::ObjectDecl * alignofVar = makeVar( location,
+			alignofName( typeName ), ast::deepCopy( layoutType ) );
+
+		ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
+			new ast::NameExpr( location, layoutofName( inst->base ) ),
+			{
+				new ast::AddressExpr(
+					new ast::VariableExpr( location, sizeofVar ) ),
+				new ast::AddressExpr(
+					new ast::VariableExpr( location, alignofVar ) ),
+			} );
+
+		addSTypeParamsToLayoutCall( layoutCall, sizedParams );
+
+		stmtsToAddBefore.emplace_back(
+			new ast::ExprStmt( location, layoutCall ) );
+
+		return true;
+	}
+	return false;
+}
+
+void PolyGenericCalculator::addSTypeParamsToLayoutCall(
+		ast::UntypedExpr * layoutCall,
+		const ast::vector<ast::Type> & otypeParams ) {
+	CodeLocation const & location = layoutCall->location;
+	ast::vector<ast::Expr> & args = layoutCall->args;
+	for ( ast::ptr<ast::Type> const & param : otypeParams ) {
+		if ( findGeneric( location, param ) ) {
+			// Push size/align vars for a generic parameter back.
+			std::string paramName = Mangle::mangleType( param );
+			args.emplace_back(
+				new ast::NameExpr( location, sizeofName( paramName ) ) );
+			args.emplace_back(
+				new ast::NameExpr( location, alignofName( paramName ) ) );
+		} else {
+			args.emplace_back(
+				new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
+			args.emplace_back(
+				new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
+		}
+	}
+}
+
+void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
+	std::set<std::string> genericParams;
+	for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
+		genericParams.insert( decl->name );
+	}
+	for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
+		auto field = decl.as<ast::ObjectDecl>();
+		if ( nullptr == field ) continue;
+
+		ast::Type const * type = replaceTypeInst( field->type, typeSubs );
+		auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
+		if ( nullptr == typeInst ) continue;
+
+		// Do not try to monoporphize generic parameters.
+		if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
+				!genericParams.count( typeInst->name ) ) {
+			// Polymorphic aggregate members should be converted into
+			// monomorphic members. Using char[size_T] here respects
+			// the expected sizing rules of an aggregate type.
+			decl = ast::mutate_field( field, &ast::ObjectDecl::type,
+				polyToMonoType( field->location, field->type ) );
+		}
+	}
+}
+
+ast::Expr const * PolyGenericCalculator::genSizeof(
+		CodeLocation const & location, ast::Type const * type ) {
+	if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
+		// Generate calculated size for possibly generic array.
+		ast::Expr const * sizeofBase = genSizeof( location, array->base );
+		if ( nullptr == sizeofBase ) return nullptr;
+		ast::Expr const * dim = array->dimension;
+		return makeOp( location, "?*?", sizeofBase, dim );
+	} else if ( findGeneric( location, type ) ) {
+		// Generate calculated size for generic type.
+		return new ast::NameExpr( location, sizeofName(
+				Mangle::mangleType( type ) ) );
+	} else {
+		return nullptr;
+	}
+}
+
+void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
+	GuardScope( scopeTypeVars );
+	makeTypeVarMap( type, scopeTypeVars );
+}
+
+void PolyGenericCalculator::beginGenericScope() {
+	GuardScope( *this );
+	// We expect the first function type see to be the type relating to this
+	// scope but any further type is probably some unrelated function pointer
+	// keep track of whrich is the first.
+	GuardValue( expect_func_type ) = true;
+}
+
+// --------------------------------------------------------------------------
+/// No common theme found.
+/// * Replaces initialization of polymorphic values with alloca.
+/// * Replaces declaration of dtype/ftype with appropriate void expression.
+/// * Replaces sizeof expressions of polymorphic types with a variable.
+/// * Strips fields from generic structure declarations.
+struct Eraser final :
+		public BoxPass,
+		public ast::WithGuards {
+	void guardTypeVarMap( ast::Type const * type ) {
+		GuardScope( scopeTypeVars );
+		makeTypeVarMap( type, scopeTypeVars );
+	}
+
+	ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
+	ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
+	ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
+	ast::StructDecl const * previsit( ast::StructDecl const * decl );
+	ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
+	void previsit( ast::TypeDecl const * decl );
+	void previsit( ast::PointerType const * type );
+	void previsit( ast::FunctionType const * type );
+};
+
+ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
+	guardTypeVarMap( decl->type );
+	return scrubAllTypeVars( decl );
+}
+
+ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
+	guardTypeVarMap( decl->type );
+	return scrubAllTypeVars( decl );
+}
+
+ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
+	guardTypeVarMap( decl->base );
+	return scrubAllTypeVars( decl );
+}
+
+/// Strips the members from a generic aggregate.
+template<typename node_t>
+node_t const * stripGenericMembers( node_t const * decl ) {
+	if ( decl->params.empty() ) return decl;
+	auto mutDecl = ast::mutate( decl );
+	mutDecl->members.clear();
+	return mutDecl;
+}
+
+ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
+	return stripGenericMembers( decl );
+}
+
+ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
+	return stripGenericMembers( decl );
+}
+
+void Eraser::previsit( ast::TypeDecl const * decl ) {
+	addToTypeVarMap( decl, scopeTypeVars );
+}
+
+void Eraser::previsit( ast::PointerType const * type ) {
+	guardTypeVarMap( type );
+}
+
+void Eraser::previsit( ast::FunctionType const * type ) {
+	guardTypeVarMap( type );
+}
+
+} // namespace
+
+// --------------------------------------------------------------------------
+void box( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
+	ast::Pass<CallAdapter>::run( translationUnit );
+	ast::Pass<DeclAdapter>::run( translationUnit );
+	ast::Pass<RewireAdapters>::run( translationUnit );
+	ast::Pass<PolyGenericCalculator>::run( translationUnit );
+	ast::Pass<Eraser>::run( translationUnit );
+}
+
+} // namespace GenPoly
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/GenPoly/InstantiateGeneric.h
===================================================================
--- src/GenPoly/InstantiateGeneric.h	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/GenPoly/InstantiateGeneric.h	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// InstantiateGeneric.h --
+// InstantiateGeneric.h -- Create concrete instances of generic types.
 //
 // Author           : Aaron B. Moss
@@ -24,10 +24,12 @@
 
 namespace GenPoly {
-/// Replaces all generic types that have static layout with concrete
-/// instantiations. Types with concrete values for otype parameters will be
-/// template-expanded, while dtype and ftype parameters will be replaced by
-/// the appropriate void type.
+
 void instantiateGeneric( std::list< Declaration* > &translationUnit );
 void instantiateGeneric( ast::TranslationUnit & translationUnit );
+/// Replaces all generic types that have static layout with concrete
+/// instantiations. Sized types are replaced with the concrete argument types
+/// while unsized types are erased to a void type.
+/// This pass can cause designators to ignore the pretty print option.
+
 } // namespace GenPoly
 
Index: src/GenPoly/InstantiateGenericNew.cpp
===================================================================
--- src/GenPoly/InstantiateGenericNew.cpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/GenPoly/InstantiateGenericNew.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// InstantiateGenericNew.cpp --
+// InstantiateGenericNew.cpp -- Create concrete instances of generic types.
 //
 // Author           : Andrew Beach
@@ -335,10 +335,8 @@
 ast::Expr const * FixDtypeStatic::postvisit( ast::MemberExpr const * expr ) {
 	ast::ptr<ast::Type> const & type = expr->aggregate->result;
-	if ( !isGenericType( type ) ) {
-		return expr;
-	} else if ( auto inst = type.as<ast::StructInstType>() ) {
-		return fixMemberExpr( inst, expr );
+	if ( auto inst = type.as<ast::StructInstType>() ) {
+		if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
 	} else if ( auto inst = type.as<ast::UnionInstType>() ) {
-		return fixMemberExpr( inst, expr );
+		if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
 	}
 	return expr;
@@ -451,6 +449,9 @@
 	ast::Expr const * postvisit( ast::MemberExpr const * expr );
 	ast::Expr const * postvisit( ast::Expr const * expr );
-	void previsit( ast::ParseNode const * node );
-
+	ast::Designation const * postvisit( ast::Designation const * );
+
+	void previsit( ast::ParseNode const * node ) {
+		GuardValue( location ) = &node->location;
+	}
 	void previsit( ast::FunctionType const * ) {
 		GuardValue( inFunctionType ) = true;
@@ -628,6 +629,29 @@
 }
 
-void GenericInstantiator::previsit( ast::ParseNode const * node ) {
-	GuardValue( location ) = &node->location;
+// This attempts to figure out what the final name of the field will be.
+// Pretty printing can cause this to become incorrect.
+std::string getPrintName( ast::DeclWithType const * decl ) {
+	return ( decl->linkage.is_mangled )
+		? decl->scopedMangleName() : decl->name;
+}
+
+ast::Designation const * GenericInstantiator::postvisit(
+		ast::Designation const * designation ) {
+	// Disconnect designator names from their fields.
+	// It is now incorrect to point at the generic definition where the used
+	// type now is replaced with a concrete instance. Ideally, new variable
+	// expressions would point at fields in the concrete instances, but that
+	// is work and that information should not be needed this late in
+	// compilation.
+
+	// Modify all designations, even if not needed.
+	auto mutNode = mutate( designation );
+	for ( ast::ptr<ast::Expr> & designator : mutNode->designators ) {
+		if ( auto var = designator.as<ast::VariableExpr>() ) {
+			designator = new ast::NameExpr(
+				var->location, getPrintName( var->var ) );
+		}
+	}
+	return mutNode;
 }
 
Index: src/GenPoly/module.mk
===================================================================
--- src/GenPoly/module.mk	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/GenPoly/module.mk	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -22,4 +22,5 @@
 
 SRC += $(SRC_GENPOLY) \
+	GenPoly/BoxNew.cpp \
 	GenPoly/Box.cc \
 	GenPoly/Box.h \
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/Parser/StatementNode.cc	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -498,4 +498,9 @@
 } // build_mutex
 
+ast::Stmt * build_corun( const CodeLocation & location, StatementNode * stmt ) {
+	ast::Stmt * body = maybeMoveBuild( stmt );
+	return new ast::CorunStmt( location, body );
+} // build_corun
+
 // Local Variables: //
 // tab-width: 4 //
Index: src/Parser/StatementNode.h
===================================================================
--- src/Parser/StatementNode.h	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/Parser/StatementNode.h	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -105,2 +105,3 @@
 ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
+ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt );
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/Parser/lex.ll	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
  * Created On       : Sat Sep 22 08:58:10 2001
  * Last Modified By : Peter A. Buhr
- * Last Modified On : Fri Jun  9 10:04:00 2023
- * Update Count     : 770
+ * Last Modified On : Tue Oct  3 17:10:57 2023
+ * Update Count     : 773
  */
 
@@ -217,5 +217,7 @@
 
 				/* keywords */
+alignas			{ KEYWORD_RETURN(ALIGNAS); }			// CFA
 _Alignas		{ KEYWORD_RETURN(ALIGNAS); }			// C11
+alignof			{ KEYWORD_RETURN(ALIGNOF); }			// CFA
 _Alignof		{ KEYWORD_RETURN(ALIGNOF); }			// C11
 __alignof		{ KEYWORD_RETURN(ALIGNOF); }			// GCC
@@ -239,4 +241,6 @@
 choose			{ KEYWORD_RETURN(CHOOSE); }				// CFA
 coerce			{ KEYWORD_RETURN(COERCE); }				// CFA
+corun			{ KEYWORD_RETURN(CORUN); }				// CFA
+cofor			{ KEYWORD_RETURN(COFOR); }				// CFA
 _Complex		{ KEYWORD_RETURN(COMPLEX); }			// C99
 __complex		{ KEYWORD_RETURN(COMPLEX); }			// GCC
@@ -319,5 +323,5 @@
 static			{ KEYWORD_RETURN(STATIC); }
 _Static_assert	{ KEYWORD_RETURN(STATICASSERT); }		// C11
-_static_assert	{ KEYWORD_RETURN(STATICASSERT); }		// C23
+static_assert	{ KEYWORD_RETURN(STATICASSERT); }		// C23
 struct			{ KEYWORD_RETURN(STRUCT); }
 suspend			{ KEYWORD_RETURN(SUSPEND); }			// CFA
@@ -326,4 +330,5 @@
 __thread		{ KEYWORD_RETURN(THREADLOCALGCC); }		// GCC
 _Thread_local	{ KEYWORD_RETURN(THREADLOCALC11); }		// C11
+thread_local	{ KEYWORD_RETURN(THREADLOCALC11); }		// C23
 throw			{ KEYWORD_RETURN(THROW); }				// CFA
 throwResume		{ KEYWORD_RETURN(THROWRESUME); }		// CFA
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/Parser/parser.yy	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Sep  4 18:28:12 2023
-// Update Count     : 6393
+// Last Modified On : Tue Oct  3 17:14:12 2023
+// Update Count     : 6396
 //
 
@@ -350,4 +350,5 @@
 %token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
 %token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR WAITUNTIL // CFA
+%token CORUN COFOR
 %token DISABLE ENABLE TRY THROW THROWRESUME AT			// CFA
 %token ASM												// C99, extension ISO/IEC 9899:1999 Section J.5.10(1)
@@ -422,4 +423,5 @@
 %type<stmt> with_statement
 %type<expr> with_clause_opt
+%type<stmt> corun_statement				cofor_statement
 %type<stmt> exception_statement
 %type<clause> handler_clause			finally_clause
@@ -1140,4 +1142,6 @@
 	| waitfor_statement
 	| waituntil_statement
+	| corun_statement
+	| cofor_statement
 	| exception_statement
 	| enable_disable_statement
@@ -1713,4 +1717,14 @@
 	wor_waituntil_clause								%prec THEN
 		{ $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) );	}
+	;
+
+corun_statement:
+	CORUN statement
+		{ $$ = new StatementNode( build_corun( yylloc, $2 ) ); }
+	;
+
+cofor_statement:
+	COFOR '(' for_control_expression_list ')' statement
+		{ SemanticError( yylloc, "cofor statement is currently unimplemented." ); $$ = nullptr; }
 	;
 
Index: src/ResolvExpr/EraseWith.cpp
===================================================================
--- src/ResolvExpr/EraseWith.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ src/ResolvExpr/EraseWith.cpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,46 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// EraseWith.cpp -- After resolution, erase all with constructs.
+//
+// Author           : Andrew Beach
+// Created On       : Sun Oct  8  9:42:00 2023
+// Last Modified By : Andrew Beach
+// Last Modified On : Sun Oct  8 10:03:00 2023
+// Update Count     : 0
+//
+
+#include "EraseWith.hpp"
+
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Stmt.hpp"
+
+namespace ResolvExpr {
+
+namespace {
+
+struct WithEraser {
+	ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl ) {
+		if ( decl->withExprs.empty() ) return decl;
+		auto mutDecl = mutate( decl );
+		mutDecl->withExprs.clear();
+		return mutDecl;
+	}
+
+	ast::Stmt const * postvisit( ast::DeclStmt const * stmt ) {
+		if ( auto decl = stmt->decl.as<ast::WithStmt>() ) return decl->stmt;
+		return stmt;
+	}
+};
+
+} // namespace
+
+void eraseWith( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<WithEraser>::run( translationUnit );
+}
+
+} // namespace ResolvExpr
Index: src/ResolvExpr/EraseWith.hpp
===================================================================
--- src/ResolvExpr/EraseWith.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ src/ResolvExpr/EraseWith.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,29 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// EraseWith.hpp -- After resolution, erase all with constructs.
+//
+// Author           : Andrew Beach
+// Created On       : Sun Oct  8  9:36:00 2023
+// Last Modified By : Andrew Beach
+// Last Modified On : Sun Oct  8  9:47:00 2023
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace ResolvExpr {
+
+void eraseWith( ast::TranslationUnit & translationUnit );
+/// Remove withExprs from functions and any WithStmt nodes.
+/// This must be done after all resolution that needs to see the names from
+/// a with. We put it after the last pass to use WithSymbolTable.
+
+}
Index: src/ResolvExpr/module.mk
===================================================================
--- src/ResolvExpr/module.mk	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/ResolvExpr/module.mk	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -72,5 +72,7 @@
 	ResolvExpr/AlternativePrinter.h \
 	ResolvExpr/CandidatePrinter.cpp \
-	ResolvExpr/CandidatePrinter.hpp
+	ResolvExpr/CandidatePrinter.hpp \
+	ResolvExpr/EraseWith.cpp \
+	ResolvExpr/EraseWith.hpp
 
 SRCDEMANGLE += $(SRC_RESOLVEXPR)
Index: src/Validate/NoIdSymbolTable.hpp
===================================================================
--- src/Validate/NoIdSymbolTable.hpp	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/Validate/NoIdSymbolTable.hpp	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -20,10 +20,19 @@
 namespace Validate {
 
-// A SymbolTable that only has the operations used in the Translate Dimension
-// pass. More importantly, it doesn't have some methods that should no be
+// A SymbolTable that only tracks names relevant to Validate passes.
+// It tracks type names but not identifier names.
+// Some of the canonicalization that occurs before the resolver
+// affects how identifier name errors get reported to the user.
+// The Validate phase needs to chase type names,
+// but it is too early to try tracking identifier names.
+// Identifier skipping is acheived by omitting methods that should not be
 // called by the Pass template (lookupId and addId).
 class NoIdSymbolTable {
 	ast::SymbolTable base;
 public:
+	// All names that are tracked (now) are eligible for collision validation (now).
+	// (Names that are only tracked later get their collision validation then.)
+	NoIdSymbolTable() : base(ast::SymbolTable::ValidateOnAdd) {}
+
 #	define FORWARD_X( func, types_and_names, just_names ) \
 	inline auto func types_and_names -> decltype( base.func just_names ) { \
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ src/main.cc	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Apr 10 21:12:17 2023
-// Update Count     : 682
+// Last Modified On : Thu Sep 28 22:28:45 2023
+// Update Count     : 687
 //
 
@@ -46,4 +46,5 @@
 #include "Common/utility.h"                 // for deleteAll, filter, printAll
 #include "Concurrency/Actors.hpp"           // for implementActors
+#include "Concurrency/Corun.hpp"            // for implementCorun
 #include "Concurrency/Keywords.h"           // for implementMutex, implement...
 #include "Concurrency/Waitfor.h"            // for generateWaitfor
@@ -62,4 +63,5 @@
 #include "Parser/RunParser.hpp"             // for buildList, dumpParseTree,...
 #include "ResolvExpr/CandidatePrinter.hpp"  // for printCandidates
+#include "ResolvExpr/EraseWith.hpp"         // for eraseWith
 #include "ResolvExpr/Resolver.h"            // for resolve
 #include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
@@ -344,4 +346,5 @@
 		PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
 		PASS( "Fix Unique Ids", Validate::fixUniqueIds, transUnit );
+		PASS( "Implement Corun", Concurrency::implementCorun, transUnit );
 		PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
 
@@ -396,4 +399,5 @@
 
 		PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
+		PASS( "Erase With", ResolvExpr::eraseWith, transUnit );
 
 		// fix ObjectDecl - replaces ConstructorInit nodes
@@ -419,11 +423,9 @@
 
 		PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit );
+		DUMP( bboxp, std::move( transUnit ) );
+		PASS( "Box", GenPoly::box, transUnit );
+		PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit );
 
 		translationUnit = convert( std::move( transUnit ) );
-
-		DUMP( bboxp, translationUnit );
-		PASS( "Box", GenPoly::box, translationUnit );
-
-		PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit );
 
 		// Code has been lowered to C, now we can start generation.
@@ -540,22 +542,22 @@
 	{ "ascodegen", codegenp, true, "print AST as codegen rather than AST" },
 	{ "asterr", errorp, true, "print AST on error" },
-	{ "declstats", declstatsp, true, "code property statistics" },
-	{ "parse", yydebug, true, "yacc (parsing) debug information" },
+	{ "declstats", declstatsp, true, "print code property statistics" },
+	{ "parse", yydebug, true, "print yacc (parsing) debug information" },
 	{ "pretty", prettycodegenp, true, "prettyprint for ascodegen flag" },
 	{ "rproto", resolvprotop, true, "resolver-proto instance" },
 	{ "rsteps", resolvep, true, "print resolver steps" },
-	// code dumps
+	// AST dumps
 	{ "ast", astp, true, "print AST after parsing" },
-	{ "exdecl", exdeclp, true, "print AST after translating exception decls" },
+	{ "excpdecl", exdeclp, true, "print AST after translating exception decls" },
 	{ "symevt", symtabp, true, "print AST after symbol table events" },
-	{ "altexpr", expraltp, true, "print alternatives for expressions" },
-	{ "astdecl", validp, true, "print AST after declaration validation pass" },
-	{ "resolver", bresolvep, true, "print AST before resolver step" },
-	{ "astexpr", exprp, true, "print AST after expression analysis" },
+	{ "expralt", expraltp, true, "print AST after expressions alternatives" },
+	{ "valdecl", validp, true, "print AST after declaration validation pass" },
+	{ "bresolver", bresolvep, true, "print AST before resolver step" },
+	{ "expranly", exprp, true, "print AST after expression analysis" },
 	{ "ctordtor", ctorinitp, true, "print AST after ctor/dtor are replaced" },
 	{ "tuple", tuplep, true, "print AST after tuple expansion" },
-	{ "astgen", genericsp, true, "print AST after instantiate generics" },
-	{ "box", bboxp, true, "print AST before box step" },
-	{ "codegen", bcodegenp, true, "print AST before code generation" },
+	{ "instgen", genericsp, true, "print AST after instantiate generics" },
+	{ "bbox", bboxp, true, "print AST before box pass" },
+	{ "bcodegen", bcodegenp, true, "print AST before code generation" },
 };
 enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) };
Index: tests/.expect/linkonce.txt
===================================================================
--- tests/.expect/linkonce.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/.expect/linkonce.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,1 +1,1 @@
-signed=-7 unsigned=12
+signed=7 unsigned=12
Index: tests/collections/.expect/string-istream-manip.txt
===================================================================
--- tests/collections/.expect/string-istream-manip.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/collections/.expect/string-istream-manip.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,2 +1,58 @@
+preS1 0123456
+preS1 x
+preS2 01234567
+preS2 x
+preS3 012345678
+preS3 x
+preS4 0123456789
+preS4 x
+preSMN1 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456
+preSMN1 x
+preSMN2 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567
+preSMN2 x
+preSMN3 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678
+preSMN3 x
+preSMN4 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789
+preSMN4 x
+preRMN1 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456
+preRMN1 x
+preRMN2 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567
+preRMN2 x
+preRMN3 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678
+preRMN3 x
+preRMN4 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789
+preRMN4 x
+preSMI1 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...       "
+preSMI1 "x"
+preSMI2 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...        "
+preSMI2 "x"
+preSMI3 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...         "
+preSMI3 "x"
+preSMI4 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...          "
+preSMI4 "x"
+preSME1 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...       "
+preSME1 "x"
+preSME2 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...        "
+preSME2 "x"
+preSME3 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...         "
+preSME3 "x"
+preSME4 "...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...          "
+preSME4 "x"
+preSMG1 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456
+preSMG1 x
+preSMG2 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567
+preSMG2 x
+preSMG3 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678
+preSMG3 x
+preSMG4 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789
+preSMG4 x
+preSMD1 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456
+preSMD1 x
+preSMD2 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567
+preSMD2 x
+preSMD3 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678
+preSMD3 x
+preSMD4 ...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789
+preSMD4 x
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -12,4 +68,6 @@
 12 wwwwwwww
 13 wwwwwwww
+14 cccc
+15 
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -25,2 +83,4 @@
 12 wwwwwwww
 13 wwwwwwww
+14 cccc
+15 
Index: tests/collections/.in/string-istream-manip.txt
===================================================================
--- tests/collections/.in/string-istream-manip.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/collections/.in/string-istream-manip.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,12 +1,46 @@
+0123456 x
+01234567 x
+012345678 x
+0123456789 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789 x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...       -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...        -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...         -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...          -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...       -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...        -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...         -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...          -x-
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456
+x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567
+x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678
+x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789
+x
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456@x@
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...01234567@x@
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...012345678@x@
+...:...:...:...|...:...:...:...|...:...:...:...|...:...:...:...#...:...:...:...|...:...:...:...|...:...:...:...|...:...0123456789@x@
 abc 
-abc 
+cccccb 
 xx
 abcxxx
 abcyyy
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
+uuuuuccccuuuuu
 abc 
-abc 
+cccccb 
 xx
 abcxxx
 abcyyy
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
+uuuuuccccuuuuu
Index: tests/collections/string-istream-manip.cfa
===================================================================
--- tests/collections/string-istream-manip.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/collections/string-istream-manip.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -3,6 +3,139 @@
 #include <collections/string.hfa>
 #include <collections/string_res.hfa>
+#include <stdio.h>
+
+// No-op manipulators.
+// Temporary hack while there are two code paths in the string implementation.
+// (One for reading plain strings, the other for reading via a manipulator.)
+// The test cases that use plainjane(-) are exercising the via-manipulator code path,
+// just with trivial manipulation.
+static _Istream_Sstr plainjane( string     & s )  { return (_Istream_Sstr)@{  s, {{0p}, -1, {.flags.rwd : false}} }; }
+static _Istream_Rstr plainjane( string_res & s )  { return (_Istream_Rstr)@{ &s, {{0p}, -1, {.flags.rwd : false}} }; }
+
+static void forceStringHeapFreeSpaceTo(int desiredSize) {
+    for (1_000_000) {
+        string x = "a";
+        (void)x;
+      if (desiredSize == DEBUG_string_bytes_avail_until_gc(DEBUG_string_heap())) return;
+    }
+    sout | "Unable to force size" | desiredSize | "in 1,000,000 tries";
+}
 
 int main() {
+    // These "pre" cases deal with issues analogous to the "pre" cases of io/manipulatorsInput.
+    // The acceptance criterion is simpler but driving the cases is harder.
+    // The tests just read strings and echo what they read; acceptance of simple echoing assures
+    // no spurious splitting merging.
+    // The lengths of the strings are chosen to match white-box knowledge of when the string layer
+    // has tor drive the cstring layer through a second iteration:
+    //  - for no-manip, lengths are near the room at end of string heap
+    //    (chosen target size of 9 showed the original bug on preS2, aligned with the other cases)
+    //  - for manip, lengths are near the auxiliary buffer size of 128
+    // Only first case repeats for string_res; rest run only from the passthru string layer.
+    // Similarly, the manipulator breadth isn't checked at the cstring layer either.
+    {
+        // S: string, no manipulator
+        void echoTillX(const char * casename) {
+            string s;
+            do {
+                forceStringHeapFreeSpaceTo(9);
+                sin | s;
+                sout | casename | s;
+            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
+        }
+        echoTillX("preS1");
+        echoTillX("preS2");
+        echoTillX("preS3");
+        echoTillX("preS4");
+    }
+    {
+        // SMN: string, manipulator for no-op
+        void echoTillX(const char * casename) {
+            string s;
+            do {
+                sin | plainjane( s );
+                sout | casename | s;
+            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
+        }
+        echoTillX("preSMN1");
+        echoTillX("preSMN2");
+        echoTillX("preSMN3");
+        echoTillX("preSMN4");
+    }
+    {
+        // RMN: string_res, manipulator for no-op
+        void echoTillX(const char * casename) {
+            string_res s;
+            do {
+                sin | plainjane( s );
+                sout | casename | s;
+            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
+        }
+        echoTillX("preRMN1");
+        echoTillX("preRMN2");
+        echoTillX("preRMN3");
+        echoTillX("preRMN4");
+    }
+    {
+        // SMI: string, manipulator `incl`
+        void echoTillX(const char * casename) {
+            string s;
+            do {
+                sin | skip("-\n");
+                sin | incl( ".:|# x", s );
+                sout | casename | " \"" | s | "\"";
+            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
+        }
+        echoTillX("preSMI1");
+        echoTillX("preSMI2");
+        echoTillX("preSMI3");
+        echoTillX("preSMI4");
+    }
+    {
+        // SME: string, manipulator `excl`
+        void echoTillX(const char * casename) {
+            string s;
+            do {
+                sin | skip("-\n");
+                sin | excl( "-\n", s );
+                sout | casename | " \"" | s | "\"";
+            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
+        }
+        echoTillX("preSME1");
+        echoTillX("preSME2");
+        echoTillX("preSME3");
+        echoTillX("preSME4");
+    }
+    sin | skip("-\n");
+    {
+        // SMG: string, manipulator `getline`
+        void echoTillX(const char * casename) {
+            string s;
+            do {
+                sin | getline( s );
+                sout | casename | s;
+            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
+        }
+        echoTillX("preSMG1");
+        echoTillX("preSMG2");
+        echoTillX("preSMG3");
+        echoTillX("preSMG4");
+    }
+    {
+        // SMD: string, manipulator (`getline` with custom) delimiter
+        void echoTillX(const char * casename) {
+            string s;
+            do {
+                sin | getline( s, '@' );
+                sout | casename | s;
+            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
+            sin | skip(" \n");
+        }
+        echoTillX("preSMD1");
+        echoTillX("preSMD2");
+        echoTillX("preSMD3");
+        echoTillX("preSMD4");
+    }
+
     /* Keep harmonized with io/manipulatorsInput */
     {
@@ -23,5 +156,13 @@
         sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
         sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
-    }
+
+		s = "q";
+		sin | incl( "abc", s );                         sout | "14" | s;
+		s = "q";
+		sin | excl( "u", s );                           sout | "15" | s;
+		sin | skip( "u" );
+		sin | "\n";
+	}
+    // Full repeat on string_res layer assures the full manipulator vocabulary is supported there.
     {
         string_res s = "yyyyyyyyyyyyyyyyyyyy";
@@ -41,4 +182,11 @@
         sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
         sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
+
+		s = "q";
+		sin | incl( "abc", s );                         sout | "14" | s;
+		s = "q";
+		sin | excl( "u", s );                           sout | "15" | s;
+		sin | skip( "u" );
+		sin | "\n";
     }
 }
Index: tests/concurrency/cofor.cfa
===================================================================
--- tests/concurrency/cofor.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/concurrency/cofor.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,14 +1,21 @@
 #include <cofor.hfa>
 
-long total = 0;
-void add_num( void * arg ) { __atomic_fetch_add( &total, (long)arg, __ATOMIC_SEQ_CST ); }
+
+void add_num( long * total, long val ) { __atomic_fetch_add( total, (long)val, __ATOMIC_SEQ_CST ); }
 
 int main() {
     printf("start\n");
     processor p[4];
+    long total = 0;
     COFOR( i, 0, 10, __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST ); );
-    parallel_stmt_t stmts[5] = { add_num, add_num, add_num, add_num, add_num };
-    void * nums[5] = { (void *)11, (void *)12, (void *)13, (void *)14, (void *)15 };
-    parallel( stmts, nums, 5 );
+    {
+        corun;      // does nothing
+        corun{};    // does nothing
+        corun add_num( &total, 11 );
+        corun { add_num( &total, 12 ); }
+        corun __atomic_fetch_add( &total, 13, __ATOMIC_SEQ_CST );
+        corun { __atomic_fetch_add( &total, 14, __ATOMIC_SEQ_CST ); }
+        __atomic_fetch_add( &total, 15, __ATOMIC_SEQ_CST ); // run by main thd
+    }
     printf("total: %ld\n", total);
     printf("done\n");
Index: tests/errors/.expect/scope-type.txt
===================================================================
--- tests/errors/.expect/scope-type.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/errors/.expect/scope-type.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,14 @@
+errors/scope-type.cfa:13:1 error: redeclaration of struct thisIsAnError with body
+
+errors/scope-type.cfa:48:1 error: redeclaration of union thisIsAnError_u with body
+
+errors/scope-type.cfa:62:1 error: redeclaration of enum thisIsAnError_e with body
+... with members
+  E0: const instance of enum thisIsAnError_e with body
+
+
+errors/scope-type.cfa:76:1 error: redeclaration of struct thisIsAnError_p with body
+... with parameters
+  Tx: data type
+
+
Index: tests/errors/.expect/scope.txt
===================================================================
--- tests/errors/.expect/scope.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/errors/.expect/scope.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,4 +1,4 @@
-errors/scope.cfa:2:1 error: duplicate object definition for thisIsAnError: signed int
-errors/scope.cfa:20:1 error: duplicate function definition for butThisIsAnError: function
+errors/scope.cfa:13:1 error: duplicate object definition for thisIsAnError: signed int
+errors/scope.cfa:30:1 error: duplicate function definition for butThisIsAnError: function
 ... with parameters
   double
Index: tests/errors/scope-type.cfa
===================================================================
--- tests/errors/scope-type.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/errors/scope-type.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,92 @@
+// The type-level analog of errors/scope.
+// Keep harmonized with errors/scope.
+
+#ifdef OMIT_DRIVING_REJECTIONS
+// For manual sanity checking:
+// Leave out the offensive declarations and verify that what's left is accepted.
+#define EXPREJ(...)
+#else 
+#define EXPREJ(...) __VA_ARGS__
+#endif
+
+        struct thisIsAnError {};
+EXPREJ( struct thisIsAnError {}; )
+
+        struct thisIsNotAnError {};
+
+        // There's no type-level analog to overloading at one level:
+        //x    float thisIsNotAnError;
+
+        int thisIsAlsoNotAnError() {
+          struct thisIsNotAnError { int xxx; };
+        }
+
+        // There's no type-level analog to overloading at one level, again:
+        //x    int thisIsAlsoNotAnError( double x ) {
+        //x    }
+
+        struct thisIsStillNotAnError;
+        struct thisIsStillNotAnError;
+
+        // Has analog at type level but would be a repeat (no analog of function vs variable):
+        //x
+        //x    double butThisIsAnError( double ) {
+        //x    }
+        //x
+        //x    double butThisIsAnError( double ) {
+        //x    }
+
+
+
+        //
+        // Repeat the validly harmonized cases, across various type forms
+        //
+
+        // union
+
+        union thisIsAnError_u {};
+EXPREJ( union thisIsAnError_u {}; )
+
+        union thisIsNotAnError_u {};
+
+        int thisIsAlsoNotAnError_u() {
+          union thisIsNotAnError_u { int xxx; };
+        }
+
+        union thisIsStillNotAnError_u;
+        union thisIsStillNotAnError_u;
+
+        // enum
+
+        enum thisIsAnError_e { E0 };
+EXPREJ( enum thisIsAnError_e { E0 }; )
+
+        enum thisIsNotAnError_e { E1 };
+
+        int thisIsAlsoNotAnError_e() {
+          enum thisIsNotAnError_e { E1_xxx };
+        }
+
+        enum thisIsStillNotAnError_e;
+        enum thisIsStillNotAnError_e;
+
+        // polymorphic
+
+        forall(T&)  struct thisIsAnError_p {};
+EXPREJ( forall(Tx&) struct thisIsAnError_p {}; )
+
+        forall(T&)  struct thisIsNotAnError_p {};
+
+        int thisIsAlsoNotAnError_p() {
+          forall(Tx&) struct thisIsNotAnError_p { int xxx; };
+        }
+
+        forall(Tx&) 
+        int thisIsAlsoNotAnError_p2() {
+          struct thisIsNotAnError_p { Tx * xxx; };
+        }
+
+        forall(T&)  struct thisIsStillNotAnError_p;
+      #ifdef SHOW_TRAC_284
+        forall(Tx&) struct thisIsStillNotAnError_p;  // should be accepted, but blocked
+      #endif
Index: tests/errors/scope.cfa
===================================================================
--- tests/errors/scope.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/errors/scope.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,23 +1,35 @@
-int thisIsAnError;
-int thisIsAnError;
+// Keep harmonized with errors/scope.
 
-int thisIsNotAnError;
-float thisIsNotAnError;
+#ifdef OMIT_DRIVING_REJECTIONS
+// For manual sanity checking:
+// Leave out the offensive declarations and verify that what's left is accepted.
+#define EXPREJ(...)
+#else 
+#define EXPREJ(...) __VA_ARGS__
+#endif
 
-int thisIsAlsoNotAnError() {
-  int thisIsNotAnError;
-}
 
-int thisIsAlsoNotAnError( double x ) {
-}
+        int thisIsAnError;
+EXPREJ( int thisIsAnError; )
 
-double thisIsStillNotAnError( double );
-double thisIsStillNotAnError( double );
+        int thisIsNotAnError;
+        float thisIsNotAnError;
 
-double butThisIsAnError( double ) {
-}
+        int thisIsAlsoNotAnError() {
+          int thisIsNotAnError;
+        }
 
-double butThisIsAnError( double ) {
-}
+        int thisIsAlsoNotAnError( double x ) {
+        }
+
+        double thisIsStillNotAnError( double );
+        double thisIsStillNotAnError( double );
+
+        double butThisIsAnError( double ) {
+        }
+EXPREJ(
+        double butThisIsAnError( double ) {
+        }
+)
 
 // Local Variables: //
Index: tests/exceptions/.expect/hotpotato.arm64.txt
===================================================================
--- tests/exceptions/.expect/hotpotato.arm64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/.expect/hotpotato.arm64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,143 @@
+5 0 42
+9 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 3 is eliminated
+  POTATO goes off after 4 ticks
+U 0 -> 4 -> 0 -> 1 is eliminated
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 election
+ -> 8 election
+ -> 2 : umpire 8
+  POTATO goes off after 5 ticks
+U 8 -> 2 -> 4 -> 2 -> 8 is eliminated
+election
+ -> 2 election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 : umpire 7
+  POTATO goes off after 2 ticks
+U 7 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 6 -> 5 -> 6 -> 5 -> 6 is eliminated
+  POTATO goes off after 9 ticks
+U 7 -> 4 -> 7 -> 5 -> 4 -> 7 -> 4 -> 7 -> 4 is eliminated
+  POTATO goes off after 1 tick
+U 7 is eliminated
+election
+ -> 5 : umpire 5
+  POTATO goes off after 6 ticks
+U 5 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 9 ticks
+U 0 -> 5 -> 0 -> 5 -> 0 -> 3 -> 0 -> 5 -> 6 is eliminated
+  POTATO goes off after 5 ticks
+U 0 -> 5 -> 0 -> 3 -> 2 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 3 -> 0 -> 3 -> 0 -> 3 -> 0 -> 5 -> 0 -> 5 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 3 -> 0 -> 3 -> 1 -> 3 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 4 -> 7 -> 4 -> 3 -> 0 -> 3 -> 0 -> 3 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 -> 7 -> 4 -> 7 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 is eliminated
+election
+ -> 4 : umpire 4
+  POTATO goes off after 7 ticks
+U 4 wins the Match!
+
+
+4 players in the game
+  POTATO goes off after 3 ticks
+U 0 -> 1 -> 0 is eliminated
+election
+ -> 3 election
+ -> 2 election
+ -> 1 : umpire 3
+  POTATO goes off after 9 ticks
+U 3 -> 1 -> 2 -> 3 -> 1 -> 2 -> 1 -> 2 -> 3 is eliminated
+election
+ -> 2 election
+ -> 1 : umpire 2
+  POTATO goes off after 2 ticks
+U 2 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 2 wins the Match!
+
+
+10 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 8 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 9 -> 0 -> 9 -> 0 -> 9 -> 7 -> 9 -> 7 -> 9 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 7 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 0 -> 6 -> 5 -> 6 -> 5 -> 4 -> 5 -> 6 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 5 -> 0 is eliminated
+election
+ -> 7 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 4 -> 5 -> 7 -> 5 -> 4 -> 3 -> 4 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 5 -> 3 -> 2 -> 3 -> 2 -> 3 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 3 -> 7 -> 5 -> 3 -> 5 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 3 -> 7 -> 3 -> 7 -> 3 -> 7 -> 3 is eliminated
+  POTATO goes off after 2 ticks
+U 7 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 6 election
+ -> 7 election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 7 -> 6 -> 7 -> 6 -> 7 -> 6 -> 7 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 6 : umpire 6
+  POTATO goes off after 1 tick
+U 6 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 5
+  POTATO goes off after 7 ticks
+U 5 -> 1 -> 2 -> 1 -> 5 -> 1 -> 2 is eliminated
+  POTATO goes off after 2 ticks
+U 5 -> 4 is eliminated
+  POTATO goes off after 9 ticks
+U 5 -> 1 -> 5 -> 1 -> 3 -> 1 -> 3 -> 5 -> 3 is eliminated
+  POTATO goes off after 8 ticks
+U 5 -> 1 -> 5 -> 1 -> 5 -> 1 -> 5 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 5 wins the Match!
Index: tests/exceptions/.expect/hotpotato.x64.txt
===================================================================
--- tests/exceptions/.expect/hotpotato.x64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/.expect/hotpotato.x64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,143 @@
+5 0 42
+9 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 3 is eliminated
+  POTATO goes off after 4 ticks
+U 0 -> 4 -> 0 -> 1 is eliminated
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 election
+ -> 8 election
+ -> 2 : umpire 8
+  POTATO goes off after 5 ticks
+U 8 -> 2 -> 4 -> 2 -> 8 is eliminated
+election
+ -> 2 election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 : umpire 7
+  POTATO goes off after 2 ticks
+U 7 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 6 -> 5 -> 6 -> 5 -> 6 is eliminated
+  POTATO goes off after 9 ticks
+U 7 -> 4 -> 7 -> 5 -> 4 -> 7 -> 4 -> 7 -> 4 is eliminated
+  POTATO goes off after 1 tick
+U 7 is eliminated
+election
+ -> 5 : umpire 5
+  POTATO goes off after 6 ticks
+U 5 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 9 ticks
+U 0 -> 5 -> 0 -> 5 -> 0 -> 3 -> 0 -> 5 -> 6 is eliminated
+  POTATO goes off after 5 ticks
+U 0 -> 5 -> 0 -> 3 -> 2 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 3 -> 0 -> 3 -> 0 -> 3 -> 0 -> 5 -> 0 -> 5 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 3 -> 0 -> 3 -> 1 -> 3 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 4 -> 7 -> 4 -> 3 -> 0 -> 3 -> 0 -> 3 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 -> 7 -> 4 -> 7 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 is eliminated
+election
+ -> 4 : umpire 4
+  POTATO goes off after 7 ticks
+U 4 wins the Match!
+
+
+4 players in the game
+  POTATO goes off after 3 ticks
+U 0 -> 1 -> 0 is eliminated
+election
+ -> 3 election
+ -> 2 election
+ -> 1 : umpire 3
+  POTATO goes off after 9 ticks
+U 3 -> 1 -> 2 -> 3 -> 1 -> 2 -> 1 -> 2 -> 3 is eliminated
+election
+ -> 2 election
+ -> 1 : umpire 2
+  POTATO goes off after 2 ticks
+U 2 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 2 wins the Match!
+
+
+10 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 8 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 9 -> 0 -> 9 -> 0 -> 9 -> 7 -> 9 -> 7 -> 9 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 7 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 0 -> 6 -> 5 -> 6 -> 5 -> 4 -> 5 -> 6 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 5 -> 0 is eliminated
+election
+ -> 7 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 4 -> 5 -> 7 -> 5 -> 4 -> 3 -> 4 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 5 -> 3 -> 2 -> 3 -> 2 -> 3 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 3 -> 7 -> 5 -> 3 -> 5 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 3 -> 7 -> 3 -> 7 -> 3 -> 7 -> 3 is eliminated
+  POTATO goes off after 2 ticks
+U 7 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 6 election
+ -> 7 election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 7 -> 6 -> 7 -> 6 -> 7 -> 6 -> 7 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 6 : umpire 6
+  POTATO goes off after 1 tick
+U 6 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 5
+  POTATO goes off after 7 ticks
+U 5 -> 1 -> 2 -> 1 -> 5 -> 1 -> 2 is eliminated
+  POTATO goes off after 2 ticks
+U 5 -> 4 is eliminated
+  POTATO goes off after 9 ticks
+U 5 -> 1 -> 5 -> 1 -> 3 -> 1 -> 3 -> 5 -> 3 is eliminated
+  POTATO goes off after 8 ticks
+U 5 -> 1 -> 5 -> 1 -> 5 -> 1 -> 5 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 5 wins the Match!
Index: tests/exceptions/.expect/hotpotato.x86.txt
===================================================================
--- tests/exceptions/.expect/hotpotato.x86.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/.expect/hotpotato.x86.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,153 @@
+5 0 42
+2 players in the game
+  POTATO goes off after 5 ticks
+U 0 -> 1 -> 0 -> 1 -> 0 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 2 ticks
+U 1 wins the Match!
+
+
+9 players in the game
+  POTATO goes off after 8 ticks
+U 0 -> 5 -> 0 -> 5 -> 4 -> 5 -> 4 -> 3 is eliminated
+  POTATO goes off after 2 ticks
+U 0 -> 5 is eliminated
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 7 election
+ -> 8 election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 4 : umpire 8
+  POTATO goes off after 8 ticks
+U 8 -> 7 -> 4 -> 2 -> 4 -> 2 -> 4 -> 2 is eliminated
+  POTATO goes off after 3 ticks
+U 8 -> 7 -> 4 is eliminated
+  POTATO goes off after 7 ticks
+U 8 -> 7 -> 1 -> 6 -> 8 -> 6 -> 8 is eliminated
+election
+ -> 6 election
+ -> 1 election
+ -> 7 : umpire 7
+  POTATO goes off after 6 ticks
+U 7 -> 1 -> 6 -> 1 -> 6 -> 7 is eliminated
+election
+ -> 6 election
+ -> 1 : umpire 6
+  POTATO goes off after 3 ticks
+U 6 -> 1 -> 6 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 1 tick
+U 1 wins the Match!
+
+
+3 players in the game
+  POTATO goes off after 9 ticks
+U 0 -> 1 -> 0 -> 2 -> 1 -> 0 -> 1 -> 2 -> 0 is eliminated
+election
+ -> 2 election
+ -> 1 : umpire 2
+  POTATO goes off after 9 ticks
+U 2 -> 1 -> 2 -> 1 -> 2 -> 1 -> 2 -> 1 -> 2 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 9 ticks
+U 1 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 5 ticks
+U 0 -> 7 -> 6 -> 7 -> 0 is eliminated
+election
+ -> 7 election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 7
+  POTATO goes off after 10 ticks
+U 7 -> 5 -> 4 -> 3 -> 4 -> 5 -> 4 -> 5 -> 4 -> 5 is eliminated
+  POTATO goes off after 3 ticks
+U 7 -> 4 -> 7 is eliminated
+election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 6
+  POTATO goes off after 10 ticks
+U 6 -> 4 -> 3 -> 4 -> 3 -> 2 -> 3 -> 2 -> 1 -> 2 is eliminated
+  POTATO goes off after 1 tick
+U 6 is eliminated
+election
+ -> 1 election
+ -> 3 election
+ -> 4 : umpire 4
+  POTATO goes off after 5 ticks
+U 4 -> 1 -> 3 -> 1 -> 4 is eliminated
+election
+ -> 1 election
+ -> 3 : umpire 3
+  POTATO goes off after 7 ticks
+U 3 -> 1 -> 3 -> 1 -> 3 -> 1 -> 3 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 5 ticks
+U 1 wins the Match!
+
+
+10 players in the game
+  POTATO goes off after 7 ticks
+U 0 -> 5 -> 4 -> 5 -> 4 -> 5 -> 0 is eliminated
+election
+ -> 7 election
+ -> 8 election
+ -> 9 election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 9
+  POTATO goes off after 5 ticks
+U 9 -> 6 -> 1 -> 2 -> 3 is eliminated
+  POTATO goes off after 3 ticks
+U 9 -> 6 -> 9 is eliminated
+election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 4 election
+ -> 5 election
+ -> 7 election
+ -> 8 : umpire 8
+  POTATO goes off after 2 ticks
+U 8 -> 7 is eliminated
+  POTATO goes off after 9 ticks
+U 8 -> 6 -> 8 -> 5 -> 4 -> 5 -> 4 -> 2 -> 1 is eliminated
+  POTATO goes off after 1 tick
+U 8 is eliminated
+election
+ -> 6 election
+ -> 2 election
+ -> 4 election
+ -> 5 : umpire 6
+  POTATO goes off after 3 ticks
+U 6 -> 2 -> 6 is eliminated
+election
+ -> 2 election
+ -> 4 election
+ -> 5 : umpire 5
+  POTATO goes off after 2 ticks
+U 5 -> 2 is eliminated
+  POTATO goes off after 5 ticks
+U 5 -> 4 -> 5 -> 4 -> 5 is eliminated
+election
+ -> 4 : umpire 4
+  POTATO goes off after 1 tick
+U 4 wins the Match!
Index: tests/exceptions/.expect/hotpotato_checked.arm64.txt
===================================================================
--- tests/exceptions/.expect/hotpotato_checked.arm64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/.expect/hotpotato_checked.arm64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,143 @@
+5 0 42
+9 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 3 is eliminated
+  POTATO goes off after 4 ticks
+U 0 -> 4 -> 0 -> 1 is eliminated
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 election
+ -> 8 election
+ -> 2 : umpire 8
+  POTATO goes off after 5 ticks
+U 8 -> 2 -> 4 -> 2 -> 8 is eliminated
+election
+ -> 2 election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 : umpire 7
+  POTATO goes off after 2 ticks
+U 7 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 6 -> 5 -> 6 -> 5 -> 6 is eliminated
+  POTATO goes off after 9 ticks
+U 7 -> 4 -> 7 -> 5 -> 4 -> 7 -> 4 -> 7 -> 4 is eliminated
+  POTATO goes off after 1 tick
+U 7 is eliminated
+election
+ -> 5 : umpire 5
+  POTATO goes off after 6 ticks
+U 5 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 9 ticks
+U 0 -> 5 -> 0 -> 5 -> 0 -> 3 -> 0 -> 5 -> 6 is eliminated
+  POTATO goes off after 5 ticks
+U 0 -> 5 -> 0 -> 3 -> 2 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 3 -> 0 -> 3 -> 0 -> 3 -> 0 -> 5 -> 0 -> 5 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 3 -> 0 -> 3 -> 1 -> 3 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 4 -> 7 -> 4 -> 3 -> 0 -> 3 -> 0 -> 3 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 -> 7 -> 4 -> 7 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 is eliminated
+election
+ -> 4 : umpire 4
+  POTATO goes off after 7 ticks
+U 4 wins the Match!
+
+
+4 players in the game
+  POTATO goes off after 3 ticks
+U 0 -> 1 -> 0 is eliminated
+election
+ -> 3 election
+ -> 2 election
+ -> 1 : umpire 3
+  POTATO goes off after 9 ticks
+U 3 -> 1 -> 2 -> 3 -> 1 -> 2 -> 1 -> 2 -> 3 is eliminated
+election
+ -> 2 election
+ -> 1 : umpire 2
+  POTATO goes off after 2 ticks
+U 2 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 2 wins the Match!
+
+
+10 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 8 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 9 -> 0 -> 9 -> 0 -> 9 -> 7 -> 9 -> 7 -> 9 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 7 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 0 -> 6 -> 5 -> 6 -> 5 -> 4 -> 5 -> 6 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 5 -> 0 is eliminated
+election
+ -> 7 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 4 -> 5 -> 7 -> 5 -> 4 -> 3 -> 4 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 5 -> 3 -> 2 -> 3 -> 2 -> 3 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 3 -> 7 -> 5 -> 3 -> 5 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 3 -> 7 -> 3 -> 7 -> 3 -> 7 -> 3 is eliminated
+  POTATO goes off after 2 ticks
+U 7 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 6 election
+ -> 7 election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 7 -> 6 -> 7 -> 6 -> 7 -> 6 -> 7 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 6 : umpire 6
+  POTATO goes off after 1 tick
+U 6 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 5
+  POTATO goes off after 7 ticks
+U 5 -> 1 -> 2 -> 1 -> 5 -> 1 -> 2 is eliminated
+  POTATO goes off after 2 ticks
+U 5 -> 4 is eliminated
+  POTATO goes off after 9 ticks
+U 5 -> 1 -> 5 -> 1 -> 3 -> 1 -> 3 -> 5 -> 3 is eliminated
+  POTATO goes off after 8 ticks
+U 5 -> 1 -> 5 -> 1 -> 5 -> 1 -> 5 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 5 wins the Match!
Index: tests/exceptions/.expect/hotpotato_checked.x64.txt
===================================================================
--- tests/exceptions/.expect/hotpotato_checked.x64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/.expect/hotpotato_checked.x64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,143 @@
+5 0 42
+9 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 3 is eliminated
+  POTATO goes off after 4 ticks
+U 0 -> 4 -> 0 -> 1 is eliminated
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 election
+ -> 8 election
+ -> 2 : umpire 8
+  POTATO goes off after 5 ticks
+U 8 -> 2 -> 4 -> 2 -> 8 is eliminated
+election
+ -> 2 election
+ -> 4 election
+ -> 5 election
+ -> 6 election
+ -> 7 : umpire 7
+  POTATO goes off after 2 ticks
+U 7 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 6 -> 5 -> 6 -> 5 -> 6 is eliminated
+  POTATO goes off after 9 ticks
+U 7 -> 4 -> 7 -> 5 -> 4 -> 7 -> 4 -> 7 -> 4 is eliminated
+  POTATO goes off after 1 tick
+U 7 is eliminated
+election
+ -> 5 : umpire 5
+  POTATO goes off after 6 ticks
+U 5 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 9 ticks
+U 0 -> 5 -> 0 -> 5 -> 0 -> 3 -> 0 -> 5 -> 6 is eliminated
+  POTATO goes off after 5 ticks
+U 0 -> 5 -> 0 -> 3 -> 2 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 3 -> 0 -> 3 -> 0 -> 3 -> 0 -> 5 -> 0 -> 5 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 3 -> 0 -> 3 -> 1 -> 3 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 4 -> 7 -> 4 -> 3 -> 0 -> 3 -> 0 -> 3 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 -> 7 -> 4 -> 7 is eliminated
+  POTATO goes off after 7 ticks
+U 0 -> 4 -> 0 -> 4 -> 0 -> 4 -> 0 is eliminated
+election
+ -> 4 : umpire 4
+  POTATO goes off after 7 ticks
+U 4 wins the Match!
+
+
+4 players in the game
+  POTATO goes off after 3 ticks
+U 0 -> 1 -> 0 is eliminated
+election
+ -> 3 election
+ -> 2 election
+ -> 1 : umpire 3
+  POTATO goes off after 9 ticks
+U 3 -> 1 -> 2 -> 3 -> 1 -> 2 -> 1 -> 2 -> 3 is eliminated
+election
+ -> 2 election
+ -> 1 : umpire 2
+  POTATO goes off after 2 ticks
+U 2 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 2 wins the Match!
+
+
+10 players in the game
+  POTATO goes off after 2 ticks
+U 0 -> 8 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 9 -> 0 -> 9 -> 0 -> 9 -> 7 -> 9 -> 7 -> 9 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 7 -> 1 is eliminated
+  POTATO goes off after 10 ticks
+U 0 -> 7 -> 0 -> 6 -> 5 -> 6 -> 5 -> 4 -> 5 -> 6 is eliminated
+  POTATO goes off after 3 ticks
+U 0 -> 5 -> 0 is eliminated
+election
+ -> 7 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 4 -> 5 -> 7 -> 5 -> 4 -> 3 -> 4 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 5 -> 3 -> 2 -> 3 -> 2 -> 3 -> 2 is eliminated
+  POTATO goes off after 6 ticks
+U 7 -> 3 -> 7 -> 5 -> 3 -> 5 is eliminated
+  POTATO goes off after 8 ticks
+U 7 -> 3 -> 7 -> 3 -> 7 -> 3 -> 7 -> 3 is eliminated
+  POTATO goes off after 2 ticks
+U 7 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 6 election
+ -> 7 election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 7
+  POTATO goes off after 9 ticks
+U 7 -> 5 -> 7 -> 6 -> 7 -> 6 -> 7 -> 6 -> 7 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 6 : umpire 6
+  POTATO goes off after 1 tick
+U 6 is eliminated
+election
+ -> 5 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 5
+  POTATO goes off after 7 ticks
+U 5 -> 1 -> 2 -> 1 -> 5 -> 1 -> 2 is eliminated
+  POTATO goes off after 2 ticks
+U 5 -> 4 is eliminated
+  POTATO goes off after 9 ticks
+U 5 -> 1 -> 5 -> 1 -> 3 -> 1 -> 3 -> 5 -> 3 is eliminated
+  POTATO goes off after 8 ticks
+U 5 -> 1 -> 5 -> 1 -> 5 -> 1 -> 5 -> 1 is eliminated
+  POTATO goes off after 7 ticks
+U 5 wins the Match!
Index: tests/exceptions/.expect/hotpotato_checked.x86.txt
===================================================================
--- tests/exceptions/.expect/hotpotato_checked.x86.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/.expect/hotpotato_checked.x86.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,153 @@
+5 0 42
+2 players in the game
+  POTATO goes off after 5 ticks
+U 0 -> 1 -> 0 -> 1 -> 0 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 2 ticks
+U 1 wins the Match!
+
+
+9 players in the game
+  POTATO goes off after 8 ticks
+U 0 -> 5 -> 0 -> 5 -> 4 -> 5 -> 4 -> 3 is eliminated
+  POTATO goes off after 2 ticks
+U 0 -> 5 is eliminated
+  POTATO goes off after 1 tick
+U 0 is eliminated
+election
+ -> 7 election
+ -> 8 election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 4 : umpire 8
+  POTATO goes off after 8 ticks
+U 8 -> 7 -> 4 -> 2 -> 4 -> 2 -> 4 -> 2 is eliminated
+  POTATO goes off after 3 ticks
+U 8 -> 7 -> 4 is eliminated
+  POTATO goes off after 7 ticks
+U 8 -> 7 -> 1 -> 6 -> 8 -> 6 -> 8 is eliminated
+election
+ -> 6 election
+ -> 1 election
+ -> 7 : umpire 7
+  POTATO goes off after 6 ticks
+U 7 -> 1 -> 6 -> 1 -> 6 -> 7 is eliminated
+election
+ -> 6 election
+ -> 1 : umpire 6
+  POTATO goes off after 3 ticks
+U 6 -> 1 -> 6 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 1 tick
+U 1 wins the Match!
+
+
+3 players in the game
+  POTATO goes off after 9 ticks
+U 0 -> 1 -> 0 -> 2 -> 1 -> 0 -> 1 -> 2 -> 0 is eliminated
+election
+ -> 2 election
+ -> 1 : umpire 2
+  POTATO goes off after 9 ticks
+U 2 -> 1 -> 2 -> 1 -> 2 -> 1 -> 2 -> 1 -> 2 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 9 ticks
+U 1 wins the Match!
+
+
+8 players in the game
+  POTATO goes off after 5 ticks
+U 0 -> 7 -> 6 -> 7 -> 0 is eliminated
+election
+ -> 7 election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 7
+  POTATO goes off after 10 ticks
+U 7 -> 5 -> 4 -> 3 -> 4 -> 5 -> 4 -> 5 -> 4 -> 5 is eliminated
+  POTATO goes off after 3 ticks
+U 7 -> 4 -> 7 is eliminated
+election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 : umpire 6
+  POTATO goes off after 10 ticks
+U 6 -> 4 -> 3 -> 4 -> 3 -> 2 -> 3 -> 2 -> 1 -> 2 is eliminated
+  POTATO goes off after 1 tick
+U 6 is eliminated
+election
+ -> 1 election
+ -> 3 election
+ -> 4 : umpire 4
+  POTATO goes off after 5 ticks
+U 4 -> 1 -> 3 -> 1 -> 4 is eliminated
+election
+ -> 1 election
+ -> 3 : umpire 3
+  POTATO goes off after 7 ticks
+U 3 -> 1 -> 3 -> 1 -> 3 -> 1 -> 3 is eliminated
+election
+ -> 1 : umpire 1
+  POTATO goes off after 5 ticks
+U 1 wins the Match!
+
+
+10 players in the game
+  POTATO goes off after 7 ticks
+U 0 -> 5 -> 4 -> 5 -> 4 -> 5 -> 0 is eliminated
+election
+ -> 7 election
+ -> 8 election
+ -> 9 election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 3 election
+ -> 4 election
+ -> 5 : umpire 9
+  POTATO goes off after 5 ticks
+U 9 -> 6 -> 1 -> 2 -> 3 is eliminated
+  POTATO goes off after 3 ticks
+U 9 -> 6 -> 9 is eliminated
+election
+ -> 6 election
+ -> 1 election
+ -> 2 election
+ -> 4 election
+ -> 5 election
+ -> 7 election
+ -> 8 : umpire 8
+  POTATO goes off after 2 ticks
+U 8 -> 7 is eliminated
+  POTATO goes off after 9 ticks
+U 8 -> 6 -> 8 -> 5 -> 4 -> 5 -> 4 -> 2 -> 1 is eliminated
+  POTATO goes off after 1 tick
+U 8 is eliminated
+election
+ -> 6 election
+ -> 2 election
+ -> 4 election
+ -> 5 : umpire 6
+  POTATO goes off after 3 ticks
+U 6 -> 2 -> 6 is eliminated
+election
+ -> 2 election
+ -> 4 election
+ -> 5 : umpire 5
+  POTATO goes off after 2 ticks
+U 5 -> 2 is eliminated
+  POTATO goes off after 5 ticks
+U 5 -> 4 -> 5 -> 4 -> 5 is eliminated
+election
+ -> 4 : umpire 4
+  POTATO goes off after 1 tick
+U 4 wins the Match!
Index: tests/exceptions/hotpotato.cfa
===================================================================
--- tests/exceptions/hotpotato.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/hotpotato.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,200 @@
+#include <fstream.hfa>									// sin/sout
+#include <stdlib.hfa>									// convert
+#include <string.h>
+#include <coroutine.hfa>
+
+struct Potato {
+        PRNG & prng;
+        unsigned int deadline;                                                          // when timer goes off
+        unsigned int timer;                                                                     // up counter to deadline
+}; // Potato
+
+void reset( Potato & potato, unsigned int maxTicks = 10 );
+void ?{}( Potato & potato, PRNG & prng, unsigned int maxTicks = 10 );
+
+void ?{}( Potato & potato, PRNG & prng, unsigned int maxTicks ) with(potato) {
+	&potato.prng = &prng;
+	reset( potato, maxTicks );
+} // Potato
+
+coroutine Player {
+        PRNG & prng;
+        int id;                                                                                         // player identity
+        Potato & potato;                                                                        // potato being tossed
+        Player * partner[2];                                                            // left and right player
+}; // Player
+
+void ?{}( Player & player, PRNG & prng, unsigned int id, Potato & potato ) {
+	&player.prng = &prng;
+	player.id = id;
+	&player.potato = &potato;
+} // Player
+
+Player & umpire;
+
+ExceptionDecl( Explode );
+ExceptionDecl( Terminate, Player * victim; );
+ExceptionDecl( Election );
+ExceptionDecl( cmd_error ); // convert(...) throws out_of_range or invalid_argument
+
+void reset( Potato & potato, unsigned int maxTicks ) with(potato) {
+  if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional
+	deadline = prng( prng, 1, maxTicks );
+	timer = 0;
+	sout | "  POTATO goes off after " | deadline | " tick" | nosep | (deadline > 1 ? "s" : "");
+} // reset
+
+void countdown( Potato & potato ) with(potato) {
+	timer += 1;
+	if ( timer == deadline ) throwResume ExceptionInst( Explode );
+} // countdown
+
+static unsigned int rightOf( unsigned int me, unsigned int total ) {
+	return ( me + 1 ) % total;
+} // rightOf
+
+static unsigned int leftOf( unsigned int me, unsigned int total ) {
+	return ( me + total - 1) % total;
+} // leftOf
+
+enum { LEFT = 0, RIGHT = 1 };
+
+static void vote( Player & player, Election & election ) {					// cause partner to vote
+    resumeAt( player, election );
+	resume( player );
+} // vote
+
+void init( Player & player, Player & lp, Player & rp ) with(player) { // supply partners
+	partner[LEFT] = &lp;
+	partner[RIGHT] = &rp;
+	resume( player );									// establish main as starter for termination
+} // init
+
+int getId( Player & player ) {							// player id
+	return player.id;
+} // getId
+
+void main( Player & player ) with(player) {
+    suspend;									// return immediately after establishing starter
+	try {
+        for ( ;; ) {
+            poll();                                     // check for non-local exceptions before proceeding
+
+            if ( partner[LEFT] == &player ) {			// stop when only one player
+                sout | id | " wins the Match!";
+                return;
+            } // exit
+            
+            countdown( potato );				// player is eliminated if countdown() returned true
+            
+            size_t side = prng( prng, 2 );
+            sout | id | " -> " | nonl;
+            resume( *partner[ side ] );			// random toss left/right
+        } // for
+	} catchResume( Terminate * v ) {
+		v->victim->partner[LEFT]->partner[RIGHT] = v->victim->partner[RIGHT]; // unlink node
+		v->victim->partner[RIGHT]->partner[LEFT] = v->victim->partner[LEFT];
+        delete( v->victim );
+		reset( potato );
+		sout | "U " | nonl;								// start new game
+		flush( sout );
+	} catchResume( Election * election ) {
+		sout | "election";
+		sout | " -> " | id | nonl;
+		if ( id > getId( umpire ) ) &umpire = &player; // set umpire to highest id so far
+		vote( *partner[RIGHT], *election );
+	} catchResume ( Explode * ) {
+        sout | id | " is eliminated";
+        if ( &player == &umpire ) {
+            id = -1;					// remove from election
+            vote( *partner[RIGHT], ExceptionInst( Election ) );		// start election
+            try { poll(); } catchResume( Election * election ) {} // handle end of election
+            sout | " : umpire " | getId( umpire );
+        } // if
+        resumeAt( umpire, ExceptionInst( Terminate, &player ) );
+        resume( umpire );                   // resume umpire to terminate this player
+        assert( false );					// no return
+    } // try
+} // main
+
+
+int main( int argc, char * argv[] ) {
+	enum {
+		MinNoPlayers = 2,								// minimum players in the game
+		MaxNoPlayers = 10,								// maximum players in the game
+		DefaultGames = 5,								// default games to play
+	};
+	intmax_t numGames = DefaultGames;					// games to play
+	intmax_t numPlayers = 0;							// players for a particular game
+	intmax_t seed = 42;									// random-number seed
+	bool playersSet = false;
+	char * nosummary = getenv( "NOSUMMARY" );			// print extra output
+
+	try {
+		choose ( argc ) {
+		  case 4:
+			if ( strcmp( argv[3], "d" ) != 0 ) {		// default ?
+				seed = convert( argv[3] ); if ( seed < 1 ) throw ExceptionInst( cmd_error ); // invalid ?
+			} // if
+			fallthrough;
+		  case 3:
+			if ( strcmp( argv[2], "d" ) != 0 ) {		// default ?
+				numPlayers = convert( argv[2] ); if ( numPlayers < 2 ) throw ExceptionInst( cmd_error ); // invalid ?
+				playersSet = true;
+			} // if
+			fallthrough;
+		  case 2:
+			if ( strcmp( argv[1], "d" ) != 0 ) {		// default ?
+				numGames = convert( argv[1] ); if ( numGames < 0 ) throw ExceptionInst( cmd_error ); // invalid ?
+			} // if
+			fallthrough;
+		  case 1: ;										// defaults
+		  default:										// too many arguments
+			throw ExceptionInst( cmd_error );
+		} // choose
+	} catch( exception_t * ) {							// catch any
+		exit | "Usage: " | argv[0]
+			 | " [ games (>=0) | 'd' (default " | DefaultGames
+			 | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
+			 | ") [ seed (>0) | 'd' (random) ] ] ]";
+	} // try
+	sout | numGames | numPlayers | seed;
+
+	PRNG mprng, hprng, pprng;
+	if ( seed != 0 ) {									// specified on command line ?
+		set_seed( mprng, seed );  set_seed( hprng, seed );  set_seed( pprng, seed );
+	} // if
+
+	for ( game; 1 ~= numGames ) {
+		if ( ! playersSet ) numPlayers = prng( mprng, MinNoPlayers, MaxNoPlayers ); 
+		sout | numPlayers | " players in the game";
+		{
+			Potato potato{ hprng };						// hot potato to be tossed
+			Player * players[numPlayers];
+
+			for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) { // start the players
+				players[i] = malloc();
+				?{}( *players[i], pprng, i, potato );
+			} // for
+		
+			// Do not swap player[0] with itself.
+			unsigned int rposn = prng( mprng, 1, numPlayers - 1 ); // swap random position with 0
+			swap( players[0], players[rposn] );
+
+			// Tell each player its partner.
+			for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) {
+				init( *players[i], *players[leftOf(i, numPlayers)], *players[rightOf(i, numPlayers)] );
+			} // for
+
+			&umpire = players[rposn];					// designate umpire and start game
+			sout | "U " | nonl;
+			resume( *players[rposn] );
+			delete( &umpire );
+		}
+		if ( game < (unsigned int)numGames ) sout | nl | nl; // whitespace between games
+	} // for
+} // main
+
+// Local Variables: //
+// compile-command: "make hotpotato" //
+// End: //
Index: tests/exceptions/hotpotato_checked.cfa
===================================================================
--- tests/exceptions/hotpotato_checked.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
+++ tests/exceptions/hotpotato_checked.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -0,0 +1,221 @@
+#include <fstream.hfa>									// sin/sout
+#include <stdlib.hfa>									// convert
+#include <string.h>
+#include <coroutine.hfa>
+
+struct Potato {
+        PRNG & prng;
+        unsigned int deadline;                                                          // when timer goes off
+        unsigned int timer;                                                                     // up counter to deadline
+}; // Potato
+
+void reset( Potato & potato, unsigned int maxTicks = 10 );
+void ?{}( Potato & potato, PRNG & prng, unsigned int maxTicks = 10 );
+
+void ?{}( Potato & potato, PRNG & prng, unsigned int maxTicks ) with(potato) {
+	&potato.prng = &prng;
+	reset( potato, maxTicks );
+} // Potato
+
+coroutine Player {
+        PRNG & prng;
+        int id;                                                                                         // player identity
+        Potato & potato;                                                                        // potato being tossed
+        Player * partner[2];                                                            // left and right player
+}; // Player
+
+void ?{}( Player & player, PRNG & prng, unsigned int id, Potato & potato ) {
+	&player.prng = &prng;
+	player.id = id;
+	&player.potato = &potato;
+} // Player
+
+Player & umpire;
+
+ExceptionDecl( Explode );
+ExceptionDecl( Terminate, Player * victim; );
+ExceptionDecl( Election );
+ExceptionDecl( cmd_error ); // convert(...) throws out_of_range or invalid_argument
+
+void reset( Potato & potato, unsigned int maxTicks ) with(potato) {
+  if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional
+	deadline = prng( prng, 1, maxTicks );
+	timer = 0;
+	sout | "  POTATO goes off after " | deadline | " tick" | nosep | (deadline > 1 ? "s" : "");
+} // reset
+
+void countdown( Potato & potato ) with(potato) {
+	timer += 1;
+	if ( timer == deadline ) throwResume ExceptionInst( Explode );
+} // countdown
+
+static unsigned int rightOf( unsigned int me, unsigned int total ) {
+	return ( me + 1 ) % total;
+} // rightOf
+
+static unsigned int leftOf( unsigned int me, unsigned int total ) {
+	return ( me + total - 1) % total;
+} // leftOf
+
+enum { LEFT = 0, RIGHT = 1 };
+
+static void vote( Player & player ) {					// cause partner to vote
+	resume( player ); checked_poll();
+} // vote
+
+static void terminate( Player & player ) {				// resume umpire
+	resume( player ); 
+    checked_poll();
+    sout | "THIS SHOULD NOT BE REACHED";
+} // terminate
+
+void init( Player & player, Player & lp, Player & rp ) with(player) { // supply partners
+	partner[LEFT] = &lp;
+	partner[RIGHT] = &rp;
+	resume( player );									// establish main as starter for termination
+    checked_poll();
+} // init
+
+int getId( Player & player ) {							// player id
+	return player.id;
+} // getId
+
+void toss( Player & player ) {							// tossed the potato
+    resume( player );
+	checked_poll();
+} // toss
+
+void main( Player & player ) with(player) {
+	try {
+        enable_ehm();								// allow delivery of nonlocal exceptions
+        suspend;									// return immediately after establishing starter
+        checked_poll();
+
+        for ( ;; ) {
+            checked_poll();
+            if ( partner[LEFT] == &player ) {			// stop when only one player
+                sout | id | " wins the Match!";
+                return;
+            } // exit
+
+            countdown( potato );				// player is eliminated if countdown() returned true
+
+            size_t side = prng( prng, 2 );
+            sout | id | " -> " | nonl;
+            toss( *partner[ side ] );			// random toss left/right
+        } // for
+        disable_ehm();
+	} catchResume( Terminate * v ) {
+		v->victim->partner[LEFT]->partner[RIGHT] = v->victim->partner[RIGHT]; // unlink node
+		v->victim->partner[RIGHT]->partner[LEFT] = v->victim->partner[LEFT];
+        delete( v->victim );
+		reset( potato );
+		sout | "U " | nonl;								// start new game
+		flush( sout );
+	} catchResume( Election * election ) {
+		sout | "election";
+		sout | " -> " | id | nonl;
+		if ( id > getId( umpire ) ) &umpire = &player; // set umpire to highest id so far
+        resumeAt( *partner[RIGHT], *election );
+        disable_ehm();              // disable ehm since we can't handle execption thrown in vote here and want to poll later
+		vote( *partner[RIGHT] );
+        enable_ehm();               // enable after vote
+	} catchResume( Explode * ) {
+        sout | id | " is eliminated";
+        if ( &player == &umpire ) {
+            try {
+                id = -1;					// remove from election
+                resumeAt( *partner[RIGHT], ExceptionInst( Election ) );
+                vote( *partner[RIGHT] );		// start election
+                checked_poll(); 
+            } catchResume( Election * election ) {
+                sout | " : umpire " | getId( umpire );
+            } // try
+        } // if
+        resumeAt( umpire, ExceptionInst( Terminate, &player ) );
+        terminate( umpire );
+        assert( false );					// no return
+    } // try
+} // main
+
+
+int main( int argc, char * argv[] ) {
+	enum {
+		MinNoPlayers = 2,								// minimum players in the game
+		MaxNoPlayers = 10,								// maximum players in the game
+		DefaultGames = 5,								// default games to play
+	};
+	intmax_t numGames = DefaultGames;					// games to play
+	intmax_t numPlayers = 0;							// players for a particular game
+	intmax_t seed = 42;									// random-number seed
+	bool playersSet = false;
+	char * nosummary = getenv( "NOSUMMARY" );			// print extra output
+
+	try {
+		choose ( argc ) {
+		  case 4:
+			if ( strcmp( argv[3], "d" ) != 0 ) {		// default ?
+				seed = convert( argv[3] ); if ( seed < 1 ) throw ExceptionInst( cmd_error ); // invalid ?
+			} // if
+			fallthrough;
+		  case 3:
+			if ( strcmp( argv[2], "d" ) != 0 ) {		// default ?
+				numPlayers = convert( argv[2] ); if ( numPlayers < 2 ) throw ExceptionInst( cmd_error ); // invalid ?
+				playersSet = true;
+			} // if
+			fallthrough;
+		  case 2:
+			if ( strcmp( argv[1], "d" ) != 0 ) {		// default ?
+				numGames = convert( argv[1] ); if ( numGames < 0 ) throw ExceptionInst( cmd_error ); // invalid ?
+			} // if
+			fallthrough;
+		  case 1: ;										// defaults
+		  default:										// too many arguments
+			throw ExceptionInst( cmd_error );
+		} // choose
+	} catch( exception_t * ) {							// catch any
+		exit | "Usage: " | argv[0]
+			 | " [ games (>=0) | 'd' (default " | DefaultGames
+			 | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
+			 | ") [ seed (>0) | 'd' (random) ] ] ]";
+	} // try
+	sout | numGames | numPlayers | seed;
+
+	PRNG mprng, hprng, pprng;
+	if ( seed != 0 ) {									// specified on command line ?
+		set_seed( mprng, seed );  set_seed( hprng, seed );  set_seed( pprng, seed );
+	} // if
+
+	for ( game; 1 ~= numGames ) {
+		if ( ! playersSet ) numPlayers = prng( mprng, MinNoPlayers, MaxNoPlayers ); 
+		sout | numPlayers | " players in the game";
+		{
+			Potato potato{ hprng };						// hot potato to be tossed
+			Player * players[numPlayers];
+
+			for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) { // start the players
+				players[i] = malloc();
+				?{}( *players[i], pprng, i, potato );
+			} // for
+		
+			// Do not swap player[0] with itself.
+			unsigned int rposn = prng( mprng, 1, numPlayers - 1 ); // swap random position with 0
+			swap( players[0], players[rposn] );
+
+			// Tell each player its partner.
+			for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) {
+				init( *players[i], *players[leftOf(i, numPlayers)], *players[rightOf(i, numPlayers)] );
+			} // for
+
+			&umpire = players[rposn];					// designate umpire and start game
+			sout | "U " | nonl;
+			toss( *players[rposn] );
+			delete( &umpire );
+		}
+		if ( game < (unsigned int)numGames ) sout | nl | nl; // whitespace between games
+	} // for
+} // main
+
+// Local Variables: //
+// compile-command: "make hotpotato" //
+// End: //
Index: tests/io/.expect/manipulatorsInput.arm64.txt
===================================================================
--- tests/io/.expect/manipulatorsInput.arm64.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/io/.expect/manipulatorsInput.arm64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,5 +1,8 @@
 pre1 "123456", canary ok
-pre2a "1234567", exception occurred, canary ok
-pre2b "89", canary ok
+pre2 "1234567", canary ok
+pre3a "1234567", exception occurred, canary ok
+pre3b "8", canary ok
+pre4a "1234567", exception occurred, canary ok
+pre4b "89", canary ok
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -15,4 +18,6 @@
 12 wwwwwwww
 13 wwwwwwww
+14 rc=1, cccc
+15 rc=0, q
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -28,4 +33,6 @@
 12 wwwwwwww
 13 wwwwwwww
+14 cccc
+15
 a
 a
Index: tests/io/.expect/manipulatorsInput.x64.txt
===================================================================
--- tests/io/.expect/manipulatorsInput.x64.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/io/.expect/manipulatorsInput.x64.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,5 +1,8 @@
 pre1 "123456", canary ok
-pre2a "1234567", exception occurred, canary ok
-pre2b "89", canary ok
+pre2 "1234567", canary ok
+pre3a "1234567", exception occurred, canary ok
+pre3b "8", canary ok
+pre4a "1234567", exception occurred, canary ok
+pre4b "89", canary ok
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -15,4 +18,6 @@
 12 wwwwwwww
 13 wwwwwwww
+14 rc=1, cccc
+15 rc=0, q
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -28,4 +33,6 @@
 12 wwwwwwww
 13 wwwwwwww
+14 cccc
+15
 a
 a
Index: tests/io/.expect/manipulatorsInput.x86.txt
===================================================================
--- tests/io/.expect/manipulatorsInput.x86.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/io/.expect/manipulatorsInput.x86.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,5 +1,8 @@
 pre1 "123456", canary ok
-pre2a "1234567", exception occurred, canary ok
-pre2b "89", canary ok
+pre2 "1234567", canary ok
+pre3a "1234567", exception occurred, canary ok
+pre3b "8", canary ok
+pre4a "1234567", exception occurred, canary ok
+pre4b "89", canary ok
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -15,4 +18,6 @@
 12 wwwwwwww
 13 wwwwwwww
+14 rc=1, cccc
+15 rc=0, q
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -28,4 +33,6 @@
 12 wwwwwwww
 13 wwwwwwww
+14 cccc
+15
 a
 a
Index: tests/io/.in/manipulatorsInput.txt
===================================================================
--- tests/io/.in/manipulatorsInput.txt	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/io/.in/manipulatorsInput.txt	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,16 +1,20 @@
 123456
+1234567
+12345678
 123456789
 abc 
-abc 
+cccccb 
 xx
 abcxxx
 abcyyy
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
+uuuuuccccuuuuu
 abc 
-abc 
+cccccb 
 xx
 abcxxx
 abcyyy
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
+uuuuuccccuuuuu
 ab
 0xff 017 15-15
Index: tests/io/manipulatorsInput.cfa
===================================================================
--- tests/io/manipulatorsInput.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/io/manipulatorsInput.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -45,13 +45,17 @@
 		}
 
-		rep("pre1");
-		rep("pre2a");
-		rep("pre2b");
+		rep("pre1");	// 123456     |  123456
+		rep("pre2");	// 1234567    |  1234567
+		rep("pre3a");	// 12345678   |  1234567
+		rep("pre3b");	//            |  8
+		rep("pre4a");	// 123456789  |  1234567
+		rep("pre4b");   //            |  89
+
 		scanf("\n");  // next test does not start with %s so does not tolerate leading whitespace
 	}
 	{
 		char s[] = "yyyyyyyyyyyyyyyyyyyy";
-		const char sk[] = "abc";
-		scanf( "abc " ); scanf( sk ); for ( 5 ) scanf( "%*c" );	printf( "1 %s\n", s );
+		const char sk_fmt[] = "%*[abc]";
+		scanf( "abc " ); scanf( sk_fmt ); for ( 5 ) scanf( "%*c" ); printf( "1 %s\n", s );
 		scanf( "%s", s );								printf( "2 %s\n", s );
 		scanf( "%*s" );									printf( "3 %s\n", s );
@@ -67,4 +71,12 @@
 		scanf( "%*8[abc]" );							printf( "12 %s\n", s );
 		scanf( "%*8[^abc]" );							printf( "13 %s\n", s );
+
+		int rc;
+		s[0] = 'q'; s[1] = '\0'; rc = 99;
+		rc = scanf( "%[abc]", s );						printf( "14 rc=%d, %s\n", rc, s );
+		s[0] = 'q'; s[1] = '\0'; rc = 99;
+		rc = scanf( "%[^u]", s );						printf( "15 rc=%d, %s\n", rc, s );
+		scanf( "%*[u]" );
+		scanf("\n");
 	}
 	{
@@ -85,4 +97,11 @@
 		sin | ignore( incl( "abc", wdi( sizeof(s), 8, s ) ) ); sout | "12" | s;
 		sin | ignore( excl( "abc", wdi( sizeof(s), 8, s ) ) ); sout | "13" | s;
+
+		s[0] = 'q'; s[1] = '\0';
+		sin | incl( "abc", wdi( sizeof(s), s ) );		sout | "14" | s;
+		s[0] = 'q'; s[1] = '\0';
+		sin | excl( "u", wdi( sizeof(s), s ) );			sout | "15" | s;
+		sin | skip( "u" );
+		sin | "\n";
 	}
     /* Keep harmonized with collections/string-istream-manip */
Index: tests/link-once/main.cfa
===================================================================
--- tests/link-once/main.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/link-once/main.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,5 +1,5 @@
 // Test our new cfa_linkonce attribute:
 
-__attribute__(( cfa_linkonce )) signed int example = -7;
+__attribute__(( cfa_linkonce )) signed int example = 7;
 __attribute__(( cfa_linkonce )) unsigned int example = 12;
 
Index: tests/link-once/partner.cfa
===================================================================
--- tests/link-once/partner.cfa	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/link-once/partner.cfa	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -1,5 +1,5 @@
 // Side file for the link-once test.
 
-__attribute__(( cfa_linkonce )) signed int example = -7;
+__attribute__(( cfa_linkonce )) signed int example = 7;
 __attribute__(( cfa_linkonce )) unsigned int example = 12;
 
Index: tests/test.py
===================================================================
--- tests/test.py	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tests/test.py	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -116,5 +116,5 @@
 	parser.add_argument('--no-invariant', help='Tell the compiler not to check invariants.', action='store_false', dest='invariant')
 	parser.add_argument('--invariant', help='Tell the compiler to check invariants.', action='store_const', const=True)
-	parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180)
+	parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=240)
 	parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
 	parser.add_argument('--timeout-with-gdb', help='Instead of killing the command when it times out, orphan it and print process id to allow gdb to attach', type=yes_no, default="no")
@@ -125,5 +125,5 @@
 	parser.add_argument('--archive-errors', help='If called with a valid path, on test crashes the test script will copy the core dump and the executable to the specified path.', type=str, default='')
 	parser.add_argument('-j', '--jobs', help='Number of tests to run simultaneously, 0 (default) for unlimited', nargs='?', const=0, type=int)
-	parser.add_argument('--list-comp', help='List all valide arguments', action='store_true')
+	parser.add_argument('--list-comp', help='List all valid arguments', action='store_true')
 	parser.add_argument('--list-dist', help='List all tests for distribution', action='store_true')
 	parser.add_argument('-I','--include', help='Directory of test to include, can be used multiple time, All  if omitted', action='append')
Index: tools/build/cfa.m4
===================================================================
--- tools/build/cfa.m4	(revision 85034edc709b6220ea9dabc9a07efab793e34dab)
+++ tools/build/cfa.m4	(revision 8cbe732066c1d0d00e6d6622a2e8b5a6b1f72c45)
@@ -67,5 +67,5 @@
 		"x86_64"     ) cannon_arch_name="x64";;
 		"aarch64"    ) cannon_arch_name="arm64";;
-		"arm4"       ) cannon_arch_name="arm64";;
+		"arm64"      ) cannon_arch_name="arm64";;
 		"ARM64"      ) cannon_arch_name="arm64";;
 		"x86"        ) cannon_arch_name="x86";;
