Index: doc/theses/mike_brooks_MMath/background.tex
===================================================================
--- doc/theses/mike_brooks_MMath/background.tex	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ doc/theses/mike_brooks_MMath/background.tex	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -1,5 +1,5 @@
 \chapter{Background}
 
-Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string, 
+Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string.
 
 
@@ -45,140 +45,134 @@
 Hence, in all cases, @sizeof@ is informing about type information.
 
-So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up the type system.
-This misguided analogue can be forced onto single-dimension arrays but there is no advantage other than possibly teaching beginning programmers about basic runtime array-access.
-
-Continuing, a shortened form for declaring local variables exists, provided that length information is given in the initializer:
+So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up by the type system.
+This misguided analogue works for a single-dimension array but there is no advantage other than possibly teaching beginning programmers about basic runtime array-access.
+
+Continuing, a short form for declaring array variables exists using length information provided implicitly by an initializer.
 \lstinput{59-62}{bkgd-carray-arrty.c}
-In these declarations, the resulting types are both arrays, but their lengths are inferred.
-
-My contribution is enabled by recognizing
+The compiler counts the number of initializer elements and uses this value as the first dimension.
+Unfortunately, the implicit element counting does not extend to dimensions beyond the first.
+\lstinput{64-67}{bkgd-carray-arrty.c}
+
+My contribution is recognizing:
 \begin{itemize}
-	\item There is value in using a type that knows how big the whole thing is.
+	\item There is value in using a type that knows its size.
 	\item The type pointer to (first) element does not.
 	\item C \emph{has} a type that knows the whole picture: array, e.g. @T[10]@.
-	\item This type has all the usual derived forms, which also know the whole picture.  A usefully noteworthy example is pointer to array, e.g. @T(*)[10]@.
+	\item This type has all the usual derived forms, which also know the whole picture.
+	A usefully noteworthy example is pointer to array, e.g. @T (*)[10]@.\footnote{
+	The parenthesis are necessary because subscript has higher priority than pointer in C declarations.
+	(Subscript also has higher priority than dereference in C expressions.)}
 \end{itemize}
 
-Each of these sections, which introduces another layer of of the C arrays' story,
-concludes with an \emph{Unfortunate Syntactic Reference}.
-It shows how to spell the types under discussion,
-along with interactions with orthogonal (but easily confused) language features.
-Alternate spellings are listed within a row.
+
+\section{Reading Declarations}
+
+A significant area of confusion for reading C declarations results from embedding a declared variable in a declaration, mimicking the way the variable is used in executable statements.
+\begin{cquote}
+\begin{tabular}{@{}ll@{}}
+\multicolumn{1}{@{}c}{\textbf{Array}} & \multicolumn{1}{c@{}}{\textbf{Function Pointer}} \\
+\begin{cfa}
+int @(*@ar@)[@5@]@; // definition
+  ... @(*@ar@)[@3@]@ += 1; // usage
+\end{cfa}
+&
+\begin{cfa}
+int @(*@f@())[@5@]@ { ... }; // definition
+  ... @(*@f@())[@3@]@ += 1; // usage
+\end{cfa}
+\end{tabular}
+\end{cquote}
+Essentially, the type is wrapped around the name in successive layers (like an \Index{onion}).
+While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise:
+\begin{quote}
+In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93}
+\end{quote}
+After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right!
+
+\CFA provides its own type, variable and routine declarations, using a simpler syntax.
+The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type.
+The qualifiers have the same meaning in \CFA as in C.
+Then, a \CFA declaration is read left to right, where a function return type is enclosed in brackets @[@\,@]@.
+\begin{cquote}
+\begin{tabular}{@{}l@{\hspace{3em}}ll@{}}
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{read left to right}}	\\
+\begin{cfa}
+int @*@ x1 @[5]@;
+int @(*@x2@)[5]@;
+int @(*@f( int p )@)[5]@;
+\end{cfa}
+&
+\begin{cfa}
+@[5] *@ int x1;
+@* [5]@ int x2;
+@[ * [5] int ]@ f( int p );
+\end{cfa}
+&
+\begin{cfa}
+// array of 5 pointers to int
+// pointer to array of 5 int
+// function returning pointer to array of 5 ints
+\end{cfa}
+\\
+& &
+\LstCommentStyle{//\ \ \ and taking an int argument}
+\end{tabular}
+\end{cquote}
+As declaration complexity increases, it becomes corresponding difficult to read and understand the C declaration form.
+Note, writing declarations left to right is common in other programming languages, where the function return-type is often placed after the parameter declarations.
+
+\VRef[Table]{bkgd:ar:usr:avp} introduces the many layers of the C and \CFA array story, where the \CFA story is discussion in \VRef{XXX}.
+The \CFA-thesis column shows the new array declaration form, which is my contributed improvements for safety and ergonomics.
+The table shows there are multiple yet equivalent forms for the array types under discussion, and subsequent discussion shows interactions with orthogonal (but easily confused) language features.
+Each row of the table shows alternate syntactic forms.
 The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$.
-The Type column gives the spelling used in a cast or error message (though note Section TODO points out that some types cannot be casted to).
-The Declaration column gives the spelling used in an object declaration, such as variable or aggregate member; parameter declarations (section TODO) follow entirely different rules.
-
-After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right!
-
-
-\CFA-specific spellings (not yet introduced) are also included here for referenceability; these can be skipped on linear reading.
-The \CFA-C column gives the, more fortunate, ``new'' syntax of section TODO, for spelling \emph{exactly the same type}.
-This fortunate syntax does not have different spellings for types vs declarations;
-a declaration is always the type followed by the declared identifier name;
-for the example of letting @x@ be a \emph{pointer to array}, the declaration is spelled:
-\begin{cfa}
-[ * [10] T ] x;
-\end{cfa}
-The \CFA-Full column gives the spelling of a different type, introduced in TODO, which has all of my contributed improvements for safety and ergonomics.
-
-\VRef[Figure]{bkgd:ar:usr:avp} gives this reference for the discussion so far.
-
-\begin{figure}
+Removing the declared variable @x@, gives the type used for variable, structure field, cast or error messages \PAB{(though note Section TODO points out that some types cannot be casted to)}.
+Unfortunately, parameter declarations \PAB{(section TODO)} have more syntactic forms and rules.
+
+\begin{table}
 \centering
-\setlength{\tabcolsep}{3pt}
-\begin{tabular}{llllll}
-	& Description & Type & Declaration & \CFA-C  & \CFA-Full \\ \hline
-	$\triangleright$ & val.
-	    & @T@ 
-	    & @T x;@ 
-	    & @[ T ]@
-	    & 
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} val.\\ \footnotesize{no writing the val.\ in \lstinline{x}}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T} \\ \lstinline{T const}   }
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x;} \\ \lstinline{T const x;}   }
-	    & @[ const T ]@
-	    & 
-	    \\ \hline \hline
-	$\triangleright$ & ptr.\ to val.
-	    & @T *@ 
-	    & @T * x;@ 
-	    & @[ * T ]@
-	    &
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
-	    & @T * const@ 
-	    & @T * const x;@ 
-	    & @[ const * T ]@
-	    & 
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *}   }
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x;} \\ \lstinline{T const * x;}   }
-	    & @[ * const T ]@
-	    & 
-	    \\ \hline \hline
-	$\triangleright$ & ar.\ of val.
-	    & @T[10]@ 
-	    & @T x[10];@ 
-	    & @[ [10] T ]@
-	    & @[ array(T, 10) ]@
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{x[5]}}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T[10]} \\ \lstinline{T const[10]}   }
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x[10];} \\ \lstinline{T const x[10];}   }
-	    & @[ [10] const T ]@
-	    & @[ const array(T, 10) ]@
-	    \\ \hline
-	& ar.\ of ptr.\ to val.
-	    & @T*[10]@
-	    & @T *x[10];@
-	    & @[ [10] * T ]@
-	    & @[ array(* T, 10) ]@
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x[5]}}   }\vspace{2pt}
-	    & @T * const [10]@ 
-	    & @T * const x[10];@ 
-	    & @[ [10] const * T ]@
-	    & @[ array(const * T, 10) ]@
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*(x[5])}}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * [10]} \\ \lstinline{T const * [10]}   }
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x[10];} \\ \lstinline{T const * x[10];}   }
-	    & @[ [10] * const T ]@
-	    & @[ array(* const T, 10) ]@
-	    \\ \hline \hline
-	$\triangleright$ & ptr.\ to ar.\ of val.
-	    & @T(*)[10]@
-	    & @T (*x)[10];@
-	    & @[ * [10] T ]@
-	    & @[ * array(T, 10) ]@
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
-	    & @T(* const)[10]@
-	    & @T (* const x)[10];@
-	    & @[ const * [10] T ]@
-	    & @[ const * array(T, 10) ]@
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{(*x)[5]}}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T(*)[10]} \\ \lstinline{T const (*) [10]}   }
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T (*x)[10];} \\ \lstinline{T const (*x)[10];}   }
-	    & @[ * [10] const T ]@
-	    & @[ * const array(T, 10) ]@
-	    \\ \hline
-	& ptr.\ to ar.\ of ptr.\ to val.
-	    & @T*(*)[10]@
-	    & @T *(*x)[10];@
-	    & @[ * [10] * T ]@
-	    & @[ * array(* T, 10) ]@
-	    \\ \hline
+\caption{Syntactic Reference for Array vs Pointer. Includes interaction with \lstinline{const}ness.}
+\label{bkgd:ar:usr:avp}
+\begin{tabular}{ll|l|l|l}
+	& Description & \multicolumn{1}{c|}{C} & \multicolumn{1}{c|}{\CFA}  & \multicolumn{1}{c}{\CFA-thesis} \\
+	\hline
+$\triangleright$ & value & @T x;@ & @T x;@ & \\
+	\hline
+	& immutable value & @const T x;@ & @const T x;@ & \\
+	& & @T const x;@ & @T const x;@ & \\
+	\hline \hline
+$\triangleright$ & pointer to value & @T * x;@ & @* T x;@ & \\
+	\hline
+	& immutable ptr. to val. & @T * const x;@ & @const * T x;@ & \\
+	\hline
+	& ptr. to immutable val. & @const T * x;@ & @* const T x;@ & \\
+	& & @T const * x;@ & @* T const x;@ & \\
+	\hline \hline
+$\triangleright$ & array of value & @T x[10];@ & @[10] T x@ & @array(T, 10) x@ \\
+	\hline
+	& ar.\ of immutable val. & @const T x[10];@ & @[10] const T x@ & @const array(T, 10) x@ \\
+    & & @T const x[10];@ & @[10] T const x@ & @array(T, 10) const x@ \\
+	\hline
+	& ar.\ of ptr.\ to value & @T * x[10];@ & @[10] * T x@ & @array(T *, 10) x@ \\
+	& & & & @array(* T, 10) x@ \\
+	\hline
+	& ar.\ of imm. ptr.\ to val. & @T * const x[10];@ & @[10] const * T x@ & @array(* const T, 10) x@ \\
+	& & & & @array(const * T, 10) x@ \\
+	\hline
+	& ar.\ of ptr.\ to imm. val. & @const T * x[10];@ & @[10] * const T x@ & @array(const T *, 10) x@ \\
+	& & @T const * x[10];@ & @[10] * T const x@ & @array(* const T, 10) x@ \\
+	\hline \hline
+$\triangleright$ & ptr.\ to ar.\ of value & @T (*x)[10];@ & @* [10] T x@ & @* array(T, 10) x@ \\
+	\hline
+	& imm. ptr.\ to ar.\ of val. & @T (* const x)[10];@ & @const * [10] T x@ & @const * array(T, 10) x@ \\
+	\hline
+	& ptr.\ to ar.\ of imm. val. & @const T (*x)[10];@ & @* [10] const T x@ & @* const array(T, 10) x@ \\
+	& & @T const (*x)[10];@ & @* [10] T const x@ & @* array(T, 10) const x@ \\
+	\hline
+	& ptr.\ to ar.\ of ptr.\ to val. & @T *(*x)[10];@ & @* [10] * T x@ & @* array(T *, 10) x@ \\
+	& & & & @* array(* T, 10) x@ \\
+	\hline
 \end{tabular}
