Index: doc/theses/mike_brooks_MMath/background.tex
===================================================================
--- doc/theses/mike_brooks_MMath/background.tex	(revision feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ doc/theses/mike_brooks_MMath/background.tex	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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 feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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 feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ src/AST/Pass.proto.hpp	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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 NULL");
+	}
 }
 
@@ -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 );
+	}
 }
 
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ src/Parser/StatementNode.cc	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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 feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ src/Parser/module.mk	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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 feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ 	(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 feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ src/Parser/parserutility.h	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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 feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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
@@ -1587,10 +1586,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;
@@ -1618,5 +1617,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() );
@@ -2201,4 +2200,20 @@
 }
 
+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 )
+	);
+}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -70,4 +70,7 @@
 	const ast::Expr * expr, Cost & cost );
 
+/// 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 feb999f1fbddbd9d84e6082c9f58dbf8d9c2eac4)
+++ src/ResolvExpr/Resolver.cc	(revision b78c54fee28c2555a5cdaed9b00ce8e8db3187e1)
@@ -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 );
 