-\caption{Unfortunate Syntactic Reference for Array vs Pointer.  Includes interaction with constness.}
-\label{bkgd:ar:usr:avp}
-\end{figure}
-
-
-
-
+\end{table}
 
 TODO: Address these parked unfortunate syntaxes
@@ -186,5 +180,5 @@
 	\item static
 	\item star as dimension
-	\item under pointer decay:				int p1[const 3]  being  int const *p1
+	\item under pointer decay: @int p1[const 3]@ being @int const *p1@
 \end{itemize}
 
@@ -203,23 +197,18 @@
 \lstinput{10-10}{bkgd-carray-decay.c}
 
-So, C provides an implicit conversion from @float[10]@ to @float*@, as described in ARM-6.3.2.1.3:
+So, C provides an implicit conversion from @float[10]@ to @float *@.
 \begin{quote}
-Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a
-string literal used to initialize an array
-an expression that has type ``array of type'' is
-converted to an expression with type ``pointer to type'' that points to the initial element of
-the array object
+Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a string literal used to
+initialize an array an expression that has type ``array of \emph{type}'' is converted to an expression with type
+``pointer to \emph{type}'' that points to the initial element of the array object~\cite[\S~6.3.2.1.3]{C11}
 \end{quote}
-
 This phenomenon is the famous ``pointer decay,'' which is a decay of an array-typed expression into a pointer-typed one.
-
 It is worthy to note that the list of exception cases does not feature the occurrence of @ar@ in @ar[i]@.
-Thus, subscripting happens on pointers, not arrays.
-
-Subscripting proceeds first with pointer decay, if needed.  Next, ARM-6.5.2.1.2 explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@.
-ARM-6.5.6.8 explains that the addition, of a pointer with an integer type,  is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough.
-Finally, ARM-6.5.3.2.4 explains that the @*@ operator's result is the referenced element.
-
-Taken together, these rules also happen to illustrate that @ar[i]@ and @i[a]@ mean the same thing.
+Thus, subscripting happens on pointers not arrays.
+
+Subscripting proceeds first with pointer decay, if needed.  Next, \cite[\S~6.5.2.1.2]{C11} explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@.
+\cite[\S~6.5.6.8]{C11} explains that the addition, of a pointer with an integer type,  is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough.
+Finally, \cite[\S~6.5.3.2.4]{C11} explains that the @*@ operator's result is the referenced element.
+Taken together, these rules illustrate that @ar[i]@ and @i[a]@ mean the same thing!
 
 Subscripting a pointer when the target is standard-inappropriate is still practically well-defined.
@@ -233,28 +222,23 @@
 fs[5] = 3.14;
 \end{cfa}
-The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (ARM-7.22.3.4.2).
-But program says \emph{nothing} more about this pointer value, that might cause its referent to \emph{be} an array, before doing the subscript.
-
-Under this assumption, a pointer being subscripted (or added to, then dereferenced)
-by any value (positive, zero, or negative), gives a view of the program's entire address space,
-centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks,
-each potentially (re)interpreted as @typeof(*p)@.
-
-I call this phenomenon ``array diffraction,''  which is a diffraction of a single-element pointer
-into the assumption that its target is in the middle of an array whose size is unlimited in both directions.
-
+The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (\cite[\S~7.22.3.4.2]{C11}).
+But \emph{nothing} more is said about this pointer value, specifically that its referent might \emph{be} an array allowing subscripting.
+
+Under this assumption, a pointer being subscripted (or added to, then dereferenced) by any value (positive, zero, or negative), gives a view of the program's entire address space, centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks, each potentially (re)interpreted as @typeof(*p)@.
+I call this phenomenon ``array diffraction,''  which is a diffraction of a single-element pointer into the assumption that its target is in the middle of an array whose size is unlimited in both directions.
 No pointer is exempt from array diffraction.
-
 No array shows its elements without pointer decay.
 
 A further pointer--array confusion, closely related to decay, occurs in parameter declarations.
-ARM-6.7.6.3.7 explains that when an array type is written for a parameter,
-the parameter's type becomes a type that I summarize as being the array-decayed type.
-The respective handlings of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.
+\cite[\S~6.7.6.3.7]{C11} explains that when an array type is written for a parameter,
+the parameter's type becomes a type that can be summarized as the array-decayed type.
+The respective handling of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.
 \lstinput{12-16}{bkgd-carray-decay.c}
 As the @sizeof(x)@ meaning changed, compared with when run on a similarly-spelled local variable declaration,
-GCC also gives this code the warning: ```sizeof' on array function parameter `x' will return size of `float *'.''
-
-The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it's spelled:
+@gcc@ also gives this code the warning for the first assertion:
+\begin{cfa}
+warning: 'sizeof' on array function parameter 'x' will return size of 'float *'
+\end{cfa}
+The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it is spelled:
 \lstinput{18-21}{bkgd-carray-decay.c}
 This fragment gives no warnings.
@@ -272,5 +256,4 @@
 depending on whether the object is a local variable or a parameter.
 
-
 In summary, when a function is written with an array-typed parameter,
 \begin{itemize}
@@ -283,76 +266,72 @@
 As a result, a function with a pointer-to-array parameter sees the parameter exactly as the caller does:
 \lstinput{32-42}{bkgd-carray-decay.c}
-
-\VRef[Figure]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter decalarations.
-
-\begin{figure}
+\VRef[Table]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter declarations.
+
+\begin{table}
+\caption{Syntactic Reference for Decay during Parameter-Passing.
+Includes interaction with \lstinline{const}ness, where ``immutable'' refers to a restriction on the callee's ability.}
+\label{bkgd:ar:usr:decay-parm}
 \centering
 \begin{tabular}{llllll}
-	& Description & Type & Param. Decl & \CFA-C  \\ \hline
-	$\triangleright$ & ptr.\ to val.
-	    & @T *@ 
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{T * x,} \\ \lstinline{T x[10],} \\ \lstinline{T x[],}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * T ]} \\ \lstinline{[ [10] T ]} \\ \lstinline{[ [] T  ]}   }
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
-	    & @T * const@ 
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{T * const x,} \\ \lstinline{T x[const 10],} \\ \lstinline{T x[const],}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{[ const * T ]} \\ \lstinline{[ [const 10] T ]} \\ \lstinline{[ [const] T  ]}   }
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *}   }
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x,} \\ \lstinline{T const * x,} \\ \lstinline{const T x[10],} \\ \lstinline{T const x[10],} \\ \lstinline{const T x[],} \\ \lstinline{T const x[],}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{[* const T]} \\ \lstinline{[ [10] const T ]} \\ \lstinline{[ [] const T  ]}   }
-	    \\ \hline \hline
-	$\triangleright$ & ptr.\ to ar.\ of val.
-	    & @T(*)[10]@
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{T (*x)[10],} \\ \lstinline{T x[3][10],} \\ \lstinline{T x[][10],}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{[* [10] T]} \\ \lstinline{[ [3] [10] T ]} \\ \lstinline{[ [] [10] T  ]}   }
-	    \\ \hline
-	& ptr.\ to ptr.\ to val.
-	    & @T **@
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{T ** x,} \\ \lstinline{T *x[10],} \\ \lstinline{T *x[],}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * * T ]} \\ \lstinline{[ [10] * T ]} \\ \lstinline{[ [] * T  ]}   }
-	    \\ \hline
-	& \pbox{20cm}{ \vspace{2pt} ptr.\ to ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{**argv}}   }\vspace{2pt}
-	    & @const char **@
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{const char *argv[],} \\ \footnotesize{(others elided)}   }\vspace{2pt}
-	    & \pbox{20cm}{ \vspace{2pt} \lstinline{[ [] * const char ]} \\ \footnotesize{(others elided)}   }
-	    \\ \hline
+	& Description & Type & Parameter Declaration & \CFA  \\
+	\hline
+	& & & @T * x,@ & @* T x,@ \\
+$\triangleright$ & pointer to value & @T *@ & @T x[10],@ & @[10] T x,@ \\
+	& & & @T x[],@ & @[] T x,@ \\
+	\hline
+	& & & @T * const x,@ & @const * T x@ \\
+	& immutable ptr.\ to val. & @T * const@ & @T x[const 10],@ & @[const 10] T x,@ \\
+	& & & @T x[const],@ & @[const] T x,@\\
+	\hline
+	& & & @const T * x,@ & @ * const T x,@ \\
+	& &	& @T const * x,@ & @ * T const x,@ \\
+	& ptr.\ to immutable val. & @const T *@ & @const T x[10],@ & @[10] const T x,@ \\
+	& & @T const *@ & @T const x[10],@ &  @[10] T const x,@ \\
+	& & & @const T x[],@ & @[] const T x,@ \\
+	& & & @T const x[],@ & @[] T const x,@ \\
+	\hline \hline
+	& & & @T (*x)[10],@ & @* [10] T x,@ \\
+$\triangleright$ & ptr.\ to ar.\ of val. & @T(*)[10]@ & @T x[3][10],@ & @[3][10] T x,@ \\
+	& & & @T x[][10],@ & @[][10] T x,@ \\
+	\hline
+	& & & @T ** x,@ & @** T x,@ \\
+	& ptr.\ to ptr.\ to val. & @T **@ & @T * x[10],@ & @[10] * T x,@ \\
+	& & & @T * x[],@ & @[] * T x,@ \\
+	\hline
+	& ptr.\ to ptr.\ to imm.\ val. & @const char **@ & @const char * argv[],@ & @[] * const char argv,@ \\
+    & & & \emph{others elided} & \emph{others elided} \\
+	\hline
 \end{tabular}
-\caption{Unfortunate Syntactic Reference for Decay during Parameter-Passing.  Includes interaction with constness, where ``no writing'' refers to a restriction on the callee's ability.}
-\label{bkgd:ar:usr:decay-parm}
-\end{figure}
+\end{table}
 
 
 \subsection{Lengths may vary, checking does not}
 
-When the desired number of elements is unknown at compile time,
-a variable-length array is a solution:
-\begin{cfa}
-int main( int argc, const char *argv[] ) {
+When the desired number of elements is unknown at compile time, a variable-length array is a solution:
+\begin{cfa}
+int main( int argc, const char * argv[] ) {
 	assert( argc == 2 );
 	size_t n = atol( argv[1] );
-	assert( 0 < n && n < 1000 );
-
+	assert( 0 < n );
 	float ar[n];
 	float b[10];
-
 	// ... discussion continues here
 }
 \end{cfa}
-This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, just as it puts 10 elements on the @main@ stack frame for @b@.
-The variable-sized allocation of @ar@ is provided by @alloca@.
-
-In a situation where the array sizes are not known to be small enough for stack allocation to be sensible, corresponding heap allocations are achievable as:
-\begin{cfa}
-float *ax1 = malloc( sizeof( float[n] ) );
-float *ax2 = malloc( n * sizeof( float ) );
-float *bx1 = malloc( sizeof( float[1000000] ) );
-float *bx2 = malloc( 1000000 * sizeof( float ) );
-\end{cfa}
-
-
-VLA
+This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, called a \newterm{variable length array} (VLA), as well as 10 elements in the same stack frame for @b@.
+The variable-sized allocation of @ar@ is provided by the @alloca@ routine, which bumps the stack pointer.
+Note, the C standard supports VLAs~\cite[\S~6.7.6.2.4]{C11} as a conditional feature, but the \CC standard does not;
+both @gcc@ and @g++@ support VLAs.
+As well, there is misinformation about VLAs, \eg VLAs cause stack failures or are inefficient.
+VLAs exist as far back as Algol W~\cite[\S~5.2]{AlgolW} and are a sound and efficient data type.
+
+For high-performance applications, the stack size can be fixed and small (coroutines or user-level threads).
+Here, VLAs can overflow the stack, so a heap allocation is used.
+\begin{cfa}
+float * ax1 = malloc( sizeof( float[n] ) );
+float * ax2 = malloc( n * sizeof( float ) );
+float * bx1 = malloc( sizeof( float[1000000] ) );
+float * bx2 = malloc( 1000000 * sizeof( float ) );
+\end{cfa}
 
 Parameter dependency
@@ -363,6 +342,5 @@
 
 
-
-\subsection{C has full-service, dynamically sized, multidimensional arrays (and \CC does not)}
+\subsection{Dynamically sized, multidimensional arrays}
 
 In C and \CC, ``multidimensional array'' means ``array of arrays.''  Other meanings are discussed in TODO.
@@ -416,4 +394,33 @@
 \section{Linked List}
 
+Linked-lists are blocks of storage connected using one or more pointers.
+The storage block is logically divided into data and links (pointers), where the links are the only component used by the list structure.
+Since the data is opaque, list structures are often polymorphic over the data, which is normally homogeneous.
+
 
 \section{String}
+
+A string is a logical sequence of symbols, where the form of the symbols can vary significantly: 7/8-bit characters (ASCII/Latin-1), or 2/4/8-byte (UNICODE) characters/symbols or variable length (UTF-8/16/32) characters.
+A string can be read left-to-right, right-to-left, top-to-bottom, and have stacked elements (Arabic).
+
+An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in @'x'@.
+A wide character constant is the same, except prefixed by the letter @L@, @u@, or @U@.
+With a few exceptions detailed later, the elements of the sequence are any members of the source character set;
+they are mapped in an implementation-defined manner to members of the execution character set.
+
+A C character-string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in @"xyz"@.
+A UTF-8 string literal is the same, except prefixed by @u8@.
+A wide string literal is the same, except prefixed by the letter @L@, @u@, or @U@.
+
+For UTF-8 string literals, the array elements have type @char@, and are initialized with the characters of the multibyte character sequence, as encoded in UTF-8.
+For wide string literals prefixed by the letter @L@, the array elements have type @wchar_t@ and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by the @mbstowcs@ function with an implementation-defined current locale.
+For wide string literals prefixed by the letter @u@ or @U@, the array elements have type @char16_t@ or @char32_t@, respectively, and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by successive calls to the @mbrtoc16@, or @mbrtoc32@ function as appropriate for its type, with an implementation-defined current locale.
+The value of a string literal containing a multibyte character or escape sequence not represented in the executioncharacter set is implementation-defined.
+
+
+Another bad C design decision is to have null-terminated strings rather than maintaining a separate string length.
+\begin{quote}
+Technically, a string is an array whose elements are single characters.
+The compiler automatically places the null character @\0@ at the end of each such string, so programs can conveniently find the end.
+This representation means that there is no real limit to how long a string can be, but programs have to scan one completely to determine its length.
+\end{quote}
Index: doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c
===================================================================
--- doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -57,9 +57,13 @@
 	f( &ar );
 
-	float fs[] = {3.14, 1.707};
+	float fs[] = {3.14, 1.77};
 	char cs[] = "hello";
 	static_assert( sizeof(fs) == 2 * sizeof(float) );
 	static_assert( sizeof(cs) == 6 * sizeof(char) );  $\C{// 5 letters + 1 null terminator}$
 
+	float fm[][2] = { {3.14, 1.77}, {12.4, 0.01}, {7.8, 1.23} };  $\C{// brackets define structuring}$
+	char cm[][sizeof("hello")] = { "hello", "hello", "hello" };
+	static_assert( sizeof(fm) == 3 * 2 * sizeof(float) );
+	static_assert( sizeof(cm) == 3 * 6 * sizeof(char) );
 }
 
Index: doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c
===================================================================
--- doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -4,13 +4,13 @@
 	float (*pa)[10] = &a;		$\C{// pointer to array}$
 	float a0 = a[0];			$\C{// element}$
-	float *pa0 = &(a[0]);		$\C{// pointer to element}$
+	float * pa0 = &(a[0]);		$\C{// pointer to element}$
 
-	float *pa0x = a;			$\C{// (ok)}$
+	float * pa0x = a;			$\C{// (ok)}$
 	assert( pa0 == pa0x );
 	assert( sizeof(pa0x) != sizeof(a) );
 
-	void f( float x[10], float *y ) {
-		static_assert( sizeof(x) == sizeof(void*) );
-		static_assert( sizeof(y) == sizeof(void*) );
+	void f( float x[10], float * y ) {
+		static_assert( sizeof(x) == sizeof(void *) );
+		static_assert( sizeof(y) == sizeof(void *) );
 	}
 	f(0,0);
@@ -22,14 +22,14 @@
 
 	char ca[] = "hello";		$\C{// array on stack, initialized from read-only data}$
-	char *cp = "hello";			$\C{// pointer to read-only data [decay here]}$
-	void edit( char c[] ) {		$\C{// param is pointer}$
+	char * cp = "hello";		$\C{// pointer to read-only data [decay here]}$
+	void edit( char c[] ) {		$\C{// parameter is pointer}$
 		c[3] = 'p';
 	}
 	edit( ca );					$\C{// ok [decay here]}$
-	edit( c p );				$\C{// Segmentation fault}$
+	edit( cp );					$\C{// Segmentation fault}$
 	edit( "hello" );			$\C{// Segmentation fault [decay here]}$
 
 	void decay( float x[10] ) {
-		static_assert( sizeof(x) == sizeof(void*) );
+		static_assert( sizeof(x) == sizeof(void *) );
 	}
 	static_assert( sizeof(a) == 10 * sizeof(float) );
Index: libcfa/src/concurrency/kernel/cluster.cfa
===================================================================
--- libcfa/src/concurrency/kernel/cluster.cfa	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ libcfa/src/concurrency/kernel/cluster.cfa	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -341,5 +341,5 @@
 	// Make sure that everything is consistent
 	/* paranoid */ check_readyQ( cltr );
-	/* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
+//	/* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
 
 	__cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue done\n");
@@ -416,4 +416,5 @@
 		fix_times(readyQ.tscs, ncount);
 	}
+
 	cltr->sched.caches = alloc( target, cltr->sched.caches`realloc );
 
@@ -428,5 +429,5 @@
 
 	// Make sure that everything is consistent
-	/* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
+//	/* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
 	/* paranoid */ check_readyQ( cltr );
 
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -672,6 +672,6 @@
 	uint_fast32_t last_size = ready_mutate_lock();
 
-		// Adjust the ready queue size
-		ready_queue_shrink( &this );
+	// Adjust the ready queue size
+	ready_queue_shrink( &this );
 
 	// Unlock the RWlock
@@ -682,6 +682,6 @@
 	/* paranoid */ verify( this.sched.readyQ.tscs == 0p );
  	/* paranoid */ verify( this.sched.readyQ.count == 0 );
-	/* paranoid */ verify( this.sched.io.tscs == 0p );
-	/* paranoid */ verify( this.sched.caches == 0p );
+//	/* paranoid */ verify( this.sched.io.tscs == 0p );
+//	/* paranoid */ verify( this.sched.caches == 0p );
 
 	enable_interrupts( false ); // Don't poll, could be in main cluster
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ libcfa/src/heap.cfa	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -10,6 +10,6 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jan  3 21:30:54 2024
-// Update Count     : 1619
+// Last Modified On : Sun Apr  7 21:54:29 2024
+// Update Count     : 1644
 //
 
@@ -114,5 +114,5 @@
 
 
-// generic Bsearchl does not inline, so substitute with hand-coded binary-search.
+// CFA generic Bsearchl does not inline, so substitute with hand-coded binary-search.
 inline __attribute__((always_inline))
 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
@@ -190,5 +190,5 @@
 		unsigned int realloc_calls, realloc_0_calls;
 		unsigned long long int realloc_storage_request, realloc_storage_alloc;
-		unsigned int free_calls, free_null_calls;
+		unsigned int free_calls, free_null_0_calls;
 		unsigned long long int free_storage_request, free_storage_alloc;
 		unsigned int return_pulls, return_pushes;
@@ -232,17 +232,13 @@
 		struct Header {									// header
 			union Kind {
-				struct RealHeader {
+				struct RealHeader {						// 4-byte word => 8-byte header, 8-byte word => 16-byte header
 					union {
-						struct {						// 4-byte word => 8-byte header, 8-byte word => 16-byte header
-							union {
-								// 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
-								// FreeHeader * home;		// allocated block points back to home locations (must overlay alignment)
-								void * home;			// allocated block points back to home locations (must overlay alignment)
-								size_t blockSize;		// size for munmap (must overlay alignment)
-								Storage * next;			// freed block points to next freed block of same size
-							};
-							size_t size;				// allocation size in bytes
-						};
+						// 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
+						// FreeHeader * home;			// allocated block points back to home locations (must overlay alignment)
+						void * home;					// allocated block points back to home locations (must overlay alignment)
+						size_t blockSize;				// size for munmap (must overlay alignment)
+						Storage * next;					// freed block points to next freed block of same size
 					};
+					size_t size;						// allocation size in bytes
 				} real; // RealHeader
 
@@ -261,5 +257,4 @@
 
 	struct CALIGN FreeHeader {
-		size_t blockSize CALIGN;						// size of allocations on this list
 		#ifdef OWNERSHIP
 		#ifdef RETURNSPIN
@@ -271,4 +266,5 @@
 		Storage * freeList;								// thread free list
 		Heap * homeManager;								// heap owner (free storage to bucket, from bucket to heap)
+		size_t blockSize;								// size of allocations on this list
 	}; // FreeHeader
 
@@ -369,5 +365,5 @@
 static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing
 static __thread Heap * heapManager CALIGN TLSMODEL;
-static  __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
+static __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
 static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing
 
@@ -595,6 +591,4 @@
 
 #ifdef __STATISTICS__
-static HeapStatistics stats;							// zero filled
-
 #define prtFmt \
 	"\nHeap statistics: (storage request / allocation)\n" \
@@ -607,5 +601,5 @@
 	"  resize    >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
 	"  realloc   >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
-	"  free      !null calls %'u; null calls %'u; storage %'llu / %'llu bytes\n" \
+	"  free      !null calls %'u; null/0 calls %'u; storage %'llu / %'llu bytes\n" \
 	"  return    pulls %'u; pushes %'u; storage %'llu / %'llu bytes\n" \
 	"  sbrk      calls %'u; storage %'llu bytes\n" \
@@ -627,5 +621,5 @@
 			resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
 			realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
-			free_calls, free_null_calls, free_storage_request, free_storage_alloc,
+			free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
 			return_pulls, return_pushes, return_storage_request, return_storage_alloc,
 			sbrk_calls, sbrk_storage,
@@ -650,5 +644,5 @@
 	"<total type=\"resize\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
 	"<total type=\"realloc\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
-	"<total type=\"free\" !null=\"%'u;\" 0 null=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
+	"<total type=\"free\" !null=\"%'u;\" 0 null/0=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
 	"<total type=\"return\" pulls=\"%'u;\" 0 pushes=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
 	"<total type=\"sbrk\" count=\"%'u;\" size=\"%'llu\"/> bytes\n" \
@@ -670,5 +664,5 @@
 			resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
 			realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
-			free_calls, free_null_calls, free_storage_request, free_storage_alloc,
+			free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
 			return_pulls, return_pushes, return_storage_request, return_storage_alloc,
 			sbrk_calls, sbrk_storage,
@@ -799,7 +793,8 @@
 	} else {
 		fakeHeader( header, alignment );
-		if ( unlikely( MmappedBit( header ) ) ) {		// mmapped ?
+		if ( unlikely( MmappedBit( header ) ) ) {		// mmapped storage ?
 			verify( addr < heapBegin || heapEnd < addr );
 			size = ClearStickyBits( header->kind.real.blockSize ); // mmap size
+			freeHead = 0p;								// prevent uninitialized warning
 			return true;
 		} // if
@@ -904,14 +899,9 @@
 
 
-#define BOOT_HEAP_MANAGER \
-  	if ( unlikely( ! heapMasterBootFlag ) ) { \
-		heapManagerCtor(); /* trigger for first heap */ \
-	} /* if */
-
 #ifdef __STATISTICS__
 #define STAT_NAME __counter
 #define STAT_PARM , unsigned int STAT_NAME
 #define STAT_ARG( name ) , name
-#define STAT_0_CNT( counter ) stats.counters[counter].calls_0 += 1
+#define STAT_0_CNT( counter ) heapManager->stats.counters[counter].calls_0 += 1
 #else
 #define STAT_NAME
@@ -921,22 +911,36 @@
 #endif // __STATISTICS__
 
-// Uncomment to get allocation addresses for a 0-sized allocation rather than a null pointer.
-//#define __NONNULL_0_ALLOC__
-#if ! defined( __NONNULL_0_ALLOC__ )
-#define __NULL_0_ALLOC__ unlikely( size == 0 ) ||		/* 0 BYTE ALLOCATION RETURNS NULL POINTER */
+#define BOOT_HEAP_MANAGER \
+  	if ( unlikely( ! heapMasterBootFlag ) ) { \
+		heapManagerCtor(); /* trigger for first heap */ \
+	} /* if */ \
+	verify( heapManager );
+
+#define __NONNULL_0_ALLOC__ /* Uncomment to return non-null address for malloc( 0 ). */
+#ifndef __NONNULL_0_ALLOC__
+#define __NULL_0_ALLOC__( counter, ... ) /* 0 byte allocation returns null pointer */ \
+	if ( unlikely( size == 0 ) ) { \
+		STAT_0_CNT( counter ); \
+		__VA_ARGS__; /* call routine, if specified */ \
+		return 0p; \
+	} /* if */
 #else
-#define __NULL_0_ALLOC__
+#define __NULL_0_ALLOC__( counter, ... )
 #endif // __NONNULL_0_ALLOC__
+
+#ifdef __DEBUG__
+#define __OVERFLOW_MALLOC__( ... ) \
+	if ( unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \
+		__VA_ARGS__; /* call routine, if specified */ \
+		return 0p; \
+	} /* if */
+#else
+#define __OVERFLOW_MALLOC__( ... )
+#endif // __DEBUG__
 
 #define PROLOG( counter, ... ) \
 	BOOT_HEAP_MANAGER; \
-	if ( \
-		__NULL_0_ALLOC__ \
-		unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \
-		STAT_0_CNT( counter ); \
-		__VA_ARGS__; \
-		return 0p; \
-	} /* if */
-
+	__NULL_0_ALLOC__( counter, __VA_ARGS__ ) \
+	__OVERFLOW_MALLOC__( __VA_ARGS__ )
 
 #define SCRUB_SIZE 1024lu
@@ -948,5 +952,4 @@
 	PROLOG( STAT_NAME );
 
-	verify( heapManager );
 	Heap.Storage * block;								// pointer to new block of storage
 
@@ -956,5 +959,10 @@
 
 	#ifdef __STATISTICS__
-	stats.counters[STAT_NAME].calls += 1;
+	#ifdef __NONNULL_0_ALLOC__
+	if ( unlikely( size == 0 ) )						// malloc( 0 ) ?
+		stats.counters[STAT_NAME].calls_0 += 1;
+	else
+	#endif // __NONNULL_0_ALLOC__
+		stats.counters[STAT_NAME].calls += 1;
 	stats.counters[STAT_NAME].request += size;
 	#endif // __STATISTICS__
@@ -1078,4 +1086,8 @@
 
 static void doFree( void * addr ) libcfa_nopreempt with( *heapManager ) {
+	// char buf[64];
+	// int len = sprintf( buf, "doFree addr %p\n", addr );
+	// write( 2, buf, len );
+
 	verify( addr );
 
@@ -1091,5 +1103,12 @@
 	#endif // __STATISTICS__ || __CFA_DEBUG__
 
+	// Do not move these down because heap can be null!
 	#ifdef __STATISTICS__
+	#ifdef __NONNULL_0_ALLOC__
+	if ( unlikely( rsize == 0 ) )						// malloc( 0 ) ?
+		stats.free_null_0_calls += 1;
+	else
+	#endif // __NONNULL_0_ALLOC__
+		heapManager->stats.free_calls += 1;				// count free amd implicit frees from resize/realloc
 	stats.free_storage_request += rsize;
 	stats.free_storage_alloc += size;
@@ -1117,4 +1136,5 @@
 		} // if
 	} else {
+		assert( freeHead );
 		#ifdef __CFA_DEBUG__
 		// memset is NOT always inlined!
@@ -1321,5 +1341,5 @@
 	// call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
 	void * resize( void * oaddr, size_t size ) libcfa_public {
-	  if ( unlikely( oaddr == 0p ) ) {				// => malloc( size )
+	  if ( unlikely( oaddr == 0p ) ) {					// => malloc( size )
 			return doMalloc( size STAT_ARG( RESIZE ) );
 		} // if
@@ -1333,5 +1353,5 @@
 
 		size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket
-		// same size, DO NOT preserve STICKY PROPERTIES.
+		// same size, DO NOT PRESERVE STICKY PROPERTIES.
 		if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
 			ClearZeroFillBit( header );					// no alignment and turn off 0 fill
@@ -1346,5 +1366,5 @@
 		} // if
 
-		// change size, DO NOT preserve STICKY PROPERTIES.
+		// change size, DO NOT PRESERVE STICKY PROPERTIES.
 		doFree( oaddr );								// free previous storage
 
@@ -1356,4 +1376,7 @@
 	// the old and new sizes.
 	void * realloc( void * oaddr, size_t size ) libcfa_public {
+		// char buf[64];
+		// int len = sprintf( buf, "realloc1 oaddr %p size %d\n", oaddr, size );
+		// write( 2, buf, len );
 	  if ( unlikely( oaddr == 0p ) ) {					// => malloc( size )
 		  return doMalloc( size STAT_ARG( REALLOC ) );
@@ -1498,8 +1521,4 @@
 		} // if
 
-		#ifdef __STATISTICS__
-		incCalls( FREE );
-		#endif // __STATISTICS__
-
 		doFree( addr );									// handles heapManager == nullptr
 	} // free
@@ -1579,5 +1598,4 @@
 		#endif // __STATISTICS__
 	} // malloc_stats_clear
-
 
 	// Changes the file descriptor where malloc_stats() writes statistics.
@@ -1700,5 +1718,5 @@
 	} // if
 
-	// change size, DO NOT preserve STICKY PROPERTIES.
+	// change size, DO NOT PRESERVE STICKY PROPERTIES.
 	doFree( oaddr );									// free previous storage
 	return memalignNoStats( nalign, size STAT_ARG( RESIZE ) ); // create new aligned area
@@ -1707,4 +1725,7 @@
 
 void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public {
+	// char buf[64];
+	// int len = sprintf( buf, "realloc2 oaddr %p size %d\n", oaddr, size );
+	// write( 2, buf, len );
   if ( unlikely( oaddr == 0p ) ) {						// => malloc( size )
 		return memalignNoStats( nalign, size STAT_ARG( REALLOC ) );
Index: libcfa/src/heap.hfa
===================================================================
--- libcfa/src/heap.hfa	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ libcfa/src/heap.hfa	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -10,6 +10,6 @@
 // Created On       : Tue May 26 11:23:55 2020
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Sep 11 11:18:18 2023
-// Update Count     : 24
+// Last Modified On : Mon Apr  1 09:36:20 2024
+// Update Count     : 25
 // 
 
@@ -46,4 +46,5 @@
 } // extern "C"
 
+// New allocation operations.
 void * resize( void * oaddr, size_t alignment, size_t size );
 void * realloc( void * oaddr, size_t alignment, size_t size );
@@ -51,5 +52,4 @@
 
 // Local Variables: //
-// mode: c //
 // tab-width: 4 //
 // End: //
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ libcfa/src/stdlib.hfa	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:12:35 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Mar 17 08:25:31 2024
-// Update Count     : 796
+// Last Modified On : Fri Apr 12 07:39:15 2024
+// Update Count     : 812
 //
 
@@ -109,13 +109,13 @@
 	1. Replace the current forall-block that contains defintions of S_fill and S_realloc with following:
 		forall( T & | sized(T) ) {
-			union  U_fill 		{ char c; T * a; T t; };
-			struct S_fill 		{ char tag; U_fill(T) fill; };
-			struct S_realloc	{ inline T *; };
+			union  U_fill { char c; T * a; T t; };
+			struct S_fill { char tag; U_fill(T) fill; };
+			struct S_realloc { inline T *; };
 		}
 
 	2. Replace all current postfix-fill functions with following for updated S_fill:
-		S_fill(T) ?`fill( char a )					{ S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; }
-		S_fill(T) ?`fill( T    a ) 					{ S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; }
-		S_fill(T) ?`fill( T    a[], size_t nmemb ) 	{ S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }
+		S_fill(T) ?`fill( char a ) { S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; }
+		S_fill(T) ?`fill( T a ) { S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; }
+		S_fill(T) ?`fill( T a[], size_t nmemb ) { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }
 
 	3. Replace the alloc_internal$ function which is outside ttype forall-block with following function:
@@ -148,15 +148,16 @@
 */
 
-typedef struct S_align 			{ inline size_t;  } T_align;
-typedef struct S_resize			{ inline void *;  }	T_resize;
+typedef struct S_align { inline size_t;  } T_align;
+typedef struct S_resize { inline void *;  }	T_resize;
 
 forall( T & ) {
-	struct S_fill 		{ char tag; char c; size_t size; T * at; char t[50]; };
-	struct S_realloc	{ inline T *; };
+	struct S_fill { char tag; char c; size_t size; T * at; char t[50]; };
+	struct S_realloc { inline T *; };
 }
 
-static inline T_align 	?`align   ( size_t a ) 	{ return (T_align){a}; }
-static inline T_resize 	?`resize  ( void * a )	{ return (T_resize){a}; }
-
+static inline T_align ?`align( size_t a ) { return (T_align){a}; }
+static inline T_resize ?`resize( void * a )	{ return (T_resize){a}; }
+
+extern "C" ssize_t write(int fd, const void *buf, size_t count);
 static inline forall( T & | sized(T) ) {
 	S_fill(T) ?`fill ( T t ) {
@@ -169,10 +170,10 @@
 		return ret;
 	}
-	S_fill(T) 		?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved
-	S_fill(T) 		?`fill ( T * a ) 				{ return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved
-	S_fill(T) 		?`fill ( char c ) 				{ return (S_fill(T)){ 'c', c };	}
-	S_fill(T) 		?`fill ( T a[], size_t nmemb ) 	{ return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }
-
-	S_realloc(T) 	?`realloc ( T * a )				{ return (S_realloc(T)){a}; }
+	S_fill(T) ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved
+	S_fill(T) ?`fill ( T * a ) { return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved
+	S_fill(T) ?`fill ( char c ) { return (S_fill(T)){ 'c', c };	}
+	S_fill(T) ?`fill ( T a[], size_t nmemb ) { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }
+
+	S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; }
 
 	T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
@@ -182,10 +183,10 @@
 
 		if ( Resize ) {
-			ptr = (T*) (void *) resize( (void *)Resize, Align, Dim * size );
+			ptr = (T*)(void *)resize( (void *)Resize, Align, Dim * size );
 		} else if ( Realloc ) {
 			if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size );
-			ptr = (T *) (void *) realloc( (void *)Realloc, Align, Dim * size );
+			ptr = (T *)(void *)realloc( (void *)Realloc, Align, Dim * size );
 		} else {
-			ptr = (T *) (void *) memalign( Align, Dim * size );
+			ptr = (T *)(void *) memalign( Align, Dim * size );
 		}
 
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/AST/Pass.hpp	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -252,23 +252,13 @@
 private:
 
-	__pass::result1<ast::Stmt> call_accept( const ast::Stmt * );
-	__pass::result1<ast::Expr> call_accept( const ast::Expr * );
-
-	/// This has a `type` member that is the return type for the
-	/// generic call_accept if the generic call_accept is defined.
+	/// The return type of the general call_accept function.
 	template< typename node_t >
-	using generic_call_accept_result =
-		std::enable_if<
-				!std::is_base_of<ast::Expr, node_t>::value &&
-				!std::is_base_of<ast::Stmt, node_t>::value
-			, __pass::result1<
-				typename std::remove_pointer< typename std::result_of<
-					decltype(&node_t::accept)(node_t*, type&) >::type >::type
-			>
+	using call_accept_result_t = __pass::result1<
+		typename std::remove_pointer< typename std::result_of<
+			decltype(&node_t::accept)(node_t*, type&) >::type >::type
 		>;
 
 	template< typename node_t >
-	auto call_accept( const node_t * node )
-		-> typename generic_call_accept_result<node_t>::type;
+	auto call_accept( const node_t * node ) -> call_accept_result_t<node_t>;
 
 	// requests WithStmtsToAdd directly add to this statement, as if it is a compound.
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/AST/Pass.impl.hpp	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -109,16 +109,4 @@
 		return val;
 	}
-
-	//------------------------------
-	/// Check if value was mutated, different for pointers and containers
-	template<typename lhs_t, typename rhs_t>
-	bool differs( const lhs_t * old_val, const rhs_t * new_val ) {
-		return old_val != new_val;
-	}
-
-	template< template <class...> class container_t, typename node_t >
-	bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) {
-		return !new_val.empty();
-	}
 }
 
@@ -126,37 +114,10 @@
 template< typename node_t >
 auto ast::Pass< core_t >::call_accept( const node_t * node ) ->
-	typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
-{
+		ast::Pass< core_t >::call_accept_result_t<node_t> {
 	__pedantic_pass_assert( __visit_children() );
 	__pedantic_pass_assert( node );
 
-	static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" );
-	static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" );
-
 	auto nval = node->accept( *this );
-	__pass::result1<
-		typename std::remove_pointer< decltype( node->accept(*this) ) >::type
-	> res;
-	res.differs = nval != node;
-	res.value = nval;
-	return res;
-}
-
-template< typename core_t >
-ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
-	__pedantic_pass_assert( __visit_children() );
-	__pedantic_pass_assert( expr );
-
-	auto nval = expr->accept( *this );
-	return { nval != expr, nval };
-}
-
-template< typename core_t >
-ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
-	__pedantic_pass_assert( __visit_children() );
-	__pedantic_pass_assert( stmt );
-
-	const ast::Stmt * nval = stmt->accept( *this );
-	return { nval != stmt, nval };
+	return { nval != node, nval };
 }
 
@@ -230,5 +191,5 @@
 ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
 	__pedantic_pass_assert( __visit_children() );
-	if ( statements.empty() ) return {};
+	__pedantic_pass_assert( !statements.empty() );
 
 	// We are going to aggregate errors for all these statements
@@ -263,5 +224,4 @@
 			const ast::Stmt * new_stmt = stmt->accept( *this );
 			assert( new_stmt );
-			if ( new_stmt != stmt ) { new_kids.differs = true; }
 
 			// Make sure that it is either adding statements or declartions but not both
@@ -276,7 +236,8 @@
 			// Now add the statement if there is one
 			if ( new_stmt != stmt ) {
-				new_kids.values.emplace_back( new_stmt, i, false );
+				new_kids.differs = true;
+				new_kids.values.emplace_back( new_stmt );
 			} else {
-				new_kids.values.emplace_back( nullptr, i, true );
+				new_kids.values.emplace_back( i );
 			}
 
@@ -298,5 +259,7 @@
 ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
 	__pedantic_pass_assert( __visit_children() );
-	if ( container.empty() ) return {};
+	__pedantic_pass_assert( !container.empty() );
+
+	// Collect errors from processing all these nodes.
 	SemanticErrorException errors;
 
@@ -342,11 +305,8 @@
 	static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
 
-	auto new_val = call_accept( old_val );
-
-	static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
-
-	if ( new_val.differs ) {
+	auto result = call_accept( old_val );
+	if ( result.differs ) {
 		auto new_parent = __pass::mutate<core_t>(parent);
-		new_val.apply(new_parent, field);
+		result.apply( new_parent, field );
 		parent = new_parent;
 	}
@@ -366,11 +326,8 @@
 	static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
 
-	auto new_val = call_accept_top( old_val );
-
-	static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
-
-	if ( new_val.differs ) {
+	auto result = call_accept_top( old_val );
+	if ( result.differs ) {
 		auto new_parent = __pass::mutate<core_t>(parent);
-		new_val.apply(new_parent, field);
+		result.apply( new_parent, field );
 		parent = new_parent;
 	}
@@ -390,11 +347,8 @@
 	static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
 
-	auto new_val = call_accept_as_compound( old_val );
-
-	static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" );
-
-	if ( new_val.differs ) {
+	auto result = call_accept_as_compound( old_val );
+	if ( result.differs ) {
 		auto new_parent = __pass::mutate<core_t>(parent);
-		new_val.apply( new_parent, child );
+		result.apply( new_parent, child );
 		parent = new_parent;
 	}
@@ -452,5 +406,5 @@
 template< typename core_t >
 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
-	if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) {
+	if ( auto ptr = __pass::translationUnit( visitor.core, 0 ) ) {
 		ValueGuard<const TranslationUnit *> guard( *ptr );
 		*ptr = &unit;
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/AST/Pass.proto.hpp	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -154,6 +154,6 @@
 		bool is_old;
 
-		delta(const Stmt * s, ssize_t i, bool old) :
-			new_val(s), old_idx(i), is_old(old) {}
+		explicit delta(const Stmt * s) : new_val(s), old_idx(-1), is_old(false) {}
+		explicit delta(ssize_t i) : new_val(nullptr), old_idx(i), is_old(true) {}
 	};
 
@@ -188,5 +188,5 @@
 		std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ),
 			[](ast::ptr<ast::Stmt>& stmt) -> delta {
-				return delta( stmt.release(), -1, false );
+				return delta( stmt.release() );
 			});
 		stmts->clear();
@@ -201,5 +201,5 @@
 			[](ast::ptr<ast::Decl>& decl) -> delta {
 				ast::Decl const * d = decl.release();
-				return delta( new DeclStmt( d->location, d ), -1, false );
+				return delta( new DeclStmt( d->location, d ) );
 			});
 		decls->clear();
@@ -226,50 +226,4 @@
 		// Now the original containers should still have the unchanged values
 		// but also contain the new values.
-	}
-};
-
-/// Used by previsit implementation
-/// We need to reassign the result to 'node', unless the function
-/// returns void, then we just leave 'node' unchanged
-template<bool is_void>
-struct __assign;
-
-template<>
-struct __assign<true> {
-	template<typename core_t, typename node_t>
-	static inline void result( core_t & core, const node_t * & node ) {
-		core.previsit( node );
-	}
-};
-
-template<>
-struct __assign<false> {
-	template<typename core_t, typename node_t>
-	static inline void result( core_t & core, const node_t * & node ) {
-		node = core.previsit( node );
-		assertf(node, "Previsit must not return NULL");
-	}
-};
-
-/// Used by postvisit implementation
-/// We need to return the result unless the function
-/// returns void, then we just return the original node
-template<bool is_void>
-struct __return;
-
-template<>
-struct __return<true> {
-	template<typename core_t, typename node_t>
-	static inline const node_t * result( core_t & core, const node_t * & node ) {
-		core.postvisit( node );
-		return node;
-	}
-};
-
-template<>
-struct __return<false> {
-	template<typename core_t, typename node_t>
-	static inline auto result( core_t & core, const node_t * & node ) {
-		return core.postvisit( node );
 	}
 };
@@ -297,9 +251,12 @@
 	);
 
-	__assign<
-		std::is_void<
-			decltype( core.previsit( node ) )
-		>::value
-	>::result( core, node );
+	// We need to reassign the result to 'node', unless the function
+	// returns void, then we just leave 'node' unchanged
+	if constexpr ( std::is_void_v<decltype( core.previsit( node ) )> ) {
+		core.previsit( node );
+	} else {
+		node = core.previsit( node );
+		assertf( node, "Previsit must not return nullptr." );
+	}
 }
 
@@ -312,9 +269,12 @@
 	decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
 {
-	return __return<
-		std::is_void<
-			decltype( core.postvisit( node ) )
-		>::value
-	>::result( core, node );
+	// We need to return the result unless the function
+	// returns void, then we just return the original node
+	if constexpr ( std::is_void_v<decltype( core.postvisit( node ) )> ) {
+		core.postvisit( node );
+		return node;
+	} else {
+		return core.postvisit( node );
+	}
 }
 
@@ -350,4 +310,5 @@
 FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
 FIELD_PTR( visitor, ast::Pass<core_t> * const )
+FIELD_PTR( translationUnit, const TranslationUnit * )
 
 // Remove the macro to make sure we don't clash
@@ -546,18 +507,4 @@
 } // namespace forall
 
-// For passes that need access to the global context. Searches `translationUnit`
-namespace translation_unit {
-	template<typename core_t>
-	static inline auto get_cptr( core_t & core, int )
-			-> decltype( &core.translationUnit ) {
-		return &core.translationUnit;
-	}
-
-	template<typename core_t>
-	static inline const TranslationUnit ** get_cptr( core_t &, long ) {
-		return nullptr;
-	}
-}
-
 // For passes, usually utility passes, that have a result.
 namespace result {
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/Parser/StatementNode.cc	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -122,6 +122,5 @@
 	ast::Expr * cond = nullptr;
 	if ( ctl->condition ) {
-		// compare the provided condition against 0
-		cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
+		cond = maybeMoveBuild( ctl->condition );
 	} else {
 		for ( ast::ptr<ast::Stmt> & stmt : inits ) {
@@ -129,5 +128,5 @@
 			auto declStmt = stmt.strict_as<ast::DeclStmt>();
 			auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
-			ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
+			ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt );
 			cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
 		}
@@ -200,5 +199,5 @@
 	// do-while cannot have declarations in the contitional, so init is always empty
 	return new ast::WhileDoStmt( location,
-		notZeroExpr( maybeMoveBuild( ctl ) ),
+		maybeMoveBuild( ctl ),
 		buildMoveSingle( stmt ),
 		buildMoveOptional( else_ ),
@@ -213,5 +212,5 @@
 
 	ast::Expr * astcond = nullptr;						// maybe empty
-	astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
+	astcond = maybeMoveBuild( forctl->condition );
 
 	ast::Expr * astincr = nullptr;						// maybe empty
@@ -330,5 +329,5 @@
 	clause->target = maybeBuild( targetExpr );
 	clause->stmt = maybeMoveBuild( stmt );
-	clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
+	clause->when_cond = maybeMoveBuild( when );
 
 	ExpressionNode * next = targetExpr->next;
@@ -345,5 +344,5 @@
 ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
 	existing->else_stmt = maybeMoveBuild( stmt );
-	existing->else_cond = notZeroExpr( maybeMoveBuild( when ) );
+	existing->else_cond = maybeMoveBuild( when );
 
 	(void)location;
@@ -354,5 +353,5 @@
 	existing->timeout_time = maybeMoveBuild( timeout );
 	existing->timeout_stmt = maybeMoveBuild( stmt );
-	existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) );
+	existing->timeout_cond = maybeMoveBuild( when );
 
 	(void)location;
@@ -362,5 +361,5 @@
 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
 	ast::WhenClause * clause = new ast::WhenClause( loc );
-	clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
+	clause->when_cond = maybeMoveBuild( when );
 	clause->stmt = maybeMoveBuild( stmt );
 	clause->target = maybeMoveBuild( targetExpr );
@@ -369,5 +368,5 @@
 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
 	ast::WhenClause * clause = new ast::WhenClause( loc );
-	clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
+	clause->when_cond = maybeMoveBuild( when );
 	clause->stmt = maybeMoveBuild( stmt );
 	return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
@@ -508,5 +507,5 @@
 
 	ast::Expr * astcond = nullptr;						// maybe empty
-	astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
+	astcond = maybeMoveBuild( forctl->condition );
 
 	ast::Expr * astincr = nullptr;						// maybe empty
Index: src/Parser/module.mk
===================================================================
--- src/Parser/module.mk	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/Parser/module.mk	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -31,5 +31,4 @@
        Parser/parser.yy \
        Parser/ParserTypes.h \
-       Parser/parserutility.cc \
        Parser/parserutility.h \
        Parser/RunParser.cpp \
Index: c/Parser/parserutility.cc
===================================================================
--- src/Parser/parserutility.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ 	(revision )
@@ -1,50 +1,0 @@
-//
-// 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.
-//
-// parserutility.cc --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 15:30:39 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Mar  1 10:42:00 2023
-// Update Count     : 9
-//
-
-#include "parserutility.h"
-
-#include <list>                  // for list
-#include <string>                // for string
-
-#include "AST/Expr.hpp"          // for UntypedExpr, CastExpr, ConstantExpr
-#include "AST/Type.hpp"          // for BasicType, ZeroType, BasicType::Kind...
-
-// rewrite
-//    if ( x ) ...
-// as
-//    if ( (int)(x != 0) ) ...
-
-ast::Expr * notZeroExpr( const ast::Expr * orig ) {
-	return ( !orig ) ? nullptr : new ast::CastExpr( orig->location,
-		ast::UntypedExpr::createCall( orig->location,
-			"?!=?",
-			{
-				orig,
-				new ast::ConstantExpr( orig->location,
-					new ast::ZeroType(),
-					"0",
-					std::optional<unsigned long long>( 0 )
-				),
-			}
-		),
-		new ast::BasicType( ast::BasicType::SignedInt )
-	);
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/parserutility.h
===================================================================
--- src/Parser/parserutility.h	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/Parser/parserutility.h	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -17,9 +17,4 @@
 
 #include "AST/Copy.hpp"            // for shallowCopy
-namespace ast {
-	class Expr;
-}
-
-ast::Expr * notZeroExpr( const ast::Expr *orig );
 
 template< typename T >
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -46,5 +46,4 @@
 #include "AST/Type.hpp"
 #include "Common/utility.h"       // for move, copy
-#include "Parser/parserutility.h" // for notZeroExpr
 #include "SymTab/Mangler.h"
 #include "Tuples/Tuples.h"        // for handleTupleAssignment
@@ -1514,10 +1513,10 @@
 	void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
 		CandidateFinder finder1( context, tenv );
-		ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 );
+		ast::ptr<ast::Expr> arg1 = createCondExpr( logicalExpr->arg1 );
 		finder1.find( arg1, ResolveMode::withAdjustment() );
 		if ( finder1.candidates.empty() ) return;
 
 		CandidateFinder finder2( context, tenv );
-		ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 );
+		ast::ptr<ast::Expr> arg2 = createCondExpr( logicalExpr->arg2 );
 		finder2.find( arg2, ResolveMode::withAdjustment() );
 		if ( finder2.candidates.empty() ) return;
@@ -1545,5 +1544,5 @@
 	void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
 		// candidates for condition
-		ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );
+		ast::ptr<ast::Expr> arg1 = createCondExpr( conditionalExpr->arg1 );
 		CandidateFinder finder1( context, tenv );
 		finder1.find( arg1, ResolveMode::withAdjustment() );
@@ -2166,5 +2165,20 @@
 		CandidateRef & choice = winners.front();
 		return choice->expr;
-		// return std::move( choice->expr.get() );
+}
+
+const ast::Expr * createCondExpr( const ast::Expr * expr ) {
+	assert( expr );
+	return new ast::CastExpr( expr->location,
+		ast::UntypedExpr::createCall( expr->location,
+			"?!=?",
+			{
+				expr,
+				new ast::ConstantExpr( expr->location,
+					new ast::ZeroType(), "0", std::make_optional( 0ull )
+				),
+			}
+		),
+		new ast::BasicType( ast::BasicType::SignedInt )
+	);
 }
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -72,4 +72,6 @@
 const ast::Expr * getValueEnumCall(const ast::Expr * expr,
 	const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env );
+/// Wrap an expression to convert the result to a conditional result.
+const ast::Expr * createCondExpr( const ast::Expr * expr );
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/ResolvExpr/Resolver.cc	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -340,4 +340,12 @@
 	}
 
+	ast::ptr< ast::Expr > findCondExpression(
+		const ast::Expr * untyped, const ResolveContext & context
+	) {
+		if ( nullptr == untyped ) return untyped;
+		ast::ptr<ast::Expr> condExpr = createCondExpr( untyped );
+		return findIntegralExpression( condExpr, context );
+	}
+
 	/// check if a type is a character type
 	bool isCharType( const ast::Type * t ) {
@@ -356,5 +364,5 @@
 		return it != end;
 	}
-}
+} // anonymous namespace
 
 class Resolver final
@@ -729,10 +737,10 @@
 const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
 	return ast::mutate_field(
-		ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
+		ifStmt, &ast::IfStmt::cond, findCondExpression( ifStmt->cond, context ) );
 }
 
 const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
 	return ast::mutate_field(
-		whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
+		whileDoStmt, &ast::WhileDoStmt::cond, findCondExpression( whileDoStmt->cond, context ) );
 }
 
@@ -740,5 +748,5 @@
 	if ( forStmt->cond ) {
 		forStmt = ast::mutate_field(
-			forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
+			forStmt, &ast::ForStmt::cond, findCondExpression( forStmt->cond, context ) );
 	}
 
@@ -1075,5 +1083,5 @@
 
 		// Resolve the conditions as if it were an IfStmt, statements normally
-		clause2->when_cond = findSingleExpression( clause.when_cond, context );
+		clause2->when_cond = findCondExpression( clause.when_cond, context );
 		clause2->stmt = clause.stmt->accept( *visitor );
 
@@ -1089,5 +1097,5 @@
 			new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
 		auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
-		auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
+		auto timeout_cond = findCondExpression( stmt->timeout_cond, context );
 		auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
 
@@ -1102,5 +1110,5 @@
 	if ( stmt->else_stmt ) {
 		// resolve the condition like IfStmt, stmts normally
-		auto else_cond = findSingleExpression( stmt->else_cond, context );
+		auto else_cond = findCondExpression( stmt->else_cond, context );
 		auto else_stmt = stmt->else_stmt->accept( *visitor );
 
Index: src/Validate/ImplementEnumFunc.cpp
===================================================================
--- src/Validate/ImplementEnumFunc.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/Validate/ImplementEnumFunc.cpp	(revision dc58e5daa87c5b617ac609696ff96cc7f4d5a5a6)
@@ -516,6 +516,5 @@
     ast::EnumInstType enumInst(enumDecl->name);
     enumInst.base = enumDecl;
-    // ast::EnumAttrType attr = ast::EnumAttrType(&enumInst);
-    // EnumAttrFuncGenerator gen(enumDecl, &enumInst functionNesting);
+
     EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
     gen.generateAndAppendFunctions(declsToAddAfter);
