Index: doc/proposals/concurrency/Makefile
===================================================================
--- doc/proposals/concurrency/Makefile	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ doc/proposals/concurrency/Makefile	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -9,4 +9,6 @@
 SOURCES = ${addsuffix .tex, \
 concurrency \
+style \
+glossary \
 }
 
Index: doc/proposals/concurrency/concurrency.tex
===================================================================
--- doc/proposals/concurrency/concurrency.tex	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ doc/proposals/concurrency/concurrency.tex	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -14,10 +14,10 @@
 
 % Latex packages used in the document.
-\usepackage[T1]{fontenc}                                % allow Latin1 (extended ASCII) characters
+\usepackage[T1]{fontenc}					% allow Latin1 (extended ASCII) characters
 \usepackage{textcomp}
 \usepackage[latin1]{inputenc}
 \usepackage{fullpage,times,comment}
 \usepackage{epic,eepic}
-\usepackage{upquote}									% switch curled `'" to straight
+\usepackage{upquote}						% switch curled `'" to straight
 \usepackage{calc}
 \usepackage{xspace}
@@ -25,15 +25,15 @@
 \usepackage{tabularx}
 \usepackage[acronym]{glossaries}
-\usepackage{varioref}								% extended references
+\usepackage{varioref}						% extended references
 \usepackage{inconsolata}
-\usepackage{listings}									% format program code
-\usepackage[flushmargin]{footmisc}						% support label/reference in footnote
-\usepackage{latexsym}                                   % \Box glyph
-\usepackage{mathptmx}                                   % better math font with "times"
+\usepackage{listings}						% format program code
+\usepackage[flushmargin]{footmisc}				% support label/reference in footnote
+\usepackage{latexsym}						% \Box glyph
+\usepackage{mathptmx}						% better math font with "times"
 \usepackage[usenames]{color}
 \usepackage[pagewise]{lineno}
 \usepackage{fancyhdr}
 \renewcommand{\linenumberfont}{\scriptsize\sffamily}
-\input{common}                                          % bespoke macros used in the document
+\input{style}							% bespoke macros used in the document
 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
 \usepackage{breakurl}
@@ -44,5 +44,5 @@
 \renewcommand{\UrlFont}{\small\sf}
 
-\setlength{\topmargin}{-0.45in}							% move running title into header
+\setlength{\topmargin}{-0.45in}				% move running title into header
 \setlength{\headsep}{0.25in}
 
@@ -86,5 +86,5 @@
 \title{Concurrency in \CFA}
 \author{Thierry Delisle \\
-Dept. of Computer Science, University of Waterloo, \\ Waterloo, Ontario, Canada
+School of Computer Science, University of Waterloo, \\ Waterloo, Ontario, Canada
 }
 
@@ -100,8 +100,7 @@
 
 \section{Introduction}
-This proposal provides a minimal core concurrency API that is both simple, efficient and can be reused to build higher-level features. The simplest possible core is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level construct as the basis of the concurrency in \CFA.
-Indeed, for highly productive parallel programming high-level approaches are much more popular\cite{HPP:Study}. Examples are task based parallelism, message passing, implicit threading.
-
-There are actually two problems that need to be solved in the design of the concurrency for a language. Which concurrency tools are available to the users and which parallelism tools are available. While these two concepts are often seen together, they are in fact distinct concepts that require different sorts of tools\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization while parallelism tools are more about performance, cost and resource utilization.
+This proposal provides a minimal core concurrency API that is both simple, efficient and can be reused to build higher-level features. The simplest possible concurrency core is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of the concurrency in \CFA. Indeed, for highly productive parallel programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading.
+
+There are actually two problems that need to be solved in the design of the concurrency for a programming language: which concurrency tools are available to the users and which parallelism tools are available. While these two concepts are often seen together, they are in fact distinct concepts that require different sorts of tools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are more about performance, cost and resource utilization.
 
 %  #####  ####### #     #  #####  #     # ######  ######  ####### #     #  #####  #     #
@@ -114,14 +113,5 @@
 
 \section{Concurrency}
-% Several tool can be used to solve concurrency challenges. Since these challenges always appear with the use of mutable shared state, some languages and libraries simply disallow mutable shared-state (Erlang\cite{Erlang}, Haskell\cite{Haskell}, Akka (Scala)\cite{Akka}). In these paradigms, interaction among concurrent objects rely on message passing or other paradigms that often closely relate to networking concepts. However, in imperative or OO languages, these approaches entail a clear distinction between concurrent and non-concurrent paradigms (i.e. message passing versus routine call). Which in turns mean that programmers need to learn two sets of designs patterns in order to be effective. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on non-concurrent constructs like routine calls and objects. At a lower level these can be implemented as locks and atomic operations. However, for productivity reasons it is desireable to have a higher-level construct to be the core concurrency paradigm\cite{HPP:Study}. This project proposes Monitors\cite{Hoare74} as the core concurrency construct.
-% \\
-
-Several tool can be used to solve concurrency challenges. Since these challenges always appear with the use of mutable shared state, some languages and libraries simply disallow mutable shared-state (Erlang\cite{Erlang}, Haskell\cite{Haskell}, Akka (Scala)\cite{Akka}). In these paradigms, interaction among concurrent objects rely on message passing\cite{Thoth,Harmony,V-Kernel} or other paradigms that often closely relate to networking concepts. However, in imperative or OO languages, these approaches entail a clear distinction between concurrent and non-concurrent paradigms (i.e. message passing versus routine call). Which in turns mean that programmers need to learn two sets of designs patterns in order to be effective. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on non-concurrent constructs like routine calls and objects. At a lower level these can be implemented as locks and atomic operations. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct to be the core concurrency paradigm\cite{HPP:Study}. One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}.
-
-Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}.
-Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes Monitors as the core concurrency construct.
-\\
-
-Finally, an approach that is worth mentionning because it is gaining in popularity is transactionnal memory\cite{Dice10}. However, the performance and feature set is currently too restrictive to be possible to add such a paradigm to a language like C or \CC\cit, which is why it was rejected as the core paradigm for concurrency in \CFA.
+Several tool can be used to solve concurrency challenges. Since these challenges always appear with the use of mutable shared-state, some languages and libraries simply disallow mutable shared-state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}). In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms that closely relate to networking concepts (channels\cit for example). However, in languages that use routine calls as their core abstraction mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (i.e., message passing versus routine call). Which in turn means that, in order to be effective, programmers need to learn two sets of designs patterns. This distinction can be hidden away in library code, but effective use of the librairy still has to take both paradigms into account. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and objects. At a lower level these can be implemented as locks and atomic operations. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct be the core concurrency paradigm~\cite{HPP:Study}. An approach that is worth mentionning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cit, the performance and feature set is currently too restrictive to add such a paradigm to a language like C or \CC\cit, which is why it was rejected as the core paradigm for concurrency in \CFA. One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}. Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes monitors as the core concurrency construct.
 
 % #     # ####### #     # ### ####### ####### ######   #####
@@ -134,5 +124,5 @@
 
 \subsection{Monitors}
-A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java\cite{Java} or \uC\cite{uC++book} but does not strictly require OOP semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it :
+A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OOP semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it :
 \begin{lstlisting}
 	typedef /*some monitor type*/ monitor;
@@ -154,27 +144,23 @@
 
 \subsubsection{Call semantics} \label{call}
-The above example of monitors already displays some of their intrinsic caracteristics. Indeed, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable.
-\\
-
-Another aspect to consider is when a monitor acquires its mutual exclusion. Indeed, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual exclusion on entry. Examples of this can be both generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following example :
-
-\begin{lstlisting}
-	mutex struct counter_t { /*...*/ };
-
-	void ?{}(counter_t & nomutex this);
-	int ++?(counter_t & mutex this);
-	void ?{}(Int * this, counter_t & mutex cnt);
-\end{lstlisting}
-*semantics of the declaration of \code{mutex struct counter_t} are discussed in details in section \ref{data}
-\\
-
-This example is of a monitor implementing an atomic counter. Here, the constructor uses the \code{nomutex} keyword to signify that it does not acquire the coroutine mutual exclusion when constructing. This is because object not yet constructed should never be shared and therefore do not require mutual exclusion. The prefix increment operator
-uses \code{mutex} to protect the incrementing process from race conditions. Finally, we have a conversion operator from \code{counter_t} to \code{Int}. This conversion may or may not require the \code{mutex} key word depending whether or not reading an \code{Int} is an atomic operation or not.
-\\
-
-Having both \code{mutex} and \code{nomutex} keywords could be argued to be redundant based on the meaning of a routine having neither of these keywords. If there were a meaning to routine \code{void foo(counter_t & this)} then one could argue that it should be to default to the safest option : \code{mutex}. On the other hand, the option of having routine \code{void foo(counter_t & this)} mean \code{nomutex} is unsafe by default and may easily cause subtle errors. It can be argued that this is the more "normal" behavior, \code{nomutex} effectively stating explicitly that "this routine has nothing special". An other alternative is to make one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routine \code{void foo(counter_t & this)}. Mandatory keywords would also have the added benefice of being more clearly self-documented but at the cost of extra typing. In the end, which solution should be picked is still up for debate. For the reminder of this proposal, the explicit approach will be used for the sake of clarity.
-\\
-
-Regardless of which keyword is kept, it is important to establish when mutex/nomutex may be used depending on type parameters.
+The above monitor example displays some of the intrinsic characteristics. Indeed, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable.
+
+Another aspect to consider is when a monitor acquires its mutual exclusion. For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry. Pass through can be both generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following to implement an atomic counter :
+
+\begin{lstlisting}
+	mutex struct counter_t { /*...see section Â§\ref{data}Â§...*/ };
+
+	void ?{}(counter_t & nomutex this); //constructor
+	size_t ++?(counter_t & mutex this); //increment
+
+	//need for mutex is platform dependent here
+	void ?{}(size_t * this, counter_t & mutex cnt); //conversion
+\end{lstlisting}
+
+Here, the constructor(\code{?\{\}}) uses the \code{nomutex} keyword to signify that it does not acquire the monitor mutual exclusion when constructing. This semantics is because an object not yet constructed should never be shared and therefore does not require mutual exclusion. The prefix increment operator uses \code{mutex} to protect the incrementing process from race conditions. Finally, there is a conversion operator from \code{counter_t} to \code{size_t}. This conversion may or may not require the \code{mutex} key word depending on whether or not reading an \code{size_t} is an atomic operation or not.
+
+Having both \code{mutex} and \code{nomutex} keywords could be argued to be redundant based on the meaning of a routine having neither of these keywords. For example, given a routine without wualifiers \code{void foo(counter_t & this)} then one could argue that it should default to the safest option \code{mutex}. On the other hand, the option of having routine \code{void foo(counter_t & this)} mean \code{nomutex} is unsafe by default and may easily cause subtle errors. It can be argued that \code{nomutex} is the more "normal" behaviour, the \code{nomutex} keyword effectively stating explicitly that "this routine has nothing special". Another alternative is to make having exactly one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routine \code{void foo(counter_t & this)}. Mandatory keywords would also have the added benefice of being self-documented but at the cost of extra typing. In the end, which solution should be picked is still up for debate. For the reminder of this proposal, the explicit approach is used for clarity.
+
+The next semantic decision is to establish when mutex/nomutex may be used as a type qualifier. Consider the following declarations:
 \begin{lstlisting}
 	int f1(monitor & mutex m);
@@ -184,6 +170,5 @@
 	int f5(graph(monitor*) & mutex m);
 \end{lstlisting}
-
-The problem is to indentify which object(s) should be acquired. Furthermore we also need to acquire each objects only once. In case of simple routines like \code{f1} and \code{f2} it is easy to identify an exhaustive list of objects to acquire on entering. Adding indirections (\code{f3}) still allows the compiler and programmer to indentify which object will be acquired. However, adding in arrays (\code{f4}) makes it much harder. Array lengths aren't necessarily known in C and even then making sure we only acquire objects once becomes also none trivial. This can be extended to absurd limits like \code{f5} which uses a custom graph of monitors. To keep everyone as sane as possible\cite{Chicken}, this projects imposes the requirement that a routine may only acquire one monitor per parameter and it must be the type of the parameter (ignoring potential qualifiers and indirections).
+The problem is to indentify which object(s) should be acquired. Furthermore, each object needs to be acquired only once. In the case of simple routines like \code{f1} and \code{f2} it is easy to identify an exhaustive list of objects to acquire on entry. Adding indirections (\code{f3}) still allows the compiler and programmer to indentify which object is acquired. However, adding in arrays (\code{f4}) makes it much harder. Array lengths are not necessarily known in C and even then making sure we only acquire objects once becomes also none trivial. This can be extended to absurd limits like \code{f5}, which uses a graph of monitors. To keep everyone as sane as possible~\cite{Chicken}, this projects imposes the requirement that a routine may only acquire one monitor per parameter and it must be the type of the parameter (ignoring potential qualifiers and indirections). Also note that while routine \code{f3} can be supported, meaning that monitor \code{**m} is be acquired, passing an array to this routine would be type safe and yet result in undefined behavior because only the first element of the array is acquired. However, this ambiguity is part of the C type system with respects to arrays. For this reason, it would also be reasonnable to disallow mutex in the context where arrays may be passed.
 
 % ######     #    #######    #
@@ -196,5 +181,5 @@
 
 \subsubsection{Data semantics} \label{data}
-Once the call semantics are established, the next step is to establish data semantics. Indeed, until now a monitor is used simply as a generic handle but in most cases monitors contian shared data. This data should be intrinsic to the monitor declaration to prevent any accidental use of data without its appripriate protection. For example here is a more fleshed-out version of the counter showed in \ref{call}:
+Once the call semantics are established, the next step is to establish data semantics. Indeed, until now a monitor is used simply as a generic handle but in most cases monitors contian shared data. This data should be intrinsic to the monitor declaration to prevent any accidental use of data without its appropriate protection. For example, here is a complete version of the counter showed in section \ref{call}:
 \begin{lstlisting}
 	mutex struct counter_t {
@@ -207,34 +192,31 @@
 
 	int ++?(counter_t & mutex this) {
-		return ++this->value;
-	}
-
+		return ++this.value;
+	}
+
+	//need for mutex is platform dependent here
 	void ?{}(int * this, counter_t & mutex cnt) {
 		*this = (int)cnt;
 	}
 \end{lstlisting}
-\begin{tabular}{ c c }
-Thread 1 & Thread 2 \\
-\begin{lstlisting}
-	void f(counter_t & mutex c) {
-		for(;;) {
-			sout | (int)c | endl;
-		}
-	}
-\end{lstlisting} &\begin{lstlisting}
-	void g(counter_t & mutex c) {
-		for(;;) {
-			++c;
-		}
-	}
-
+
+This simple counter is used as follows:
+\begin{center}
+\begin{tabular}{c @{\hskip 0.35in} c @{\hskip 0.35in} c}
+\begin{lstlisting}
+	//shared counter
+	counter_t cnt;
+
+	//multiple threads access counter
+	thread 1 : cnt++;
+	thread 2 : cnt++;
+	thread 3 : cnt++;
+	  ...
+	thread N : cnt++;
 \end{lstlisting}
 \end{tabular}
-\\
-
-
-This simple counter offers an example of monitor usage. Notice how the counter is used without any explicit synchronisation and yet supports thread-safe semantics for both reading and writting. \\
-
-These simple mutual exclusion semantics also naturally expand to multi-monitor calls.
+\end{center}
+
+Notice how the counter is used without any explicit synchronisation and yet supports thread-safe semantics for both reading and writting. Unlike object-oriented monitors, where calling a mutex member \emph{implicitly} acquires mutual-exclusion, \CFA uses an explicit mechanism to acquire mutual-exclusion. A consequence of this approach is that it extends to multi-monitor calls.
 \begin{lstlisting}
 	int f(MonitorA & mutex a, MonitorB & mutex b);
@@ -244,25 +226,30 @@
 	f(a,b);
 \end{lstlisting}
-
-This code acquires both locks before entering the critical section. In practice, writing multi-locking routines that can not lead to deadlocks can be very tricky. Having language level support for such feature is therefore a significant asset for \CFA. However, this does have significant repercussions relating to scheduling (see \ref{insched} and \ref{extsched}). Furthermore, the ability to acquire multiple monitors at the same time does incur a significant pitfall even without looking into scheduling. For example :
-\begin{lstlisting}
-	void foo(A & mutex a, B & mutex a) {
-		//...
-	}
-
-	void bar(A & mutex a, B & nomutex a)
-		//...
-		foo(a, b);
-		//...
-	}
-
-	void baz(A & nomutex a, B & mutex a)
-		//...
-		foo(a, b);
-		//...
-	}
-\end{lstlisting}
-
-Recursive mutex routine calls are allowed in \CFA but if not done carefully it can lead to nested monitor call problems\cite{Lister77}. These problems which are a specific  implementation of the lock acquiring order problem. In the example above, the user uses implicit ordering in the case of function \code{bar} but explicit ordering in the case of \code{baz}. This subtle mistake can mean that calling these two functions concurrently will lead to deadlocks, depending on the implicit ordering matching the explicit ordering. As shown on several occasion\cit, there isn't really any solutions to this problem, users simply need to be carefull when acquiring multiple monitors at the same time.
+This code acquires both locks before entering the critical section, called \emph{\gls{group-acquire}}. In practice, writing multi-locking routines that do not lead to deadlocks is tricky. Having language support for such a feature is therefore a significant asset for \CFA. In the case presented above, \CFA guarantees that the order of aquisition is consistent across calls to routines using the same monitors as arguments. However, since \CFA monitors use multi-acquisition locks, users can effectively force the acquiring order. For example, notice which routines use \code{mutex}/\code{nomutex} and how this affects aquiring order :
+\begin{lstlisting}
+	void foo(A & mutex a, B & mutex b) { //acquire a & b
+		//...
+	}
+
+	void bar(A & mutex a, B & nomutex b) { //acquire a
+		//...
+		foo(a, b); //acquire b
+		//...
+	}
+
+	void baz(A & nomutex a, B & mutex b) { //acquire b
+		//...
+		foo(a, b); //acquire a
+		//...
+	}
+\end{lstlisting}
+
+The multi-acquisition monitor lock allows a monitor lock to be acquired by both \code{bar} or \code{baz} and acquired again in \code{foo}. In the calls to \code{bar} and \code{baz} the monitors are acquired in opposite order. such use leads to nested monitor call problems~\cite{Lister77}, which is a specific implementation of the lock acquiring order problem. In the example above, the user uses implicit ordering in the case of function \code{foo} but explicit ordering in the case of \code{bar} and \code{baz}. This subtle mistake means that calling these routines concurrently may lead to deadlock and is therefore undefined behavior. As shown on several occasion\cit, solving this problem requires :
+\begin{enumerate}
+	\item Dynamically tracking of the monitor-call order.
+	\item Implement rollback semantics.
+\end{enumerate}
+
+While the first requirement is already a significant constraint on the system, implementing a general rollback semantics in a C-like language is prohibitively complex \cit. In \CFA, users simply need to be carefull when acquiring multiple monitors at the same time.
 
 % ######  ####### #######    #    ### #        #####
@@ -283,7 +270,74 @@
 
 \subsubsection{Implementation Details: Interaction with polymorphism}
-At first glance, interaction between monitors and \CFA's concept of polymorphism seem complexe to support. However, it can be reasoned that entry-point locking can solve most of the issues that could be present with polymorphism.
-
-First of all, interaction between \code{otype} polymorphism and monitors is impossible since monitors do not support copying. Therefore the main question is how to support \code{dtype} polymorphism. We must remember that monitors' main purpose is to ensure mutual exclusion when accessing shared data. This implies that mutual exclusion is only required for routines that do in fact access shared data. However, since \code{dtype} polymorphism always handle incomplete types (by definition) no \code{dtype} polymorphic routine can access shared data since the data would require knowledge about the type. Therefore the only concern when combining \code{dtype} polymorphism and monitors is to protect access to routines. With callsite-locking, this would require significant amount of work since any \code{dtype} routine could have to obtain some lock before calling a routine. However, with entry-point-locking calling a monitor routine becomes exactly the same as calling it from anywhere else.
+At first glance, interaction between monitors and \CFA's concept of polymorphism seems complex to support. However, it is shown that entry-point locking can solve most of the issues.
+
+Before looking into complex control flow, it is important to present the difference between the two acquiring options : \gls{callsite-locking} and \gls{entry-point-locking}, i.e. acquiring the monitors before making a mutex call or as the first instruction of the mutex call. For example:
+
+\begin{center}
+\begin{tabular}{|c|c|c|}
+Code & \gls{callsite-locking} & \gls{entry-point-locking} \\
+\CFA & pseudo-code & pseudo-code \\
+\hline
+\begin{lstlisting}
+void foo(monitor & mutex a) {
+
+
+
+	//Do Work
+	//...
+
+}
+
+void main() {
+	monitor a;
+
+
+
+	foo(a);
+
+}
+\end{lstlisting} &\begin{lstlisting}
+foo(& a) {
+
+
+
+	//Do Work
+	//...
+
+}
+
+main() {
+	monitor a;
+	//calling routine
+	//handles concurrency
+	acquire(a);
+	foo(a);
+	release(a);
+}
+\end{lstlisting} &\begin{lstlisting}
+foo(& a) {
+	//called routine
+	//handles concurrency
+	acquire(a);
+	//Do Work
+	//...
+	release(a);
+}
+
+main() {
+	monitor a;
+
+
+
+	foo(a);
+
+}
+\end{lstlisting}
+\end{tabular}
+\end{center}
+
+First of all, interaction between \code{otype} polymorphism and monitors is impossible since monitors do not support copying. Therefore, the main question is how to support \code{dtype} polymorphism. Since a monitor's main purpose is to ensure mutual exclusion when accessing shared data, this implies that mutual exclusion is only required for routines that do in fact access shared data. However, since \code{dtype} polymorphism always handles incomplete types (by definition), no \code{dtype} polymorphic routine can access shared data since the data requires knowledge about the type. Therefore, the only concern when combining \code{dtype} polymorphism and monitors is to protect access to routines. \Gls{callsite-locking} would require a significant amount of work, since any \code{dtype} routine may have to obtain some lock before calling a routine, depending on whether or not the type passed is a monitor. However, with \gls{entry-point-locking} calling a monitor routine becomes exactly the same as calling it from anywhere else.
+
+
 
 % ### #     # #######         #####   #####  #     # ####### ######
@@ -296,5 +350,5 @@
 
 \subsection{Internal scheduling} \label{insched}
-Monitors should also be able to schedule what threads access it as a mean of synchronization. Internal scheduling is one of the simple examples of such a feature. It allows users to declare condition variables and wait for them to be signaled. Here is a simple example of such a technique :
+Monitors also need to schedule waiting threads internally as a mean of synchronization. Internal scheduling is one of the simple examples of such a feature. It allows users to declare condition variables and have threads wait and signaled from them. Here is a simple example of such a technique :
 
 \begin{lstlisting}
@@ -314,6 +368,5 @@
 \end{lstlisting}
 
-Here routine \code{foo} waits on the \code{signal} from \code{bar} before making further progress, effectively ensuring a basic ordering. This semantic can easily be extended to multi-monitor calls by offering the same guarantee.
-
+Note that in \CFA, \code{condition} have no particular need to be stored inside a monitor, beyond any software engineering reasons. Here routine \code{foo} waits for the \code{signal} from \code{bar} before making further progress, effectively ensuring a basic ordering. This semantic can easily be extended to multi-monitor calls by offering the same guarantee.
 \begin{center}
 \begin{tabular}{ c @{\hskip 0.65in} c }
@@ -321,5 +374,5 @@
 \begin{lstlisting}
 void foo(monitor & mutex a,
-         monitor & mutex b) {
+           monitor & mutex b) {
 	//...
 	wait(a.e);
@@ -330,5 +383,5 @@
 \end{lstlisting} &\begin{lstlisting}
 void bar(monitor & mutex a,
-         monitor & mutex b) {
+           monitor & mutex b) {
 	signal(a.e);
 }
@@ -340,6 +393,5 @@
 \end{tabular}
 \end{center}
-
-A direct extension of the single monitor semantics would be to release all locks when waiting and transferring ownership of all locks when signalling. However, for the purpose of synchronization it may be usefull to only release some of the locks but keep others. On the technical side, partially releasing lock is feasible but from the user perspective a choice must be made for the syntax of this feature. It is possible to do without any extra syntax by relying on order of acquisition (Note that here the use of helper routines is irrelevant, only routines the acquire mutual exclusion have an impact on internal scheduling):
+A direct extension of the single monitor semantics is to release all locks when waiting and transferring ownership of all locks when signalling. However, for the purpose of synchronization it may be usefull to only release some of the locks but keep others. It is possible to support internal scheduling and \gls{group-acquire} without any extra syntax by relying on order of acquisition. Here is an example of the different contexts in which internal scheduling can be used. (Note that here the use of helper routines is irrelevant, only routines acquire mutual exclusion have an impact on internal scheduling):
 
 \begin{center}
@@ -350,7 +402,9 @@
 condition e;
 
+//acquire a & b
 void foo(monitor & mutex a,
-         monitor & mutex b) {
-	wait(e);
+           monitor & mutex b) {
+
+	wait(e); //release a & b
 }
 
@@ -364,12 +418,14 @@
 condition e;
 
+//acquire a
 void bar(monitor & mutex a,
-         monitor & nomutex b) {
+           monitor & nomutex b) {
 	foo(a,b);
 }
 
+//acquire a & b
 void foo(monitor & mutex a,
-         monitor & mutex b) {
-	wait(e);
+           monitor & mutex b) {
+	wait(e);  //release a & b
 }
 
@@ -378,12 +434,14 @@
 condition e;
 
+//acquire a
 void bar(monitor & mutex a,
-         monitor & nomutex b) {
-	foo(a,b);
-}
-
+           monitor & nomutex b) {
+	baz(a,b);
+}
+
+//acquire b
 void baz(monitor & nomutex a,
-         monitor & mutex b) {
-	wait(e);
+           monitor & mutex b) {
+	wait(e);  //release b
 }
 
@@ -393,147 +451,109 @@
 \end{center}
 
-This can be interpreted in two different ways :
-\begin{flushleft}
-\begin{enumerate}
-	\item \code{wait} atomically releases the monitors acquired by the inner-most routine, \underline{ignoring} nested calls.
-	\item \code{wait} atomically releases the monitors acquired by the inner-most routine, \underline{considering} nested calls.
-\end{enumerate}
-\end{flushleft}
-While the difference between these two is subtle, it has a significant impact. In the first case it means that the calls to \code{foo} would behave the same in Context 1 and 2. This semantic would also mean that the call to \code{wait} in routine \code{baz} would only release \code{monitor b}. While this may seem intuitive with these examples, it does have one significant implication, it creates a strong distinction between acquiring multiple monitors in sequence and acquiring the same monitors simulatenously, i.e. :
+Context 1 is the simplest way of acquiring more than one monitor (\gls{group-acquire}), using a routine with multiple parameters having the \code{mutex} keyword. Context 2 also uses \gls{group-acquire} as well in routine \code{foo}. However, the routine is called by routine \code{bar}, which only acquires monitor \code{a}. Since monitors can be acquired multiple times this does not cause a deadlock by itself but it does force the acquiring order to \code{a} then \code{b}. Context 3 also forces the acquiring order to be \code{a} then \code{b} but does not use \gls{group-acquire}. The previous example tries to illustrate the semantics that must be established to support releasing monitors in a \code{wait} statement. In all cases, the behavior of the wait statment is to release all the locks that were acquired my the inner-most monitor call. That is \code{a & b} in context 1 and 2 and \code{b} only in context 3. Here are a few other examples of this behavior.
+
 
 \begin{center}
-\begin{tabular}{c @{\hskip 0.35in} c @{\hskip 0.35in} c}
-\begin{lstlisting}
-enterMonitor(a);
-enterMonitor(b);
-// do stuff
-leaveMonitor(b);
-leaveMonitor(a);
-\end{lstlisting} & != &\begin{lstlisting}
-enterMonitor(a);
-enterMonitor(a, b);
-// do stuff
-leaveMonitor(a, b);
-leaveMonitor(a);
+\begin{tabular}{|c|c|c|}
+\begin{lstlisting}
+condition e;
+
+//acquire b
+void foo(monitor & nomutex a,
+           monitor & mutex b) {
+	bar(a,b);
+}
+
+//acquire a
+void bar(monitor & mutex a,
+           monitor & nomutex b) {
+
+	wait(e); //release a
+	          //keep b
+}
+
+foo(a, b);
+\end{lstlisting} &\begin{lstlisting}
+condition e;
+
+//acquire a & b
+void foo(monitor & mutex a,
+           monitor & mutex b) {
+	bar(a,b);
+}
+
+//acquire b
+void bar(monitor & mutex a,
+           monitor & nomutex b) {
+
+	wait(e); //release b
+	          //keep a
+}
+
+foo(a, b);
+\end{lstlisting} &\begin{lstlisting}
+condition e;
+
+//acquire a & b
+void foo(monitor & mutex a,
+           monitor & mutex b) {
+	bar(a,b);
+}
+
+//acquire none
+void bar(monitor & nomutex a,
+           monitor & nomutex b) {
+
+	wait(e); //release a & b
+	          //keep none
+}
+
+foo(a, b);
 \end{lstlisting}
 \end{tabular}
 \end{center}
-
-This is not intuitive because even if both methods display the same monitors state both inside and outside the critical section respectively, the behavior is different. Furthermore, the actual acquiring order will be exaclty the same since acquiring a monitor from inside its mutual exclusion is a no-op. This means that even if the data and the actual control flow are the same using both methods, the behavior of the \code{wait} will be different. The alternative is option 2, that is releasing acquired monitors, \underline{considering} nesting. This solves the issue of having the two acquiring method differ at the cost of making routine \code{foo} behave differently depending on from which context it is called (Context 1 or 2). Indeed in Context 2, routine \code{foo} actually behaves like routine \code{baz} rather than having the same behavior than in Context 1. The fact that both implicit approaches can be unintuitive depending on the perspective may be a sign that the explicit approach is superior. For this reason this \CFA does not support implicit monitor releasing and uses explicit semantics.
-\\
-
-The following examples shows three alternatives of explicit wait semantics :
-\\
-
+Note the right-most example is actually a trick pulled on the reader. Monitor state information is stored in thread local storage rather then in the routine context, which means that helper routines and other \code{nomutex} routines are invisible to the runtime system in regards to concurrency. This means that in the right-most example, the routine parameters are completly unnecessary. However, calling this routine from outside a valid monitor context is undefined.
+
+These semantics imply that in order to release of subset of the monitors currently held, users must write (and name) a routine that only acquires the desired subset and simply calls wait. While users can use this method, \CFA offers the \code{wait_release}\footnote{Not sure if an overload of \code{wait} would work...} which will release only the specified monitors. In the center previous examples, the code in the center uses the \code{bar} routine to only release monitor \code{b}. Using the \code{wait_release} helper, this can be rewritten without having the name two routines :
 \begin{center}
-\begin{tabular}{|c|c|c|}
-Case 1 & Case 2 & Case 3 \\
-Branding on construction & Explicit release list & Explicit ignore list \\
-\hline
-\begin{lstlisting}
-void foo(monitor & mutex a,
-         monitor & mutex b,
-	   condition & c)
-{
-	// Releases monitors
-	// branded in ctor
-	wait(c);
-}
-
-monitor a;
-monitor b;
-condition1 c1 = {a};
-condition2 c2 = {a, b};
-
-//Will release only a
-foo(a,b,c1);
-
-//Will release a and b
-foo(a,b,c2);
+\begin{tabular}{ c c c }
+\begin{lstlisting}
+	condition e;
+
+	//acquire a & b
+	void foo(monitor & mutex a,
+	           monitor & mutex b) {
+		bar(a,b);
+	}
+
+	//acquire b
+	void bar(monitor & mutex a,
+	           monitor & nomutex b) {
+
+		wait(e); //release b
+		          //keep a
+	}
+
+	foo(a, b);
 \end{lstlisting} &\begin{lstlisting}
-void foo(monitor & mutex a,
-         monitor & mutex b,
-	   condition & c)
-{
-	// Releases monitor a
-	// Holds monitor b
-	waitRelease(c, [a]);
-}
-
-monitor a;
-monitor b;
-condition c;
-
-
-
-foo(a,b,c);
-
-
-
+	=>
 \end{lstlisting} &\begin{lstlisting}
-void foo(monitor & mutex a,
-         monitor & mutex b,
-	   condition & c)
-{
-	// Releases monitor a
-	// Holds monitor b
-	waitHold(c, [b]);
-}
-
-monitor a;
-monitor b;
-condition c;
-
-
-
-foo(a,b,c);
-
-
-
+	condition e;
+
+	//acquire a & b
+	void foo(monitor & mutex a,
+	           monitor & mutex b) {
+		wait_release(e,b); //release b
+			                 //keep a
+	}
+
+	foo(a, b);
 \end{lstlisting}
 \end{tabular}
 \end{center}
-(Note : Case 2 and 3 use tuple semantics to pass a variable length list of elements.)
-\\
-
-All these cases have their pros and cons. Case 1 is more distinct because it means programmers need to be carefull about where the condition is initialized as well as where it is used. On the other hand, it is very clear and explicitly states which monitor is released and which monitor stays acquired. This is similar to Case 2, which releases only the monitors explictly listed. However, in Case 2, calling the \code{wait} routine instead of the \code{waitRelease} routine releases all the acquired monitor. The Case 3 is an improvement on that since it releases all the monitors except those specified. The result is that the \code{wait} routine can be written as follows :
-\begin{lstlisting}
-void wait(condition & cond) {
-	waitHold(cond, []);
-}
-\end{lstlisting}
-This alternative offers nice and consistent behavior between \code{wait} and \code{waitHold}. However, one large pitfall is that mutual exclusion can now be violated by calls to library code. Indeed, even if the following example seems benign there is one significant problem :
-\begin{lstlisting}
-monitor global;
-
-extern void doStuff(); //uses global
-
-void foo(monitor & mutex m) {
-	//...
-	doStuff(); //warning can release monitor m
-	//...
-}
-
-foo(global);
-\end{lstlisting}
-
-Indeed, if Case 2 or 3 are chosen it any code can violate the mutual exclusion of the calling code by issuing calls to \code{wait} or \code{waitHold} in a nested monitor context. Case 2 can be salvaged by removing the \code{wait} routine from the API but Case 3 cannot prevent users from calling \code{waitHold(someCondition, [])}. For this reason the syntax proposed in Case 3 is rejected. Note that the syntax proposed in case 1 and 2 are not exclusive. Indeed, by supporting two types of condition both cases can be supported :
-\begin{lstlisting}
-struct condition { /*...*/ };
-
-// Second argument is a variable length tuple.
-void wait(condition & cond, [...] monitorsToRelease);
-void signal(condition & cond);
-
-struct conditionN { /*...*/ };
-
-void ?{}(conditionN* this, /*list of N monitors to release*/);
-void wait(conditionN & cond);
-void signal(conditionN & cond);
-\end{lstlisting}
-
-Regardless of the option chosen for wait semantics, signal must be symmetrical. In all cases, signal only needs a single parameter, the condition variable that needs to be signalled. But \code{signal} needs to be called from the same monitor(s) that call to \code{wait}. Otherwise, mutual exclusion cannot be properly transferred back to the waiting monitor.
-
-Finally, an additionnal semantic which can be very usefull is the \code{signalBlock} routine. This routine behaves like signal for all of the semantics discussed above, but with the subtelty that mutual exclusion is transferred to the waiting task immediately rather than wating for the end of the critical section.
+
+Regardless of the context in which the \code{wait} statement is used, \code{signal} must be called holding the same set of monitors. In all cases, signal only needs a single parameter, the condition variable that needs to be signalled. But \code{signal} needs to be called from the same monitor(s) that call to \code{wait}. Otherwise, mutual exclusion cannot be properly transferred back to the waiting monitor.
+
+Finally, an additional semantic which can be very usefull is the \code{signal_block} routine. This routine behaves like signal for all of the semantics discussed above, but with the subtelty that mutual exclusion is transferred to the waiting task immediately rather than wating for the end of the critical section.
 \\
 
@@ -545,7 +565,7 @@
 % #        #   #     #    ###    #     # #     # #     # #       #     #
 % ####### #     #    #    ###     #####   #####  #     # ####### ######
-
+\newpage
 \subsection{External scheduling} \label{extsched}
-As one might expect, the alternative to Internal scheduling is to use External scheduling instead. This method is somewhat more robust to deadlocks since one of the threads keeps a relatively tight control on scheduling. Indeed, as the following examples will demonstrate, external scheduling allows users to wait for events from other threads without the concern of unrelated events occuring. External scheduling can generally be done either in terms of control flow (ex: \uC) or in terms of data (ex: Go). Of course, both of these paradigms have their own strenghts and weaknesses but for this project control flow semantics where chosen to stay consistent with the rest of the languages semantics. Two challenges specific to \CFA arise when trying to add external scheduling with loose object definitions and multi-monitor routines. The following example shows what a simple use \code{accept} versus \code{wait}/\code{signal} and its advantages.
+An alternative to internal scheduling is to use external scheduling instead. This method is more constrained and explicit which may help users tone down the undeterministic nature of concurrency. Indeed, as the following examples demonstrates, external scheduling allows users to wait for events from other threads without the concern of unrelated events occuring. External scheduling can generally be done either in terms of control flow (ex: \uC) or in terms of data (ex: Go). Of course, both of these paradigms have their own strenghts and weaknesses but for this project control flow semantics where chosen to stay consistent with the rest of the languages semantics. Two challenges specific to \CFA arise when trying to add external scheduling with loose object definitions and multi-monitor routines. The following example shows a simple use \code{accept} versus \code{wait}/\code{signal} and its advantages.
 
 \begin{center}
@@ -565,5 +585,5 @@
 
 	public:
-		void f();
+		void f() { /*...*/ }
 		void g() { _Accept(f); }
 	private:
@@ -573,5 +593,5 @@
 \end{center}
 
-In the case of internal scheduling, the call to \code{wait} only guarantees that \code{g} was the last routine to access the monitor. This intails that the routine \code{f} may have acquired mutual exclusion several times while routine \code{h} was waiting. On the other hand, external scheduling guarantees that while routine \code{h} was waiting, no routine other than \code{g} could acquire the monitor.
+In the case of internal scheduling, the call to \code{wait} only guarantees that \code{g} is the last routine to access the monitor. This intails that the routine \code{f} may have acquired mutual exclusion several times while routine \code{h} was waiting. On the other hand, external scheduling guarantees that while routine \code{h} was waiting, no routine other than \code{g} could acquire the monitor.
 \\
 
@@ -756,21 +776,23 @@
 % #       #     # #     # #     # ####### ####### ####### ####### ###  #####  #     #
 \section{Parallelism}
-Historically, computer performance was about processor speeds and instructions count. However, with heat dissipation being an ever growing challenge, parallelism has become the new source of greatest performance \cite{Sutter05, Sutter05b}. In this decade, it is not longer reasonnable to create high-performance application without caring about parallelism. Indeed, parallelism is an important aspect of performance and more specifically throughput and hardware utilization. The lowest level approach of parallelism is to use \glspl{kthread}. However since these have significant costs and limitations \glspl{kthread} are now mostly used as an implementation tool rather than a user oriented one. There are several alternatives to solve these issues which all have strengths and weaknesses.
+Historically, computer performance was about processor speeds and instructions count. However, with heat dissipation being a direct consequence of speed increase, parallelism has become the new source for increased performance~\cite{Sutter05, Sutter05b}. In this decade, it is not longer reasonnable to create a high-performance application without caring about parallelism. Indeed, parallelism is an important aspect of performance and more specifically throughput and hardware utilization. The lowest-level approach of parallelism is to use \glspl{kthread} in combination with semantics like \code{fork}, \code{join}, etc. However, since these have significant costs and limitations, \glspl{kthread} are now mostly used as an implementation tool rather than a user oriented one. There are several alternatives to solve these issues that all have strengths and weaknesses. While there are many variations of the presented paradigms, most of these variations do not actually change the guarantees or the semantics, they simply move costs in order to achieve better performance for certain workloads.
 
 \subsection{User-level threads}
-A direct improvement on the \gls{kthread} approach is to use \glspl{uthread}. These threads offer most of the same features that the operating system already provide but can be used on a much larger scale. This is the most powerfull solution as it allows all the features of multi-threading while removing several of the more expensives costs of using kernel threads. The down side is that almost none of the low-level threading complexities are hidden, users still have to think about data races, deadlocks and synchronization issues. This can be somewhat alleviated by a concurrency toolkit with strong garantees but the parallelism toolkit offers very little to reduce complexity in itself.
-
-Examples of languages that support are Java\cite{Java}, Haskell\cite{Haskell} and \uC\cite{uC++book}.
+A direct improvement on the \gls{kthread} approach is to use \glspl{uthread}. These threads offer most of the same features that the operating system already provide but can be used on a much larger scale. This approach is the most powerfull solution as it allows all the features of multi-threading, while removing several of the more expensives costs of using kernel threads. The down side is that almost none of the low-level threading problems are hidden, users still have to think about data races, deadlocks and synchronization issues. These issues can be somewhat alleviated by a concurrency toolkit with strong garantees but the parallelism toolkit offers very little to reduce complexity in itself.
+
+Examples of languages that support \glspl{uthread} are Erlang~\cite{Erlang} and \uC~\cite{uC++book}.
+
+\subsubsection{Fibers : user-level threads without preemption}
+A popular varient of \glspl{uthread} is what is often reffered to as \glspl{fiber}. However, \glspl{fiber} do not present meaningful semantical differences with \glspl{uthread}. Advocates of \glspl{fiber} list their high performance and ease of implementation as majors strenghts of \glspl{fiber} but the performance difference between \glspl{uthread} and \glspl{fiber} is controversial and the ease of implementation, while true, is a weak argument in the context of language design. Therefore this proposal largely ignore fibers.
+
+An example of a language that uses fibers is Go~\cite{Go}
 
 \subsection{Jobs and thread pools}
-The approach on the opposite end of the spectrum is to base parallelism on \glspl{job}. Indeed, \glspl{job} offer limited flexibility but at the benefit of a simpler user interface. In \gls{job} based systems users express parallelism as units of work and the dependency graph (either explicit or implicit) that tie them together. This means users need not to worry about concurrency but significantly limits the interaction that can occur between different jobs. Indeed, any \gls{job} that blocks also blocks the underlying \gls{kthread}, this effectively mean the CPU utilization, and therefore throughput, will suffer noticeably.
-The golden standard of this implementation is Intel's TBB library\cite{TBB}.
-
-\subsection{Fibers : user-level threads without preemption}
-Finally, in the middle of the flexibility versus complexity spectrum lay \glspl{fiber} which offer \glspl{uthread} without the complexity of preemption. This means users don't have to worry about other \glspl{fiber} suddenly executing between two instructions which signficantly reduces complexity. However, any call to IO or other concurrency primitives can lead to context switches. Furthermore, users can also block \glspl{fiber} in the middle of their execution without blocking a full processor core. This means users still have to worry about mutual exclusion, deadlocks and race conditions in their code, raising the complexity significantly.
-An example of a language that uses fibers is Go\cite{Go}
+The approach on the opposite end of the spectrum is to base parallelism on \glspl{pool}. Indeed, \glspl{pool} offer limited flexibility but at the benefit of a simpler user interface. In \gls{pool} based systems, users express parallelism as units of work and a dependency graph (either explicit or implicit) that tie them together. This approach means users need not worry about concurrency but significantly limits the interaction that can occur among jobs. Indeed, any \gls{job} that blocks also blocks the underlying worker, which effectively means the CPU utilization, and therefore throughput, suffers noticeably. It can be argued that a solution to this problem is to use more workers than available cores. However, unless the number of jobs and the number of workers are comparable, having a significant amount of blocked jobs always results in idles cores.
+
+The gold standard of this implementation is Intel's TBB library~\cite{TBB}.
 
 \subsection{Paradigm performance}
-While the choice between the three paradigms listed above may have significant performance implication, it is difficult to pin the performance implications of chosing a model at the language level. Indeed, in many situations one of these paradigms will show better performance but it all strongly depends on the usage. Having mostly indepent units of work to execute almost guarantess that the \gls{job} based system will have the best performance. However, add interactions between jobs and the processor utilisation might suffer. User-level threads may allow maximum ressource utilisation but context switches will be more expansive and it is also harder for users to get perfect tunning. As with every example, fibers sit somewhat in the middle of the spectrum. Furthermore, if the units of uninterrupted work are large enough the paradigm choice will be largely amorticised by the actual work done.
+While the choice between the three paradigms listed above may have significant performance implication, it is difficult to pindown the performance implications of chosing a model at the language level. Indeed, in many situations one of these paradigms may show better performance but it all strongly depends on the workload. Having a large amount of mostly independent units of work to execute almost guarantess that the \gls{pool} based system has the best performance thanks to the lower memory overhead. However, interactions between jobs can easily exacerbate contention. User-level threads allow fine-grain context switching, which results in better resource utilisation, but context switches will be more expansive and the extra control means users need to tweak more variables to get the desired performance. Furthermore, if the units of uninterrupted work are large enough the paradigm choice is largely amorticised by the actual work done.
 
 %  #####  #######    #          ####### ######  ######
@@ -783,20 +805,5 @@
 
 \section{\CFA 's Thread Building Blocks}
-As a system level language, \CFA should offer both performance and flexibilty as its primary goals, simplicity and user-friendliness being a secondary concern. Therefore, the core of parallelism in \CFA should prioritize power and efficiency. With this said, it is possible to deconstruct the three paradigms details aboved in order to get simple building blocks. Here is a table showing the core caracteristics of the mentionned paradigms :
-\begin{center}
-\begin{tabular}[t]{| r | c | c |}
-\cline{2-3}
-\multicolumn{1}{ c| }{} & Has a stack & Preemptive \\
-\hline
-\Glspl{job} & X & X \\
-\hline
-\Glspl{fiber} & \checkmark & X \\
-\hline
-\Glspl{uthread} & \checkmark & \checkmark \\
-\hline
-\end{tabular}
-\end{center}
-
-As shown in section \ref{cfaparadigms} these different blocks being available in \CFA it is trivial to reproduce any of these paradigm.
+As a system-level language, \CFA should offer both performance and flexibilty as its primary goals, simplicity and user-friendliness being a secondary concern. Therefore, the core of parallelism in \CFA should prioritize power and efficiency. With this said, deconstructing popular paradigms in order to get simple building blocks yields \glspl{uthread} as the core parallelism block. \Glspl{pool} and other parallelism paradigms can then be built on top of the underlying threading model.
 
 % ####### #     # ######  #######    #    ######   #####
@@ -809,5 +816,5 @@
 
 \subsection{Thread Interface}
-The basic building blocks of \CFA are \glspl{cfathread}. By default these are implemented as \glspl{uthread} and as such offer a flexible and lightweight threading interface (lightweight comparatievely to \glspl{kthread}). A thread can be declared using a struct declaration prefix with the \code{thread} as follows :
+The basic building blocks of \CFA are \glspl{cfathread}. By default these are implemented as \glspl{uthread}, and as such, offer a flexible and lightweight threading interface (lightweight compared to \glspl{kthread}). A thread can be declared using a struct declaration with prefix \code{thread} as follows :
 
 \begin{lstlisting}
@@ -815,14 +822,14 @@
 \end{lstlisting}
 
-Obviously, for this thread implementation to be usefull it must run some user code. Several other threading interfaces use some function pointer representation as the interface of threads (for example : \Csharp \cite{Csharp} and Scala \cite{Scala}). However, we consider that statically tying a \code{main} routine to a thread superseeds this approach. Since the \code{main} routine is definetely a special routine in \CFA, we can reuse the existing syntax for declaring routines with unordinary name, i.e. operator overloading. As such the \code{main} routine of a thread can be defined as such :
+Obviously, for this thread implementation to be usefull it must run some user code. Several other threading interfaces use a function-pointer representation as the interface of threads (for example : \Csharp~\cite{Csharp} and Scala~\cite{Scala}). However, this proposal considers that statically tying a \code{main} routine to a thread superseeds this approach. Since the \code{main} routine is already a special routine in \CFA (where the program begins), the existing syntax for declaring routines names with special semantics can be extended, i.e. operator overloading. As such the \code{main} routine of a thread can be defined as :
 \begin{lstlisting}
 	thread struct foo {};
 
-	void ?main(thread foo* this) {
-		/*... Some useful code ...*/
-	}
-\end{lstlisting}
-
-With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously :
+	void ?main(foo* this) {
+		sout | "Hello World!" | endl;
+	}
+\end{lstlisting}
+
+In this example, threads of type \code{foo} will start there execution in the \code{void ?main(foo*)} routine which in this case prints \code{"Hello World!"}. While this proposoal encourages this approach which is enforces strongly type programming. Users may prefer to use the routine based thread semantics for the sake of simplicity. With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously :
 \begin{lstlisting}
 	typedef void (*voidFunc)(void);
@@ -833,26 +840,24 @@
 
 	//ctor
-	void ?{}(thread FuncRunner* this, voidFunc inFunc) {
+	void ?{}(FuncRunner* this, voidFunc inFunc) {
 		func = inFunc;
 	}
 
 	//main
-	void ?main(thread FuncRunner* this) {
+	void ?main(FuncRunner* this) {
 		this->func();
 	}
 \end{lstlisting}
 
-% In this example \code{func} is a function pointer stored in \acrfull{tls}, which is \CFA is both easy to use and completly typesafe.
-
-Of course for threads to be useful, it must be possible to start and stop threads and wait for them to complete execution. While using an \acrshort{api} such as \code{fork} and \code{join} is relatively common in the literature, such an interface is not needed. Indeed, the simplest approach is to use \acrshort{raii} principles and have threads \code{fork} once the constructor has completed and \code{join} before the destructor runs.
-\begin{lstlisting}
-thread struct FuncRunner; //FuncRunner declared above
-
-void world() {
+Of course for threads to be useful, it must be possible to start and stop threads and wait for them to complete execution. While using an \acrshort{api} such as \code{fork} and \code{join} is relatively common in the literature, such an interface is unnecessary. Indeed, the simplest approach is to use \acrshort{raii} principles and have threads \code{fork} once the constructor has completed and \code{join} before the destructor runs.
+\begin{lstlisting}
+thread struct World; //FuncRunner declared above
+
+void ?main(thread World* this) {
 	sout | "World!" | endl;
 }
 
 void main() {
-	FuncRunner run = {world};
+	World w;
 	//Thread run forks here
 
@@ -863,7 +868,6 @@
 }
 \end{lstlisting}
-This semantic has several advantages over explicit semantics : typesafety is guaranteed, any thread will always be started and stopped exaclty once and users can't make any progamming errors. Furthermore it naturally follows the memory allocation semantics which means users don't need to learn multiple semantics.
-
-These semantics also naturally scale to multiple threads meaning basic synchronisation is very simple :
+This semantic has several advantages over explicit semantics : typesafety is guaranteed, a thread is always started and stopped exaclty once and users cannot make any progamming errors. However, one of the apparent drawbacks of this system is that threads now always form a lattice, that is they are always destroyed in opposite order of construction. While this seems like a significant limitation, existing \CFA semantics can solve this problem. Indeed, by using dynamic allocation to create threads will naturally let threads outlive the scope in which the thread was created much like dynamically allocating memory will let objects outlive the scope in which thy were created :
+
 \begin{lstlisting}
 	thread struct MyThread {
@@ -872,8 +876,45 @@
 
 	//ctor
-	void ?{}(thread MyThread* this) {}
+	void ?{}(MyThread* this,
+		     bool is_special = false) {
+		//...
+	}
 
 	//main
-	void ?main(thread MyThread* this) {
+	void ?main(MyThread* this) {
+		//...
+	}
+
+	void foo() {
+		MyThread* special_thread;
+		{
+			MyThread thrds = {false};
+			//Start a thread at the beginning of the scope
+
+			DoStuff();
+
+			//create a other thread that will outlive the thread in this scope
+			special_thread = new MyThread{true};
+
+			//Wait for the thread to finish
+		}
+		DoMoreStuff();
+
+		//Now wait for the special
+	}
+\end{lstlisting}
+
+Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple :
+
+\begin{lstlisting}
+	thread struct MyThread {
+		//...
+	};
+
+	//ctor
+	void ?{}(MyThread* this) {}
+
+	//main
+	void ?main(MyThread* this) {
 		//...
 	}
@@ -889,6 +930,64 @@
 \end{lstlisting}
 
+\subsection{Coroutines : A stepping stone}\label{coroutine}
+While the main focus of this proposal is concurrency and paralellism, it is important to adress coroutines which are actually a significant underlying aspect of the concurrency system. Indeed, while having nothing todo with parallelism and arguably very little to do with concurrency, coroutines need to deal with context-switchs and and other context management operations. Therefore, this proposal includes coroutines both as an intermediate step for the implementation of threads and a first class feature of \CFA.
+
+The core API of coroutines revolve around two features : independent stacks and suspedn/resume. Much like threads the syntax for declaring a coroutine is declaring a type and a main routine for it to start :
+\begin{lstlisting}
+	coroutine struct MyCoroutine {
+		//...
+	};
+
+	//ctor
+	void ?{}(MyCoroutine* this) {
+
+	}
+
+	//main
+	void ?main(MyCoroutine* this) {
+		sout | "Hello World!" | endl;
+	}
+\end{lstlisting}
+
+One a coroutine is created, users can context switch to it using \code{suspend} and come back using \code{resume}. Here is an example of a solution to the fibonnaci problem using coroutines :
+\begin{lstlisting}
+	coroutine struct Fibonacci {
+		int fn; // used for communication
+	};
+
+	void ?main(Fibonacci* this) {
+		int fn1, fn2; 		// retained between resumes
+		this->fn = 0;
+		fn1 = this->fn;
+		suspend(this); 		// return to last resume
+
+		this->fn = 1;
+		fn2 = fn1;
+		fn1 = this->fn;
+		suspend(this); 		// return to last resume
+
+		for ( ;; ) {
+			this->fn = fn1 + fn2;
+			fn2 = fn1;
+			fn1 = this->fn;
+			suspend(this); 	// return to last resume
+		}
+	}
+
+	int next(Fibonacci& this) {
+		resume(&this); // transfer to last suspend
+		return this.fn;
+	}
+
+	void main() {
+		Fibonacci f1, f2;
+		for ( int i = 1; i <= 10; i += 1 ) {
+			sout | next(f1) | '§\verb+ +§' | next(f2) | endl;
+		}
+	}
+\end{lstlisting}
+
 \newpage
-\large{\textbf{WORK IN PROGRESS}}
+\bf{WORK IN PROGRESS}
 \subsection{The \CFA Kernel : Processors, Clusters and Threads}\label{kernel}
 
Index: doc/proposals/concurrency/glossary.tex
===================================================================
--- doc/proposals/concurrency/glossary.tex	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ doc/proposals/concurrency/glossary.tex	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -1,3 +1,23 @@
 \makeglossaries
+
+\longnewglossaryentry{callsite-locking}
+{name={callsite-locking}}
+{
+Locking done by the calling routine. With this technique, a routine calling a monitor routine will aquire the monitor \emph{before} making the call to the actuall routine.
+}
+
+\longnewglossaryentry{entry-point-locking}
+{name={entry-point-locking}}
+{
+Locking done by the called routine. With this technique, a monitor routine called by another routine will aquire the monitor \emph{after} entering the routine body but prior to any other code.
+}
+
+\longnewglossaryentry{group-acquire}
+{name={bulked acquiring}}
+{
+Implicitly acquiring several monitors when entering a monitor.
+}
+
+
 \longnewglossaryentry{uthread}
 {name={user-level thread}}
@@ -30,4 +50,12 @@
 
 \textit{Synonyms : Tasks.}
+}
+
+\longnewglossaryentry{pool}
+{name={thread-pool}}
+{
+Group of homogeneuous threads that loop executing units of works after another.
+
+\textit{Synonyms : }
 }
 
Index: doc/proposals/concurrency/style.tex
===================================================================
--- doc/proposals/concurrency/style.tex	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ doc/proposals/concurrency/style.tex	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,9 @@
+\input{common}                                          % bespoke macros used in the document
+
+\lstset{
+morekeywords=[2]{nomutex,mutex,thread,wait,wait_release,signal,signal_block,accept,monitor,suspend,resume,coroutine},
+keywordstyle=[2]\color{blue},				% second set of keywords for concurency
+basicstyle=\linespread{0.9}\tt\small,		% reduce line spacing and use typewriter font
+stringstyle=\sf\color{Mahogany},			% use sanserif font
+commentstyle=\itshape\color{OliveGreen},		% green and italic comments
+}%
Index: doc/proposals/concurrency/version
===================================================================
--- doc/proposals/concurrency/version	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ doc/proposals/concurrency/version	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -1,1 +1,1 @@
-0.4.99
+0.7.48
Index: doc/proposals/virtual.txt
===================================================================
--- doc/proposals/virtual.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ doc/proposals/virtual.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,163 @@
+Proposal for virtual functionality
+
+Imagine the following code :
+
+trait drawable(otype T) {
+      void draw(T* );
+};
+
+struct text {
+      char* text;
+};
+
+void draw(text*);
+
+struct line{
+      vec2 start;
+      vec2 end;
+};
+
+void draw(line*);
+
+While all the members of this simple UI support drawing creating a UI that easily
+supports both these UI requires some tedious boiler-plate code :
+
+enum type_t { text, line };
+
+struct widget {
+      type_t type;
+      union {
+            text t;
+            line l;
+      };
+};
+
+void draw(widget* w) {
+      switch(w->type) {
+            case text : draw(&w->text); break;
+            case line : draw(&w->line); break;
+            default : handle_error(); break;
+      }
+}
+
+While this code will work as indented, adding any new widgets or any new widget behaviors
+requires changing existing code to add the desired functionality. To ease this maintenance
+effort required CFA introduces the concept of dynamic types, in a manner similar to C++.
+
+A simple usage of dynamic type with the previous example would look like :
+
+drawable* objects[10];
+fill_objects(objects);
+
+while(running) {
+      for(drawable* object : objects) {
+            draw(object);
+      }
+}
+
+However, this is not currently do-able in the current CFA and furthermore is not
+possible to implement statically. Therefore we need to add a new feature to handle
+having dynamic types like this (That is types that are found dynamically not types
+that change dynamically).
+
+C++ uses inheritance and virtual functions to find the
+desired type dynamically. CFA takes inspiration from this solution.
+
+What we really want to do is express the fact that calling draw() on a object
+should find the dynamic type of the parameter before calling the routine, much like the
+hand written example given above. We can express this by adding the virtual keyword on
+the parameter of the constraints on our trait:
+
+trait drawable(otype T) {
+      void draw(virtual T* );
+};
+
+This expresses the idea that drawable is similar to an abstract base class in C++ and
+also gives meaning to trying to take a pointer of drawable. That is anything that can
+be cast to a drawable pointer has the necessary information to call the draw routine on
+that type. Before that drawable was only a abstract type while now it also points to a
+piece of storage which specify which behavior the object will have at run time.
+
+This storage needs to be allocate somewhere. C++ just adds an invisible pointer at
+the beginning of the struct but we can do something more explicit for users, actually
+have a visible special field :
+
+struct text {
+      char* text;
+      vtable drawable;
+};
+
+struct line{
+      vtable drawable;
+      vec2 start;
+      vec2 end;
+};
+
+With these semantics, adding a "vtable drawable" means that text pointers and line pointers are now
+convertible to drawable pointers. This conversion will not necessarily be a type only change however, indeed,
+the drawable pointer will point to the field "vtable drawable" not the head of the struct. However, since all
+the types are known at compile time, converting pointers becomes a simple offset operations.
+
+The vtable field contains a pointer to a vtable which contains all the information needed for the caller
+to find the function pointer of the desired behavior.
+
+One of the limitations of this design is that it does not support double dispatching, which
+concretely means traits cannot have routines with more than one virtual parameter. This design
+would have many ambiguities if it did support multiple virtual parameter. A futher limitation is 
+that traits over more than one type cannot have vtables meaningfully defined for them, as the 
+particular vtable to use would be a function of the other type(s) the trait is defined over.
+
+It is worth noting that the function pointers in these vtables are bound at object construction, rather than 
+function call-site, as in Cforall's existing polymorphic functions. As such, it is possible that two objects 
+with the same static type would have a different vtable (consider what happens if draw(line*) is overridden 
+between the definitions of two line objects). Given that the virtual drawable* erases static types though, 
+this should not be confusing in practice. A more distressing possibility is that of creating an object that 
+outlives the scope of one of the functions in its vtable. This is certainly a possible bug, but it is of a 
+type that C programmers are familiar with, and should be able to avoid by the usual methods.
+
+Extensibility.
+
+One of the obvious critics of this implementation is that it lacks extensibility for classes
+that cannot be modified (ex: Linux C headers). However this solution can be extended to
+allow more extensibility by adding "Fat pointers".
+
+Indeed, users could already "solve" this issue by writing their own fat pointers as such:
+
+trait MyContext(otype T) {
+      void* get_stack(virtual T*)
+};
+
+void* get_stack(ucontext_t *context);
+
+struct fat_ucontext_t {
+      vtable MyContext;
+      ucontext_t *context;
+}
+
+//Tedious forwarding routine
+void* get_stack(fat_ucontext_t *ptr) {
+      return get_stack(ptr->context);
+}
+
+However, users would have to write all the virtual methods they want to override and make
+them all simply forward to the existing method that takes the corresponding POCO(Plain Old C Object).
+
+The alternative we propose is to use language level fat pointers :
+
+trait MyContext(otype T) {
+      void* get_stack(virtual T*)
+};
+
+void* get_stack(ucontext_t *context);
+
+//The type vptr(ucontext_t) all
+vptr(ucontext_t) context;
+
+These behave exactly as the previous example but all the forwarding routines are automatically generated.
+
+Bikeshedding.
+
+It may be desirable to add fewer new keywords than discussed in this proposal; it is possible that "virtual" 
+could replace both "vtable" and "vptr" above with unambiguous contextual meaning. However, for purposes of 
+clarity in the design discussion it is beneficial to keep the keywords for separate concepts distinct.
+
Index: doc/working/.gitignore
===================================================================
--- doc/working/.gitignore	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ doc/working/.gitignore	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,4 @@
+.declarative_resolver.tex.swp
+declarative_resolver.aux
+declarative_resolver.log
+declarative_resolver.pdf
Index: doc/working/declarative_resolver.tex
===================================================================
--- doc/working/declarative_resolver.tex	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ doc/working/declarative_resolver.tex	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,172 @@
+\documentclass{article}
+
+\usepackage{amsmath}
+\usepackage{amssymb}
+
+\usepackage{listings}
+\lstset{
+  basicstyle=\ttfamily,
+  mathescape
+}
+
+\newcommand{\TODO}{\textbf{TODO:}~}
+\newcommand{\NOTE}{\textit{NOTE:}~}
+
+\newcommand{\Z}{\mathbb{Z}}
+\newcommand{\Znn}{\Z^{\oplus}}
+
+\newcommand{\conv}[2]{#1 \rightarrow #2}
+\newcommand{\C}[1]{\mathtt{#1}}
+
+\newcommand{\ls}[1]{\left[ #1 \right]}
+\newcommand{\rng}[2]{\left\{#1, \cdots #2\right\}}
+\title{Declarative Description of Expression Resolution Problem}
+\author{Aaron Moss}
+
+\begin{document}
+\maketitle
+
+\section{Inputs}
+\begin{itemize}
+\item A set of types $T$.
+\item A set of conversions $C \subset \{ \conv{from}{to} : from, to \in T \}$.
+  \begin{itemize}
+  \item $C$ is a directed acyclic graph (DAG).
+  \item \TODO There should be two of these, to separate the safe and unsafe conversions.
+  \end{itemize}
+\item A set of names $N$
+\item A set of declarations $F$. Each declaration $f \in F$ has the following properties:
+  \begin{itemize}
+  \item A name $f.name \in N$, not guaranteed to be unqiue in $F$.
+  \item A return type $f.type \in T$
+  \item A number of parameters $f.n \in \Znn$.
+  \item A list of parameter types $params = \ls{f_1, \cdots f_{f.n}}$, where each $f_i \in T$. 
+    \begin{itemize}
+    \item \TODO This should be a list of elements from $T$ to account for tuples and void-returning functions.
+    \end{itemize}
+  \item \TODO This model needs to account for polymorphic functions.
+  \end{itemize}
+\item A tree of expressions $E$, rooted at an expression $root$. Each expression $e \in E$ has the following properties:
+  \begin{itemize}
+  \item A name $e.name \in N$, not guaranteed to be unique in $E$
+  \item A number of arguments $e.n \in \Znn$
+  \item A list of arguments $args = \ls{e_1, \cdots e_{e.n}}$, where each $e_i \in E$; these arguments $e_i$ are considered the children of $e$ in the tree.
+  \end{itemize}
+\end{itemize}
+
+\section{Problem}
+An interpretation $x \in I$ has the following properties:
+\begin{itemize}
+\item An interpreted expression $x.expr \in E$.
+\item A base declaration $x.decl \in F$.
+\item A type $x.type \in T$
+\item A cost $x.cost \in \Znn$.
+  \begin{itemize}
+  \item \TODO Make this cost a tuple containing unsafe and polymorphic conversion costs later.
+  \end{itemize}
+\item A number of sub-interpretations $x.n \in \Znn$.
+\item A list of sub-interpretations $subs = \ls{x_1, \cdots x_{x.n}}$, where each $x_i \in I$.
+\end{itemize}
+
+Starting from $I = \{\}$, iteratively generate interpretations according to the following rules until a fixed point is reached:
+\begin{itemize}
+\item \textbf{Generate all interpretations, given subexpression interpretations.} \\
+      $\forall e \in E, f \in F$ such that $e.name = f.name$ and $e.n = f.n$, let $n = e.n$. \\
+      If $\forall i \in \rng{1}{n}, \exists x_i \in I$ such that $x_i.expr = e_i \land x_i.type = f_i$, \\
+      For each combination of $x_i$, generate a new interpretation $x$ as follows:
+      \begin{itemize}
+      \item $x.expr = e$.
+      \item $x.decl = f$.
+      \item $x.type = f.type$.
+      \item $x.cost = \sum_{i \in \rng{1}{n}} x_i.cost$.
+      \item $x.n = n$.
+      \end{itemize}
+
+\item \textbf{Generate conversions.} \\
+      $\forall x \in I, \forall t \in T, \exists (x.type, t) \in C$, \\
+      generate a new interpretation $x'$ as follows:
+      \begin{itemize}
+      \item $x'.type = t$.
+      \item $x'.cost = x.cost + 1$.
+      \item All other properties of $x'$ are identical to those of $x$.
+      \end{itemize}
+\end{itemize}
+
+
+Once $I$ has been completely generated, let $I' = { x \in I : x.expr = root }$.
+\begin{itemize}
+\item If $I' = \{\}$, report failure (no valid interpretation).
+\item If there exists a unqiue $x^* \in I'$ such that $x^*.cost$ is minimal in $I'$, report $x^*$ (success).
+\item Otherwise report failure (ambiguous).
+\end{itemize}
+
+\section{Example}
+
+Here is a worked example for the following C code block:
+\begin{lstlisting}
+int x;  // $x$
+void* x;  // $x'$
+
+long f(int, void*);  // $f$
+void* f(void*, int);  // $f'$
+void* f(void*, long);  // $f''$
+
+f( f( x, x ), x );  // $root:$f( $\gamma:$f( $\alpha:$x, $\beta:$x ), $\delta:$x )
+\end{lstlisting}
+
+Using the following subset of the C type system, this example includes the following set of declarations and expressions\footnote{$n$ can be inferred from the length of the appropriate list in the elements of $F$, $E$, and $I$, and has been ommitted for brevity.}:
+\begin{align*}
+  T = \{ &\C{int}, \C{long}, \C{void*} \} \\
+  C = \{ &\conv{\C{int}}{\C{long}} \} \\
+  N = \{ &\C{x}, \C{f} \} \\
+  F = \{ &x = \{ name: \C{x}, type: \C{int}, params: \ls{} \}, \\
+         &x' = \{ name: \C{x}, type: \C{void*}, params: \ls{} \}, \\
+         &f = \{ name: \C{f}, type: \C{long}, params: \ls{\C{int}, \C{void*}} \}, \\
+         &f' = \{ name: \C{f}, type: \C{void*}, params: \ls{\C{void*}, \C{int}} \}, \\
+         &f'' = \{ name: \C{f}, type: \C{void*}, params: \ls{\C{void*}, \C{long}} \} \} \\
+  E = \{ &\alpha = \{ name: \C{x}, args: \ls{} \}, \\
+         &\beta = \{ name: \C{x}, args: \ls{} \}, \\
+         &\gamma = \{ name: \C{f}, args: \ls{\alpha, \beta} \}, \\
+         &\delta = \{ name: \C{x}, args: \ls{} \}, \\
+         &root = \{ name: \C{f}, args: \ls{\gamma, \delta} \} \}
+\end{align*}
+
+Given these initial facts, the initial interpretations for the leaf expressions $\alpha$, $\beta$ \& $\delta$ can be generated from the subexpression rule:
+\begin{align}
+ \{ &expr: \alpha, decl: x, type: \C{int}, cost: 0, subs: \ls{} \} \\
+ \{ &expr: \alpha, decl: x', type: \C{void*}, cost: 0, subs: \ls{} \} \\
+ \{ &expr: \beta, decl: x, type: \C{int}, cost: 0, subs: \ls{} \} \\
+ \{ &expr: \beta, decl: x', type: \C{void*}, cost: 0, subs: \ls{} \} \\
+ \{ &expr: \delta, decl: x, type: \C{int}, cost: 0, subs: \ls{} \} \\
+ \{ &expr: \delta, decl: x', type: \C{void*}, cost: 0, subs: \ls{} \}
+\end{align}
+
+These new interpretations allow generation of further interpretations by the conversion rule and the $\conv{\C{int}}{\C{long}}$ conversion:
+\begin{align}
+\{ &expr: \alpha, decl: x, type: \C{long}, cost: 1, subs: \ls{} \} \\
+\{ &expr: \beta, decl: x, type: \C{long}, cost: 1, subs: \ls{} \} \\
+\{ &expr: \delta, decl: x, type: \C{long}, cost: 1, subs: \ls{} \}
+\end{align}
+
+Applying the subexpression rule again to this set of interpretations, we can generate interpretations for $\gamma$ [$\C{f( x, x )}$]:
+\begin{align}
+\{ &expr: \gamma, decl: f, type: \C{long}, cost: 0, subs: \ls{ (1), (4) } \} \\
+\{ &expr: \gamma, decl: f', type: \C{void*}, cost: 0, subs: \ls{ (2), (3) } \} \\
+\{ &expr: \gamma, decl: f'', type: \C{void*}, cost: 1, subs: \ls{ (2), (8) } \}
+\end{align}
+
+Since all of the new interpretations have types for which no conversions are applicable ($\C{void*}$ and $\C{long}$), the conversion rule generates no new interpretations.
+If $\C{f(x, x)}$ was the root expression, the set of candidate interpretations $I'$ would equal $\{ (10), (11), (12) \}$. Since both $(10)$ and $(11)$ have cost $0$, there is no unique minimal-cost element of this set, and the resolver would report failure due to this ambiguity.
+
+However, having generated all the interpretations of $\C{f( x, x )}$, the subexpression rule can now be applied again to generate interpretations of the $root$ expression:
+\begin{align}
+\{ &expr: root, decl: f', type: \C{void*}, cost: 0, subs: \ls{ (11), (5) } \} \\
+\{ &expr: root, decl: f'', type: \C{void*}, cost: 1, subs: \ls{ (11), (9) } \} \\
+\{ &expr: root, decl: f', type: \C{void*}, cost: 1, subs: \ls{ (12), (5) } \} \\
+\{ &expr: root, decl: f'', type: \C{void*}, cost: 2, subs: \ls{ (12), (9) } \}
+\end{align}
+
+Since again none of these new interpretations are of types with conversions defined, the conversion rule cannot be applied again; since the root expression has been resolved, no further applications of the subexpression rule are applicable either, therefore a fixed point has been reached and we have found the complete set of interpretations. If this fixed point had been reached before finding any valid interpretations of $root$ (e.g.~as would have happened if $f$ was the only declaration of $\C{f}$ in the program), the algorithm would have reported a failure with no valid interpretations.
+
+At the termination of this process, the set $I'$ of valid root interpretations is $\{ (13), (14), (15), (16)\}$; since $(13)$ has the unique minimal cost, it is the accepted interpretation of the root expression, and in this case the source $\C{f( f( x, x ), x )}$ is interpreted as $f'( f'( x', x ), x )$.
+\end{document}
Index: doc/working/resolver_design.md
===================================================================
--- doc/working/resolver_design.md	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ doc/working/resolver_design.md	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -1382,4 +1382,12 @@
 hypothesis needs to be empirically validated.
 
+Another approach would be to abandon expression-tree ordering for 
+subexpression matching, and order by "most constrained symbol"; symbols would  
+be more constrained if there were fewer matching declarations, fewer 
+subexpressions yet to resolve, or possibly fewer possible types the expression 
+could resolve to. Ordering the expressions in a priority-queue by this metric 
+would not necessarily produce a top-down or a bottom-up order, but would add 
+opportunities for pruning based on memoized upper and lower bounds.
+
 Both Baker and Cormack explicitly generate all possible interpretations of a 
 given expression; thinking of the set of interpretations of an expression as a 
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/CodeGen/CodeGenerator.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -307,10 +307,12 @@
 						} else {
 							// no address-of operator, so must be a pointer - add dereference
+							// NOTE: if the assertion starts to trigger, check that the application expr isn't being shared.
+							// Since its arguments are modified here, this assertion most commonly triggers when the application
+							// is visited multiple times.
 							UntypedExpr * newExpr = new UntypedExpr( new NameExpr( "*?" ) );
 							newExpr->get_args().push_back( *arg );
-							assert( (*arg)->get_results().size() == 1 );
-							Type * type = InitTweak::getPointerBase( (*arg)->get_results().front() );
-							assert( type );
-							newExpr->get_results().push_back( type->clone() );
+							Type * type = InitTweak::getPointerBase( (*arg)->get_result() );
+							assertf( type, "First argument to a derefence must be a pointer. Ensure that expressions are not being shared." );
+							newExpr->set_result( type->clone() );
 							*arg = newExpr;
 						} // if
@@ -527,10 +529,10 @@
 		extension( castExpr );
 		output << "(";
-		if ( castExpr->get_results().empty() ) {
+		if ( castExpr->get_result()->isVoid() ) {
 			output << "(void)" ;
-		} else if ( ! castExpr->get_results().front()->get_isLvalue() ) {
+		} else if ( ! castExpr->get_result()->get_isLvalue() ) {
 			// at least one result type of cast, but not an lvalue
 			output << "(";
-			output << genType( castExpr->get_results().front(), "" );
+			output << genType( castExpr->get_result(), "" );
 			output << ")";
 		} else {
@@ -640,5 +642,5 @@
 	}
 
-	void CodeGenerator::visit( TupleExpr * tupleExpr ) {}
+	void CodeGenerator::visit( TupleExpr * tupleExpr ) { assert( false ); }
 
 	void CodeGenerator::visit( TypeExpr * typeExpr ) {}
@@ -654,4 +656,39 @@
 		asmExpr->get_operand()->accept( *this );
 		output << " )";
+	}
+
+	void CodeGenerator::visit( CompoundLiteralExpr *compLitExpr ) {
+		assert( compLitExpr->get_type() && dynamic_cast< ListInit * > ( compLitExpr->get_initializer() ) );
+		output << "(" << genType( compLitExpr->get_type(), "" ) << ")";
+		compLitExpr->get_initializer()->accept( *this );
+	}
+
+	void CodeGenerator::visit( StmtExpr * stmtExpr ) {
+		std::list< Statement * > & stmts = stmtExpr->get_statements()->get_kids();
+		output << "({" << std::endl;
+		cur_indent += CodeGenerator::tabsize;
+		unsigned int numStmts = stmts.size();
+		unsigned int i = 0;
+		for ( Statement * stmt : stmts ) {
+			output << indent << printLabels( stmt->get_labels() );
+			if ( i+1 == numStmts ) {
+				// last statement in a statement expression needs to be handled specially -
+				// cannot cast to void, otherwise the expression statement has no value
+				if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( stmt ) ) {
+					exprStmt->get_expr()->accept( *this );
+					output << ";" << endl;
+					++i;
+					break;
+				}
+			}
+			stmt->accept( *this );
+			output << endl;
+			if ( wantSpacing( stmt ) ) {
+				output << endl;
+			} // if
+			++i;
+		}
+		cur_indent -= CodeGenerator::tabsize;
+		output << indent << "})";
 	}
 
Index: src/CodeGen/CodeGenerator.h
===================================================================
--- src/CodeGen/CodeGenerator.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/CodeGen/CodeGenerator.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -70,7 +70,9 @@
 		virtual void visit( ConditionalExpr *conditionalExpr );
 		virtual void visit( CommaExpr *commaExpr );
+		virtual void visit( CompoundLiteralExpr *compLitExpr );
 		virtual void visit( TupleExpr *tupleExpr );
 		virtual void visit( TypeExpr *typeExpr );
 		virtual void visit( AsmExpr * );
+		virtual void visit( StmtExpr * );
 
 		//*** Statements
Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/CodeGen/GenType.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -227,7 +227,4 @@
 			typeString = "_Atomic " + typeString;
 		} // if
-		if ( type->get_isAttribute() ) {
-			typeString = "__attribute(( )) " + typeString;
-		} // if
 	}
 } // namespace CodeGen
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Common/utility.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -148,4 +148,5 @@
 }
 
+// replace element of list with all elements of another list
 template< typename T >
 void replace( std::list< T > &org, typename std::list< T >::iterator pos, std::list< T > &with ) {
@@ -158,4 +159,11 @@
 
 	return;
+}
+
+// replace range of a list with a single element
+template< typename T >
+void replace( std::list< T > &org, typename std::list< T >::iterator begin, typename std::list< T >::iterator end, const T & with ) {
+	org.insert( begin, with );
+	org.erase( begin, end );
 }
 
Index: c/ControlStruct/LabelTypeChecker.cc
===================================================================
--- src/ControlStruct/LabelTypeChecker.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ 	(revision )
@@ -1,86 +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.
-//
-// LabelTypeChecker.cc --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Rob Schluntz
-// Last Modified On : Wed Jun 24 16:24:48 2015
-// Update Count     : 3
-//
-
-#include <list>
-#include <cassert>
-
-#include "SynTree/Type.h"
-#include "SynTree/Statement.h"
-#include "SynTree/Expression.h"
-#include "SynTree/Declaration.h"
-
-#include "LabelTypeChecker.h"
-
-namespace ControlStruct {
-	void LabelTypeChecker::visit(UntypedExpr *untypedExpr) {
-		assert( untypedExpr != 0 );
-		NameExpr *fname;
-		if ( ((fname = dynamic_cast<NameExpr *>(untypedExpr->get_function())) != 0)
-			 && fname->get_name() == std::string("&&") )
-			std::cerr << "Taking the label of an address." << std::endl;
-		else {
-			acceptAll( untypedExpr->get_results(), *this );
-			acceptAll( untypedExpr->get_args(), *this );
-		} // if
-		return;
-	}
-
-	void LabelTypeChecker::visit(CompoundStmt *compoundStmt) {
-		index.enterScope();
-		acceptAll( compoundStmt->get_kids(), *this );
-		index.leaveScope();
-	}
-
-	void LabelTypeChecker::visit(DeclStmt *declStmt) {
-		declStmt->accept( index );
-
-		//ObjectDecl *odecl = 0;
-		// if ( ( odecl = dynamic_cast<ObjectDecl *>(declStmt->get_decl()) ) != 0 ) {
-		return;
-	}
-
-	void LabelTypeChecker::visit(BranchStmt *branchStmt) {
-		if ( branchStmt->get_type() != BranchStmt::Goto ) return;
-		Expression *target;
-		if ( (target = branchStmt->get_computedTarget()) == 0 ) return;
-
-		NameExpr *name;
-		if ( (name = dynamic_cast<NameExpr *>(target)) == 0 )
-			return; // Not a name expression
-
-		std::list< DeclarationWithType * > interps;
-		index.lookupId(name->get_name(), interps);
-		if ( interps.size() != 1)
-			// in case of multiple declarations
-			throw SemanticError("Illegal label expression: " + name->get_name() );
-
-		PointerType *ptr;
-		if ( (ptr = dynamic_cast<PointerType *>(interps.front()->get_type())) != 0 )
-			if ( dynamic_cast<VoidType *>(ptr->get_base()) != 0 )
-				return;
-			else
-				throw SemanticError("Wrong type of parameter for computed goto");
-		else
-			throw SemanticError("Wrong type of parameter for computed goto");
-
-		return;
-	}
-} // namespace ControlStruct
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: c/ControlStruct/LabelTypeChecker.h
===================================================================
--- src/ControlStruct/LabelTypeChecker.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ 	(revision )
@@ -1,45 +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.
-//
-// LabelTypeChecker.h -- 
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jan 25 21:22:30 2016
-// Update Count     : 4
-//
-
-#ifndef LABEL_TYPE_H
-#define LABEL_TYPE_H
-
-#include "SynTree/Visitor.h"
-#include "SymTab/Indexer.h"
-#include "SynTree/Statement.h"
-
-#include "Common/utility.h"
-
-namespace ControlStruct {
-	class LabelTypeChecker : public Visitor {
-	  public:
-		//LabelTypeChecker() {
-
-		virtual void visit( CompoundStmt *compoundStmt );
-		virtual void visit( DeclStmt *declStmt );
-		virtual void visit( BranchStmt *branchStmt );
-		virtual void visit( UntypedExpr *untypedExpr );
-	  private:
-		SymTab::Indexer index;
-	};
-} // namespace ControlStruct
-
-#endif // LABEL_TYPE_H
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ControlStruct/Mutate.cc
===================================================================
--- src/ControlStruct/Mutate.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ControlStruct/Mutate.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -23,5 +23,4 @@
 #include "MLEMutator.h"
 #include "ForExprMutator.h"
-#include "LabelTypeChecker.h"
 //#include "ExceptMutator.h"
 
@@ -41,10 +40,8 @@
 
 		//ExceptMutator exc;
-		// LabelTypeChecker lbl;
 
 		mutateAll( translationUnit, formut );
 		acceptAll( translationUnit, lfix );
 		//mutateAll( translationUnit, exc );
-		//acceptAll( translationUnit, lbl );
 	}
 } // namespace CodeGen
Index: src/ControlStruct/module.mk
===================================================================
--- src/ControlStruct/module.mk	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ControlStruct/module.mk	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -6,5 +6,5 @@
 ## file "LICENCE" distributed with Cforall.
 ##
-## module.mk -- 
+## module.mk --
 ##
 ## Author           : Richard C. Bilson
@@ -19,5 +19,4 @@
         ControlStruct/MLEMutator.cc \
 	ControlStruct/Mutate.cc \
-	ControlStruct/ForExprMutator.cc \
-	ControlStruct/LabelTypeChecker.cc
+	ControlStruct/ForExprMutator.cc
 
Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/GenPoly/Box.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -113,5 +113,5 @@
 			void addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars );
 			/// Stores assignment operators from assertion list in local map of assignment operations
-			void findTypeOps( const std::list< TypeDecl *> &forall );
+			void findTypeOps( const Type::ForallList &forall );
 			void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars );
 			FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
@@ -619,8 +619,8 @@
 		}
 
-		void Pass1::findTypeOps( const std::list< TypeDecl *> &forall ) {
+		void Pass1::findTypeOps( const Type::ForallList &forall ) {
 			// what if a nested function uses an assignment operator?
 			// assignOps.clear();
-			for ( std::list< TypeDecl *>::const_iterator i = forall.begin(); i != forall.end(); ++i ) {
+			for ( Type::ForallList::const_iterator i = forall.begin(); i != forall.end(); ++i ) {
 				for ( std::list< DeclarationWithType *>::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
 					std::string typeName;
@@ -687,5 +687,5 @@
 				std::list< DeclarationWithType *> &paramList = functionType->get_parameters();
 				std::list< FunctionType *> functions;
-				for ( std::list< TypeDecl *>::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
+				for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
 					for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) {
 						findFunction( (*assert)->get_type(), functions, scopeTyVars, needsAdapter );
@@ -789,6 +789,6 @@
 
 			// add size/align for generic types to parameter list
-			if ( appExpr->get_function()->get_results().empty() ) return;
-			FunctionType *funcType = getFunctionType( appExpr->get_function()->get_results().front() );
+			if ( ! appExpr->get_function()->has_result() ) return;
+			FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result() );
 			assert( funcType );
 
@@ -806,6 +806,6 @@
 			for ( ; fnParm != funcType->get_parameters().end() && fnArg != appExpr->get_args().end(); ++fnParm, ++fnArg ) {
 				VariableExpr *fnArgBase = getBaseVar( *fnArg );
-				if ( ! fnArgBase || fnArgBase->get_results().empty() ) continue;
-				passArgTypeVars( appExpr, (*fnParm)->get_type(), fnArgBase->get_results().front(), arg, exprTyVars, seenTypes );
+				if ( ! fnArgBase ) continue; // xxx - previously had check for non-empty fnArgBase results
+				passArgTypeVars( appExpr, (*fnParm)->get_type(), fnArgBase->get_result(), arg, exprTyVars, seenTypes );
 			}
 		}
@@ -897,5 +897,5 @@
 			Type * adapteeType = new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
 			appExpr->get_args().push_front( new CastExpr( appExpr->get_function(), adapteeType ) );
-			appExpr->set_function( new NameExpr( adapterName ) );
+			appExpr->set_function( new NameExpr( adapterName ) ); // xxx - result is never set on NameExpr
 
 			return ret;
@@ -903,10 +903,10 @@
 
 		void Pass1::boxParam( Type *param, Expression *&arg, const TyVarMap &exprTyVars ) {
-			assert( ! arg->get_results().empty() );
+			assert( arg->has_result() );
 			if ( isPolyType( param, exprTyVars ) ) {
-				if ( isPolyType( arg->get_results().front() ) ) {
+				if ( isPolyType( arg->get_result() ) ) {
 					// if the argument's type is polymorphic, we don't need to box again!
 					return;
-				} else if ( arg->get_results().front()->get_isLvalue() ) {
+				} else if ( arg->get_result()->get_isLvalue() ) {
 					// VariableExpr and MemberExpr are lvalues; need to check this isn't coming from the second arg of a comma expression though (not an lvalue)
 					// xxx - need to test that this code is still reachable
@@ -953,5 +953,5 @@
 		void Pass1::addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) {
 			std::list< Expression *>::iterator cur = arg;
-			for ( std::list< TypeDecl *>::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
+			for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
 				for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) {
 					InferredParams::const_iterator inferParam = appExpr->get_inferParams().find( (*assert)->get_uniqueId() );
@@ -994,5 +994,5 @@
 					UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
 					deref->get_args().push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) );
-					deref->get_results().push_back( arg->get_type()->clone() );
+					deref->set_result( arg->get_type()->clone() );
 					return deref;
 				} // if
@@ -1020,7 +1020,7 @@
 			Statement *bodyStmt;
 
-			std::list< TypeDecl *>::iterator tyArg = realType->get_forall().begin();
-			std::list< TypeDecl *>::iterator tyParam = adapterType->get_forall().begin();
-			std::list< TypeDecl *>::iterator realTyParam = adaptee->get_forall().begin();
+			Type::ForallList::iterator tyArg = realType->get_forall().begin();
+			Type::ForallList::iterator tyParam = adapterType->get_forall().begin();
+			Type::ForallList::iterator realTyParam = adaptee->get_forall().begin();
 			for ( ; tyParam != adapterType->get_forall().end(); ++tyArg, ++tyParam, ++realTyParam ) {
 				assert( tyArg != realType->get_forall().end() );
@@ -1071,5 +1071,5 @@
 			std::list< DeclarationWithType *> &paramList = functionType->get_parameters();
 			std::list< FunctionType *> functions;
-			for ( std::list< TypeDecl *>::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
+			for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
 				for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) {
 					findFunction( (*assert)->get_type(), functions, exprTyVars, needsAdapter );
@@ -1131,5 +1131,5 @@
 			} // if
 			addAssign->get_args().push_back( new NameExpr( sizeofName( mangleType( polyType ) ) ) );
-			addAssign->get_results().front() = appExpr->get_results().front()->clone();
+			addAssign->set_result( appExpr->get_result()->clone() );
 			if ( appExpr->get_env() ) {
 				addAssign->set_env( appExpr->get_env() );
@@ -1145,8 +1145,8 @@
 				if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic ) {
 					if ( varExpr->get_var()->get_name() == "?[?]" ) {
-						assert( ! appExpr->get_results().empty() );
+						assert( appExpr->has_result() );
 						assert( appExpr->get_args().size() == 2 );
-						Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_results().front(), scopeTyVars, env );
-						Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_results().front(), scopeTyVars, env );
+						Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_result(), scopeTyVars, env );
+						Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_result(), scopeTyVars, env );
 						assert( ! baseType1 || ! baseType2 ); // the arguments cannot both be polymorphic pointers
 						UntypedExpr *ret = 0;
@@ -1168,5 +1168,5 @@
 						} // if
 						if ( baseType1 || baseType2 ) {
-							ret->get_results().push_front( appExpr->get_results().front()->clone() );
+							ret->set_result( appExpr->get_result()->clone() );
 							if ( appExpr->get_env() ) {
 								ret->set_env( appExpr->get_env() );
@@ -1178,10 +1178,10 @@
 						} // if
 					} else if ( varExpr->get_var()->get_name() == "*?" ) {
-						assert( ! appExpr->get_results().empty() );
+						assert( appExpr->has_result() );
 						assert( ! appExpr->get_args().empty() );
-						if ( isPolyType( appExpr->get_results().front(), scopeTyVars, env ) ) {
+						if ( isPolyType( appExpr->get_result(), scopeTyVars, env ) ) {
 							Expression *ret = appExpr->get_args().front();
-							delete ret->get_results().front();
-							ret->get_results().front() = appExpr->get_results().front()->clone();
+							delete ret->get_result();
+							ret->set_result( appExpr->get_result()->clone() );
 							if ( appExpr->get_env() ) {
 								ret->set_env( appExpr->get_env() );
@@ -1193,8 +1193,8 @@
 						} // if
 					} else if ( varExpr->get_var()->get_name() == "?++" || varExpr->get_var()->get_name() == "?--" ) {
-						assert( ! appExpr->get_results().empty() );
+						assert( appExpr->has_result() );
 						assert( appExpr->get_args().size() == 1 );
-						if ( Type *baseType = isPolyPtr( appExpr->get_results().front(), scopeTyVars, env ) ) {
-							Type *tempType = appExpr->get_results().front()->clone();
+						if ( Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env ) ) {
+							Type *tempType = appExpr->get_result()->clone();
 							if ( env ) {
 								env->apply( tempType );
@@ -1213,19 +1213,19 @@
 						} // if
 					} else if ( varExpr->get_var()->get_name() == "++?" || varExpr->get_var()->get_name() == "--?" ) {
-						assert( ! appExpr->get_results().empty() );
+						assert( appExpr->has_result() );
 						assert( appExpr->get_args().size() == 1 );
-						if ( Type *baseType = isPolyPtr( appExpr->get_results().front(), scopeTyVars, env ) ) {
+						if ( Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env ) ) {
 							return makeIncrDecrExpr( appExpr, baseType, varExpr->get_var()->get_name() == "++?" );
 						} // if
 					} else if ( varExpr->get_var()->get_name() == "?+?" || varExpr->get_var()->get_name() == "?-?" ) {
-						assert( ! appExpr->get_results().empty() );
+						assert( appExpr->has_result() );
 						assert( appExpr->get_args().size() == 2 );
-						Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_results().front(), scopeTyVars, env );
-						Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_results().front(), scopeTyVars, env );
+						Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_result(), scopeTyVars, env );
+						Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_result(), scopeTyVars, env );
 						if ( baseType1 && baseType2 ) {
 							UntypedExpr *divide = new UntypedExpr( new NameExpr( "?/?" ) );
 							divide->get_args().push_back( appExpr );
 							divide->get_args().push_back( new SizeofExpr( baseType1->clone() ) );
-							divide->get_results().push_front( appExpr->get_results().front()->clone() );
+							divide->set_result( appExpr->get_result()->clone() );
 							if ( appExpr->get_env() ) {
 								divide->set_env( appExpr->get_env() );
@@ -1245,7 +1245,7 @@
 						} // if
 					} else if ( varExpr->get_var()->get_name() == "?+=?" || varExpr->get_var()->get_name() == "?-=?" ) {
-						assert( ! appExpr->get_results().empty() );
+						assert( appExpr->has_result() );
 						assert( appExpr->get_args().size() == 2 );
-						Type *baseType = isPolyPtr( appExpr->get_results().front(), scopeTyVars, env );
+						Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env );
 						if ( baseType ) {
 							UntypedExpr *multiply = new UntypedExpr( new NameExpr( "?*?" ) );
@@ -1273,9 +1273,7 @@
 			useRetval = oldUseRetval;
 
-			assert( ! appExpr->get_function()->get_results().empty() );
-			PointerType *pointer = dynamic_cast< PointerType *>( appExpr->get_function()->get_results().front() );
-			assert( pointer );
-			FunctionType *function = dynamic_cast< FunctionType *>( pointer->get_base() );
-			assert( function );
+			assert( appExpr->get_function()->has_result() );
+			PointerType *pointer = safe_dynamic_cast< PointerType *>( appExpr->get_function()->get_result() );
+			FunctionType *function = safe_dynamic_cast< FunctionType *>( pointer->get_base() );
 
 			if ( Expression *newExpr = handleIntrinsics( appExpr ) ) {
@@ -1315,5 +1313,5 @@
 
 		Expression *Pass1::mutate( UntypedExpr *expr ) {
-			if ( ! expr->get_results().empty() && isPolyType( expr->get_results().front(), scopeTyVars, env ) ) {
+			if ( expr->has_result() && isPolyType( expr->get_result(), scopeTyVars, env ) ) {
 				if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) {
 					if ( name->get_name() == "*?" ) {
@@ -1329,17 +1327,15 @@
 
 		Expression *Pass1::mutate( AddressExpr *addrExpr ) {
-			assert( ! addrExpr->get_arg()->get_results().empty() );
+			assert( addrExpr->get_arg()->has_result() && ! addrExpr->get_arg()->get_result()->isVoid() );
 
 			bool needs = false;
 			if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->get_arg() ) ) {
-				if ( ! expr->get_results().empty() && isPolyType( expr->get_results().front(), scopeTyVars, env ) ) {
+				if ( expr->has_result() && isPolyType( expr->get_result(), scopeTyVars, env ) ) {
 					if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) {
 						if ( name->get_name() == "*?" ) {
 							if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->get_args().front() ) ) {
-								assert( ! appExpr->get_function()->get_results().empty() );
-								PointerType *pointer = dynamic_cast< PointerType *>( appExpr->get_function()->get_results().front() );
-								assert( pointer );
-								FunctionType *function = dynamic_cast< FunctionType *>( pointer->get_base() );
-								assert( function );
+								assert( appExpr->get_function()->has_result() );
+								PointerType *pointer = safe_dynamic_cast< PointerType *>( appExpr->get_function()->get_result() );
+								FunctionType *function = safe_dynamic_cast< FunctionType *>( pointer->get_base() );
 								needs = needsAdapter( function, scopeTyVars );
 							} // if
@@ -1350,10 +1346,10 @@
 			// isPolyType check needs to happen before mutating addrExpr arg, so pull it forward
 			// out of the if condition.
-			bool polytype = isPolyType( addrExpr->get_arg()->get_results().front(), scopeTyVars, env );
+			bool polytype = isPolyType( addrExpr->get_arg()->get_result(), scopeTyVars, env );
 			addrExpr->set_arg( mutateExpression( addrExpr->get_arg() ) );
 			if ( polytype || needs ) {
 				Expression *ret = addrExpr->get_arg();
-				delete ret->get_results().front();
-				ret->get_results().front() = addrExpr->get_results().front()->clone();
+				delete ret->get_result();
+				ret->set_result( addrExpr->get_result()->clone() );
 				addrExpr->set_arg( 0 );
 				delete addrExpr;
@@ -1393,5 +1389,5 @@
 		Statement * Pass1::mutate( ReturnStmt *returnStmt ) {
 			if ( retval && returnStmt->get_expr() ) {
-				assert( ! returnStmt->get_expr()->get_results().empty() );
+				assert( returnStmt->get_expr()->has_result() && ! returnStmt->get_expr()->get_result()->isVoid() );
 				// ***** Code Removal ***** After introducing a temporary variable for all return expressions, the following code appears superfluous.
 				// if ( returnStmt->get_expr()->get_results().front()->get_isLvalue() ) {
@@ -1427,7 +1423,7 @@
 					// find each of its needed secondary assignment operators
 					std::list< Expression* > &tyParams = refType->get_parameters();
-					std::list< TypeDecl* > &forallParams = functionDecl->get_type()->get_forall();
+					Type::ForallList &forallParams = functionDecl->get_type()->get_forall();
 					std::list< Expression* >::const_iterator tyIt = tyParams.begin();
-					std::list< TypeDecl* >::const_iterator forallIt = forallParams.begin();
+					Type::ForallList::const_iterator forallIt = forallParams.begin();
 					for ( ; tyIt != tyParams.end() && forallIt != forallParams.end(); ++tyIt, ++forallIt ) {
 						// Add appropriate mapping to assignment expression environment
@@ -1473,5 +1469,5 @@
 				// replace return statement with appropriate assignment to out parameter
 				Expression *retParm = new NameExpr( retval->get_name() );
-				retParm->get_results().push_back( new PointerType( Type::Qualifiers(), retval->get_type()->clone() ) );
+				retParm->set_result( new PointerType( Type::Qualifiers(), retval->get_type()->clone() ) );
 				assignExpr->get_args().push_back( retParm );
 				assignExpr->get_args().push_back( returnStmt->get_expr() );
@@ -1603,5 +1599,5 @@
 			ObjectDecl newPtr( "", DeclarationNode::NoStorageClass, LinkageSpec::C, 0,
 			                   new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 );
-			for ( std::list< TypeDecl *>::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {
+			for ( Type::ForallList::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {
 				ObjectDecl *sizeParm, *alignParm;
 				// add all size and alignment parameters to parameter list
Index: src/GenPoly/CopyParams.cc
===================================================================
--- src/GenPoly/CopyParams.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/GenPoly/CopyParams.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -54,5 +54,5 @@
 				std::map< std::string, DeclarationWithType* > assignOps;
 				// assume the assignment operator is the first assert param after any "type" parameter
-				for ( std::list< TypeDecl* >::const_iterator tyVar = funcDecl->get_functionType()->get_forall().begin(); tyVar != funcDecl->get_functionType()->get_forall().end(); ++tyVar ) {
+				for ( Type::ForallList::const_iterator tyVar = funcDecl->get_functionType()->get_forall().begin(); tyVar != funcDecl->get_functionType()->get_forall().end(); ++tyVar ) {
 					if ( (*tyVar)->get_kind() == TypeDecl::Any ) {
 						assert( !(*tyVar)->get_assertions().empty() );
Index: src/GenPoly/FindFunction.cc
===================================================================
--- src/GenPoly/FindFunction.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/GenPoly/FindFunction.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -29,5 +29,5 @@
 		virtual Type *mutate( PointerType *pointerType );
 	  private:
-		void handleForall( const std::list< TypeDecl* > &forall );
+		void handleForall( const Type::ForallList &forall );
 
 		std::list< FunctionType* > &functions;
@@ -51,6 +51,6 @@
 	}
 
-	void FindFunction::handleForall( const std::list< TypeDecl* > &forall ) {
-		for ( std::list< TypeDecl* >::const_iterator i = forall.begin(); i != forall.end(); ++i ) {
+	void FindFunction::handleForall( const Type::ForallList &forall ) {
+		for ( Type::ForallList::const_iterator i = forall.begin(); i != forall.end(); ++i ) {
 			TyVarMap::iterator var = tyVars.find( (*i)->get_name() );
 			if ( var != tyVars.end() ) {
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/GenPoly/GenPoly.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -110,5 +110,5 @@
 	ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) {
 		if ( function->get_returnVals().empty() ) return 0;
-		
+
 		return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
 	}
@@ -127,5 +127,5 @@
 // 		} // if
 		if ( isDynRet( adaptee, tyVars ) ) return true;
-		
+
 		for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) {
 // 			if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) {
@@ -228,5 +228,5 @@
 
 	void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
-		for ( std::list< TypeDecl* >::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
+		for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
 			assert( *tyVar );
 			tyVarMap[ (*tyVar)->get_name() ] = (*tyVar)->get_kind();
Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/GenPoly/Lvalue.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Lvalue.cc -- 
+// Lvalue.cc --
 //
 // Author           : Richard C. Bilson
@@ -41,5 +41,5 @@
 		  public:
 			Pass1();
-  
+
 			virtual Expression *mutate( ApplicationExpr *appExpr );
 			virtual Statement *mutate( ReturnStmt *appExpr );
@@ -55,4 +55,13 @@
 		  private:
 		};
+
+		/// GCC-like Generalized Lvalues (which have since been removed from GCC)
+		/// https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html#Lvalues
+		/// Replaces &(a,b) with (a, &b), &(a ? b : c) with (a ? &b : &c)
+		class GeneralizedLvalue : public Mutator {
+			typedef Mutator Parent;
+
+			virtual Expression * mutate( AddressExpr * addressExpr );
+		};
 	} // namespace
 
@@ -60,6 +69,8 @@
 		Pass1 p1;
 		Pass2 p2;
+		GeneralizedLvalue genLval;
 		mutateAll( translationUnit, p1 );
 		acceptAll( translationUnit, p2 );
+		mutateAll( translationUnit, genLval );
 	}
 
@@ -99,16 +110,12 @@
 			appExpr->get_function()->acceptMutator( *this );
 			mutateAll( appExpr->get_args(), *this );
-  
-			assert( ! appExpr->get_function()->get_results().empty() );
 
-			PointerType *pointer = dynamic_cast< PointerType* >( appExpr->get_function()->get_results().front() );
-			assert( pointer );
-			FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() );
-			assert( function );
+			PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
+			FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
 
 			Type *funType = isLvalueRet( function );
 			if ( funType && ! isIntrinsicApp( appExpr ) ) {
 				Expression *expr = appExpr;
-				Type *appType = appExpr->get_results().front();
+				Type *appType = appExpr->get_result();
 				if ( isPolyType( funType ) && ! isPolyType( appType ) ) {
 					// make sure cast for polymorphic type is inside dereference
@@ -116,6 +123,6 @@
 				}
 				UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
-				deref->get_results().push_back( appType->clone() );
-				appExpr->get_results().front() = new PointerType( Type::Qualifiers(), appType );
+				deref->set_result( appType->clone() );
+				appExpr->set_result( new PointerType( Type::Qualifiers(), appType ) );
 				deref->get_args().push_back( expr );
 				return deref;
@@ -127,6 +134,5 @@
 		Statement * Pass1::mutate(ReturnStmt *retStmt) {
 			if ( retval && retStmt->get_expr() ) {
-				assert( ! retStmt->get_expr()->get_results().empty() );
-				if ( retStmt->get_expr()->get_results().front()->get_isLvalue() ) {
+				if ( retStmt->get_expr()->get_result()->get_isLvalue() ) {
 					// ***** Code Removal ***** because casts may be stripped already
 
@@ -155,6 +161,23 @@
 				retParm->set_type( new PointerType( Type::Qualifiers(), retParm->get_type() ) );
 			} // if
-  
+
 			Visitor::visit( funType );
+		}
+
+		Expression * GeneralizedLvalue::mutate( AddressExpr * addrExpr ) {
+			addrExpr = safe_dynamic_cast< AddressExpr * >( Parent::mutate( addrExpr ) );
+			if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( addrExpr->get_arg() ) ) {
+				Expression * arg1 = commaExpr->get_arg1()->clone();
+				Expression * arg2 = commaExpr->get_arg2()->clone();
+				delete addrExpr;
+				return new CommaExpr( arg1, new AddressExpr( arg2 ) );
+			} else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( addrExpr->get_arg() ) ) {
+				Expression * arg1 = condExpr->get_arg1()->clone();
+				Expression * arg2 = condExpr->get_arg2()->clone();
+				Expression * arg3 = condExpr->get_arg3()->clone();
+				delete addrExpr;
+				return new ConditionalExpr( arg1, new AddressExpr( arg2 ), new AddressExpr( arg3 ) );
+			}
+			return addrExpr;
 		}
 	} // namespace
Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/GenPoly/Specialize.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -148,6 +148,6 @@
 
 	Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
-		assert( ! actual->get_results().empty() ); // using front, should have this assert
-		if ( needsSpecialization( formalType, actual->get_results().front(), env ) ) {
+		assertf( actual->has_result(), "attempting to specialize an untyped expression" );
+		if ( needsSpecialization( formalType, actual->get_result(), env ) ) {
 			FunctionType *funType;
 			if ( ( funType = getFunctionType( formalType ) ) ) {
@@ -172,6 +172,6 @@
 	void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) {
 		// create thunks for the explicit parameters
-		assert( ! appExpr->get_function()->get_results().empty() );
-		FunctionType *function = getFunctionType( appExpr->get_function()->get_results().front() );
+		assert( appExpr->get_function()->has_result() );
+		FunctionType *function = getFunctionType( appExpr->get_function()->get_result() );
 		assert( function );
 		std::list< DeclarationWithType* >::iterator formal;
@@ -201,6 +201,6 @@
 	Expression * Specialize::mutate( AddressExpr *addrExpr ) {
 		addrExpr->get_arg()->acceptMutator( *this );
-		assert( ! addrExpr->get_results().empty() );
-		addrExpr->set_arg( doSpecialization( addrExpr->get_results().front(), addrExpr->get_arg() ) );
+		assert( addrExpr->has_result() );
+		addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
 		return addrExpr;
 	}
@@ -208,9 +208,9 @@
 	Expression * Specialize::mutate( CastExpr *castExpr ) {
 		castExpr->get_arg()->acceptMutator( *this );
-		if ( castExpr->get_results().empty() ) {
+		if ( castExpr->get_result()->isVoid() ) {
 			// can't specialize if we don't have a return value
 			return castExpr;
 		}
-		Expression *specialized = doSpecialization( castExpr->get_results().front(), castExpr->get_arg() );
+		Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() );
 		if ( specialized != castExpr->get_arg() ) {
 			// assume here that the specialization incorporates the cast
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/InitTweak/FixInit.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -18,4 +18,6 @@
 #include <iterator>
 #include <algorithm>
+#include <unordered_map>
+#include <unordered_set>
 #include "InitTweak.h"
 #include "FixInit.h"
@@ -35,10 +37,10 @@
 #include "GenPoly/DeclMutator.h"
 #include "SynTree/AddStmtVisitor.h"
-#include "CodeGen/GenType.h"  // for warnings
-
-bool ctordtorp = false;
-bool ctorp = false;
-bool cpctorp = false;
-bool dtorp = false;
+#include "CodeGen/GenType.h"  // for warning/error messages
+
+bool ctordtorp = false; // print all debug
+bool ctorp = false; // print ctor debug
+bool cpctorp = false; // print copy ctor debug
+bool dtorp = false; // print dtor debug
 #define PRINT( text ) if ( ctordtorp ) { text }
 #define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text }
@@ -47,7 +49,4 @@
 namespace InitTweak {
 	namespace {
-		const std::list<Label> noLabels;
-		const std::list<Expression*> noDesignators;
-
 		class InsertImplicitCalls final : public GenPoly::PolyMutator {
 		public:
@@ -67,11 +66,17 @@
 			static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
 
-			using SymTab::Indexer::visit;
+			typedef SymTab::Indexer Parent;
+			using Parent::visit;
+
 			virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ) override;
+			virtual void visit( UniqueExpr * unqExpr );
 
 			/// create and resolve ctor/dtor expression: fname(var, [cpArg])
-			ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL );
+			Expression * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL );
+			Expression * makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg = NULL );
 			/// true if type does not need to be copy constructed to ensure correctness
-			bool skipCopyConstruct( Type * );
+			bool skipCopyConstruct( Type * type );
+			void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr );
+			void destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
 		private:
 			TypeSubstitution * env;
@@ -183,4 +188,5 @@
 			using GenPoly::PolyMutator::mutate;
 			virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) override;
+			virtual Expression * mutate( UniqueExpr * unqExpr ) override;
 		};
 
@@ -368,8 +374,13 @@
 		}
 
-		ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) {
+		Expression * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) {
 			assert( var );
+			return makeCtorDtor( fname, new AddressExpr( new VariableExpr( var ) ), cpArg );
+		}
+
+		Expression * ResolveCopyCtors::makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg ) {
+			assert( thisArg );
 			UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) );
-			untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ) );
+			untyped->get_args().push_back( thisArg );
 			if (cpArg) untyped->get_args().push_back( cpArg->clone() );
 
@@ -378,20 +389,52 @@
 			// (VariableExpr and already resolved expression)
 			CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; )
-			ApplicationExpr * resolved = dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untyped, *this ) );
+			Expression * resolved = ResolvExpr::findVoidExpression( untyped, *this );
+			assert( resolved );
 			if ( resolved->get_env() ) {
 				env->add( *resolved->get_env() );
 			} // if
 
-			assert( resolved );
 			delete untyped;
 			return resolved;
 		}
 
+		void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr ) {
+			static UniqueName tempNamer("_tmp_cp");
+			CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; )
+			assert( arg->has_result() );
+			Type * result = arg->get_result();
+			if ( skipCopyConstruct( result ) ) return; // skip certain non-copyable types
+
+			// type may involve type variables, so apply type substitution to get temporary variable's actual type
+			result = result->clone();
+			impCpCtorExpr->get_env()->apply( result );
+			ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 );
+			tmp->get_type()->set_isConst( false );
+
+			// create and resolve copy constructor
+			CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
+			Expression * cpCtor = makeCtorDtor( "?{}", tmp, arg );
+
+			if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( cpCtor ) ) {
+				// if the chosen constructor is intrinsic, the copy is unnecessary, so
+				// don't create the temporary and don't call the copy constructor
+				VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() );
+				assert( function );
+				if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) return;
+			}
+
+			// replace argument to function call with temporary
+			arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
+			impCpCtorExpr->get_tempDecls().push_back( tmp );
+			impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) );
+		}
+
+		void ResolveCopyCtors::destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
+			impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", new AddressExpr( ret ) ) );
+		}
+
 		void ResolveCopyCtors::visit( ImplicitCopyCtorExpr *impCpCtorExpr ) {
-			static UniqueName tempNamer("_tmp_cp");
-			static UniqueName retNamer("_tmp_cp_ret");
-
 			CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
-			Visitor::visit( impCpCtorExpr );
+			Parent::visit( impCpCtorExpr );
 			env = impCpCtorExpr->get_env(); // xxx - maybe we really should just have a PolyIndexer...
 
@@ -400,29 +443,5 @@
 			// take each argument and attempt to copy construct it.
 			for ( Expression * & arg : appExpr->get_args() ) {
-				CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; )
-				// xxx - need to handle tuple arguments
-				assert( ! arg->get_results().empty() );
-				Type * result = arg->get_results().front();
-				if ( skipCopyConstruct( result ) ) continue; // skip certain non-copyable types
-				// type may involve type variables, so apply type substitution to get temporary variable's actual type
-				result = result->clone();
-				impCpCtorExpr->get_env()->apply( result );
-				ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 );
-				tmp->get_type()->set_isConst( false );
-
-				// create and resolve copy constructor
-				CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
-				ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg );
-
-				// if the chosen constructor is intrinsic, the copy is unnecessary, so
-				// don't create the temporary and don't call the copy constructor
-				VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() );
-				assert( function );
-				if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) {
-					// replace argument to function call with temporary
-					arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
-					impCpCtorExpr->get_tempDecls().push_back( tmp );
-					impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) );
-				} // if
+				copyConstructArg( arg, impCpCtorExpr );
 			} // for
 
@@ -434,5 +453,7 @@
 			// level. Trying to pass that environment along.
 			callExpr->set_env( impCpCtorExpr->get_env()->clone() );
-			for ( Type * result : appExpr->get_results() ) {
+			Type * result = appExpr->get_result();
+			if ( ! result->isVoid() ) {
+				static UniqueName retNamer("_tmp_cp_ret");
 				result = result->clone();
 				impCpCtorExpr->get_env()->apply( result );
@@ -441,7 +462,32 @@
 				impCpCtorExpr->get_returnDecls().push_back( ret );
 				CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
-				impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
+				if ( ! result->get_isLvalue() ) {
+					// destructing lvalue returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
+					destructRet( new VariableExpr( ret ), impCpCtorExpr );
+				}
 			} // for
 			CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
+		}
+
+		void ResolveCopyCtors::visit( UniqueExpr * unqExpr ) {
+			static std::unordered_set< int > vars;
+			if ( vars.count( unqExpr->get_id() ) ) {
+				// xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
+				return;
+			}
+
+			Parent::visit( unqExpr );
+			// it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
+			assert( unqExpr->get_result() );
+			if ( ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast<ImplicitCopyCtorExpr*>( unqExpr->get_expr() ) ) {
+				// note the variable used as the result from the call
+				assert( impCpCtorExpr->get_result() && impCpCtorExpr->get_returnDecls().size() == 1 );
+				unqExpr->set_var( new VariableExpr( impCpCtorExpr->get_returnDecls().front() ) );
+			} else {
+				// expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
+				unqExpr->set_object( new ObjectDecl( toString("_unq_expr_", unqExpr->get_id()), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, unqExpr->get_result()->clone(), nullptr ) );
+				unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) );
+			}
+			vars.insert( unqExpr->get_id() );
 		}
 
@@ -490,8 +536,8 @@
 				// know the result type of the assignment is the type of the LHS (minus the pointer), so
 				// add that onto the assignment expression so that later steps have the necessary information
-				assign->add_result( returnDecl->get_type()->clone() );
+				assign->set_result( returnDecl->get_type()->clone() );
 
 				Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) );
-				if ( callExpr->get_results().front()->get_isLvalue() ) {
+				if ( callExpr->get_result()->get_isLvalue() ) {
 					// lvalue returning functions are funny. Lvalue.cc inserts a *? in front of any lvalue returning
 					// non-intrinsic function. Add an AddressExpr to the call to negate the derefence and change the
@@ -500,17 +546,15 @@
 					// an AddressExpr.  Effectively, this turns
 					//   lvalue T f();
-					//   &*f()
+					//   &*f();
 					// into
+					//   T * f();
 					//   T * tmp_cp_retN;
-					//   tmp_cp_ret_N = &*(tmp_cp_ret_N = &*f(), tmp_cp_ret);
+					//   &*(tmp_cp_retN = &*f(), tmp_cp_retN);		// the first * and second & are generated here
 					// which work out in terms of types, but is pretty messy. It would be nice to find a better way.
 					assign->get_args().back() = new AddressExpr( assign->get_args().back() );
 
-					Type * resultType = returnDecl->get_type()->clone();
 					returnDecl->set_type( new PointerType( Type::Qualifiers(), returnDecl->get_type() ) );
-					UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) );
-					deref->get_args().push_back( retExpr );
-					deref->add_result( resultType );
-					retExpr = deref;
+					retExpr->set_result( new PointerType( Type::Qualifiers(), retExpr->get_result() ) );
+					retExpr = UntypedExpr::createDeref( retExpr );
 				} // if
 				retExpr->set_env( env->clone() );
@@ -519,4 +563,35 @@
 				return callExpr;
 			} // if
+		}
+
+		Expression * FixCopyCtors::mutate( UniqueExpr * unqExpr ) {
+			static std::unordered_map< int, UniqueExpr * > unqMap;
+			static std::unordered_set< int > addDeref;
+			// has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes
+			unqExpr = safe_dynamic_cast< UniqueExpr * >( Parent::mutate( unqExpr ) );
+			if ( unqMap.count( unqExpr->get_id() ) ) {
+				// take data from other UniqueExpr to ensure consistency
+				delete unqExpr->get_expr();
+				unqExpr->set_expr( unqMap[unqExpr->get_id()]->get_expr()->clone() );
+				delete unqExpr->get_result();
+				unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
+				if ( addDeref.count( unqExpr->get_id() ) ) {
+					// other UniqueExpr was dereferenced because it was an lvalue return, so this one should be too
+					return UntypedExpr::createDeref( unqExpr );
+				}
+				return unqExpr;
+			}
+			unqMap[unqExpr->get_id()] = unqExpr;
+			if ( UntypedExpr * deref = dynamic_cast< UntypedExpr * >( unqExpr->get_expr() ) ) {
+				// unique expression is now a dereference, because the inner expression is an lvalue returning function call.
+				// Normalize the expression by dereferencing the unique expression, rather than the inner expression
+				// (i.e. move the dereference out a level)
+				assert( getFunctionName( deref ) == "*?" );
+				unqExpr->set_expr( getCallArg( deref, 0 ) );
+				getCallArg( deref, 0 ) = unqExpr;
+				addDeref.insert( unqExpr->get_id() );
+				return deref;
+			}
+			return unqExpr;
 		}
 
@@ -950,6 +1025,7 @@
 		Expression * FixCtorExprs::mutate( ConstructorExpr * ctorExpr ) {
 			static UniqueName tempNamer( "_tmp_ctor_expr" );
-			assert( ctorExpr->get_results().size() == 1 );
-			ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, ctorExpr->get_results().front()->clone(), nullptr );
+			// xxx - is the size check necessary?
+			assert( ctorExpr->has_result() && ctorExpr->get_result()->size() == 1 );
+			ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, ctorExpr->get_result()->clone(), nullptr );
 			addDeclaration( tmp );
 
@@ -963,5 +1039,5 @@
 			assign->get_args().push_back( new VariableExpr( tmp ) );
 			assign->get_args().push_back( firstArg );
-			cloneAll( ctorExpr->get_results(), assign->get_results() );
+			assign->set_result( ctorExpr->get_result()->clone() );
 			firstArg = assign;
 
Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/InitTweak/GenInit.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -29,4 +29,5 @@
 #include "GenPoly/DeclMutator.h"
 #include "GenPoly/ScopedSet.h"
+#include "ResolvExpr/typeops.h"
 
 namespace InitTweak {
@@ -50,5 +51,5 @@
 
 	  protected:
-		std::list<DeclarationWithType*> returnVals;
+		FunctionType * ftype;
 		UniqueName tempNamer;
 		std::string funcName;
@@ -86,4 +87,5 @@
 
 		bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed
+		bool isManaged( Type * type ) const; // determine if type is managed
 		void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor
 		GenPoly::ScopedSet< std::string > managedTypes;
@@ -136,5 +138,5 @@
 
 	Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) {
-		// update for multiple return values
+		std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
 		assert( returnVals.size() == 0 || returnVals.size() == 1 );
 		// hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address
@@ -158,9 +160,24 @@
 
 	DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
-		ValueGuard< std::list<DeclarationWithType*> > oldReturnVals( returnVals );
+		// xxx - need to handle named return values - this pass may need to happen
+		// after resolution? the ordering is tricky because return statements must be
+		// constructed - the simplest way to do that (while also handling multiple
+		// returns) is to structure the returnVals into a tuple, as done here.
+		// however, if the tuple return value is structured before resolution,
+		// it's difficult to resolve named return values, since the name is lost
+		// in conversion to a tuple. this might be easiest to deal with
+		// after reference types are added, as it may then be possible to
+		// uniformly move named return values to the parameter list directly
+		ValueGuard< FunctionType * > oldFtype( ftype );
 		ValueGuard< std::string > oldFuncName( funcName );
 
-		FunctionType * type = functionDecl->get_functionType();
-		returnVals = type->get_returnVals();
+		ftype = functionDecl->get_functionType();
+		std::list< DeclarationWithType * > & retVals = ftype->get_returnVals();
+		if ( retVals.size() > 1 ) {
+			TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) );
+			ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) );
+			retVals.clear();
+			retVals.push_back( newRet );
+		}
 		funcName = functionDecl->get_name();
 		DeclarationWithType * decl = Mutator::mutate( functionDecl );
@@ -222,4 +239,14 @@
 	}
 
+	bool CtorDtor::isManaged( Type * type ) const {
+		if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
+			// tuple is also managed if any of its components are managed
+			if ( std::any_of( tupleType->get_types().begin(), tupleType->get_types().end(), [&](Type * type) { return isManaged( type ); }) ) {
+				return true;
+			}
+		}
+		return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
+	}
+
 	bool CtorDtor::isManaged( ObjectDecl * objDecl ) const {
 		Type * type = objDecl->get_type();
@@ -227,5 +254,5 @@
 			type = at->get_base();
 		}
-		return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
+		return isManaged( type );
 	}
 
@@ -238,4 +265,36 @@
 			managedTypes.insert( SymTab::Mangler::mangle( type->get_base() ) );
 		}
+	}
+
+	ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
+		// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
+		// for each constructable object
+		std::list< Statement * > ctor;
+		std::list< Statement * > dtor;
+
+		InitExpander srcParam( objDecl->get_init() );
+		InitExpander nullParam( (Initializer *)NULL );
+		SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
+		SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
+
+		// Currently genImplicitCall produces a single Statement - a CompoundStmt
+		// which  wraps everything that needs to happen. As such, it's technically
+		// possible to use a Statement ** in the above calls, but this is inherently
+		// unsafe, so instead we take the slightly less efficient route, but will be
+		// immediately informed if somehow the above assumption is broken. In this case,
+		// we could always wrap the list of statements at this point with a CompoundStmt,
+		// but it seems reasonable at the moment for this to be done by genImplicitCall
+		// itself. It is possible that genImplicitCall produces no statements (e.g. if
+		// an array type does not have a dimension). In this case, it's fine to ignore
+		// the object for the purposes of construction.
+		assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
+		if ( ctor.size() == 1 ) {
+			// need to remember init expression, in case no ctors exist
+			// if ctor does exist, want to use ctor expression instead of init
+			// push this decision to the resolver
+			assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
+			return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
+		}
+		return nullptr;
 	}
 
@@ -250,32 +309,5 @@
 			if ( ! checkInitDepth( objDecl ) ) throw SemanticError( "Managed object's initializer is too deep ", objDecl );
 
-			// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
-			// for each constructable object
-			std::list< Statement * > ctor;
-			std::list< Statement * > dtor;
-
-			InitExpander srcParam( objDecl->get_init() );
-			InitExpander nullParam( (Initializer *)NULL );
-			SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
-			SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
-
-			// Currently genImplicitCall produces a single Statement - a CompoundStmt
-			// which  wraps everything that needs to happen. As such, it's technically
-			// possible to use a Statement ** in the above calls, but this is inherently
-			// unsafe, so instead we take the slightly less efficient route, but will be
-			// immediately informed if somehow the above assumption is broken. In this case,
-			// we could always wrap the list of statements at this point with a CompoundStmt,
-			// but it seems reasonable at the moment for this to be done by genImplicitCall
-			// itself. It is possible that genImplicitCall produces no statements (e.g. if
-			// an array type does not have a dimension). In this case, it's fine to ignore
-			// the object for the purposes of construction.
-			assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
-			if ( ctor.size() == 1 ) {
-				// need to remember init expression, in case no ctors exist
-				// if ctor does exist, want to use ctor expression instead of init
-				// push this decision to the resolver
-				assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
-				objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
-			}
+			objDecl->set_init( genCtorInit( objDecl ) );
 		}
 		return Parent::mutate( objDecl );
@@ -290,5 +322,5 @@
 		managedTypes.beginScope();
 		// go through assertions and recursively add seen ctor/dtors
-		for ( TypeDecl * tyDecl : functionDecl->get_functionType()->get_forall() ) {
+		for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
 			for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
 				assertion = assertion->acceptMutator( *this );
Index: src/InitTweak/GenInit.h
===================================================================
--- src/InitTweak/GenInit.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/InitTweak/GenInit.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// RemoveInit.h --
+// GenInit.h --
 //
 // Author           : Rodolfo G. Esteves
@@ -27,4 +27,7 @@
 	/// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
 	void genInit( std::list< Declaration * > & translationUnit );
+
+	/// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
+	ConstructorInit * genCtorInit( ObjectDecl * objDecl );
 } // namespace
 
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/InitTweak/InitTweak.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -340,6 +340,5 @@
 		return allofCtorDtor( stmt, []( Expression * callExpr ){
 			if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
-				assert( ! appExpr->get_function()->get_results().empty() );
-				FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_results().front() );
+				FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_result() );
 				assert( funcType );
 				return funcType->get_parameters().size() == 1;
@@ -388,5 +387,5 @@
 				return memberExpr->get_member()->get_name();
 			} else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {
-				return memberExpr->get_member();
+				return funcName( memberExpr->get_member() );
 			} else {
 				assertf( false, "Unexpected expression type being called as a function in call expression" );
@@ -451,10 +450,10 @@
 		// virtual void visit( LogicalExpr *logicalExpr );
 		// virtual void visit( ConditionalExpr *conditionalExpr );
-		virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }
-		virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; }
 		virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; }
 		virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; }
 		virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; }
 		virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; }
+		virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }
+		virtual void visit( TupleAssignExpr *tupleExpr ) { isConstExpr = false; }
 
 		bool isConstExpr;
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Makefile.in	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -105,5 +105,4 @@
 	ControlStruct/driver_cfa_cpp-Mutate.$(OBJEXT) \
 	ControlStruct/driver_cfa_cpp-ForExprMutator.$(OBJEXT) \
-	ControlStruct/driver_cfa_cpp-LabelTypeChecker.$(OBJEXT) \
 	GenPoly/driver_cfa_cpp-Box.$(OBJEXT) \
 	GenPoly/driver_cfa_cpp-GenPoly.$(OBJEXT) \
@@ -190,6 +189,8 @@
 	SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT) \
 	SynTree/driver_cfa_cpp-Attribute.$(OBJEXT) \
+	SynTree/driver_cfa_cpp-VarExprReplacer.$(OBJEXT) \
 	Tuples/driver_cfa_cpp-TupleAssignment.$(OBJEXT) \
-	Tuples/driver_cfa_cpp-NameMatcher.$(OBJEXT)
+	Tuples/driver_cfa_cpp-TupleExpansion.$(OBJEXT) \
+	Tuples/driver_cfa_cpp-Explode.$(OBJEXT)
 am_driver_cfa_cpp_OBJECTS = $(am__objects_1)
 driver_cfa_cpp_OBJECTS = $(am_driver_cfa_cpp_OBJECTS)
@@ -364,6 +365,5 @@
 	ControlStruct/LabelGenerator.cc ControlStruct/LabelFixer.cc \
 	ControlStruct/MLEMutator.cc ControlStruct/Mutate.cc \
-	ControlStruct/ForExprMutator.cc \
-	ControlStruct/LabelTypeChecker.cc GenPoly/Box.cc \
+	ControlStruct/ForExprMutator.cc GenPoly/Box.cc \
 	GenPoly/GenPoly.cc GenPoly/PolyMutator.cc \
 	GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc GenPoly/Specialize.cc \
@@ -404,6 +404,7 @@
 	SynTree/Initializer.cc SynTree/Visitor.cc SynTree/Mutator.cc \
 	SynTree/AddStmtVisitor.cc SynTree/TypeSubstitution.cc \
-	SynTree/Attribute.cc Tuples/TupleAssignment.cc \
-	Tuples/NameMatcher.cc
+	SynTree/Attribute.cc SynTree/VarExprReplacer.cc \
+	Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
+	Tuples/Explode.cc
 MAINTAINERCLEANFILES = Parser/parser.output ${libdir}/${notdir \
 	${cfa_cpplib_PROGRAMS}}
@@ -541,7 +542,4 @@
 	ControlStruct/$(DEPDIR)/$(am__dirstamp)
 ControlStruct/driver_cfa_cpp-ForExprMutator.$(OBJEXT):  \
-	ControlStruct/$(am__dirstamp) \
-	ControlStruct/$(DEPDIR)/$(am__dirstamp)
-ControlStruct/driver_cfa_cpp-LabelTypeChecker.$(OBJEXT):  \
 	ControlStruct/$(am__dirstamp) \
 	ControlStruct/$(DEPDIR)/$(am__dirstamp)
@@ -769,4 +767,6 @@
 SynTree/driver_cfa_cpp-Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
 	SynTree/$(DEPDIR)/$(am__dirstamp)
+SynTree/driver_cfa_cpp-VarExprReplacer.$(OBJEXT):  \
+	SynTree/$(am__dirstamp) SynTree/$(DEPDIR)/$(am__dirstamp)
 Tuples/$(am__dirstamp):
 	@$(MKDIR_P) Tuples
@@ -777,5 +777,7 @@
 Tuples/driver_cfa_cpp-TupleAssignment.$(OBJEXT):  \
 	Tuples/$(am__dirstamp) Tuples/$(DEPDIR)/$(am__dirstamp)
-Tuples/driver_cfa_cpp-NameMatcher.$(OBJEXT): Tuples/$(am__dirstamp) \
+Tuples/driver_cfa_cpp-TupleExpansion.$(OBJEXT):  \
+	Tuples/$(am__dirstamp) Tuples/$(DEPDIR)/$(am__dirstamp)
+Tuples/driver_cfa_cpp-Explode.$(OBJEXT): Tuples/$(am__dirstamp) \
 	Tuples/$(DEPDIR)/$(am__dirstamp)
 driver/$(am__dirstamp):
@@ -800,5 +802,4 @@
 	-rm -f ControlStruct/driver_cfa_cpp-LabelFixer.$(OBJEXT)
 	-rm -f ControlStruct/driver_cfa_cpp-LabelGenerator.$(OBJEXT)
-	-rm -f ControlStruct/driver_cfa_cpp-LabelTypeChecker.$(OBJEXT)
 	-rm -f ControlStruct/driver_cfa_cpp-MLEMutator.$(OBJEXT)
 	-rm -f ControlStruct/driver_cfa_cpp-Mutate.$(OBJEXT)
@@ -884,9 +885,11 @@
 	-rm -f SynTree/driver_cfa_cpp-TypeofType.$(OBJEXT)
 	-rm -f SynTree/driver_cfa_cpp-VarArgsType.$(OBJEXT)
+	-rm -f SynTree/driver_cfa_cpp-VarExprReplacer.$(OBJEXT)
 	-rm -f SynTree/driver_cfa_cpp-Visitor.$(OBJEXT)
 	-rm -f SynTree/driver_cfa_cpp-VoidType.$(OBJEXT)
 	-rm -f SynTree/driver_cfa_cpp-ZeroOneType.$(OBJEXT)
-	-rm -f Tuples/driver_cfa_cpp-NameMatcher.$(OBJEXT)
+	-rm -f Tuples/driver_cfa_cpp-Explode.$(OBJEXT)
 	-rm -f Tuples/driver_cfa_cpp-TupleAssignment.$(OBJEXT)
+	-rm -f Tuples/driver_cfa_cpp-TupleExpansion.$(OBJEXT)
 
 distclean-compile:
@@ -907,5 +910,4 @@
 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelFixer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelGenerator.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-MLEMutator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-Mutate.Po@am__quote@
@@ -991,9 +993,11 @@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-TypeofType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VarArgsType.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VoidType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-ZeroOneType.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp-TupleAssignment.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Po@am__quote@
 
 .cc.o:
@@ -1237,18 +1241,4 @@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ControlStruct/driver_cfa_cpp-ForExprMutator.obj `if test -f 'ControlStruct/ForExprMutator.cc'; then $(CYGPATH_W) 'ControlStruct/ForExprMutator.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/ForExprMutator.cc'; fi`
 
-ControlStruct/driver_cfa_cpp-LabelTypeChecker.o: ControlStruct/LabelTypeChecker.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ControlStruct/driver_cfa_cpp-LabelTypeChecker.o -MD -MP -MF ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.o `test -f 'ControlStruct/LabelTypeChecker.cc' || echo '$(srcdir)/'`ControlStruct/LabelTypeChecker.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='ControlStruct/LabelTypeChecker.cc' object='ControlStruct/driver_cfa_cpp-LabelTypeChecker.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.o `test -f 'ControlStruct/LabelTypeChecker.cc' || echo '$(srcdir)/'`ControlStruct/LabelTypeChecker.cc
-
-ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj: ControlStruct/LabelTypeChecker.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj -MD -MP -MF ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj `if test -f 'ControlStruct/LabelTypeChecker.cc'; then $(CYGPATH_W) 'ControlStruct/LabelTypeChecker.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/LabelTypeChecker.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='ControlStruct/LabelTypeChecker.cc' object='ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj `if test -f 'ControlStruct/LabelTypeChecker.cc'; then $(CYGPATH_W) 'ControlStruct/LabelTypeChecker.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/LabelTypeChecker.cc'; fi`
-
 GenPoly/driver_cfa_cpp-Box.o: GenPoly/Box.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT GenPoly/driver_cfa_cpp-Box.o -MD -MP -MF GenPoly/$(DEPDIR)/driver_cfa_cpp-Box.Tpo -c -o GenPoly/driver_cfa_cpp-Box.o `test -f 'GenPoly/Box.cc' || echo '$(srcdir)/'`GenPoly/Box.cc
@@ -2427,4 +2417,18 @@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Attribute.obj `if test -f 'SynTree/Attribute.cc'; then $(CYGPATH_W) 'SynTree/Attribute.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Attribute.cc'; fi`
 
+SynTree/driver_cfa_cpp-VarExprReplacer.o: SynTree/VarExprReplacer.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-VarExprReplacer.o -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo -c -o SynTree/driver_cfa_cpp-VarExprReplacer.o `test -f 'SynTree/VarExprReplacer.cc' || echo '$(srcdir)/'`SynTree/VarExprReplacer.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='SynTree/VarExprReplacer.cc' object='SynTree/driver_cfa_cpp-VarExprReplacer.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-VarExprReplacer.o `test -f 'SynTree/VarExprReplacer.cc' || echo '$(srcdir)/'`SynTree/VarExprReplacer.cc
+
+SynTree/driver_cfa_cpp-VarExprReplacer.obj: SynTree/VarExprReplacer.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-VarExprReplacer.obj -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo -c -o SynTree/driver_cfa_cpp-VarExprReplacer.obj `if test -f 'SynTree/VarExprReplacer.cc'; then $(CYGPATH_W) 'SynTree/VarExprReplacer.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/VarExprReplacer.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='SynTree/VarExprReplacer.cc' object='SynTree/driver_cfa_cpp-VarExprReplacer.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-VarExprReplacer.obj `if test -f 'SynTree/VarExprReplacer.cc'; then $(CYGPATH_W) 'SynTree/VarExprReplacer.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/VarExprReplacer.cc'; fi`
+
 Tuples/driver_cfa_cpp-TupleAssignment.o: Tuples/TupleAssignment.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-TupleAssignment.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-TupleAssignment.Tpo -c -o Tuples/driver_cfa_cpp-TupleAssignment.o `test -f 'Tuples/TupleAssignment.cc' || echo '$(srcdir)/'`Tuples/TupleAssignment.cc
@@ -2441,17 +2445,31 @@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-TupleAssignment.obj `if test -f 'Tuples/TupleAssignment.cc'; then $(CYGPATH_W) 'Tuples/TupleAssignment.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/TupleAssignment.cc'; fi`
 
-Tuples/driver_cfa_cpp-NameMatcher.o: Tuples/NameMatcher.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-NameMatcher.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo -c -o Tuples/driver_cfa_cpp-NameMatcher.o `test -f 'Tuples/NameMatcher.cc' || echo '$(srcdir)/'`Tuples/NameMatcher.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='Tuples/NameMatcher.cc' object='Tuples/driver_cfa_cpp-NameMatcher.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-NameMatcher.o `test -f 'Tuples/NameMatcher.cc' || echo '$(srcdir)/'`Tuples/NameMatcher.cc
-
-Tuples/driver_cfa_cpp-NameMatcher.obj: Tuples/NameMatcher.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-NameMatcher.obj -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo -c -o Tuples/driver_cfa_cpp-NameMatcher.obj `if test -f 'Tuples/NameMatcher.cc'; then $(CYGPATH_W) 'Tuples/NameMatcher.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/NameMatcher.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='Tuples/NameMatcher.cc' object='Tuples/driver_cfa_cpp-NameMatcher.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-NameMatcher.obj `if test -f 'Tuples/NameMatcher.cc'; then $(CYGPATH_W) 'Tuples/NameMatcher.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/NameMatcher.cc'; fi`
+Tuples/driver_cfa_cpp-TupleExpansion.o: Tuples/TupleExpansion.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-TupleExpansion.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo -c -o Tuples/driver_cfa_cpp-TupleExpansion.o `test -f 'Tuples/TupleExpansion.cc' || echo '$(srcdir)/'`Tuples/TupleExpansion.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='Tuples/TupleExpansion.cc' object='Tuples/driver_cfa_cpp-TupleExpansion.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-TupleExpansion.o `test -f 'Tuples/TupleExpansion.cc' || echo '$(srcdir)/'`Tuples/TupleExpansion.cc
+
+Tuples/driver_cfa_cpp-TupleExpansion.obj: Tuples/TupleExpansion.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-TupleExpansion.obj -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo -c -o Tuples/driver_cfa_cpp-TupleExpansion.obj `if test -f 'Tuples/TupleExpansion.cc'; then $(CYGPATH_W) 'Tuples/TupleExpansion.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/TupleExpansion.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='Tuples/TupleExpansion.cc' object='Tuples/driver_cfa_cpp-TupleExpansion.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-TupleExpansion.obj `if test -f 'Tuples/TupleExpansion.cc'; then $(CYGPATH_W) 'Tuples/TupleExpansion.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/TupleExpansion.cc'; fi`
+
+Tuples/driver_cfa_cpp-Explode.o: Tuples/Explode.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-Explode.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo -c -o Tuples/driver_cfa_cpp-Explode.o `test -f 'Tuples/Explode.cc' || echo '$(srcdir)/'`Tuples/Explode.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='Tuples/Explode.cc' object='Tuples/driver_cfa_cpp-Explode.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-Explode.o `test -f 'Tuples/Explode.cc' || echo '$(srcdir)/'`Tuples/Explode.cc
+
+Tuples/driver_cfa_cpp-Explode.obj: Tuples/Explode.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-Explode.obj -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo -c -o Tuples/driver_cfa_cpp-Explode.obj `if test -f 'Tuples/Explode.cc'; then $(CYGPATH_W) 'Tuples/Explode.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/Explode.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='Tuples/Explode.cc' object='Tuples/driver_cfa_cpp-Explode.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-Explode.obj `if test -f 'Tuples/Explode.cc'; then $(CYGPATH_W) 'Tuples/Explode.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/Explode.cc'; fi`
 
 .ll.cc:
Index: src/Parser/ExpressionNode.cc
===================================================================
--- src/Parser/ExpressionNode.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Parser/ExpressionNode.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -172,4 +172,47 @@
 } // build_constantStr
 
+Expression * build_field_name_FLOATINGconstant( const std::string & str ) {
+	// str is of the form A.B -> separate at the . and return member expression
+	int a, b;
+	char dot;
+	std::stringstream ss( str );
+	ss >> a >> dot >> b;
+	UntypedMemberExpr * ret = new UntypedMemberExpr(
+		new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( b ) ) ),
+		new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( a ) ) ) );
+	delete &str;
+	return ret;
+} // build_field_name_FLOATINGconstant
+
+Expression * make_field_name_fraction_constants( Expression * fieldName, Expression * fracts ) {
+	if ( fracts ) {
+		if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( fracts ) ) {
+			memberExpr->set_member( make_field_name_fraction_constants( fieldName, memberExpr->get_aggregate() ) );
+			return memberExpr;
+		} else {
+			return new UntypedMemberExpr( fracts, fieldName );
+		}
+	}
+	return fieldName;
+} // make_field_name_fraction_constants
+
+Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ) {
+	return make_field_name_fraction_constants( fieldName, maybeMoveBuild< Expression >( fracts ) );
+} // build_field_name_fraction_constants
+
+Expression * build_field_name_REALFRACTIONconstant( const std::string & str ) {
+	assert( str[0] == '.' );
+	Expression * ret = build_constantInteger( *new std::string( str.substr(1) ) );
+	delete &str;
+	return ret;
+} // build_field_name_REALFRACTIONconstant
+
+Expression * build_field_name_REALDECIMALconstant( const std::string & str ) {
+	assert( str[str.size()-1] == '.' );
+	Expression * ret = build_constantInteger( *new std::string( str.substr( 0, str.size()-1 ) ) );
+	delete &str;
+	return ret;
+} // build_field_name_REALDECIMALconstant
+
 NameExpr * build_varref( const string *name, bool labelp ) {
 	NameExpr *expr = new NameExpr( *name, nullptr );
@@ -198,15 +241,13 @@
 }
 
-Expression *build_fieldSel( ExpressionNode *expr_node, NameExpr *member ) {
-	UntypedMemberExpr *ret = new UntypedMemberExpr( member->get_name(), maybeMoveBuild< Expression >(expr_node) );
-	delete member;
-	return ret;
-}
-
-Expression *build_pfieldSel( ExpressionNode *expr_node, NameExpr *member ) {
+Expression *build_fieldSel( ExpressionNode *expr_node, Expression *member ) {
+	UntypedMemberExpr *ret = new UntypedMemberExpr( member, maybeMoveBuild< Expression >(expr_node) );
+	return ret;
+}
+
+Expression *build_pfieldSel( ExpressionNode *expr_node, Expression *member ) {
 	UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
 	deref->get_args().push_back( maybeMoveBuild< Expression >(expr_node) );
-	UntypedMemberExpr *ret = new UntypedMemberExpr( member->get_name(), deref );
-	delete member;
+	UntypedMemberExpr *ret = new UntypedMemberExpr( member, deref );
 	return ret;
 }
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Parser/ParseNode.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -155,4 +155,8 @@
 Expression * build_constantChar( const std::string &str );
 ConstantExpr * build_constantStr( const std::string &str );
+Expression * build_field_name_FLOATINGconstant( const std::string & str );
+Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts );
+Expression * build_field_name_REALFRACTIONconstant( const std::string & str );
+Expression * build_field_name_REALDECIMALconstant( const std::string & str );
 
 NameExpr * build_varref( const std::string * name, bool labelp = false );
@@ -160,6 +164,6 @@
 
 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
-Expression * build_fieldSel( ExpressionNode * expr_node, NameExpr * member );
-Expression * build_pfieldSel( ExpressionNode * expr_node, NameExpr * member );
+Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member );
+Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member );
 Expression * build_addressOf( ExpressionNode * expr_node );
 Expression * build_sizeOfexpr( ExpressionNode * expr_node );
@@ -383,8 +387,8 @@
 //##############################################################################
 
-template< typename SynTreeType, typename NodeType >
-void buildList( const NodeType * firstNode, std::list< SynTreeType * > &outputList ) {
+template< typename SynTreeType, typename NodeType, template< typename, typename...> class Container, typename... Args >
+void buildList( const NodeType * firstNode, Container< SynTreeType *, Args... > &outputList ) {
 	SemanticError errors;
-	std::back_insert_iterator< std::list< SynTreeType * > > out( outputList );
+	std::back_insert_iterator< Container< SynTreeType *, Args... > > out( outputList );
 	const NodeType * cur = firstNode;
 
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Parser/TypeData.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -385,31 +385,33 @@
 } // TypeData::print
 
-void buildForall( const DeclarationNode * firstNode, list< TypeDecl* > &outputList ) {
+template< typename ForallList >
+void buildForall( const DeclarationNode * firstNode, ForallList &outputList ) {
 	buildList( firstNode, outputList );
-	for ( list< TypeDecl* >::iterator i = outputList.begin(); i != outputList.end(); ++i ) {
-		if ( (*i)->get_kind() == TypeDecl::Any ) {
+	for ( typename ForallList::iterator i = outputList.begin(); i != outputList.end(); ++i ) {
+		TypeDecl * td = static_cast<TypeDecl*>(*i);
+		if ( td->get_kind() == TypeDecl::Any ) {
 			// add assertion parameters to `type' tyvars in reverse order
 			// add dtor:  void ^?{}(T *)
 			FunctionType * dtorType = new FunctionType( Type::Qualifiers(), false );
-			dtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );
-			(*i)->get_assertions().push_front( new FunctionDecl( "^?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, dtorType, nullptr, false, false ) );
+			dtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
+			td->get_assertions().push_front( new FunctionDecl( "^?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, dtorType, nullptr, false, false ) );
 
 			// add copy ctor:  void ?{}(T *, T)
 			FunctionType * copyCtorType = new FunctionType( Type::Qualifiers(), false );
-			copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );
-			copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), nullptr ) );
-			(*i)->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, copyCtorType, nullptr, false, false ) );
+			copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
+			copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
+			td->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, copyCtorType, nullptr, false, false ) );
 
 			// add default ctor:  void ?{}(T *)
 			FunctionType * ctorType = new FunctionType( Type::Qualifiers(), false );
-			ctorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );
-			(*i)->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, ctorType, nullptr, false, false ) );
+			ctorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
+			td->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, ctorType, nullptr, false, false ) );
 
 			// add assignment operator:  T * ?=?(T *, T)
 			FunctionType * assignType = new FunctionType( Type::Qualifiers(), false );
-			assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );
-			assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), nullptr ) );
-			assignType->get_returnVals().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), nullptr ) );
-			(*i)->get_assertions().push_front( new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, assignType, nullptr, false, false ) );
+			assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
+			assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
+			assignType->get_returnVals().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
+			td->get_assertions().push_front( new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, assignType, nullptr, false, false ) );
 		} // if
 	} // for
@@ -515,5 +517,5 @@
 		// character types. The implementation shall define char to have the same range, representation, and behavior as
 		// either signed char or unsigned char.
-		static BasicType::Kind chartype[] = { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::Char }; 
+		static BasicType::Kind chartype[] = { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::Char };
 
 		if ( td->length != DeclarationNode::NoLength ) {
Index: src/Parser/parser.cc
===================================================================
--- src/Parser/parser.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Parser/parser.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -1030,80 +1030,80 @@
 static const yytype_uint16 yyrline[] =
 {
-       0,   306,   306,   310,   317,   318,   319,   320,   321,   325,
-     326,   327,   331,   332,   336,   337,   341,   342,   346,   350,
-     351,   362,   364,   366,   367,   369,   374,   375,   381,   383,
-     385,   386,   387,   389,   390,   392,   394,   396,   405,   406,
-     412,   413,   417,   418,   422,   424,   426,   428,   430,   432,
-     434,   439,   441,   443,   447,   449,   453,   456,   458,   460,
-     465,   478,   480,   482,   484,   486,   488,   490,   492,   494,
-     496,   498,   505,   506,   512,   513,   514,   515,   519,   520,
-     527,   528,   530,   532,   537,   538,   540,   545,   546,   548,
-     553,   554,   556,   558,   560,   565,   566,   568,   573,   574,
-     579,   580,   585,   586,   591,   592,   597,   598,   603,   604,
-     607,   614,   619,   620,   628,   629,   633,   634,   635,   636,
-     637,   638,   639,   640,   641,   642,   643,   644,   654,   656,
-     661,   662,   667,   668,   674,   675,   681,   682,   683,   684,
-     685,   686,   687,   688,   689,   699,   706,   708,   718,   719,
-     724,   726,   732,   734,   738,   739,   744,   749,   752,   754,
-     756,   766,   768,   779,   780,   782,   786,   788,   792,   793,
-     798,   799,   803,   808,   809,   813,   815,   821,   822,   826,
-     828,   830,   832,   838,   839,   843,   845,   850,   852,   854,
-     859,   861,   866,   868,   872,   875,   879,   882,   886,   888,
-     890,   892,   897,   899,   901,   906,   908,   910,   912,   914,
-     919,   921,   923,   925,   930,   942,   943,   948,   950,   955,
-     959,   961,   963,   965,   967,   973,   974,   980,   981,   985,
-     986,   991,   993,   999,  1000,  1002,  1007,  1012,  1022,  1024,
-    1028,  1029,  1034,  1036,  1040,  1041,  1045,  1047,  1051,  1052,
-    1056,  1057,  1061,  1062,  1077,  1078,  1079,  1080,  1081,  1085,
-    1090,  1097,  1107,  1112,  1117,  1125,  1130,  1135,  1140,  1145,
-    1175,  1180,  1187,  1189,  1196,  1201,  1206,  1217,  1222,  1227,
-    1232,  1237,  1246,  1251,  1259,  1260,  1261,  1262,  1268,  1273,
-    1281,  1282,  1283,  1284,  1288,  1289,  1290,  1291,  1296,  1297,
-    1306,  1307,  1312,  1313,  1318,  1320,  1322,  1324,  1326,  1329,
-    1328,  1340,  1341,  1343,  1353,  1354,  1359,  1361,  1363,  1365,
-    1367,  1370,  1372,  1375,  1380,  1382,  1384,  1386,  1388,  1390,
-    1392,  1394,  1396,  1398,  1400,  1402,  1404,  1406,  1408,  1414,
-    1415,  1417,  1419,  1421,  1426,  1427,  1433,  1434,  1436,  1438,
-    1443,  1445,  1447,  1449,  1454,  1455,  1457,  1459,  1464,  1465,
-    1467,  1472,  1473,  1475,  1477,  1482,  1484,  1486,  1491,  1492,
-    1496,  1498,  1504,  1503,  1507,  1509,  1514,  1516,  1522,  1523,
-    1528,  1529,  1531,  1532,  1541,  1542,  1544,  1546,  1551,  1553,
-    1559,  1560,  1562,  1565,  1568,  1573,  1574,  1579,  1584,  1588,
-    1590,  1596,  1595,  1602,  1604,  1610,  1611,  1619,  1620,  1624,
-    1625,  1626,  1628,  1630,  1637,  1638,  1640,  1642,  1647,  1648,
-    1654,  1655,  1659,  1660,  1665,  1666,  1667,  1669,  1677,  1678,
-    1680,  1683,  1685,  1689,  1690,  1691,  1693,  1695,  1699,  1704,
-    1712,  1713,  1722,  1724,  1729,  1730,  1731,  1735,  1736,  1737,
-    1741,  1742,  1743,  1747,  1748,  1749,  1754,  1755,  1756,  1757,
-    1763,  1764,  1766,  1771,  1772,  1777,  1778,  1779,  1780,  1781,
-    1796,  1797,  1802,  1803,  1809,  1811,  1814,  1816,  1818,  1841,
-    1842,  1844,  1846,  1851,  1852,  1854,  1859,  1864,  1865,  1871,
-    1870,  1874,  1878,  1880,  1882,  1888,  1889,  1894,  1899,  1901,
-    1906,  1908,  1909,  1911,  1916,  1918,  1920,  1925,  1927,  1932,
-    1937,  1945,  1951,  1950,  1964,  1965,  1970,  1971,  1975,  1980,
-    1985,  1993,  1998,  2009,  2010,  2015,  2016,  2022,  2023,  2027,
-    2028,  2029,  2032,  2031,  2042,  2051,  2057,  2063,  2072,  2078,
-    2084,  2090,  2096,  2104,  2110,  2118,  2124,  2133,  2134,  2135,
-    2139,  2143,  2145,  2150,  2151,  2155,  2156,  2161,  2167,  2168,
-    2171,  2173,  2174,  2178,  2179,  2180,  2181,  2215,  2217,  2218,
-    2220,  2225,  2230,  2235,  2237,  2239,  2244,  2246,  2248,  2250,
-    2255,  2257,  2266,  2268,  2269,  2274,  2276,  2278,  2283,  2285,
-    2287,  2292,  2294,  2296,  2305,  2306,  2307,  2311,  2313,  2315,
-    2320,  2322,  2324,  2329,  2331,  2333,  2348,  2350,  2351,  2353,
-    2358,  2359,  2364,  2366,  2368,  2373,  2375,  2377,  2379,  2384,
-    2386,  2388,  2398,  2400,  2401,  2403,  2408,  2410,  2412,  2417,
-    2419,  2421,  2423,  2428,  2430,  2432,  2463,  2465,  2466,  2468,
-    2473,  2478,  2486,  2488,  2490,  2495,  2497,  2502,  2504,  2518,
-    2519,  2521,  2526,  2528,  2530,  2532,  2534,  2539,  2540,  2542,
-    2544,  2549,  2551,  2553,  2559,  2561,  2563,  2567,  2569,  2571,
-    2573,  2587,  2588,  2590,  2595,  2597,  2599,  2601,  2603,  2608,
-    2609,  2611,  2613,  2618,  2620,  2622,  2628,  2629,  2631,  2640,
-    2643,  2645,  2648,  2650,  2652,  2665,  2666,  2668,  2673,  2675,
-    2677,  2679,  2681,  2686,  2687,  2689,  2691,  2696,  2698,  2706,
-    2707,  2708,  2713,  2714,  2718,  2720,  2722,  2724,  2726,  2728,
-    2735,  2737,  2739,  2741,  2743,  2746,  2748,  2750,  2752,  2754,
-    2759,  2761,  2763,  2768,  2794,  2795,  2797,  2801,  2802,  2806,
-    2808,  2810,  2812,  2814,  2816,  2823,  2825,  2827,  2829,  2831,
-    2833,  2838,  2845,  2847,  2865,  2867,  2872,  2873
+       0,   305,   305,   309,   316,   317,   318,   319,   320,   324,
+     325,   326,   330,   331,   335,   336,   340,   341,   345,   349,
+     350,   361,   363,   365,   366,   368,   373,   374,   380,   382,
+     384,   386,   388,   390,   392,   394,   396,   398,   407,   408,
+     414,   415,   419,   420,   424,   425,   427,   429,   431,   433,
+     435,   440,   442,   444,   450,   451,   459,   462,   464,   466,
+     471,   484,   486,   488,   490,   492,   494,   496,   498,   500,
+     502,   504,   511,   512,   518,   519,   520,   521,   525,   526,
+     533,   534,   536,   538,   543,   544,   546,   551,   552,   554,
+     559,   560,   562,   564,   566,   571,   572,   574,   579,   580,
+     585,   586,   591,   592,   597,   598,   603,   604,   609,   610,
+     613,   620,   625,   626,   634,   635,   639,   640,   641,   642,
+     643,   644,   645,   646,   647,   648,   649,   650,   660,   662,
+     667,   668,   673,   674,   680,   681,   687,   688,   689,   690,
+     691,   692,   693,   694,   695,   705,   712,   714,   724,   725,
+     730,   732,   738,   740,   744,   745,   750,   755,   758,   760,
+     762,   772,   774,   785,   786,   788,   792,   794,   798,   799,
+     804,   805,   809,   814,   815,   819,   821,   827,   828,   832,
+     834,   836,   838,   844,   845,   849,   851,   856,   858,   860,
+     865,   867,   872,   874,   878,   881,   885,   888,   892,   894,
+     896,   898,   903,   905,   907,   912,   914,   916,   918,   920,
+     925,   927,   929,   931,   936,   948,   949,   954,   956,   961,
+     965,   967,   969,   971,   973,   979,   980,   986,   987,   991,
+     992,   997,   999,  1005,  1006,  1008,  1013,  1018,  1028,  1030,
+    1034,  1035,  1040,  1042,  1046,  1047,  1051,  1053,  1057,  1058,
+    1062,  1063,  1067,  1068,  1083,  1084,  1085,  1086,  1087,  1091,
+    1096,  1103,  1113,  1118,  1123,  1131,  1136,  1141,  1146,  1151,
+    1181,  1186,  1193,  1195,  1202,  1207,  1212,  1223,  1228,  1233,
+    1238,  1243,  1252,  1257,  1265,  1266,  1267,  1268,  1274,  1279,
+    1287,  1288,  1289,  1290,  1294,  1295,  1296,  1297,  1302,  1303,
+    1312,  1313,  1318,  1319,  1324,  1326,  1328,  1330,  1332,  1335,
+    1334,  1346,  1347,  1349,  1359,  1360,  1365,  1367,  1369,  1371,
+    1373,  1376,  1378,  1381,  1386,  1388,  1390,  1392,  1394,  1396,
+    1398,  1400,  1402,  1404,  1406,  1408,  1410,  1412,  1414,  1420,
+    1421,  1423,  1425,  1427,  1432,  1433,  1439,  1440,  1442,  1444,
+    1449,  1451,  1453,  1455,  1460,  1461,  1463,  1465,  1470,  1471,
+    1473,  1478,  1479,  1481,  1483,  1488,  1490,  1492,  1497,  1498,
+    1502,  1504,  1510,  1509,  1513,  1515,  1520,  1522,  1528,  1529,
+    1534,  1535,  1537,  1538,  1547,  1548,  1550,  1552,  1557,  1559,
+    1565,  1566,  1568,  1571,  1574,  1579,  1580,  1585,  1590,  1594,
+    1596,  1602,  1601,  1608,  1610,  1616,  1617,  1625,  1626,  1630,
+    1631,  1632,  1634,  1636,  1643,  1644,  1646,  1648,  1653,  1654,
+    1660,  1661,  1665,  1666,  1671,  1672,  1673,  1675,  1683,  1684,
+    1686,  1689,  1691,  1695,  1696,  1697,  1699,  1701,  1705,  1710,
+    1718,  1719,  1728,  1730,  1735,  1736,  1737,  1741,  1742,  1743,
+    1747,  1748,  1749,  1753,  1754,  1755,  1760,  1761,  1762,  1763,
+    1769,  1770,  1772,  1777,  1778,  1783,  1784,  1785,  1786,  1787,
+    1802,  1803,  1808,  1809,  1815,  1817,  1820,  1822,  1824,  1847,
+    1848,  1850,  1852,  1857,  1858,  1860,  1865,  1870,  1871,  1877,
+    1876,  1880,  1884,  1886,  1888,  1894,  1895,  1900,  1905,  1907,
+    1912,  1914,  1915,  1917,  1922,  1924,  1926,  1931,  1933,  1938,
+    1943,  1951,  1957,  1956,  1970,  1971,  1976,  1977,  1981,  1986,
+    1991,  1999,  2004,  2015,  2016,  2021,  2022,  2028,  2029,  2033,
+    2034,  2035,  2038,  2037,  2048,  2057,  2063,  2069,  2078,  2084,
+    2090,  2096,  2102,  2110,  2116,  2124,  2130,  2139,  2140,  2141,
+    2145,  2149,  2151,  2156,  2157,  2161,  2162,  2167,  2173,  2174,
+    2177,  2179,  2180,  2184,  2185,  2186,  2187,  2221,  2223,  2224,
+    2226,  2231,  2236,  2241,  2243,  2245,  2250,  2252,  2254,  2256,
+    2261,  2263,  2272,  2274,  2275,  2280,  2282,  2284,  2289,  2291,
+    2293,  2298,  2300,  2302,  2311,  2312,  2313,  2317,  2319,  2321,
+    2326,  2328,  2330,  2335,  2337,  2339,  2354,  2356,  2357,  2359,
+    2364,  2365,  2370,  2372,  2374,  2379,  2381,  2383,  2385,  2390,
+    2392,  2394,  2404,  2406,  2407,  2409,  2414,  2416,  2418,  2423,
+    2425,  2427,  2429,  2434,  2436,  2438,  2469,  2471,  2472,  2474,
+    2479,  2484,  2492,  2494,  2496,  2501,  2503,  2508,  2510,  2524,
+    2525,  2527,  2532,  2534,  2536,  2538,  2540,  2545,  2546,  2548,
+    2550,  2555,  2557,  2559,  2565,  2567,  2569,  2573,  2575,  2577,
+    2579,  2593,  2594,  2596,  2601,  2603,  2605,  2607,  2609,  2614,
+    2615,  2617,  2619,  2624,  2626,  2628,  2634,  2635,  2637,  2646,
+    2649,  2651,  2654,  2656,  2658,  2671,  2672,  2674,  2679,  2681,
+    2683,  2685,  2687,  2692,  2693,  2695,  2697,  2702,  2704,  2712,
+    2713,  2714,  2719,  2720,  2724,  2726,  2728,  2730,  2732,  2734,
+    2741,  2743,  2745,  2747,  2749,  2752,  2754,  2756,  2758,  2760,
+    2765,  2767,  2769,  2774,  2800,  2801,  2803,  2807,  2808,  2812,
+    2814,  2816,  2818,  2820,  2822,  2829,  2831,  2833,  2835,  2837,
+    2839,  2844,  2851,  2853,  2871,  2873,  2878,  2879
 };
 #endif
@@ -4928,5 +4928,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 306 "parser.yy"
+#line 305 "parser.yy"
     { typedefTable.enterScope(); }
     break;
@@ -4935,5 +4935,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 310 "parser.yy"
+#line 309 "parser.yy"
     { typedefTable.leaveScope(); }
     break;
@@ -4942,9 +4942,16 @@
 
 /* Line 1806 of yacc.c  */
+#line 316 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_constantInteger( *(yyvsp[(1) - (1)].tok) ) ); }
+    break;
+
+  case 5:
+
+/* Line 1806 of yacc.c  */
 #line 317 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_constantInteger( *(yyvsp[(1) - (1)].tok) ) ); }
-    break;
-
-  case 5:
+    { (yyval.en) = new ExpressionNode( build_constantFloat( *(yyvsp[(1) - (1)].tok) ) ); }
+    break;
+
+  case 6:
 
 /* Line 1806 of yacc.c  */
@@ -4953,5 +4960,5 @@
     break;
 
-  case 6:
+  case 7:
 
 /* Line 1806 of yacc.c  */
@@ -4960,15 +4967,8 @@
     break;
 
-  case 7:
+  case 8:
 
 /* Line 1806 of yacc.c  */
 #line 320 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_constantFloat( *(yyvsp[(1) - (1)].tok) ) ); }
-    break;
-
-  case 8:
-
-/* Line 1806 of yacc.c  */
-#line 321 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_constantChar( *(yyvsp[(1) - (1)].tok) ) ); }
     break;
@@ -4977,5 +4977,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 346 "parser.yy"
+#line 345 "parser.yy"
     { (yyval.constant) = build_constantStr( *(yyvsp[(1) - (1)].str) ); }
     break;
@@ -4984,5 +4984,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 350 "parser.yy"
+#line 349 "parser.yy"
     { (yyval.str) = (yyvsp[(1) - (1)].tok); }
     break;
@@ -4991,5 +4991,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 352 "parser.yy"
+#line 351 "parser.yy"
     {
 			appendStr( (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].tok) );						// append 2nd juxtaposed string to 1st
@@ -5002,5 +5002,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 363 "parser.yy"
+#line 362 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); }
     break;
@@ -5009,5 +5009,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 365 "parser.yy"
+#line 364 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); }
     break;
@@ -5016,5 +5016,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 368 "parser.yy"
+#line 367 "parser.yy"
     { (yyval.en) = (yyvsp[(2) - (3)].en); }
     break;
@@ -5023,5 +5023,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 370 "parser.yy"
+#line 369 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_valexpr( (yyvsp[(2) - (3)].sn) ) ); }
     break;
@@ -5030,5 +5030,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 380 "parser.yy"
+#line 379 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Index, (yyvsp[(1) - (6)].en), (yyvsp[(4) - (6)].en) ) ); }
     break;
@@ -5037,5 +5037,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 382 "parser.yy"
+#line 381 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_func( (yyvsp[(1) - (4)].en), (yyvsp[(3) - (4)].en) ) ); }
     break;
@@ -5044,19 +5044,40 @@
 
 /* Line 1806 of yacc.c  */
-#line 384 "parser.yy"
+#line 383 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (3)].en), build_varref( (yyvsp[(3) - (3)].tok) ) ) ); }
     break;
 
+  case 30:
+
+/* Line 1806 of yacc.c  */
+#line 385 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
+    break;
+
+  case 31:
+
+/* Line 1806 of yacc.c  */
+#line 387 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (2)].en), build_field_name_REALFRACTIONconstant( *(yyvsp[(2) - (2)].tok) ) ) ); }
+    break;
+
   case 32:
 
 /* Line 1806 of yacc.c  */
-#line 388 "parser.yy"
+#line 389 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (3)].en), build_varref( (yyvsp[(3) - (3)].tok) ) ) ); }
     break;
 
+  case 33:
+
+/* Line 1806 of yacc.c  */
+#line 391 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
+    break;
+
   case 34:
 
 /* Line 1806 of yacc.c  */
-#line 391 "parser.yy"
+#line 393 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, (yyvsp[(1) - (2)].en) ) ); }
     break;
@@ -5065,5 +5086,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 393 "parser.yy"
+#line 395 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::DecrPost, (yyvsp[(1) - (2)].en) ) ); }
     break;
@@ -5072,5 +5093,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 395 "parser.yy"
+#line 397 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_compoundLiteral( (yyvsp[(2) - (7)].decl), new InitializerNode( (yyvsp[(5) - (7)].in), true ) ) ); }
     break;
@@ -5079,5 +5100,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 397 "parser.yy"
+#line 399 "parser.yy"
     {
 			Token fn;
@@ -5090,5 +5111,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 407 "parser.yy"
+#line 409 "parser.yy"
     { (yyval.en) = (ExpressionNode *)( (yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) )); }
     break;
@@ -5097,5 +5118,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 412 "parser.yy"
+#line 414 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -5104,20 +5125,13 @@
 
 /* Line 1806 of yacc.c  */
-#line 418 "parser.yy"
+#line 420 "parser.yy"
     { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) ); }
     break;
 
-  case 44:
-
-/* Line 1806 of yacc.c  */
-#line 423 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); }
-    break;
-
   case 45:
 
 /* Line 1806 of yacc.c  */
-#line 425 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(2) - (2)].en), build_varref( (yyvsp[(1) - (2)].tok) ) ) ); }
+#line 426 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_REALDECIMALconstant( *(yyvsp[(1) - (2)].tok) ) ), maybeMoveBuild<Expression>( (yyvsp[(2) - (2)].en) ) ) ); }
     break;
 
@@ -5125,6 +5139,6 @@
 
 /* Line 1806 of yacc.c  */
-#line 427 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(4) - (6)].en), build_varref( (yyvsp[(1) - (6)].tok) ) ) ); }
+#line 428 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_REALDECIMALconstant( *(yyvsp[(1) - (6)].tok) ) ), build_tuple( (yyvsp[(4) - (6)].en) ) ) ); }
     break;
 
@@ -5132,6 +5146,6 @@
 
 /* Line 1806 of yacc.c  */
-#line 429 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(3) - (3)].en), build_varref( (yyvsp[(1) - (3)].tok) ) ) ); }
+#line 430 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (3)].en), maybeMoveBuild<Expression>( (yyvsp[(3) - (3)].en) ) ) ); }
     break;
 
@@ -5139,6 +5153,6 @@
 
 /* Line 1806 of yacc.c  */
-#line 431 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(5) - (7)].en), build_varref( (yyvsp[(1) - (7)].tok) ) ) ); }
+#line 432 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
     break;
 
@@ -5146,6 +5160,6 @@
 
 /* Line 1806 of yacc.c  */
-#line 433 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(3) - (3)].en), build_varref( (yyvsp[(1) - (3)].tok) ) ) ); }
+#line 434 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (3)].en), maybeMoveBuild<Expression>( (yyvsp[(3) - (3)].en) ) ) ); }
     break;
 
@@ -5153,6 +5167,6 @@
 
 /* Line 1806 of yacc.c  */
-#line 435 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(5) - (7)].en), build_varref( (yyvsp[(1) - (7)].tok) ) ) ); }
+#line 436 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
     break;
 
@@ -5160,6 +5174,6 @@
 
 /* Line 1806 of yacc.c  */
-#line 440 "parser.yy"
-    { (yyval.tok) = (yyvsp[(1) - (2)].tok); }
+#line 441 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_field_name_fraction_constants( build_constantInteger( *(yyvsp[(1) - (2)].tok) ), (yyvsp[(2) - (2)].en) ) ); }
     break;
 
@@ -5167,6 +5181,6 @@
 
 /* Line 1806 of yacc.c  */
-#line 442 "parser.yy"
-    { (yyval.tok) = (yyvsp[(1) - (2)].tok); }
+#line 443 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *(yyvsp[(1) - (2)].tok) ), (yyvsp[(2) - (2)].en) ) ); }
     break;
 
@@ -5174,6 +5188,23 @@
 
 /* Line 1806 of yacc.c  */
-#line 444 "parser.yy"
-    { (yyval.tok) = (yyvsp[(1) - (2)].tok); }
+#line 445 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_field_name_fraction_constants( build_varref( (yyvsp[(1) - (2)].tok) ), (yyvsp[(2) - (2)].en) ) ); }
+    break;
+
+  case 54:
+
+/* Line 1806 of yacc.c  */
+#line 450 "parser.yy"
+    { (yyval.en) = nullptr; }
+    break;
+
+  case 55:
+
+/* Line 1806 of yacc.c  */
+#line 452 "parser.yy"
+    {
+			Expression * constant = build_field_name_REALFRACTIONconstant( *(yyvsp[(2) - (2)].tok) );
+			(yyval.en) = (yyvsp[(1) - (2)].en) != nullptr ? new ExpressionNode( build_fieldSel( (yyvsp[(1) - (2)].en),  constant ) ) : new ExpressionNode( constant );
+		}
     break;
 
@@ -5181,5 +5212,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 457 "parser.yy"
+#line 463 "parser.yy"
     { (yyval.en) = (yyvsp[(1) - (1)].en); }
     break;
@@ -5188,5 +5219,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 459 "parser.yy"
+#line 465 "parser.yy"
     { (yyval.en) = new ExpressionNode( (yyvsp[(1) - (1)].constant) ); }
     break;
@@ -5195,5 +5226,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 461 "parser.yy"
+#line 467 "parser.yy"
     { (yyval.en) = (yyvsp[(2) - (2)].en)->set_extension( true ); }
     break;
@@ -5202,5 +5233,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 466 "parser.yy"
+#line 472 "parser.yy"
     {
 			switch ( (yyvsp[(1) - (2)].op) ) {
@@ -5220,5 +5251,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 479 "parser.yy"
+#line 485 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_unary_val( (yyvsp[(1) - (2)].op), (yyvsp[(2) - (2)].en) ) ); }
     break;
@@ -5227,5 +5258,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 481 "parser.yy"
+#line 487 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::Incr, (yyvsp[(2) - (2)].en) ) ); }
     break;
@@ -5234,5 +5265,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 483 "parser.yy"
+#line 489 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::Decr, (yyvsp[(2) - (2)].en) ) ); }
     break;
@@ -5241,5 +5272,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 485 "parser.yy"
+#line 491 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_sizeOfexpr( (yyvsp[(2) - (2)].en) ) ); }
     break;
@@ -5248,5 +5279,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 487 "parser.yy"
+#line 493 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_sizeOftype( (yyvsp[(3) - (4)].decl) ) ); }
     break;
@@ -5255,5 +5286,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 489 "parser.yy"
+#line 495 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_alignOfexpr( (yyvsp[(2) - (2)].en) ) ); }
     break;
@@ -5262,5 +5293,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 491 "parser.yy"
+#line 497 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_alignOftype( (yyvsp[(3) - (4)].decl) ) ); }
     break;
@@ -5269,5 +5300,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 493 "parser.yy"
+#line 499 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_offsetOf( (yyvsp[(3) - (6)].decl), build_varref( (yyvsp[(5) - (6)].tok) ) ) ); }
     break;
@@ -5276,5 +5307,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 495 "parser.yy"
+#line 501 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_attrexpr( build_varref( (yyvsp[(1) - (1)].tok) ), nullptr ) ); }
     break;
@@ -5283,5 +5314,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 497 "parser.yy"
+#line 503 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_attrexpr( build_varref( (yyvsp[(1) - (4)].tok) ), (yyvsp[(3) - (4)].en) ) ); }
     break;
@@ -5290,5 +5321,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 499 "parser.yy"
+#line 505 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_attrtype( build_varref( (yyvsp[(1) - (4)].tok) ), (yyvsp[(3) - (4)].decl) ) ); }
     break;
@@ -5297,5 +5328,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 505 "parser.yy"
+#line 511 "parser.yy"
     { (yyval.op) = OperKinds::PointTo; }
     break;
@@ -5304,5 +5335,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 506 "parser.yy"
+#line 512 "parser.yy"
     { (yyval.op) = OperKinds::AddressOf; }
     break;
@@ -5311,5 +5342,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 512 "parser.yy"
+#line 518 "parser.yy"
     { (yyval.op) = OperKinds::UnPlus; }
     break;
@@ -5318,5 +5349,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 513 "parser.yy"
+#line 519 "parser.yy"
     { (yyval.op) = OperKinds::UnMinus; }
     break;
@@ -5325,5 +5356,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 514 "parser.yy"
+#line 520 "parser.yy"
     { (yyval.op) = OperKinds::Neg; }
     break;
@@ -5332,5 +5363,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 515 "parser.yy"
+#line 521 "parser.yy"
     { (yyval.op) = OperKinds::BitNeg; }
     break;
@@ -5339,5 +5370,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 521 "parser.yy"
+#line 527 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_cast( (yyvsp[(2) - (4)].decl), (yyvsp[(4) - (4)].en) ) ); }
     break;
@@ -5346,5 +5377,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 529 "parser.yy"
+#line 535 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Mul, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5353,5 +5384,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 531 "parser.yy"
+#line 537 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Div, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5360,5 +5391,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 533 "parser.yy"
+#line 539 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Mod, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5367,5 +5398,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 539 "parser.yy"
+#line 545 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Plus, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5374,5 +5405,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 541 "parser.yy"
+#line 547 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Minus, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5381,5 +5412,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 547 "parser.yy"
+#line 553 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::LShift, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5388,5 +5419,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 549 "parser.yy"
+#line 555 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::RShift, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5395,5 +5426,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 555 "parser.yy"
+#line 561 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::LThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5402,5 +5433,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 557 "parser.yy"
+#line 563 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::GThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5409,5 +5440,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 559 "parser.yy"
+#line 565 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::LEThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5416,5 +5447,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 561 "parser.yy"
+#line 567 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::GEThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5423,5 +5454,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 567 "parser.yy"
+#line 573 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Eq, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5430,5 +5461,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 569 "parser.yy"
+#line 575 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Neq, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5437,5 +5468,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 575 "parser.yy"
+#line 581 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::BitAnd, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5444,5 +5475,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 581 "parser.yy"
+#line 587 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Xor, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5451,5 +5482,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 587 "parser.yy"
+#line 593 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::BitOr, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5458,5 +5489,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 593 "parser.yy"
+#line 599 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_and_or( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en), true ) ); }
     break;
@@ -5465,5 +5496,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 599 "parser.yy"
+#line 605 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_and_or( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en), false ) ); }
     break;
@@ -5472,5 +5503,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 605 "parser.yy"
+#line 611 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_cond( (yyvsp[(1) - (5)].en), (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].en) ) ); }
     break;
@@ -5479,5 +5510,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 608 "parser.yy"
+#line 614 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_cond( (yyvsp[(1) - (4)].en), (yyvsp[(1) - (4)].en), (yyvsp[(4) - (4)].en) ) ); }
     break;
@@ -5486,5 +5517,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 621 "parser.yy"
+#line 627 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_ptr( (yyvsp[(2) - (3)].op), (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5493,5 +5524,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 628 "parser.yy"
+#line 634 "parser.yy"
     { (yyval.en) = nullptr; }
     break;
@@ -5500,5 +5531,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 633 "parser.yy"
+#line 639 "parser.yy"
     { (yyval.op) = OperKinds::Assign; }
     break;
@@ -5507,5 +5538,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 634 "parser.yy"
+#line 640 "parser.yy"
     { (yyval.op) = OperKinds::AtAssn; }
     break;
@@ -5514,5 +5545,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 635 "parser.yy"
+#line 641 "parser.yy"
     { (yyval.op) = OperKinds::MulAssn; }
     break;
@@ -5521,5 +5552,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 636 "parser.yy"
+#line 642 "parser.yy"
     { (yyval.op) = OperKinds::DivAssn; }
     break;
@@ -5528,5 +5559,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 637 "parser.yy"
+#line 643 "parser.yy"
     { (yyval.op) = OperKinds::ModAssn; }
     break;
@@ -5535,5 +5566,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 638 "parser.yy"
+#line 644 "parser.yy"
     { (yyval.op) = OperKinds::PlusAssn; }
     break;
@@ -5542,5 +5573,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 639 "parser.yy"
+#line 645 "parser.yy"
     { (yyval.op) = OperKinds::MinusAssn; }
     break;
@@ -5549,5 +5580,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 640 "parser.yy"
+#line 646 "parser.yy"
     { (yyval.op) = OperKinds::LSAssn; }
     break;
@@ -5556,5 +5587,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 641 "parser.yy"
+#line 647 "parser.yy"
     { (yyval.op) = OperKinds::RSAssn; }
     break;
@@ -5563,5 +5594,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 642 "parser.yy"
+#line 648 "parser.yy"
     { (yyval.op) = OperKinds::AndAssn; }
     break;
@@ -5570,5 +5601,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 643 "parser.yy"
+#line 649 "parser.yy"
     { (yyval.op) = OperKinds::ERAssn; }
     break;
@@ -5577,5 +5608,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 644 "parser.yy"
+#line 650 "parser.yy"
     { (yyval.op) = OperKinds::OrAssn; }
     break;
@@ -5584,5 +5615,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 655 "parser.yy"
+#line 661 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( (yyvsp[(4) - (6)].en) ) ) ); }
     break;
@@ -5591,5 +5622,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 657 "parser.yy"
+#line 663 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_tuple( (ExpressionNode *)(yyvsp[(3) - (7)].en)->set_last( (yyvsp[(5) - (7)].en) ) ) ); }
     break;
@@ -5598,5 +5629,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 663 "parser.yy"
+#line 669 "parser.yy"
     { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) ); }
     break;
@@ -5605,5 +5636,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 669 "parser.yy"
+#line 675 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_comma( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5612,5 +5643,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 674 "parser.yy"
+#line 680 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -5619,5 +5650,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 683 "parser.yy"
+#line 689 "parser.yy"
     { (yyval.sn) = (yyvsp[(1) - (1)].sn); }
     break;
@@ -5626,5 +5657,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 690 "parser.yy"
+#line 696 "parser.yy"
     {
 			Token fn;
@@ -5637,5 +5668,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 700 "parser.yy"
+#line 706 "parser.yy"
     {
 			(yyval.sn) = (yyvsp[(4) - (4)].sn)->add_label( (yyvsp[(1) - (4)].tok) );
@@ -5646,5 +5677,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 707 "parser.yy"
+#line 713 "parser.yy"
     { (yyval.sn) = new StatementNode( build_compound( (StatementNode *)0 ) ); }
     break;
@@ -5653,5 +5684,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 714 "parser.yy"
+#line 720 "parser.yy"
     { (yyval.sn) = new StatementNode( build_compound( (yyvsp[(5) - (7)].sn) ) ); }
     break;
@@ -5660,5 +5691,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 720 "parser.yy"
+#line 726 "parser.yy"
     { if ( (yyvsp[(1) - (3)].sn) != 0 ) { (yyvsp[(1) - (3)].sn)->set_last( (yyvsp[(3) - (3)].sn) ); (yyval.sn) = (yyvsp[(1) - (3)].sn); } }
     break;
@@ -5667,5 +5698,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 725 "parser.yy"
+#line 731 "parser.yy"
     { (yyval.sn) = new StatementNode( (yyvsp[(1) - (1)].decl) ); }
     break;
@@ -5674,5 +5705,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 727 "parser.yy"
+#line 733 "parser.yy"
     {	// mark all fields in list
 			for ( DeclarationNode *iter = (yyvsp[(2) - (2)].decl); iter != nullptr; iter = (DeclarationNode *)iter->get_next() )
@@ -5685,5 +5716,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 733 "parser.yy"
+#line 739 "parser.yy"
     { (yyval.sn) = new StatementNode( (yyvsp[(1) - (1)].decl) ); }
     break;
@@ -5692,5 +5723,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 740 "parser.yy"
+#line 746 "parser.yy"
     { if ( (yyvsp[(1) - (2)].sn) != 0 ) { (yyvsp[(1) - (2)].sn)->set_last( (yyvsp[(2) - (2)].sn) ); (yyval.sn) = (yyvsp[(1) - (2)].sn); } }
     break;
@@ -5699,5 +5730,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 745 "parser.yy"
+#line 751 "parser.yy"
     { (yyval.sn) = new StatementNode( build_expr( (yyvsp[(1) - (2)].en) ) ); }
     break;
@@ -5706,5 +5737,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 751 "parser.yy"
+#line 757 "parser.yy"
     { (yyval.sn) = new StatementNode( build_if( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn), nullptr ) ); }
     break;
@@ -5713,5 +5744,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 753 "parser.yy"
+#line 759 "parser.yy"
     { (yyval.sn) = new StatementNode( build_if( (yyvsp[(3) - (7)].en), (yyvsp[(5) - (7)].sn), (yyvsp[(7) - (7)].sn) ) ); }
     break;
@@ -5720,5 +5751,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 755 "parser.yy"
+#line 761 "parser.yy"
     { (yyval.sn) = new StatementNode( build_switch( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn) ) ); }
     break;
@@ -5727,5 +5758,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 757 "parser.yy"
+#line 763 "parser.yy"
     {
 			StatementNode *sw = new StatementNode( build_switch( (yyvsp[(3) - (9)].en), (yyvsp[(8) - (9)].sn) ) );
@@ -5742,5 +5773,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 767 "parser.yy"
+#line 773 "parser.yy"
     { (yyval.sn) = new StatementNode( build_switch( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn) ) ); }
     break;
@@ -5749,5 +5780,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 769 "parser.yy"
+#line 775 "parser.yy"
     {
 			StatementNode *sw = new StatementNode( build_switch( (yyvsp[(3) - (9)].en), (yyvsp[(8) - (9)].sn) ) );
@@ -5759,5 +5790,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 779 "parser.yy"
+#line 785 "parser.yy"
     { (yyval.en) = (yyvsp[(1) - (1)].en); }
     break;
@@ -5766,5 +5797,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 781 "parser.yy"
+#line 787 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_range( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -5773,5 +5804,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 786 "parser.yy"
+#line 792 "parser.yy"
     { (yyval.sn) = new StatementNode( build_case( (yyvsp[(1) - (1)].en) ) ); }
     break;
@@ -5780,5 +5811,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 788 "parser.yy"
+#line 794 "parser.yy"
     { (yyval.sn) = (StatementNode *)((yyvsp[(1) - (3)].sn)->set_last( new StatementNode( build_case( (yyvsp[(3) - (3)].en) ) ) ) ); }
     break;
@@ -5787,5 +5818,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 792 "parser.yy"
+#line 798 "parser.yy"
     { (yyval.sn) = (yyvsp[(2) - (3)].sn); }
     break;
@@ -5794,5 +5825,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 793 "parser.yy"
+#line 799 "parser.yy"
     { (yyval.sn) = new StatementNode( build_default() ); }
     break;
@@ -5801,5 +5832,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 799 "parser.yy"
+#line 805 "parser.yy"
     { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (2)].sn)->set_last( (yyvsp[(2) - (2)].sn) )); }
     break;
@@ -5808,5 +5839,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 803 "parser.yy"
+#line 809 "parser.yy"
     { (yyval.sn) = (yyvsp[(1) - (2)].sn)->append_last_case( new StatementNode( build_compound( (yyvsp[(2) - (2)].sn) ) ) ); }
     break;
@@ -5815,5 +5846,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 808 "parser.yy"
+#line 814 "parser.yy"
     { (yyval.sn) = 0; }
     break;
@@ -5822,5 +5853,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 814 "parser.yy"
+#line 820 "parser.yy"
     { (yyval.sn) = (yyvsp[(1) - (2)].sn)->append_last_case( new StatementNode( build_compound( (yyvsp[(2) - (2)].sn) ) ) ); }
     break;
@@ -5829,5 +5860,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 816 "parser.yy"
+#line 822 "parser.yy"
     { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (3)].sn)->set_last( (yyvsp[(2) - (3)].sn)->append_last_case( new StatementNode( build_compound( (yyvsp[(3) - (3)].sn) ) ) ) ) ); }
     break;
@@ -5836,5 +5867,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 821 "parser.yy"
+#line 827 "parser.yy"
     { (yyval.sn) = 0; }
     break;
@@ -5843,5 +5874,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 827 "parser.yy"
+#line 833 "parser.yy"
     { (yyval.sn) = (yyvsp[(1) - (2)].sn)->append_last_case( (yyvsp[(2) - (2)].sn) ); }
     break;
@@ -5850,5 +5881,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 829 "parser.yy"
+#line 835 "parser.yy"
     { (yyval.sn) = (yyvsp[(1) - (3)].sn)->append_last_case( new StatementNode( build_compound( (StatementNode *)(yyvsp[(2) - (3)].sn)->set_last( (yyvsp[(3) - (3)].sn) ) ) ) ); }
     break;
@@ -5857,5 +5888,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 831 "parser.yy"
+#line 837 "parser.yy"
     { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (3)].sn)->set_last( (yyvsp[(2) - (3)].sn)->append_last_case( (yyvsp[(3) - (3)].sn) ))); }
     break;
@@ -5864,5 +5895,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 833 "parser.yy"
+#line 839 "parser.yy"
     { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (4)].sn)->set_last( (yyvsp[(2) - (4)].sn)->append_last_case( new StatementNode( build_compound( (StatementNode *)(yyvsp[(3) - (4)].sn)->set_last( (yyvsp[(4) - (4)].sn) ) ) ) ) ) ); }
     break;
@@ -5871,5 +5902,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 838 "parser.yy"
+#line 844 "parser.yy"
     { (yyval.sn) = new StatementNode( build_branch( BranchStmt::Break ) ); }
     break;
@@ -5878,5 +5909,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 844 "parser.yy"
+#line 850 "parser.yy"
     { (yyval.sn) = 0; }
     break;
@@ -5885,5 +5916,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 846 "parser.yy"
+#line 852 "parser.yy"
     { (yyval.sn) = 0; }
     break;
@@ -5892,5 +5923,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 851 "parser.yy"
+#line 857 "parser.yy"
     { (yyval.sn) = new StatementNode( build_while( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn) ) ); }
     break;
@@ -5899,5 +5930,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 853 "parser.yy"
+#line 859 "parser.yy"
     { (yyval.sn) = new StatementNode( build_while( (yyvsp[(5) - (7)].en), (yyvsp[(2) - (7)].sn), true ) ); }
     break;
@@ -5906,5 +5937,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 855 "parser.yy"
+#line 861 "parser.yy"
     { (yyval.sn) = new StatementNode( build_for( (yyvsp[(4) - (6)].fctl), (yyvsp[(6) - (6)].sn) ) ); }
     break;
@@ -5913,5 +5944,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 860 "parser.yy"
+#line 866 "parser.yy"
     { (yyval.fctl) = new ForCtl( (yyvsp[(1) - (6)].en), (yyvsp[(4) - (6)].en), (yyvsp[(6) - (6)].en) ); }
     break;
@@ -5920,5 +5951,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 862 "parser.yy"
+#line 868 "parser.yy"
     { (yyval.fctl) = new ForCtl( (yyvsp[(1) - (4)].decl), (yyvsp[(2) - (4)].en), (yyvsp[(4) - (4)].en) ); }
     break;
@@ -5927,5 +5958,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 867 "parser.yy"
+#line 873 "parser.yy"
     { (yyval.sn) = new StatementNode( build_branch( (yyvsp[(2) - (3)].tok), BranchStmt::Goto ) ); }
     break;
@@ -5934,5 +5965,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 871 "parser.yy"
+#line 877 "parser.yy"
     { (yyval.sn) = new StatementNode( build_computedgoto( (yyvsp[(3) - (4)].en) ) ); }
     break;
@@ -5941,5 +5972,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 874 "parser.yy"
+#line 880 "parser.yy"
     { (yyval.sn) = new StatementNode( build_branch( BranchStmt::Continue ) ); }
     break;
@@ -5948,5 +5979,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 878 "parser.yy"
+#line 884 "parser.yy"
     { (yyval.sn) = new StatementNode( build_branch( (yyvsp[(2) - (3)].tok), BranchStmt::Continue ) ); }
     break;
@@ -5955,5 +5986,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 881 "parser.yy"
+#line 887 "parser.yy"
     { (yyval.sn) = new StatementNode( build_branch( BranchStmt::Break ) ); }
     break;
@@ -5962,5 +5993,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 885 "parser.yy"
+#line 891 "parser.yy"
     { (yyval.sn) = new StatementNode( build_branch( (yyvsp[(2) - (3)].tok), BranchStmt::Break ) ); }
     break;
@@ -5969,5 +6000,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 887 "parser.yy"
+#line 893 "parser.yy"
     { (yyval.sn) = new StatementNode( build_return( (yyvsp[(2) - (3)].en) ) ); }
     break;
@@ -5976,5 +6007,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 889 "parser.yy"
+#line 895 "parser.yy"
     { (yyval.sn) = new StatementNode( build_throw( (yyvsp[(2) - (3)].en) ) ); }
     break;
@@ -5983,5 +6014,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 891 "parser.yy"
+#line 897 "parser.yy"
     { (yyval.sn) = new StatementNode( build_throw( (yyvsp[(2) - (3)].en) ) ); }
     break;
@@ -5990,5 +6021,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 893 "parser.yy"
+#line 899 "parser.yy"
     { (yyval.sn) = new StatementNode( build_throw( (yyvsp[(2) - (5)].en) ) ); }
     break;
@@ -5997,5 +6028,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 898 "parser.yy"
+#line 904 "parser.yy"
     { (yyval.sn) = new StatementNode( build_try( (yyvsp[(2) - (3)].sn), (yyvsp[(3) - (3)].sn), 0 ) ); }
     break;
@@ -6004,5 +6035,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 900 "parser.yy"
+#line 906 "parser.yy"
     { (yyval.sn) = new StatementNode( build_try( (yyvsp[(2) - (3)].sn), 0, (yyvsp[(3) - (3)].sn) ) ); }
     break;
@@ -6011,5 +6042,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 902 "parser.yy"
+#line 908 "parser.yy"
     { (yyval.sn) = new StatementNode( build_try( (yyvsp[(2) - (4)].sn), (yyvsp[(3) - (4)].sn), (yyvsp[(4) - (4)].sn) ) ); }
     break;
@@ -6018,5 +6049,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 909 "parser.yy"
+#line 915 "parser.yy"
     { (yyval.sn) = new StatementNode( build_catch( 0, (yyvsp[(5) - (5)].sn), true ) ); }
     break;
@@ -6025,5 +6056,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 911 "parser.yy"
+#line 917 "parser.yy"
     { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (6)].sn)->set_last( new StatementNode( build_catch( 0, (yyvsp[(6) - (6)].sn), true ) ) ); }
     break;
@@ -6032,5 +6063,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 913 "parser.yy"
+#line 919 "parser.yy"
     { (yyval.sn) = new StatementNode( build_catch( 0, (yyvsp[(5) - (5)].sn), true ) ); }
     break;
@@ -6039,5 +6070,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 915 "parser.yy"
+#line 921 "parser.yy"
     { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (6)].sn)->set_last( new StatementNode( build_catch( 0, (yyvsp[(6) - (6)].sn), true ) ) ); }
     break;
@@ -6046,5 +6077,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 920 "parser.yy"
+#line 926 "parser.yy"
     { (yyval.sn) = new StatementNode( build_catch( (yyvsp[(5) - (9)].decl), (yyvsp[(8) - (9)].sn) ) ); }
     break;
@@ -6053,5 +6084,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 922 "parser.yy"
+#line 928 "parser.yy"
     { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (10)].sn)->set_last( new StatementNode( build_catch( (yyvsp[(6) - (10)].decl), (yyvsp[(9) - (10)].sn) ) ) ); }
     break;
@@ -6060,5 +6091,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 924 "parser.yy"
+#line 930 "parser.yy"
     { (yyval.sn) = new StatementNode( build_catch( (yyvsp[(5) - (9)].decl), (yyvsp[(8) - (9)].sn) ) ); }
     break;
@@ -6067,5 +6098,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 926 "parser.yy"
+#line 932 "parser.yy"
     { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (10)].sn)->set_last( new StatementNode( build_catch( (yyvsp[(6) - (10)].decl), (yyvsp[(9) - (10)].sn) ) ) ); }
     break;
@@ -6074,5 +6105,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 931 "parser.yy"
+#line 937 "parser.yy"
     {
 			(yyval.sn) = new StatementNode( build_finally( (yyvsp[(2) - (2)].sn) ) );
@@ -6083,5 +6114,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 944 "parser.yy"
+#line 950 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6093,5 +6124,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 949 "parser.yy"
+#line 955 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addType( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -6100,5 +6131,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 951 "parser.yy"
+#line 957 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6110,5 +6141,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 960 "parser.yy"
+#line 966 "parser.yy"
     { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (6)].flag), (yyvsp[(4) - (6)].constant), 0 ) ); }
     break;
@@ -6117,5 +6148,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 962 "parser.yy"
+#line 968 "parser.yy"
     { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (8)].flag), (yyvsp[(4) - (8)].constant), (yyvsp[(6) - (8)].en) ) ); }
     break;
@@ -6124,5 +6155,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 964 "parser.yy"
+#line 970 "parser.yy"
     { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (10)].flag), (yyvsp[(4) - (10)].constant), (yyvsp[(6) - (10)].en), (yyvsp[(8) - (10)].en) ) ); }
     break;
@@ -6131,5 +6162,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 966 "parser.yy"
+#line 972 "parser.yy"
     { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (12)].flag), (yyvsp[(4) - (12)].constant), (yyvsp[(6) - (12)].en), (yyvsp[(8) - (12)].en), (yyvsp[(10) - (12)].en) ) ); }
     break;
@@ -6138,5 +6169,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 968 "parser.yy"
+#line 974 "parser.yy"
     { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (14)].flag), (yyvsp[(5) - (14)].constant), 0, (yyvsp[(8) - (14)].en), (yyvsp[(10) - (14)].en), (yyvsp[(12) - (14)].label) ) ); }
     break;
@@ -6145,5 +6176,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 973 "parser.yy"
+#line 979 "parser.yy"
     { (yyval.flag) = false; }
     break;
@@ -6152,5 +6183,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 975 "parser.yy"
+#line 981 "parser.yy"
     { (yyval.flag) = true; }
     break;
@@ -6159,5 +6190,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 980 "parser.yy"
+#line 986 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -6166,5 +6197,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 987 "parser.yy"
+#line 993 "parser.yy"
     { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) ); }
     break;
@@ -6173,5 +6204,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 992 "parser.yy"
+#line 998 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_asmexpr( 0, (yyvsp[(1) - (4)].constant), (yyvsp[(3) - (4)].en) ) ); }
     break;
@@ -6180,5 +6211,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 994 "parser.yy"
+#line 1000 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_asmexpr( (yyvsp[(2) - (7)].en), (yyvsp[(4) - (7)].constant), (yyvsp[(6) - (7)].en) ) ); }
     break;
@@ -6187,5 +6218,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 999 "parser.yy"
+#line 1005 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -6194,5 +6225,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1001 "parser.yy"
+#line 1007 "parser.yy"
     { (yyval.en) = new ExpressionNode( (yyvsp[(1) - (1)].constant) ); }
     break;
@@ -6201,5 +6232,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1003 "parser.yy"
+#line 1009 "parser.yy"
     { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( new ExpressionNode( (yyvsp[(3) - (3)].constant) ) ); }
     break;
@@ -6208,5 +6239,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1008 "parser.yy"
+#line 1014 "parser.yy"
     {
 			(yyval.label) = new LabelNode(); (yyval.label)->labels.push_back( *(yyvsp[(1) - (1)].tok) );
@@ -6218,5 +6249,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1013 "parser.yy"
+#line 1019 "parser.yy"
     {
 			(yyval.label) = (yyvsp[(1) - (3)].label); (yyvsp[(1) - (3)].label)->labels.push_back( *(yyvsp[(3) - (3)].tok) );
@@ -6228,5 +6259,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1023 "parser.yy"
+#line 1029 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -6235,5 +6266,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1030 "parser.yy"
+#line 1036 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -6242,5 +6273,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1035 "parser.yy"
+#line 1041 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -6249,5 +6280,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1042 "parser.yy"
+#line 1048 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -6256,5 +6287,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1056 "parser.yy"
+#line 1062 "parser.yy"
     {}
     break;
@@ -6263,5 +6294,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1057 "parser.yy"
+#line 1063 "parser.yy"
     {}
     break;
@@ -6270,5 +6301,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1086 "parser.yy"
+#line 1092 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6280,5 +6311,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1093 "parser.yy"
+#line 1099 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6290,5 +6321,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1098 "parser.yy"
+#line 1104 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(5) - (6)].tok), TypedefTable::ID );
@@ -6300,5 +6331,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1108 "parser.yy"
+#line 1114 "parser.yy"
     {
 			typedefTable.setNextIdentifier( *(yyvsp[(2) - (3)].tok) );
@@ -6310,5 +6341,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1113 "parser.yy"
+#line 1119 "parser.yy"
     {
 			typedefTable.setNextIdentifier( *(yyvsp[(2) - (3)].tok) );
@@ -6320,5 +6351,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1118 "parser.yy"
+#line 1124 "parser.yy"
     {
 			typedefTable.setNextIdentifier( *(yyvsp[(3) - (4)].tok) );
@@ -6330,5 +6361,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1126 "parser.yy"
+#line 1132 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6340,5 +6371,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1131 "parser.yy"
+#line 1137 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6350,5 +6381,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1136 "parser.yy"
+#line 1142 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6360,5 +6391,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1141 "parser.yy"
+#line 1147 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6370,5 +6401,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1146 "parser.yy"
+#line 1152 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(5) - (5)].tok), TypedefTable::ID );
@@ -6380,5 +6411,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1177 "parser.yy"
+#line 1183 "parser.yy"
     {
 			(yyval.decl) = DeclarationNode::newFunction( (yyvsp[(2) - (7)].tok), (yyvsp[(1) - (7)].decl), (yyvsp[(5) - (7)].decl), 0, true );
@@ -6389,5 +6420,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1181 "parser.yy"
+#line 1187 "parser.yy"
     {
 			(yyval.decl) = DeclarationNode::newFunction( (yyvsp[(2) - (7)].tok), (yyvsp[(1) - (7)].decl), (yyvsp[(5) - (7)].decl), 0, true );
@@ -6398,5 +6429,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1188 "parser.yy"
+#line 1194 "parser.yy"
     { (yyval.decl) = DeclarationNode::newTuple( (yyvsp[(3) - (5)].decl) ); }
     break;
@@ -6405,5 +6436,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1192 "parser.yy"
+#line 1198 "parser.yy"
     { (yyval.decl) = DeclarationNode::newTuple( (yyvsp[(3) - (9)].decl)->appendList( (yyvsp[(7) - (9)].decl) ) ); }
     break;
@@ -6412,5 +6443,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1197 "parser.yy"
+#line 1203 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::TD );
@@ -6422,5 +6453,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1202 "parser.yy"
+#line 1208 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::TD );
@@ -6432,5 +6463,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1207 "parser.yy"
+#line 1213 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(5) - (5)].tok), TypedefTable::TD );
@@ -6442,5 +6473,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1218 "parser.yy"
+#line 1224 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::TD );
@@ -6452,5 +6483,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1223 "parser.yy"
+#line 1229 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::TD );
@@ -6462,5 +6493,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1228 "parser.yy"
+#line 1234 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::TD );
@@ -6472,5 +6503,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1233 "parser.yy"
+#line 1239 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::TD );
@@ -6482,5 +6513,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1238 "parser.yy"
+#line 1244 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::TD );
@@ -6492,5 +6523,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1247 "parser.yy"
+#line 1253 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(2) - (4)].tok), TypedefTable::TD );
@@ -6502,5 +6533,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1252 "parser.yy"
+#line 1258 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(5) - (7)].tok), TypedefTable::TD );
@@ -6512,5 +6543,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1269 "parser.yy"
+#line 1275 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6522,5 +6553,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1274 "parser.yy"
+#line 1280 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -6532,5 +6563,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1296 "parser.yy"
+#line 1302 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -6539,5 +6570,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1308 "parser.yy"
+#line 1314 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6546,5 +6577,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1319 "parser.yy"
+#line 1325 "parser.yy"
     { (yyval.decl) = DeclarationNode::newQualifier( DeclarationNode::Const ); }
     break;
@@ -6553,5 +6584,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1321 "parser.yy"
+#line 1327 "parser.yy"
     { (yyval.decl) = DeclarationNode::newQualifier( DeclarationNode::Restrict ); }
     break;
@@ -6560,5 +6591,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1323 "parser.yy"
+#line 1329 "parser.yy"
     { (yyval.decl) = DeclarationNode::newQualifier( DeclarationNode::Volatile ); }
     break;
@@ -6567,5 +6598,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1325 "parser.yy"
+#line 1331 "parser.yy"
     { (yyval.decl) = DeclarationNode::newQualifier( DeclarationNode::Lvalue ); }
     break;
@@ -6574,5 +6605,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1327 "parser.yy"
+#line 1333 "parser.yy"
     { (yyval.decl) = DeclarationNode::newQualifier( DeclarationNode::Atomic ); }
     break;
@@ -6581,5 +6612,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1329 "parser.yy"
+#line 1335 "parser.yy"
     {
 			typedefTable.enterScope();
@@ -6590,5 +6621,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1333 "parser.yy"
+#line 1339 "parser.yy"
     {
 			typedefTable.leaveScope();
@@ -6600,5 +6631,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1342 "parser.yy"
+#line 1348 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6607,5 +6638,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1344 "parser.yy"
+#line 1350 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->addQualifiers( (yyvsp[(2) - (3)].decl) )->addQualifiers( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -6614,5 +6645,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1355 "parser.yy"
+#line 1361 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6621,5 +6652,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1360 "parser.yy"
+#line 1366 "parser.yy"
     { (yyval.decl) = DeclarationNode::newStorageClass( DeclarationNode::Extern ); }
     break;
@@ -6628,5 +6659,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1362 "parser.yy"
+#line 1368 "parser.yy"
     { (yyval.decl) = DeclarationNode::newStorageClass( DeclarationNode::Static ); }
     break;
@@ -6635,5 +6666,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1364 "parser.yy"
+#line 1370 "parser.yy"
     { (yyval.decl) = DeclarationNode::newStorageClass( DeclarationNode::Auto ); }
     break;
@@ -6642,5 +6673,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1366 "parser.yy"
+#line 1372 "parser.yy"
     { (yyval.decl) = DeclarationNode::newStorageClass( DeclarationNode::Register ); }
     break;
@@ -6649,5 +6680,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1369 "parser.yy"
+#line 1375 "parser.yy"
     { (yyval.decl) = new DeclarationNode; (yyval.decl)->isInline = true; }
     break;
@@ -6656,5 +6687,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1371 "parser.yy"
+#line 1377 "parser.yy"
     { (yyval.decl) = DeclarationNode::newStorageClass( DeclarationNode::Fortran ); }
     break;
@@ -6663,5 +6694,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1374 "parser.yy"
+#line 1380 "parser.yy"
     { (yyval.decl) = new DeclarationNode; (yyval.decl)->isNoreturn = true; }
     break;
@@ -6670,5 +6701,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1376 "parser.yy"
+#line 1382 "parser.yy"
     { (yyval.decl) = DeclarationNode::newStorageClass( DeclarationNode::Threadlocal ); }
     break;
@@ -6677,5 +6708,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1381 "parser.yy"
+#line 1387 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Char ); }
     break;
@@ -6684,5 +6715,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1383 "parser.yy"
+#line 1389 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Double ); }
     break;
@@ -6691,5 +6722,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1385 "parser.yy"
+#line 1391 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Float ); }
     break;
@@ -6698,5 +6729,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1387 "parser.yy"
+#line 1393 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Int ); }
     break;
@@ -6705,5 +6736,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1389 "parser.yy"
+#line 1395 "parser.yy"
     { (yyval.decl) = DeclarationNode::newLength( DeclarationNode::Long ); }
     break;
@@ -6712,5 +6743,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1391 "parser.yy"
+#line 1397 "parser.yy"
     { (yyval.decl) = DeclarationNode::newLength( DeclarationNode::Short ); }
     break;
@@ -6719,5 +6750,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1393 "parser.yy"
+#line 1399 "parser.yy"
     { (yyval.decl) = DeclarationNode::newSignedNess( DeclarationNode::Signed ); }
     break;
@@ -6726,5 +6757,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1395 "parser.yy"
+#line 1401 "parser.yy"
     { (yyval.decl) = DeclarationNode::newSignedNess( DeclarationNode::Unsigned ); }
     break;
@@ -6733,5 +6764,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1397 "parser.yy"
+#line 1403 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Void ); }
     break;
@@ -6740,5 +6771,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1399 "parser.yy"
+#line 1405 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Bool ); }
     break;
@@ -6747,5 +6778,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1401 "parser.yy"
+#line 1407 "parser.yy"
     { (yyval.decl) = DeclarationNode::newComplexType( DeclarationNode::Complex ); }
     break;
@@ -6754,5 +6785,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1403 "parser.yy"
+#line 1409 "parser.yy"
     { (yyval.decl) = DeclarationNode::newComplexType( DeclarationNode::Imaginary ); }
     break;
@@ -6761,5 +6792,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1405 "parser.yy"
+#line 1411 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBuiltinType( DeclarationNode::Valist ); }
     break;
@@ -6768,5 +6799,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1407 "parser.yy"
+#line 1413 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Char ); }
     break;
@@ -6775,5 +6806,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1409 "parser.yy"
+#line 1415 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBasicType( DeclarationNode::Char ); }
     break;
@@ -6782,5 +6813,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1416 "parser.yy"
+#line 1422 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -6789,5 +6820,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1418 "parser.yy"
+#line 1424 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6796,5 +6827,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1420 "parser.yy"
+#line 1426 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->addQualifiers( (yyvsp[(2) - (3)].decl) )->addQualifiers( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -6803,5 +6834,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1422 "parser.yy"
+#line 1428 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addQualifiers( (yyvsp[(2) - (3)].decl) )->addType( (yyvsp[(1) - (3)].decl) ); }
     break;
@@ -6810,5 +6841,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1428 "parser.yy"
+#line 1434 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl)->addQualifiers( (yyvsp[(1) - (3)].decl) )->addQualifiers( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -6817,5 +6848,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1435 "parser.yy"
+#line 1441 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -6824,5 +6855,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1437 "parser.yy"
+#line 1443 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6831,5 +6862,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1439 "parser.yy"
+#line 1445 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addType( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6838,5 +6869,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1444 "parser.yy"
+#line 1450 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (4)].decl); }
     break;
@@ -6845,5 +6876,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1446 "parser.yy"
+#line 1452 "parser.yy"
     { (yyval.decl) = DeclarationNode::newTypeof( (yyvsp[(3) - (4)].en) ); }
     break;
@@ -6852,5 +6883,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1448 "parser.yy"
+#line 1454 "parser.yy"
     { (yyval.decl) = DeclarationNode::newAttr( (yyvsp[(1) - (4)].tok), (yyvsp[(3) - (4)].decl) ); }
     break;
@@ -6859,5 +6890,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1450 "parser.yy"
+#line 1456 "parser.yy"
     { (yyval.decl) = DeclarationNode::newAttr( (yyvsp[(1) - (4)].tok), (yyvsp[(3) - (4)].en) ); }
     break;
@@ -6866,5 +6897,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1456 "parser.yy"
+#line 1462 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -6873,5 +6904,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1458 "parser.yy"
+#line 1464 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6880,5 +6911,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1460 "parser.yy"
+#line 1466 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->addQualifiers( (yyvsp[(2) - (3)].decl) )->addQualifiers( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -6887,5 +6918,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1466 "parser.yy"
+#line 1472 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -6894,5 +6925,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1468 "parser.yy"
+#line 1474 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6901,5 +6932,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1474 "parser.yy"
+#line 1480 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -6908,5 +6939,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1476 "parser.yy"
+#line 1482 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6915,5 +6946,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1478 "parser.yy"
+#line 1484 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->addQualifiers( (yyvsp[(2) - (3)].decl) )->addQualifiers( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -6922,5 +6953,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1483 "parser.yy"
+#line 1489 "parser.yy"
     { (yyval.decl) = DeclarationNode::newFromTypedef( (yyvsp[(1) - (1)].tok) ); }
     break;
@@ -6929,5 +6960,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1485 "parser.yy"
+#line 1491 "parser.yy"
     { (yyval.decl) = DeclarationNode::newFromTypedef( (yyvsp[(2) - (2)].tok) )->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -6936,5 +6967,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1487 "parser.yy"
+#line 1493 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -6943,5 +6974,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1497 "parser.yy"
+#line 1503 "parser.yy"
     { (yyval.decl) = DeclarationNode::newAggregate( (yyvsp[(1) - (4)].aggKey), nullptr, nullptr, (yyvsp[(3) - (4)].decl), true ); }
     break;
@@ -6950,5 +6981,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1499 "parser.yy"
+#line 1505 "parser.yy"
     {
 			typedefTable.makeTypedef( *(yyvsp[(2) - (2)].tok) );
@@ -6960,5 +6991,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1504 "parser.yy"
+#line 1510 "parser.yy"
     { typedefTable.makeTypedef( *(yyvsp[(2) - (2)].tok) ); }
     break;
@@ -6967,5 +6998,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1506 "parser.yy"
+#line 1512 "parser.yy"
     { (yyval.decl) = DeclarationNode::newAggregate( (yyvsp[(1) - (6)].aggKey), (yyvsp[(2) - (6)].tok), nullptr, (yyvsp[(5) - (6)].decl), true ); }
     break;
@@ -6974,5 +7005,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1508 "parser.yy"
+#line 1514 "parser.yy"
     { (yyval.decl) = DeclarationNode::newAggregate( (yyvsp[(1) - (7)].aggKey), nullptr, (yyvsp[(3) - (7)].en), (yyvsp[(6) - (7)].decl), false ); }
     break;
@@ -6981,5 +7012,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1510 "parser.yy"
+#line 1516 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl); }
     break;
@@ -6988,5 +7019,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1515 "parser.yy"
+#line 1521 "parser.yy"
     { (yyval.aggKey) = DeclarationNode::Struct; }
     break;
@@ -6995,5 +7026,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1517 "parser.yy"
+#line 1523 "parser.yy"
     { (yyval.aggKey) = DeclarationNode::Union; }
     break;
@@ -7002,5 +7033,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1522 "parser.yy"
+#line 1528 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7009,5 +7040,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1524 "parser.yy"
+#line 1530 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl) != 0 ? (yyvsp[(1) - (2)].decl)->appendList( (yyvsp[(2) - (2)].decl) ) : (yyvsp[(2) - (2)].decl); }
     break;
@@ -7016,5 +7047,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1530 "parser.yy"
+#line 1536 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl)->set_extension( true ); }
     break;
@@ -7023,5 +7054,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1533 "parser.yy"
+#line 1539 "parser.yy"
     {	// mark all fields in list
 			for ( DeclarationNode *iter = (yyvsp[(2) - (3)].decl); iter != nullptr; iter = (DeclarationNode *)iter->get_next() )
@@ -7034,5 +7065,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1543 "parser.yy"
+#line 1549 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addName( (yyvsp[(2) - (2)].tok) ); }
     break;
@@ -7041,5 +7072,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1545 "parser.yy"
+#line 1551 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(1) - (3)].decl)->cloneType( (yyvsp[(3) - (3)].tok) ) ); }
     break;
@@ -7048,5 +7079,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1547 "parser.yy"
+#line 1553 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->appendList( (yyvsp[(1) - (2)].decl)->cloneType( 0 ) ); }
     break;
@@ -7055,5 +7086,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1552 "parser.yy"
+#line 1558 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addType( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7062,5 +7093,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1554 "parser.yy"
+#line 1560 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (4)].decl)->appendList( (yyvsp[(1) - (4)].decl)->cloneBaseType( (yyvsp[(4) - (4)].decl) ) ); }
     break;
@@ -7069,5 +7100,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1559 "parser.yy"
+#line 1565 "parser.yy"
     { (yyval.decl) = DeclarationNode::newName( 0 ); /* XXX */ }
     break;
@@ -7076,5 +7107,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1561 "parser.yy"
+#line 1567 "parser.yy"
     { (yyval.decl) = DeclarationNode::newBitfield( (yyvsp[(1) - (1)].en) ); }
     break;
@@ -7083,5 +7114,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1564 "parser.yy"
+#line 1570 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addBitfield( (yyvsp[(2) - (2)].en) ); }
     break;
@@ -7090,5 +7121,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1567 "parser.yy"
+#line 1573 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addBitfield( (yyvsp[(2) - (2)].en) ); }
     break;
@@ -7097,5 +7128,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1573 "parser.yy"
+#line 1579 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -7104,5 +7135,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1575 "parser.yy"
+#line 1581 "parser.yy"
     { (yyval.en) = (yyvsp[(1) - (1)].en); }
     break;
@@ -7111,5 +7142,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1580 "parser.yy"
+#line 1586 "parser.yy"
     { (yyval.en) = (yyvsp[(2) - (2)].en); }
     break;
@@ -7118,5 +7149,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1589 "parser.yy"
+#line 1595 "parser.yy"
     { (yyval.decl) = DeclarationNode::newEnum( nullptr, (yyvsp[(3) - (5)].decl) ); }
     break;
@@ -7125,5 +7156,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1591 "parser.yy"
+#line 1597 "parser.yy"
     {
 			typedefTable.makeTypedef( *(yyvsp[(2) - (2)].tok) );
@@ -7135,5 +7166,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1596 "parser.yy"
+#line 1602 "parser.yy"
     { typedefTable.makeTypedef( *(yyvsp[(2) - (2)].tok) ); }
     break;
@@ -7142,5 +7173,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1598 "parser.yy"
+#line 1604 "parser.yy"
     { (yyval.decl) = DeclarationNode::newEnum( (yyvsp[(2) - (7)].tok), (yyvsp[(5) - (7)].decl) ); }
     break;
@@ -7149,5 +7180,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1603 "parser.yy"
+#line 1609 "parser.yy"
     { (yyval.decl) = DeclarationNode::newEnumConstant( (yyvsp[(1) - (2)].tok), (yyvsp[(2) - (2)].en) ); }
     break;
@@ -7156,5 +7187,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1605 "parser.yy"
+#line 1611 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (4)].decl)->appendList( DeclarationNode::newEnumConstant( (yyvsp[(3) - (4)].tok), (yyvsp[(4) - (4)].en) ) ); }
     break;
@@ -7163,5 +7194,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1610 "parser.yy"
+#line 1616 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -7170,5 +7201,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1612 "parser.yy"
+#line 1618 "parser.yy"
     { (yyval.en) = (yyvsp[(2) - (2)].en); }
     break;
@@ -7177,5 +7208,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1619 "parser.yy"
+#line 1625 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7184,5 +7215,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1627 "parser.yy"
+#line 1633 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->appendList( (yyvsp[(5) - (5)].decl) ); }
     break;
@@ -7191,5 +7222,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1629 "parser.yy"
+#line 1635 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->addVarArgs(); }
     break;
@@ -7198,5 +7229,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1631 "parser.yy"
+#line 1637 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->addVarArgs(); }
     break;
@@ -7205,5 +7236,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1639 "parser.yy"
+#line 1645 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->appendList( (yyvsp[(5) - (5)].decl) ); }
     break;
@@ -7212,5 +7243,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1641 "parser.yy"
+#line 1647 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->appendList( (yyvsp[(5) - (5)].decl) ); }
     break;
@@ -7219,5 +7250,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1643 "parser.yy"
+#line 1649 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (9)].decl)->appendList( (yyvsp[(5) - (9)].decl) )->appendList( (yyvsp[(9) - (9)].decl) ); }
     break;
@@ -7226,5 +7257,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1649 "parser.yy"
+#line 1655 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->appendList( (yyvsp[(5) - (5)].decl) ); }
     break;
@@ -7233,5 +7264,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1654 "parser.yy"
+#line 1660 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7240,5 +7271,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1661 "parser.yy"
+#line 1667 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->addVarArgs(); }
     break;
@@ -7247,5 +7278,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1668 "parser.yy"
+#line 1674 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->appendList( (yyvsp[(5) - (5)].decl) ); }
     break;
@@ -7254,5 +7285,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1670 "parser.yy"
+#line 1676 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (5)].decl)->appendList( (yyvsp[(5) - (5)].decl) ); }
     break;
@@ -7261,5 +7292,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1679 "parser.yy"
+#line 1685 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->addName( (yyvsp[(2) - (3)].tok) ); }
     break;
@@ -7268,5 +7299,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1682 "parser.yy"
+#line 1688 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->addName( (yyvsp[(2) - (3)].tok) ); }
     break;
@@ -7275,5 +7306,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1684 "parser.yy"
+#line 1690 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addName( (yyvsp[(3) - (4)].tok) )->addQualifiers( (yyvsp[(1) - (4)].decl) ); }
     break;
@@ -7282,5 +7313,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1694 "parser.yy"
+#line 1700 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7289,5 +7320,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1700 "parser.yy"
+#line 1706 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7299,5 +7330,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1705 "parser.yy"
+#line 1711 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7309,5 +7340,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1714 "parser.yy"
+#line 1720 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addType( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7316,5 +7347,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1723 "parser.yy"
+#line 1729 "parser.yy"
     { (yyval.decl) = DeclarationNode::newName( (yyvsp[(1) - (1)].tok) ); }
     break;
@@ -7323,5 +7354,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1725 "parser.yy"
+#line 1731 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( DeclarationNode::newName( (yyvsp[(3) - (3)].tok) ) ); }
     break;
@@ -7330,5 +7361,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1750 "parser.yy"
+#line 1756 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addType( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7337,5 +7368,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1758 "parser.yy"
+#line 1764 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addType( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7344,5 +7375,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1763 "parser.yy"
+#line 1769 "parser.yy"
     { (yyval.in) = 0; }
     break;
@@ -7351,5 +7382,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1765 "parser.yy"
+#line 1771 "parser.yy"
     { (yyval.in) = (yyvsp[(2) - (2)].in); }
     break;
@@ -7358,5 +7389,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1767 "parser.yy"
+#line 1773 "parser.yy"
     { (yyval.in) = (yyvsp[(2) - (2)].in)->set_maybeConstructed( false ); }
     break;
@@ -7365,5 +7396,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1771 "parser.yy"
+#line 1777 "parser.yy"
     { (yyval.in) = new InitializerNode( (yyvsp[(1) - (1)].en) ); }
     break;
@@ -7372,5 +7403,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1772 "parser.yy"
+#line 1778 "parser.yy"
     { (yyval.in) = new InitializerNode( (yyvsp[(2) - (4)].in), true ); }
     break;
@@ -7379,5 +7410,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1777 "parser.yy"
+#line 1783 "parser.yy"
     { (yyval.in) = 0; }
     break;
@@ -7386,5 +7417,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1779 "parser.yy"
+#line 1785 "parser.yy"
     { (yyval.in) = (yyvsp[(2) - (2)].in)->set_designators( (yyvsp[(1) - (2)].en) ); }
     break;
@@ -7393,5 +7424,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1780 "parser.yy"
+#line 1786 "parser.yy"
     { (yyval.in) = (InitializerNode *)( (yyvsp[(1) - (3)].in)->set_last( (yyvsp[(3) - (3)].in) ) ); }
     break;
@@ -7400,5 +7431,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1782 "parser.yy"
+#line 1788 "parser.yy"
     { (yyval.in) = (InitializerNode *)( (yyvsp[(1) - (4)].in)->set_last( (yyvsp[(4) - (4)].in)->set_designators( (yyvsp[(3) - (4)].en) ) ) ); }
     break;
@@ -7407,5 +7438,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1798 "parser.yy"
+#line 1804 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (2)].tok) ) ); }
     break;
@@ -7414,5 +7445,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1804 "parser.yy"
+#line 1810 "parser.yy"
     { (yyval.en) = (ExpressionNode *)( (yyvsp[(1) - (2)].en)->set_last( (yyvsp[(2) - (2)].en) ) ); }
     break;
@@ -7421,5 +7452,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1810 "parser.yy"
+#line 1816 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(2) - (2)].tok) ) ); }
     break;
@@ -7428,5 +7459,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1813 "parser.yy"
+#line 1819 "parser.yy"
     { (yyval.en) = (yyvsp[(3) - (5)].en); }
     break;
@@ -7435,5 +7466,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1815 "parser.yy"
+#line 1821 "parser.yy"
     { (yyval.en) = (yyvsp[(3) - (5)].en); }
     break;
@@ -7442,5 +7473,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1817 "parser.yy"
+#line 1823 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_range( (yyvsp[(3) - (7)].en), (yyvsp[(5) - (7)].en) ) ); }
     break;
@@ -7449,5 +7480,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1819 "parser.yy"
+#line 1825 "parser.yy"
     { (yyval.en) = (yyvsp[(4) - (6)].en); }
     break;
@@ -7456,5 +7487,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1843 "parser.yy"
+#line 1849 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7463,5 +7494,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1845 "parser.yy"
+#line 1851 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -7470,5 +7501,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1847 "parser.yy"
+#line 1853 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->addQualifiers( (yyvsp[(2) - (3)].decl) )->addQualifiers( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -7477,5 +7508,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1853 "parser.yy"
+#line 1859 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7484,5 +7515,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1855 "parser.yy"
+#line 1861 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -7491,5 +7522,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1860 "parser.yy"
+#line 1866 "parser.yy"
     { (yyval.decl) = DeclarationNode::newFromTypeGen( (yyvsp[(1) - (4)].tok), (yyvsp[(3) - (4)].en) ); }
     break;
@@ -7498,5 +7529,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1866 "parser.yy"
+#line 1872 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (4)].decl)->appendList( (yyvsp[(3) - (4)].decl) ); }
     break;
@@ -7505,5 +7536,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1871 "parser.yy"
+#line 1877 "parser.yy"
     { typedefTable.addToEnclosingScope( *(yyvsp[(2) - (2)].tok), TypedefTable::TD ); }
     break;
@@ -7512,5 +7543,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1873 "parser.yy"
+#line 1879 "parser.yy"
     { (yyval.decl) = DeclarationNode::newTypeParam( (yyvsp[(1) - (4)].tclass), (yyvsp[(2) - (4)].tok) )->addAssertions( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -7519,5 +7550,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1879 "parser.yy"
+#line 1885 "parser.yy"
     { (yyval.tclass) = DeclarationNode::Otype; }
     break;
@@ -7526,5 +7557,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1881 "parser.yy"
+#line 1887 "parser.yy"
     { (yyval.tclass) = DeclarationNode::Ftype; }
     break;
@@ -7533,5 +7564,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1883 "parser.yy"
+#line 1889 "parser.yy"
     { (yyval.tclass) = DeclarationNode::Dtype; }
     break;
@@ -7540,5 +7571,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1888 "parser.yy"
+#line 1894 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7547,5 +7578,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1890 "parser.yy"
+#line 1896 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl) != 0 ? (yyvsp[(1) - (2)].decl)->appendList( (yyvsp[(2) - (2)].decl) ) : (yyvsp[(2) - (2)].decl); }
     break;
@@ -7554,5 +7585,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1895 "parser.yy"
+#line 1901 "parser.yy"
     {
 			typedefTable.openTrait( *(yyvsp[(2) - (5)].tok) );
@@ -7564,5 +7595,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1900 "parser.yy"
+#line 1906 "parser.yy"
     { (yyval.decl) = (yyvsp[(4) - (5)].decl); }
     break;
@@ -7571,5 +7602,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1902 "parser.yy"
+#line 1908 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7578,5 +7609,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1907 "parser.yy"
+#line 1913 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_typevalue( (yyvsp[(1) - (1)].decl) ) ); }
     break;
@@ -7585,5 +7616,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1910 "parser.yy"
+#line 1916 "parser.yy"
     { (yyval.en) = (ExpressionNode *)( (yyvsp[(1) - (3)].en)->set_last( new ExpressionNode( build_typevalue( (yyvsp[(3) - (3)].decl) ) ) ) ); }
     break;
@@ -7592,5 +7623,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1912 "parser.yy"
+#line 1918 "parser.yy"
     { (yyval.en) = (ExpressionNode *)( (yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) )); }
     break;
@@ -7599,5 +7630,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1917 "parser.yy"
+#line 1923 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl); }
     break;
@@ -7606,5 +7637,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1919 "parser.yy"
+#line 1925 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addQualifiers( (yyvsp[(1) - (3)].decl) ); }
     break;
@@ -7613,5 +7644,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1921 "parser.yy"
+#line 1927 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(3) - (3)].decl)->copyStorageClasses( (yyvsp[(1) - (3)].decl) ) ); }
     break;
@@ -7620,5 +7651,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1926 "parser.yy"
+#line 1932 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addAssertions( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -7627,5 +7658,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1928 "parser.yy"
+#line 1934 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (4)].decl)->addAssertions( (yyvsp[(2) - (4)].decl) )->addType( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -7634,5 +7665,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1933 "parser.yy"
+#line 1939 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(1) - (1)].tok), TypedefTable::TD );
@@ -7644,5 +7675,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1938 "parser.yy"
+#line 1944 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(1) - (6)].tok), TypedefTable::TG );
@@ -7654,5 +7685,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1946 "parser.yy"
+#line 1952 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( *(yyvsp[(2) - (9)].tok), TypedefTable::ID );
@@ -7664,5 +7695,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1951 "parser.yy"
+#line 1957 "parser.yy"
     {
 			typedefTable.enterTrait( *(yyvsp[(2) - (8)].tok) );
@@ -7674,5 +7705,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1956 "parser.yy"
+#line 1962 "parser.yy"
     {
 			typedefTable.leaveTrait();
@@ -7685,5 +7716,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1966 "parser.yy"
+#line 1972 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -7692,5 +7723,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1976 "parser.yy"
+#line 1982 "parser.yy"
     {
 			typedefTable.addToEnclosingScope2( TypedefTable::ID );
@@ -7702,5 +7733,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1981 "parser.yy"
+#line 1987 "parser.yy"
     {
 			typedefTable.addToEnclosingScope2( TypedefTable::ID );
@@ -7712,5 +7743,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1986 "parser.yy"
+#line 1992 "parser.yy"
     {
 			typedefTable.addToEnclosingScope2( *(yyvsp[(5) - (5)].tok), TypedefTable::ID );
@@ -7722,5 +7753,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1994 "parser.yy"
+#line 2000 "parser.yy"
     {
 			typedefTable.addToEnclosingScope2( TypedefTable::ID );
@@ -7732,5 +7763,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 1999 "parser.yy"
+#line 2005 "parser.yy"
     {
 			typedefTable.addToEnclosingScope2( TypedefTable::ID );
@@ -7742,5 +7773,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2009 "parser.yy"
+#line 2015 "parser.yy"
     {}
     break;
@@ -7749,5 +7780,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2011 "parser.yy"
+#line 2017 "parser.yy"
     { parseTree = parseTree != nullptr ? parseTree->appendList( (yyvsp[(1) - (1)].decl) ) : (yyvsp[(1) - (1)].decl);	}
     break;
@@ -7756,5 +7787,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2017 "parser.yy"
+#line 2023 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (3)].decl) != nullptr ? (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(3) - (3)].decl) ) : (yyvsp[(3) - (3)].decl); }
     break;
@@ -7763,5 +7794,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2022 "parser.yy"
+#line 2028 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7770,5 +7801,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2030 "parser.yy"
+#line 2036 "parser.yy"
     {}
     break;
@@ -7777,5 +7808,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2032 "parser.yy"
+#line 2038 "parser.yy"
     {
 			linkageStack.push( linkage );				// handle nested extern "C"/"Cforall"
@@ -7787,5 +7818,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2037 "parser.yy"
+#line 2043 "parser.yy"
     {
 			linkage = linkageStack.top();
@@ -7798,5 +7829,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2043 "parser.yy"
+#line 2049 "parser.yy"
     {	// mark all fields in list
 			for ( DeclarationNode *iter = (yyvsp[(2) - (2)].decl); iter != nullptr; iter = (DeclarationNode *)iter->get_next() )
@@ -7809,5 +7840,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2058 "parser.yy"
+#line 2064 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7820,5 +7851,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2064 "parser.yy"
+#line 2070 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7831,5 +7862,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2073 "parser.yy"
+#line 2079 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7842,5 +7873,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2079 "parser.yy"
+#line 2085 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7851,15 +7882,4 @@
 
   case 540:
-
-/* Line 1806 of yacc.c  */
-#line 2085 "parser.yy"
-    {
-			typedefTable.addToEnclosingScope( TypedefTable::ID );
-			typedefTable.leaveScope();
-			(yyval.decl) = (yyvsp[(2) - (3)].decl)->addFunctionBody( (yyvsp[(3) - (3)].sn) )->addQualifiers( (yyvsp[(1) - (3)].decl) );
-		}
-    break;
-
-  case 541:
 
 /* Line 1806 of yacc.c  */
@@ -7872,8 +7892,19 @@
     break;
 
+  case 541:
+
+/* Line 1806 of yacc.c  */
+#line 2097 "parser.yy"
+    {
+			typedefTable.addToEnclosingScope( TypedefTable::ID );
+			typedefTable.leaveScope();
+			(yyval.decl) = (yyvsp[(2) - (3)].decl)->addFunctionBody( (yyvsp[(3) - (3)].sn) )->addQualifiers( (yyvsp[(1) - (3)].decl) );
+		}
+    break;
+
   case 542:
 
 /* Line 1806 of yacc.c  */
-#line 2097 "parser.yy"
+#line 2103 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7886,5 +7917,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2105 "parser.yy"
+#line 2111 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7897,5 +7928,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2111 "parser.yy"
+#line 2117 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7908,5 +7939,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2119 "parser.yy"
+#line 2125 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7919,5 +7950,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2125 "parser.yy"
+#line 2131 "parser.yy"
     {
 			typedefTable.addToEnclosingScope( TypedefTable::ID );
@@ -7930,5 +7961,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2140 "parser.yy"
+#line 2146 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_range( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); }
     break;
@@ -7937,5 +7968,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2145 "parser.yy"
+#line 2151 "parser.yy"
     { delete (yyvsp[(3) - (5)].str); }
     break;
@@ -7944,5 +7975,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2150 "parser.yy"
+#line 2156 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7951,5 +7982,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2157 "parser.yy"
+#line 2163 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -7958,5 +7989,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2163 "parser.yy"
+#line 2169 "parser.yy"
     { (yyval.decl) = 0; }
     break;
@@ -7965,5 +7996,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2174 "parser.yy"
+#line 2180 "parser.yy"
     { delete (yyvsp[(3) - (4)].en); }
     break;
@@ -7972,5 +8003,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2178 "parser.yy"
+#line 2184 "parser.yy"
     { delete (yyvsp[(1) - (1)].tok); }
     break;
@@ -7979,5 +8010,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2179 "parser.yy"
+#line 2185 "parser.yy"
     { delete (yyvsp[(1) - (1)].decl); }
     break;
@@ -7986,5 +8017,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2180 "parser.yy"
+#line 2186 "parser.yy"
     { delete (yyvsp[(1) - (1)].decl); }
     break;
@@ -7993,5 +8024,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2181 "parser.yy"
+#line 2187 "parser.yy"
     { delete (yyvsp[(1) - (1)].decl); }
     break;
@@ -8000,5 +8031,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2216 "parser.yy"
+#line 2222 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8007,5 +8038,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2219 "parser.yy"
+#line 2225 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8014,5 +8045,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2221 "parser.yy"
+#line 2227 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8021,5 +8052,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2226 "parser.yy"
+#line 2232 "parser.yy"
     {
 			typedefTable.setNextIdentifier( *(yyvsp[(1) - (1)].tok) );
@@ -8031,5 +8062,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2231 "parser.yy"
+#line 2237 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8038,5 +8069,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2236 "parser.yy"
+#line 2242 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8045,5 +8076,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2238 "parser.yy"
+#line 2244 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8052,5 +8083,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2240 "parser.yy"
+#line 2246 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8059,5 +8090,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2245 "parser.yy"
+#line 2251 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addArray( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8066,5 +8097,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2247 "parser.yy"
+#line 2253 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8073,5 +8104,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2249 "parser.yy"
+#line 2255 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8080,5 +8111,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2251 "parser.yy"
+#line 2257 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8087,5 +8118,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2256 "parser.yy"
+#line 2262 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8094,5 +8125,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2258 "parser.yy"
+#line 2264 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8101,5 +8132,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2267 "parser.yy"
+#line 2273 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8108,5 +8139,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2270 "parser.yy"
+#line 2276 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8115,5 +8146,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2275 "parser.yy"
+#line 2281 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (6)].decl)->addParamList( (yyvsp[(4) - (6)].decl) ); }
     break;
@@ -8122,5 +8153,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2277 "parser.yy"
+#line 2283 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8129,5 +8160,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2279 "parser.yy"
+#line 2285 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8136,5 +8167,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2284 "parser.yy"
+#line 2290 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8143,5 +8174,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2286 "parser.yy"
+#line 2292 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8150,5 +8181,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2288 "parser.yy"
+#line 2294 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8157,5 +8188,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2293 "parser.yy"
+#line 2299 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8164,5 +8195,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2295 "parser.yy"
+#line 2301 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8171,5 +8202,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2297 "parser.yy"
+#line 2303 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8178,5 +8209,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2312 "parser.yy"
+#line 2318 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (4)].decl)->addIdList( (yyvsp[(3) - (4)].decl) ); }
     break;
@@ -8185,5 +8216,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2314 "parser.yy"
+#line 2320 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (6)].decl)->addIdList( (yyvsp[(5) - (6)].decl) ); }
     break;
@@ -8192,5 +8223,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2316 "parser.yy"
+#line 2322 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8199,5 +8230,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2321 "parser.yy"
+#line 2327 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8206,5 +8237,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2323 "parser.yy"
+#line 2329 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8213,5 +8244,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2325 "parser.yy"
+#line 2331 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8220,5 +8251,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2330 "parser.yy"
+#line 2336 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8227,5 +8258,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2332 "parser.yy"
+#line 2338 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8234,5 +8265,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2334 "parser.yy"
+#line 2340 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8241,5 +8272,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2349 "parser.yy"
+#line 2355 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8248,5 +8279,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2352 "parser.yy"
+#line 2358 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8255,5 +8286,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2354 "parser.yy"
+#line 2360 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8262,5 +8293,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2360 "parser.yy"
+#line 2366 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8269,5 +8300,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2365 "parser.yy"
+#line 2371 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8276,5 +8307,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2367 "parser.yy"
+#line 2373 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8283,5 +8314,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2369 "parser.yy"
+#line 2375 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8290,5 +8321,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2374 "parser.yy"
+#line 2380 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addArray( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8297,5 +8328,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2376 "parser.yy"
+#line 2382 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8304,5 +8335,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2378 "parser.yy"
+#line 2384 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8311,5 +8342,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2380 "parser.yy"
+#line 2386 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8318,5 +8349,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2385 "parser.yy"
+#line 2391 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (6)].decl)->addParamList( (yyvsp[(4) - (6)].decl) ); }
     break;
@@ -8325,5 +8356,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2387 "parser.yy"
+#line 2393 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8332,5 +8363,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2389 "parser.yy"
+#line 2395 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8339,5 +8370,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2399 "parser.yy"
+#line 2405 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8346,5 +8377,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2402 "parser.yy"
+#line 2408 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8353,5 +8384,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2404 "parser.yy"
+#line 2410 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8360,5 +8391,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2409 "parser.yy"
+#line 2415 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8367,5 +8398,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2411 "parser.yy"
+#line 2417 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8374,5 +8405,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2413 "parser.yy"
+#line 2419 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8381,5 +8412,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2418 "parser.yy"
+#line 2424 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addArray( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8388,5 +8419,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2420 "parser.yy"
+#line 2426 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8395,5 +8426,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2422 "parser.yy"
+#line 2428 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8402,5 +8433,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2424 "parser.yy"
+#line 2430 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8409,5 +8440,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2429 "parser.yy"
+#line 2435 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (6)].decl)->addParamList( (yyvsp[(4) - (6)].decl) ); }
     break;
@@ -8416,5 +8447,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2431 "parser.yy"
+#line 2437 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8423,5 +8454,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2433 "parser.yy"
+#line 2439 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8430,5 +8461,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2464 "parser.yy"
+#line 2470 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8437,5 +8468,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2467 "parser.yy"
+#line 2473 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8444,5 +8475,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2469 "parser.yy"
+#line 2475 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8451,5 +8482,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2474 "parser.yy"
+#line 2480 "parser.yy"
     {
 			typedefTable.setNextIdentifier( *(yyvsp[(1) - (1)].tok) );
@@ -8461,5 +8492,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2479 "parser.yy"
+#line 2485 "parser.yy"
     {
 			typedefTable.setNextIdentifier( *(yyvsp[(1) - (1)].tok) );
@@ -8471,5 +8502,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2487 "parser.yy"
+#line 2493 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8478,5 +8509,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2489 "parser.yy"
+#line 2495 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8485,5 +8516,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2491 "parser.yy"
+#line 2497 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8492,5 +8523,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2496 "parser.yy"
+#line 2502 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addArray( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8499,5 +8530,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2498 "parser.yy"
+#line 2504 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8506,5 +8537,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2503 "parser.yy"
+#line 2509 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (6)].decl)->addParamList( (yyvsp[(4) - (6)].decl) ); }
     break;
@@ -8513,5 +8544,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2505 "parser.yy"
+#line 2511 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8520,5 +8551,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2520 "parser.yy"
+#line 2526 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8527,5 +8558,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2522 "parser.yy"
+#line 2528 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8534,5 +8565,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2527 "parser.yy"
+#line 2533 "parser.yy"
     { (yyval.decl) = DeclarationNode::newPointer( 0 ); }
     break;
@@ -8541,5 +8572,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2529 "parser.yy"
+#line 2535 "parser.yy"
     { (yyval.decl) = DeclarationNode::newPointer( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8548,5 +8579,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2531 "parser.yy"
+#line 2537 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8555,5 +8586,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2533 "parser.yy"
+#line 2539 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8562,5 +8593,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2535 "parser.yy"
+#line 2541 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8569,5 +8600,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2541 "parser.yy"
+#line 2547 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8576,5 +8607,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2543 "parser.yy"
+#line 2549 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8583,5 +8614,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2545 "parser.yy"
+#line 2551 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8590,5 +8621,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2550 "parser.yy"
+#line 2556 "parser.yy"
     { (yyval.decl) = DeclarationNode::newFunction( nullptr, nullptr, (yyvsp[(3) - (5)].decl), nullptr ); }
     break;
@@ -8597,5 +8628,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2552 "parser.yy"
+#line 2558 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8604,5 +8635,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2554 "parser.yy"
+#line 2560 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8611,5 +8642,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2560 "parser.yy"
+#line 2566 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( 0, 0, false ); }
     break;
@@ -8618,5 +8649,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2562 "parser.yy"
+#line 2568 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( 0, 0, false )->addArray( (yyvsp[(3) - (3)].decl) ); }
     break;
@@ -8625,5 +8656,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2568 "parser.yy"
+#line 2574 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( (yyvsp[(3) - (5)].en), 0, false ); }
     break;
@@ -8632,5 +8663,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2570 "parser.yy"
+#line 2576 "parser.yy"
     { (yyval.decl) = DeclarationNode::newVarArray( 0 ); }
     break;
@@ -8639,5 +8670,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2572 "parser.yy"
+#line 2578 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (6)].decl)->addArray( DeclarationNode::newArray( (yyvsp[(4) - (6)].en), 0, false ) ); }
     break;
@@ -8646,5 +8677,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2574 "parser.yy"
+#line 2580 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (6)].decl)->addArray( DeclarationNode::newVarArray( 0 ) ); }
     break;
@@ -8653,5 +8684,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2589 "parser.yy"
+#line 2595 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8660,5 +8691,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2591 "parser.yy"
+#line 2597 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8667,5 +8698,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2596 "parser.yy"
+#line 2602 "parser.yy"
     { (yyval.decl) = DeclarationNode::newPointer( 0 ); }
     break;
@@ -8674,5 +8705,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2598 "parser.yy"
+#line 2604 "parser.yy"
     { (yyval.decl) = DeclarationNode::newPointer( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8681,5 +8712,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2600 "parser.yy"
+#line 2606 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8688,5 +8719,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2602 "parser.yy"
+#line 2608 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8695,5 +8726,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2604 "parser.yy"
+#line 2610 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8702,5 +8733,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2610 "parser.yy"
+#line 2616 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8709,5 +8740,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2612 "parser.yy"
+#line 2618 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8716,5 +8747,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2614 "parser.yy"
+#line 2620 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8723,5 +8754,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2619 "parser.yy"
+#line 2625 "parser.yy"
     { (yyval.decl) = DeclarationNode::newFunction( nullptr, nullptr, (yyvsp[(3) - (5)].decl), nullptr ); }
     break;
@@ -8730,5 +8761,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2621 "parser.yy"
+#line 2627 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8737,5 +8768,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2623 "parser.yy"
+#line 2629 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8744,5 +8775,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2630 "parser.yy"
+#line 2636 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addArray( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8751,5 +8782,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2641 "parser.yy"
+#line 2647 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( 0, 0, false ); }
     break;
@@ -8758,5 +8789,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2644 "parser.yy"
+#line 2650 "parser.yy"
     { (yyval.decl) = DeclarationNode::newVarArray( (yyvsp[(3) - (6)].decl) ); }
     break;
@@ -8765,5 +8796,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2646 "parser.yy"
+#line 2652 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( 0, (yyvsp[(3) - (5)].decl), false ); }
     break;
@@ -8772,5 +8803,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2649 "parser.yy"
+#line 2655 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( (yyvsp[(4) - (6)].en), (yyvsp[(3) - (6)].decl), false ); }
     break;
@@ -8779,5 +8810,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2651 "parser.yy"
+#line 2657 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( (yyvsp[(5) - (7)].en), (yyvsp[(4) - (7)].decl), true ); }
     break;
@@ -8786,5 +8817,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2653 "parser.yy"
+#line 2659 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( (yyvsp[(5) - (7)].en), (yyvsp[(3) - (7)].decl), true ); }
     break;
@@ -8793,5 +8824,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2667 "parser.yy"
+#line 2673 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8800,5 +8831,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2669 "parser.yy"
+#line 2675 "parser.yy"
     { (yyval.decl) = (yyvsp[(1) - (2)].decl)->addQualifiers( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8807,5 +8838,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2674 "parser.yy"
+#line 2680 "parser.yy"
     { (yyval.decl) = DeclarationNode::newPointer( 0 ); }
     break;
@@ -8814,5 +8845,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2676 "parser.yy"
+#line 2682 "parser.yy"
     { (yyval.decl) = DeclarationNode::newPointer( (yyvsp[(2) - (2)].decl) ); }
     break;
@@ -8821,5 +8852,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2678 "parser.yy"
+#line 2684 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8828,5 +8859,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2680 "parser.yy"
+#line 2686 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addPointer( DeclarationNode::newPointer( (yyvsp[(2) - (3)].decl) ) ); }
     break;
@@ -8835,5 +8866,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2682 "parser.yy"
+#line 2688 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8842,5 +8873,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2688 "parser.yy"
+#line 2694 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8849,5 +8880,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2690 "parser.yy"
+#line 2696 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (4)].decl)->addArray( (yyvsp[(4) - (4)].decl) ); }
     break;
@@ -8856,5 +8887,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2692 "parser.yy"
+#line 2698 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8863,5 +8894,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2697 "parser.yy"
+#line 2703 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (8)].decl)->addParamList( (yyvsp[(6) - (8)].decl) ); }
     break;
@@ -8870,5 +8901,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2699 "parser.yy"
+#line 2705 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (3)].decl); }
     break;
@@ -8877,5 +8908,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2709 "parser.yy"
+#line 2715 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -8884,5 +8915,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2719 "parser.yy"
+#line 2725 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8891,5 +8922,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2721 "parser.yy"
+#line 2727 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewPointer( DeclarationNode::newPointer( (yyvsp[(1) - (3)].decl) ) ); }
     break;
@@ -8898,5 +8929,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2723 "parser.yy"
+#line 2729 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8905,5 +8936,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2725 "parser.yy"
+#line 2731 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewPointer( DeclarationNode::newPointer( (yyvsp[(1) - (3)].decl) ) ); }
     break;
@@ -8912,5 +8943,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2727 "parser.yy"
+#line 2733 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -8919,5 +8950,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2729 "parser.yy"
+#line 2735 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewPointer( DeclarationNode::newPointer( (yyvsp[(1) - (3)].decl) ) ); }
     break;
@@ -8926,30 +8957,9 @@
 
 /* Line 1806 of yacc.c  */
-#line 2736 "parser.yy"
+#line 2742 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
     break;
 
   case 721:
-
-/* Line 1806 of yacc.c  */
-#line 2738 "parser.yy"
-    { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewArray( (yyvsp[(1) - (2)].decl) ); }
-    break;
-
-  case 722:
-
-/* Line 1806 of yacc.c  */
-#line 2740 "parser.yy"
-    { (yyval.decl) = (yyvsp[(4) - (4)].decl)->addNewArray( (yyvsp[(3) - (4)].decl) )->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
-    break;
-
-  case 723:
-
-/* Line 1806 of yacc.c  */
-#line 2742 "parser.yy"
-    { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( (yyvsp[(2) - (3)].decl) )->addNewArray( (yyvsp[(1) - (3)].decl) ); }
-    break;
-
-  case 724:
 
 /* Line 1806 of yacc.c  */
@@ -8958,33 +8968,33 @@
     break;
 
+  case 722:
+
+/* Line 1806 of yacc.c  */
+#line 2746 "parser.yy"
+    { (yyval.decl) = (yyvsp[(4) - (4)].decl)->addNewArray( (yyvsp[(3) - (4)].decl) )->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
+    break;
+
+  case 723:
+
+/* Line 1806 of yacc.c  */
+#line 2748 "parser.yy"
+    { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( (yyvsp[(2) - (3)].decl) )->addNewArray( (yyvsp[(1) - (3)].decl) ); }
+    break;
+
+  case 724:
+
+/* Line 1806 of yacc.c  */
+#line 2750 "parser.yy"
+    { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewArray( (yyvsp[(1) - (2)].decl) ); }
+    break;
+
   case 725:
 
 /* Line 1806 of yacc.c  */
-#line 2747 "parser.yy"
+#line 2753 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
     break;
 
   case 726:
-
-/* Line 1806 of yacc.c  */
-#line 2749 "parser.yy"
-    { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewArray( (yyvsp[(1) - (2)].decl) ); }
-    break;
-
-  case 727:
-
-/* Line 1806 of yacc.c  */
-#line 2751 "parser.yy"
-    { (yyval.decl) = (yyvsp[(4) - (4)].decl)->addNewArray( (yyvsp[(3) - (4)].decl) )->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
-    break;
-
-  case 728:
-
-/* Line 1806 of yacc.c  */
-#line 2753 "parser.yy"
-    { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( (yyvsp[(2) - (3)].decl) )->addNewArray( (yyvsp[(1) - (3)].decl) ); }
-    break;
-
-  case 729:
 
 /* Line 1806 of yacc.c  */
@@ -8993,8 +9003,29 @@
     break;
 
+  case 727:
+
+/* Line 1806 of yacc.c  */
+#line 2757 "parser.yy"
+    { (yyval.decl) = (yyvsp[(4) - (4)].decl)->addNewArray( (yyvsp[(3) - (4)].decl) )->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
+    break;
+
+  case 728:
+
+/* Line 1806 of yacc.c  */
+#line 2759 "parser.yy"
+    { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( (yyvsp[(2) - (3)].decl) )->addNewArray( (yyvsp[(1) - (3)].decl) ); }
+    break;
+
+  case 729:
+
+/* Line 1806 of yacc.c  */
+#line 2761 "parser.yy"
+    { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewArray( (yyvsp[(1) - (2)].decl) ); }
+    break;
+
   case 730:
 
 /* Line 1806 of yacc.c  */
-#line 2760 "parser.yy"
+#line 2766 "parser.yy"
     { (yyval.decl) = DeclarationNode::newVarArray( (yyvsp[(3) - (6)].decl) ); }
     break;
@@ -9003,5 +9034,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2762 "parser.yy"
+#line 2768 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( (yyvsp[(4) - (6)].en), (yyvsp[(3) - (6)].decl), false ); }
     break;
@@ -9010,5 +9041,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2767 "parser.yy"
+#line 2773 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( (yyvsp[(4) - (6)].en), (yyvsp[(3) - (6)].decl), true ); }
     break;
@@ -9017,5 +9048,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2769 "parser.yy"
+#line 2775 "parser.yy"
     { (yyval.decl) = DeclarationNode::newArray( (yyvsp[(5) - (7)].en), (yyvsp[(4) - (7)].decl)->addQualifiers( (yyvsp[(3) - (7)].decl) ), true ); }
     break;
@@ -9024,5 +9055,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2796 "parser.yy"
+#line 2802 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addQualifiers( (yyvsp[(1) - (2)].decl) ); }
     break;
@@ -9031,5 +9062,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2807 "parser.yy"
+#line 2813 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -9038,5 +9069,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2809 "parser.yy"
+#line 2815 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewPointer( DeclarationNode::newPointer( (yyvsp[(1) - (3)].decl) ) ); }
     break;
@@ -9045,5 +9076,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2811 "parser.yy"
+#line 2817 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -9052,5 +9083,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2813 "parser.yy"
+#line 2819 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewPointer( DeclarationNode::newPointer( (yyvsp[(1) - (3)].decl) ) ); }
     break;
@@ -9059,5 +9090,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2815 "parser.yy"
+#line 2821 "parser.yy"
     { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewPointer( DeclarationNode::newPointer( 0 ) ); }
     break;
@@ -9066,30 +9097,9 @@
 
 /* Line 1806 of yacc.c  */
-#line 2817 "parser.yy"
+#line 2823 "parser.yy"
     { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewPointer( DeclarationNode::newPointer( (yyvsp[(1) - (3)].decl) ) ); }
     break;
 
   case 745:
-
-/* Line 1806 of yacc.c  */
-#line 2824 "parser.yy"
-    { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
-    break;
-
-  case 746:
-
-/* Line 1806 of yacc.c  */
-#line 2826 "parser.yy"
-    { (yyval.decl) = (yyvsp[(4) - (4)].decl)->addNewArray( (yyvsp[(3) - (4)].decl) )->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
-    break;
-
-  case 747:
-
-/* Line 1806 of yacc.c  */
-#line 2828 "parser.yy"
-    { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewArray( (yyvsp[(1) - (2)].decl) ); }
-    break;
-
-  case 748:
 
 /* Line 1806 of yacc.c  */
@@ -9098,5 +9108,5 @@
     break;
 
-  case 749:
+  case 746:
 
 /* Line 1806 of yacc.c  */
@@ -9105,5 +9115,5 @@
     break;
 
-  case 750:
+  case 747:
 
 /* Line 1806 of yacc.c  */
@@ -9112,8 +9122,29 @@
     break;
 
+  case 748:
+
+/* Line 1806 of yacc.c  */
+#line 2836 "parser.yy"
+    { (yyval.decl) = (yyvsp[(3) - (3)].decl)->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
+    break;
+
+  case 749:
+
+/* Line 1806 of yacc.c  */
+#line 2838 "parser.yy"
+    { (yyval.decl) = (yyvsp[(4) - (4)].decl)->addNewArray( (yyvsp[(3) - (4)].decl) )->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
+    break;
+
+  case 750:
+
+/* Line 1806 of yacc.c  */
+#line 2840 "parser.yy"
+    { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addNewArray( (yyvsp[(1) - (2)].decl) ); }
+    break;
+
   case 751:
 
 /* Line 1806 of yacc.c  */
-#line 2839 "parser.yy"
+#line 2845 "parser.yy"
     { (yyval.decl) = DeclarationNode::newTuple( (yyvsp[(3) - (5)].decl) ); }
     break;
@@ -9122,5 +9153,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2846 "parser.yy"
+#line 2852 "parser.yy"
     { (yyval.decl) = DeclarationNode::newFunction( nullptr, (yyvsp[(1) - (6)].decl), (yyvsp[(4) - (6)].decl), nullptr ); }
     break;
@@ -9129,5 +9160,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2848 "parser.yy"
+#line 2854 "parser.yy"
     { (yyval.decl) = DeclarationNode::newFunction( nullptr, (yyvsp[(1) - (6)].decl), (yyvsp[(4) - (6)].decl), nullptr ); }
     break;
@@ -9136,5 +9167,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2872 "parser.yy"
+#line 2878 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -9143,5 +9174,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 2874 "parser.yy"
+#line 2880 "parser.yy"
     { (yyval.en) = (yyvsp[(2) - (2)].en); }
     break;
@@ -9150,5 +9181,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 9153 "Parser/parser.cc"
+#line 9184 "Parser/parser.cc"
       default: break;
     }
@@ -9381,5 +9412,5 @@
 
 /* Line 2067 of yacc.c  */
-#line 2877 "parser.yy"
+#line 2883 "parser.yy"
 
 // ----end of grammar----
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Parser/parser.yy	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -199,6 +199,5 @@
 
 %type<decl> field_declaration field_declaration_list field_declarator field_declaring_list
-%type<en> field field_list
-%type<tok> field_name
+%type<en> field field_list field_name fraction_constants
 
 %type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
@@ -384,8 +383,11 @@
 		{ $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
 	| postfix_expression '.' '[' push field_list pop ']' // CFA, tuple field selector
+		{ $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $5 ) ) ); }
 	| postfix_expression REALFRACTIONconstant			// CFA, tuple index
+		{ $$ = new ExpressionNode( build_fieldSel( $1, build_field_name_REALFRACTIONconstant( *$2 ) ) ); }
 	| postfix_expression ARROW no_attr_identifier
 		{ $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
 	| postfix_expression ARROW '[' push field_list pop ']' // CFA, tuple field selector
+			{ $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $5 ) ) ); }
 	| postfix_expression ICR
 	  	{ $$ = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, $1 ) ); }
@@ -421,31 +423,35 @@
 field:													// CFA, tuple field selector
 	field_name
-		{ $$ = new ExpressionNode( build_varref( $1 ) ); }
 	| REALDECIMALconstant field
-		{ $$ = new ExpressionNode( build_fieldSel( $2, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_REALDECIMALconstant( *$1 ) ), maybeMoveBuild<Expression>( $2 ) ) ); }
 	| REALDECIMALconstant '[' push field_list pop ']'
-		{ $$ = new ExpressionNode( build_fieldSel( $4, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_REALDECIMALconstant( *$1 ) ), build_tuple( $4 ) ) ); }
 	| field_name '.' field
-		{ $$ = new ExpressionNode( build_fieldSel( $3, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_fieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
 	| field_name '.' '[' push field_list pop ']'
-		{ $$ = new ExpressionNode( build_fieldSel( $5, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $5 ) ) ); }
 	| field_name ARROW field
-		{ $$ = new ExpressionNode( build_pfieldSel( $3, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_pfieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
 	| field_name ARROW '[' push field_list pop ']'
-		{ $$ = new ExpressionNode( build_pfieldSel( $5, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $5 ) ) ); }
 	;
 
 field_name:
 	INTEGERconstant	fraction_constants
-		{ $$ = $1; }
+		{ $$ = new ExpressionNode( build_field_name_fraction_constants( build_constantInteger( *$1 ), $2 ) ); }
 	| FLOATINGconstant fraction_constants
-		{ $$ = $1; }
+		{ $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); }
 	| no_attr_identifier fraction_constants
-		{ $$ = $1; }
+		{ $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) ); }
 	;
 
 fraction_constants:
 	// empty
+		{ $$ = nullptr; }
 	| fraction_constants REALFRACTIONconstant
+		{
+			Expression * constant = build_field_name_REALFRACTIONconstant( *$2 );
+			$$ = $1 != nullptr ? new ExpressionNode( build_fieldSel( $1,  constant ) ) : new ExpressionNode( constant );
+		}
 	;
 
Index: src/ResolvExpr/Alternative.cc
===================================================================
--- src/ResolvExpr/Alternative.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/Alternative.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Alternative.cc -- 
+// Alternative.cc --
 //
 // Author           : Richard C. Bilson
@@ -12,5 +12,5 @@
 // Last Modified On : Sat May 16 23:54:23 2015
 // Update Count     : 2
-// 
+//
 
 #include "Alternative.h"
@@ -20,5 +20,5 @@
 
 namespace ResolvExpr {
-	Alternative::Alternative() : expr( 0 ) {}
+	Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( 0 ) {}
 
 	Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost )
@@ -35,4 +35,19 @@
 		if ( &other == this ) return *this;
 		initialize( other, *this );
+		return *this;
+	}
+
+	Alternative::Alternative( Alternative && other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( other.expr ), env( other.env ) {
+		other.expr = nullptr;
+	}
+
+	Alternative & Alternative::operator=( Alternative && other ) {
+		if ( &other == this )  return *this;
+		delete expr;
+		cost = other.cost;
+		cvtCost = other.cvtCost;
+		expr = other.expr;
+		env = other.env;
+		other.expr = nullptr;
 		return *this;
 	}
@@ -54,6 +69,7 @@
 			expr->print( os, indent );
 			os << "(types:" << std::endl;
-			printAll( expr->get_results(), os, indent + 4 );
-			os << ")" << std::endl;
+			os << std::string( indent+4, ' ' );
+			expr->get_result()->print( os, indent + 4 );
+			os << std::endl << ")" << std::endl;
 		} else {
 			os << "Null expression!" << std::endl;
Index: src/ResolvExpr/Alternative.h
===================================================================
--- src/ResolvExpr/Alternative.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/Alternative.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Alternative.h -- 
+// Alternative.h --
 //
 // Author           : Richard C. Bilson
@@ -12,5 +12,5 @@
 // Last Modified On : Sat May 16 23:54:39 2015
 // Update Count     : 2
-// 
+//
 
 #ifndef ALTERNATIVE_H
@@ -32,10 +32,12 @@
 		Alternative( const Alternative &other );
 		Alternative &operator=( const Alternative &other );
+		Alternative( Alternative && other );
+		Alternative &operator=( Alternative && other );
 		~Alternative();
-  
+
 		void initialize( const Alternative &src, Alternative &dest );
-  
+
 		void print( std::ostream &os, int indent = 0 ) const;
-  
+
 		Cost cost;
 		Cost cvtCost;
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -38,8 +38,9 @@
 #include "SynTree/TypeSubstitution.h"
 #include "SymTab/Validate.h"
-#include "Tuples/TupleAssignment.h"
-#include "Tuples/NameMatcher.h"
+#include "Tuples/Tuples.h"
+#include "Tuples/Explode.h"
 #include "Common/utility.h"
 #include "InitTweak/InitTweak.h"
+#include "InitTweak/GenInit.h"
 #include "ResolveTypeof.h"
 
@@ -64,4 +65,12 @@
 	}
 
+	Cost sumCost( const AltList &in ) {
+		Cost total;
+		for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
+			total += i->cost;
+		}
+		return total;
+	}
+
 	namespace {
 		void printAlts( const AltList &list, std::ostream &os, int indent = 0 ) {
@@ -76,12 +85,4 @@
 				out.push_back( i->expr->clone() );
 			}
-		}
-
-		Cost sumCost( const AltList &in ) {
-			Cost total;
-			for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
-				total += i->cost;
-			}
-			return total;
 		}
 
@@ -101,8 +102,8 @@
 				PruneStruct current( candidate );
 				std::string mangleName;
-				for ( std::list< Type* >::const_iterator retType = candidate->expr->get_results().begin(); retType != candidate->expr->get_results().end(); ++retType ) {
-					Type *newType = (*retType)->clone();
+				{
+					Type * newType = candidate->expr->get_result()->clone();
 					candidate->env.apply( newType );
-					mangleName += SymTab::Mangler::mangle( newType );
+					mangleName = SymTab::Mangler::mangle( newType );
 					delete newType;
 				}
@@ -133,44 +134,12 @@
 				if ( ! target->second.isAmbiguous ) {
 					Alternative &alt = *target->second.candidate;
-					for ( std::list< Type* >::iterator result = alt.expr->get_results().begin(); result != alt.expr->get_results().end(); ++result ) {
-						alt.env.applyFree( *result );
-					}
+					alt.env.applyFree( alt.expr->get_result() );
 					*out++ = alt;
 				}
 			}
-
-		}
-
-		template< typename InputIterator, typename OutputIterator >
-		void findMinCost( InputIterator begin, InputIterator end, OutputIterator out ) {
-			AltList alternatives;
-
-			// select the alternatives that have the minimum parameter cost
-			Cost minCost = Cost::infinity;
-			for ( AltList::iterator i = begin; i != end; ++i ) {
-				if ( i->cost < minCost ) {
-					minCost = i->cost;
-					i->cost = i->cvtCost;
-					alternatives.clear();
-					alternatives.push_back( *i );
-				} else if ( i->cost == minCost ) {
-					i->cost = i->cvtCost;
-					alternatives.push_back( *i );
-				}
-			}
-			std::copy( alternatives.begin(), alternatives.end(), out );
-		}
-
-		template< typename InputIterator >
-		void simpleCombineEnvironments( InputIterator begin, InputIterator end, TypeEnvironment &result ) {
-			while ( begin != end ) {
-				result.simpleCombine( (*begin++).env );
-			}
 		}
 
 		void renameTypes( Expression *expr ) {
-			for ( std::list< Type* >::iterator i = expr->get_results().begin(); i != expr->get_results().end(); ++i ) {
-				(*i)->accept( global_renamer );
-			}
+			expr->get_result()->accept( global_renamer );
 		}
 	}
@@ -204,5 +173,5 @@
 		for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
 			if ( adjust ) {
-				adjustExprTypeList( i->expr->get_results().begin(), i->expr->get_results().end(), i->env, indexer );
+				adjustExprType( i->expr->get_result(), i->env, indexer );
 			}
 		}
@@ -240,6 +209,11 @@
 	}
 
+	// std::unordered_map< Expression *, UniqueExpr * > ;
+
 	template< typename StructOrUnionType >
-	void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string &name ) {
+	void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
+		// by this point, member must be a name expr
+		NameExpr * nameExpr = safe_dynamic_cast< NameExpr * >( member );
+		const std::string & name = nameExpr->get_name();
 		std::list< Declaration* > members;
 		aggInst->lookup( name, members );
@@ -254,4 +228,28 @@
 	}
 
+	void AlternativeFinder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
+		if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
+			// get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
+			// xxx - this should be improved by memoizing the value of constant exprs
+			// during parsing and reusing that information here.
+			std::stringstream ss( constantExpr->get_constant()->get_value() );
+			int val;
+			std::string tmp;
+			if ( ss >> val && ! (ss >> tmp) ) {
+				if ( val >= 0 && (unsigned int)val < tupleType->size() ) {
+					alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
+				} // if
+			} // if
+		} else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
+			// xxx - temporary hack until 0/1 are int constants
+			if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
+				std::stringstream ss( nameExpr->get_name() );
+				int val;
+				ss >> val;
+				alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
+			}
+		} // if
+	}
+
 	void AlternativeFinder::visit( ApplicationExpr *applicationExpr ) {
 		alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
@@ -259,10 +257,7 @@
 
 	Cost computeConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
-		ApplicationExpr *appExpr = dynamic_cast< ApplicationExpr* >( alt.expr );
-		assert( appExpr );
-		PointerType *pointer = dynamic_cast< PointerType* >( appExpr->get_function()->get_results().front() );
-		assert( pointer );
-		FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() );
-		assert( function );
+		ApplicationExpr *appExpr = safe_dynamic_cast< ApplicationExpr* >( alt.expr );
+		PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
+		FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
 
 		Cost convCost( 0, 0, 0 );
@@ -270,29 +265,50 @@
 		std::list< DeclarationWithType* >::iterator formal = formals.begin();
 		std::list< Expression* >& actuals = appExpr->get_args();
+
+		std::list< Type * > formalTypes;
+		std::list< Type * >::iterator formalType = formalTypes.end();
+
 		for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
+
 			PRINT(
 				std::cerr << "actual expression:" << std::endl;
 				(*actualExpr)->print( std::cerr, 8 );
 				std::cerr << "--- results are" << std::endl;
-				printAll( (*actualExpr)->get_results(), std::cerr, 8 );
+				(*actualExpr)->get_result()->print( std::cerr, 8 );
 			)
 			std::list< DeclarationWithType* >::iterator startFormal = formal;
 			Cost actualCost;
-			for ( std::list< Type* >::iterator actual = (*actualExpr)->get_results().begin(); actual != (*actualExpr)->get_results().end(); ++actual ) {
-				if ( formal == formals.end() ) {
-					if ( function->get_isVarArgs() ) {
-						convCost += Cost( 1, 0, 0 );
-						break;
-					} else {
-						return Cost::infinity;
+			std::list< Type * > flatActualTypes;
+			flatten( (*actualExpr)->get_result(), back_inserter( flatActualTypes ) );
+			for ( std::list< Type* >::iterator actualType = flatActualTypes.begin(); actualType != flatActualTypes.end(); ++actualType ) {
+
+
+				// tuple handling code
+				if ( formalType == formalTypes.end() ) {
+					// the type of the formal parameter may be a tuple type. To make this easier to work with,
+					// flatten the tuple type and traverse the resulting list of types, incrementing the formal
+					// iterator once its types have been extracted. Once a particular formal parameter's type has
+					// been exhausted load the next formal parameter's type.
+					if ( formal == formals.end() ) {
+						if ( function->get_isVarArgs() ) {
+							convCost += Cost( 1, 0, 0 );
+							break;
+						} else {
+							return Cost::infinity;
+						}
 					}
+					formalTypes.clear();
+					flatten( (*formal)->get_type(), back_inserter( formalTypes ) );
+					formalType = formalTypes.begin();
+					++formal;
 				}
+
 				PRINT(
 					std::cerr << std::endl << "converting ";
-					(*actual)->print( std::cerr, 8 );
+					(*actualType)->print( std::cerr, 8 );
 					std::cerr << std::endl << " to ";
 					(*formal)->get_type()->print( std::cerr, 8 );
 				)
-				Cost newCost = conversionCost( *actual, (*formal)->get_type(), indexer, alt.env );
+				Cost newCost = conversionCost( *actualType, *formalType, indexer, alt.env );
 				PRINT(
 					std::cerr << std::endl << "cost is" << newCost << std::endl;
@@ -305,7 +321,7 @@
 				actualCost += newCost;
 
-				convCost += Cost( 0, polyCost( (*formal)->get_type(), alt.env, indexer ) + polyCost( *actual, alt.env, indexer ), 0 );
-
-				formal++;
+				convCost += Cost( 0, polyCost( *formalType, alt.env, indexer ) + polyCost( *actualType, alt.env, indexer ), 0 );
+
+				formalType++;
 			}
 			if ( actualCost != Cost( 0, 0, 0 ) ) {
@@ -356,5 +372,5 @@
 	/// Adds type variables to the open variable set and marks their assertions
 	void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) {
-		for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
+		for ( Type::ForallList::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
 			unifiableVars[ (*tyvar)->get_name() ] = (*tyvar)->get_kind();
 			for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
@@ -365,5 +381,59 @@
 	}
 
-	bool AlternativeFinder::instantiateFunction( std::list< DeclarationWithType* >& formals, /*const*/ AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave ) {
+	/// instantiate a single argument by matching actuals from [actualIt, actualEnd) against formalType,
+	/// producing expression(s) in out and their total cost in cost.
+	template< typename AltIterator, typename OutputIterator >
+	bool instantiateArgument( Type * formalType, Initializer * defaultValue, AltIterator & actualIt, AltIterator actualEnd, OpenVarSet & openVars, TypeEnvironment & resultEnv, AssertionSet & resultNeed, AssertionSet & resultHave, const SymTab::Indexer & indexer, Cost & cost, OutputIterator out ) {
+		if ( TupleType * tupleType = dynamic_cast< TupleType * >( formalType ) ) {
+			// formalType is a TupleType - group actuals into a TupleExpr whose type unifies with the TupleType
+			TupleExpr * tupleExpr = new TupleExpr();
+			for ( Type * type : *tupleType ) {
+				if ( ! instantiateArgument( type, defaultValue, actualIt, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( tupleExpr->get_exprs() ) ) ) {
+					delete tupleExpr;
+					return false;
+				}
+			}
+			tupleExpr->set_result( Tuples::makeTupleType( tupleExpr->get_exprs() ) );
+			*out++ = tupleExpr;
+		} else if ( actualIt != actualEnd ) {
+			// both actualType and formalType are atomic (non-tuple) types - if they unify
+			// then accept actual as an argument, otherwise return false (fail to instantiate argument)
+			Expression * actual = actualIt->expr;
+			Type * actualType = actual->get_result();
+			PRINT(
+				std::cerr << "formal type is ";
+				formalType->print( std::cerr );
+				std::cerr << std::endl << "actual type is ";
+				actualType->print( std::cerr );
+				std::cerr << std::endl;
+			)
+			if ( ! unify( formalType, actualType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
+				return false;
+			}
+			// move the expression from the alternative to the output iterator
+			*out++ = actual;
+			actualIt->expr = nullptr;
+			cost += actualIt->cost;
+			++actualIt;
+		} else {
+			// End of actuals - Handle default values
+			if ( SingleInit *si = dynamic_cast<SingleInit *>( defaultValue )) {
+				// so far, only constant expressions are accepted as default values
+				if ( ConstantExpr *cnstexpr = dynamic_cast<ConstantExpr *>( si->get_value()) ) {
+					if ( Constant *cnst = dynamic_cast<Constant *>( cnstexpr->get_constant() ) ) {
+						if ( unify( formalType, cnst->get_type(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
+							// xxx - Don't know if this is right
+							*out++ = cnstexpr->clone();
+							return true;
+						} // if
+					} // if
+				} // if
+			} // if
+			return false;
+		} // if
+		return true;
+	}
+
+	bool AlternativeFinder::instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out ) {
 		simpleCombineEnvironments( actuals.begin(), actuals.end(), resultEnv );
 		// make sure we don't widen any existing bindings
@@ -373,45 +443,31 @@
 		resultEnv.extractOpenVars( openVars );
 
-		/*
-		  Tuples::NameMatcher matcher( formals );
-		  try {
-		  matcher.match( actuals );
-		  } catch ( Tuples::NoMatch &e ) {
-		  std::cerr << "Alternative doesn't match: " << e.message << std::endl;
-		  }
-		*/
-		std::list< DeclarationWithType* >::iterator formal = formals.begin();
-		for ( AltList::const_iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
-			for ( std::list< Type* >::iterator actual = actualExpr->expr->get_results().begin(); actual != actualExpr->expr->get_results().end(); ++actual ) {
-				if ( formal == formals.end() ) {
-					return isVarArgs;
-				}
-				PRINT(
-					std::cerr << "formal type is ";
-					(*formal)->get_type()->print( std::cerr );
-					std::cerr << std::endl << "actual type is ";
-					(*actual)->print( std::cerr );
-					std::cerr << std::endl;
-				)
-				if ( ! unify( (*formal)->get_type(), *actual, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
-					return false;
-				}
-				formal++;
-			}
-		}
-		// Handling of default values
-		while ( formal != formals.end() ) {
-			if ( ObjectDecl *od = dynamic_cast<ObjectDecl *>( *formal ) )
-				if ( SingleInit *si = dynamic_cast<SingleInit *>( od->get_init() ))
-					// so far, only constant expressions are accepted as default values
-					if ( ConstantExpr *cnstexpr = dynamic_cast<ConstantExpr *>( si->get_value()) )
-						if ( Constant *cnst = dynamic_cast<Constant *>( cnstexpr->get_constant() ) )
-							if ( unify( (*formal)->get_type(), cnst->get_type(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
-								// XXX Don't know if this is right
-								actuals.push_back( Alternative( cnstexpr->clone(), env, Cost::zero ) );
-								formal++;
-								if ( formal == formals.end()) break;
-							}
-			return false;
+		// flatten actuals so that each actual has an atomic (non-tuple) type
+		AltList exploded;
+		Tuples::explode( actuals, indexer, back_inserter( exploded ) );
+
+		AltList::iterator actualExpr = exploded.begin();
+		AltList::iterator actualEnd = exploded.end();
+		for ( DeclarationWithType * formal : formals ) {
+			// match flattened actuals with formal parameters - actuals will be grouped to match
+			// with formals as appropriate
+			Cost cost;
+			std::list< Expression * > newExprs;
+			ObjectDecl * obj = safe_dynamic_cast< ObjectDecl * >( formal );
+			if ( ! instantiateArgument( obj->get_type(), obj->get_init(), actualExpr, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( newExprs ) ) ) {
+				deleteAll( newExprs );
+				return false;
+			}
+			// success - produce argument as a new alternative
+			assert( newExprs.size() == 1 );
+			out.push_back( Alternative( newExprs.front(), resultEnv, cost ) );
+		}
+		if ( actualExpr != actualEnd ) {
+			// there are still actuals remaining, but we've run out of formal parameters to match against
+			// this is okay only if the function is variadic
+			if ( ! isVarArgs ) {
+				return false;
+			}
+			out.splice( out.end(), exploded, actualExpr, actualEnd );
 		}
 		return true;
@@ -500,7 +556,6 @@
 				//if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue;
 				Expression *varExpr = new VariableExpr( candDecl );
-				deleteAll( varExpr->get_results() );
-				varExpr->get_results().clear();
-				varExpr->get_results().push_front( adjType->clone() );
+				delete varExpr->get_result();
+				varExpr->set_result( adjType->clone() );
 				PRINT(
 					std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
@@ -545,13 +600,14 @@
 
 	template< typename OutputIterator >
-	void AlternativeFinder::makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, AltList &actualAlt, OutputIterator out ) {
+	void AlternativeFinder::makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const AltList &actualAlt, OutputIterator out ) {
 		OpenVarSet openVars;
 		AssertionSet resultNeed, resultHave;
 		TypeEnvironment resultEnv;
 		makeUnifiableVars( funcType, openVars, resultNeed );
-		if ( instantiateFunction( funcType->get_parameters(), actualAlt, funcType->get_isVarArgs(), openVars, resultEnv, resultNeed, resultHave ) ) {
+		AltList instantiatedActuals; // filled by instantiate function
+		if ( instantiateFunction( funcType->get_parameters(), actualAlt, funcType->get_isVarArgs(), openVars, resultEnv, resultNeed, resultHave, instantiatedActuals ) ) {
 			ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
-			Alternative newAlt( appExpr, resultEnv, sumCost( actualAlt ) );
-			makeExprList( actualAlt, appExpr->get_args() );
+			Alternative newAlt( appExpr, resultEnv, sumCost( instantiatedActuals ) );
+			makeExprList( instantiatedActuals, appExpr->get_args() );
 			PRINT(
 				std::cerr << "need assertions:" << std::endl;
@@ -574,5 +630,5 @@
 				PointerType pt( Type::Qualifiers(), v.clone() );
 				UntypedExpr *vexpr = untypedExpr->clone();
-				vexpr->get_results().push_front( pt.clone() );
+				vexpr->set_result( pt.clone() );
 				alternatives.push_back( Alternative( vexpr, env, Cost()) );
 				return;
@@ -587,9 +643,7 @@
 		combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
 
-		Tuples::TupleAssignSpotter tassign( this );
-		if ( tassign.isTupleAssignment( untypedExpr, possibilities ) ) {
-			// take care of possible tuple assignments, or discard expression
-			return;
-		} // else ...
+		// take care of possible tuple assignments
+		// if not tuple assignment, assignment is taken care of as a normal function call
+		Tuples::handleTupleAssignment( *this, untypedExpr, possibilities );
 
 		AltList candidates;
@@ -604,5 +658,5 @@
 				// check if the type is pointer to function
 				PointerType *pointer;
-				if ( func->expr->get_results().size() == 1 && ( pointer = dynamic_cast< PointerType* >( func->expr->get_results().front() ) ) ) {
+				if ( ( pointer = dynamic_cast< PointerType* >( func->expr->get_result() ) ) ) {
 					if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
 						for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
@@ -640,6 +694,5 @@
 						// check if the type is pointer to function
 						PointerType *pointer;
-						if ( funcOp->expr->get_results().size() == 1
-							&& ( pointer = dynamic_cast< PointerType* >( funcOp->expr->get_results().front() ) ) ) {
+						if ( ( pointer = dynamic_cast< PointerType* >( funcOp->expr->get_result() ) ) ) {
 							if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
 								for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
@@ -665,10 +718,7 @@
 
 			PRINT(
-				ApplicationExpr *appExpr = dynamic_cast< ApplicationExpr* >( withFunc->expr );
-				assert( appExpr );
-				PointerType *pointer = dynamic_cast< PointerType* >( appExpr->get_function()->get_results().front() );
-				assert( pointer );
-				FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() );
-				assert( function );
+				ApplicationExpr *appExpr = safe_dynamic_cast< ApplicationExpr* >( withFunc->expr );
+				PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
+				FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
 				std::cerr << "Case +++++++++++++" << std::endl;
 				std::cerr << "formals are:" << std::endl;
@@ -692,8 +742,6 @@
 
 	bool isLvalue( Expression *expr ) {
-		for ( std::list< Type* >::const_iterator i = expr->get_results().begin(); i != expr->get_results().end(); ++i ) {
-			if ( !(*i)->get_isLvalue() ) return false;
-		} // for
-		return true;
+		// xxx - recurse into tuples?
+		return expr->has_result() && expr->get_result()->get_isLvalue();
 	}
 
@@ -709,9 +757,8 @@
 
 	void AlternativeFinder::visit( CastExpr *castExpr ) {
-		for ( std::list< Type* >::iterator i = castExpr->get_results().begin(); i != castExpr->get_results().end(); ++i ) {
-			*i = resolveTypeof( *i, indexer );
-			SymTab::validateType( *i, &indexer );
-			adjustExprType( *i, env, indexer );
-		} // for
+		Type *& toType = castExpr->get_result();
+		toType = resolveTypeof( toType, indexer );
+		SymTab::validateType( toType, &indexer );
+		adjustExprType( toType, env, indexer );
 
 		AlternativeFinder finder( indexer, env );
@@ -727,15 +774,10 @@
 			// that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
 			// to.
-			int discardedValues = (*i).expr->get_results().size() - castExpr->get_results().size();
+			int discardedValues = (*i).expr->get_result()->size() - castExpr->get_result()->size();
 			if ( discardedValues < 0 ) continue;
-			std::list< Type* >::iterator candidate_end = (*i).expr->get_results().begin();
-			std::advance( candidate_end, castExpr->get_results().size() );
+			// xxx - may need to go into tuple types and extract relavent types and use unifyList
 			// unification run for side-effects
-			unifyList( castExpr->get_results().begin(), castExpr->get_results().end(),
-					   (*i).expr->get_results().begin(), candidate_end,
-			           i->env, needAssertions, haveAssertions, openVars, indexer );
-			Cost thisCost = castCostList( (*i).expr->get_results().begin(), candidate_end,
-										  castExpr->get_results().begin(), castExpr->get_results().end(),
-										  indexer, i->env );
+			unify( castExpr->get_result(), (*i).expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer );
+			Cost thisCost = castCost( (*i).expr->get_result(), castExpr->get_result(), indexer, i->env );
 			if ( thisCost != Cost::infinity ) {
 				// count one safe conversion for each value that is thrown away
@@ -760,10 +802,10 @@
 
 		for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
-			if ( agg->expr->get_results().size() == 1 ) {
-				if ( StructInstType *structInst = dynamic_cast< StructInstType* >( agg->expr->get_results().front() ) ) {
-					addAggMembers( structInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
-				} else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( agg->expr->get_results().front() ) ) {
-					addAggMembers( unionInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
-				} // if
+			if ( StructInstType *structInst = dynamic_cast< StructInstType* >( agg->expr->get_result() ) ) {
+				addAggMembers( structInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
+			} else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( agg->expr->get_result() ) ) {
+				addAggMembers( unionInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
+			} else if ( TupleType * tupleType = dynamic_cast< TupleType * >( agg->expr->get_result() ) ) {
+				addTupleMembers( tupleType, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
 			} // if
 		} // for
@@ -791,7 +833,9 @@
 			renameTypes( alternatives.back().expr );
 			if ( StructInstType *structInst = dynamic_cast< StructInstType* >( (*i)->get_type() ) ) {
-				addAggMembers( structInst, &newExpr, Cost( 0, 0, 1 ), env, "" );
+				NameExpr nameExpr( "" );
+				addAggMembers( structInst, &newExpr, Cost( 0, 0, 1 ), env, &nameExpr );
 			} else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( (*i)->get_type() ) ) {
-				addAggMembers( unionInst, &newExpr, Cost( 0, 0, 1 ), env, "" );
+				NameExpr nameExpr( "" );
+				addAggMembers( unionInst, &newExpr, Cost( 0, 0, 1 ), env, &nameExpr );
 			} // if
 		} // for
@@ -894,5 +938,5 @@
 			alternatives.push_back( Alternative( new AttrExpr( new VariableExpr( funcDecl ), argType->clone() ), env, Cost::zero ) );
 			for ( std::list< DeclarationWithType* >::iterator i = function->get_returnVals().begin(); i != function->get_returnVals().end(); ++i ) {
-				alternatives.back().expr->get_results().push_back( (*i)->get_type()->clone() );
+				alternatives.back().expr->set_result( (*i)->get_type()->clone() );
 			} // for
 		} // if
@@ -917,6 +961,6 @@
 							finder.find( attrExpr->get_expr() );
 							for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
-								if ( choice->expr->get_results().size() == 1 ) {
-									resolveAttr(*i, function, choice->expr->get_results().front(), choice->env );
+								if ( choice->expr->get_result()->size() == 1 ) {
+									resolveAttr(*i, function, choice->expr->get_result(), choice->env );
 								} // fi
 							} // for
@@ -960,16 +1004,8 @@
 					AssertionSet needAssertions, haveAssertions;
 					Alternative newAlt( 0, third->env, first->cost + second->cost + third->cost );
-					std::list< Type* > commonTypes;
-					if ( unifyList( second->expr->get_results().begin(), second->expr->get_results().end(), third->expr->get_results().begin(), third->expr->get_results().end(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonTypes ) ) {
+					Type* commonType = nullptr;
+					if ( unify( second->expr->get_result(), third->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
 						ConditionalExpr *newExpr = new ConditionalExpr( first->expr->clone(), second->expr->clone(), third->expr->clone() );
-						std::list< Type* >::const_iterator original = second->expr->get_results().begin();
-						std::list< Type* >::const_iterator commonType = commonTypes.begin();
-						for ( ; original != second->expr->get_results().end() && commonType != commonTypes.end(); ++original, ++commonType ) {
-							if ( *commonType ) {
-								newExpr->get_results().push_back( *commonType );
-							} else {
-								newExpr->get_results().push_back( (*original)->clone() );
-							} // if
-						} // for
+						newExpr->set_result( commonType ? commonType : second->expr->get_result()->clone() );
 						newAlt.expr = newExpr;
 						inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
@@ -999,9 +1035,5 @@
 			TupleExpr *newExpr = new TupleExpr;
 			makeExprList( *i, newExpr->get_exprs() );
-			for ( std::list< Expression* >::const_iterator resultExpr = newExpr->get_exprs().begin(); resultExpr != newExpr->get_exprs().end(); ++resultExpr ) {
-				for ( std::list< Type* >::const_iterator resultType = (*resultExpr)->get_results().begin(); resultType != (*resultExpr)->get_results().end(); ++resultType ) {
-					newExpr->get_results().push_back( (*resultType)->clone() );
-				} // for
-			} // for
+			newExpr->set_result( Tuples::makeTupleType( newExpr->get_exprs() ) );
 
 			TypeEnvironment compositeEnv;
@@ -1024,4 +1056,23 @@
 		}
 	}
+
+	void AlternativeFinder::visit( TupleIndexExpr *tupleExpr ) {
+		alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
+	}
+
+	void AlternativeFinder::visit( TupleAssignExpr *tupleAssignExpr ) {
+		alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
+	}
+
+	void AlternativeFinder::visit( UniqueExpr *unqExpr ) {
+		AlternativeFinder finder( indexer, env );
+		finder.findWithAdjustment( unqExpr->get_expr() );
+		for ( Alternative & alt : finder.alternatives ) {
+			// ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
+			UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
+			alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
+		}
+	}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/AlternativeFinder.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -67,16 +67,21 @@
 		virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr );
 		virtual void visit( ConstructorExpr * ctorExpr );
-	  public:  // xxx - temporary hack - should make Tuples::TupleAssignment a friend
+		virtual void visit( TupleIndexExpr *tupleExpr );
+		virtual void visit( TupleAssignExpr *tupleExpr );
+		virtual void visit( UniqueExpr *unqExpr );
+		/// Runs a new alternative finder on each element in [begin, end)
+		/// and writes each alternative finder to out.
 		template< typename InputIterator, typename OutputIterator >
 		void findSubExprs( InputIterator begin, InputIterator end, OutputIterator out );
 
-	  private:
 		/// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
-		template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string &name );
+		template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
+		/// Adds alternatives for member expressions where the left side has tuple type
+		void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
 		/// Adds alternatives for offsetof expressions, given the base type and name of the member
 		template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
-		bool instantiateFunction( std::list< DeclarationWithType* >& formals, /*const*/ AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave );
+		bool instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out );
 		template< typename OutputIterator >
-		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, AltList &actualAlt, OutputIterator out );
+		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const AltList &actualAlt, OutputIterator out );
 		template< typename OutputIterator >
 		void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
@@ -89,4 +94,33 @@
 
 	Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env );
+
+	template< typename InputIterator, typename OutputIterator >
+	void findMinCost( InputIterator begin, InputIterator end, OutputIterator out ) {
+		AltList alternatives;
+
+		// select the alternatives that have the minimum parameter cost
+		Cost minCost = Cost::infinity;
+		for ( InputIterator i = begin; i != end; ++i ) {
+			if ( i->cost < minCost ) {
+				minCost = i->cost;
+				i->cost = i->cvtCost;
+				alternatives.clear();
+				alternatives.push_back( *i );
+			} else if ( i->cost == minCost ) {
+				i->cost = i->cvtCost;
+				alternatives.push_back( *i );
+			}
+		}
+		std::copy( alternatives.begin(), alternatives.end(), out );
+	}
+
+	Cost sumCost( const AltList &in );
+
+	template< typename InputIterator >
+	void simpleCombineEnvironments( InputIterator begin, InputIterator end, TypeEnvironment &result ) {
+		while ( begin != end ) {
+			result.simpleCombine( (*begin++).env );
+		}
+	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/AlternativePrinter.cc
===================================================================
--- src/ResolvExpr/AlternativePrinter.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/AlternativePrinter.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// AlternativePrinter.cc -- 
+// AlternativePrinter.cc --
 //
 // Author           : Richard C. Bilson
@@ -33,5 +33,5 @@
 		for ( AltList::const_iterator i = finder.get_alternatives().begin(); i != finder.get_alternatives().end(); ++i ) {
 			os << "Alternative " << count++ << " ==============" << std::endl;
-			printAll( i->expr->get_results(), os );
+			i->expr->get_result()->print( os );
 			//    i->print( os );
 			os << std::endl;
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/ConversionCost.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -240,5 +240,5 @@
 			std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
 			std::list< Type* >::const_iterator destIt = destAsTuple->get_types().begin();
-			while ( srcIt != tupleType->get_types().end() ) {
+			while ( srcIt != tupleType->get_types().end() && destIt != destAsTuple->get_types().end() ) {
 				Cost newCost = conversionCost( *srcIt++, *destIt++, indexer, env );
 				if ( newCost == Cost::infinity ) {
Index: src/ResolvExpr/FindOpenVars.cc
===================================================================
--- src/ResolvExpr/FindOpenVars.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/FindOpenVars.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// FindOpenVars.cc -- 
+// FindOpenVars.cc --
 //
 // Author           : Richard C. Bilson
@@ -47,5 +47,5 @@
 	void FindOpenVars::common_action( Type *type ) {
 		if ( nextIsOpen ) {
-			for ( std::list< TypeDecl* >::const_iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
+			for ( Type::ForallList::const_iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
 				openVars[ (*i)->get_name() ] = (*i)->get_kind();
 				for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
@@ -56,5 +56,5 @@
 			}
 		} else {
-			for ( std::list< TypeDecl* >::const_iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
+			for ( Type::ForallList::const_iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
 				closedVars[ (*i)->get_name() ] = (*i)->get_kind();
 				for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/RenameVars.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// RenameVars.cc -- 
+// RenameVars.cc --
 //
 // Author           : Richard C. Bilson
@@ -125,5 +125,5 @@
 			mapStack.push_front( mapStack.front() );
 			// renames all "forall" type names to `_${level}_${name}'
-			for ( std::list< TypeDecl* >::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
+			for ( Type::ForallList::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
 				std::ostringstream output;
 				output << "_" << level << "_" << (*i)->get_name();
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// ResolveTypeof.cc -- 
+// ResolveTypeof.cc --
 //
 // Author           : Richard C. Bilson
@@ -58,13 +58,6 @@
 		if ( typeofType->get_expr() ) {
 			Expression *newExpr = resolveInVoidContext( typeofType->get_expr(), indexer );
-			assert( newExpr->get_results().size() > 0 );
-			Type *newType;
-			if ( newExpr->get_results().size() > 1 ) {
-				TupleType *tupleType = new TupleType( Type::Qualifiers() );
-				cloneAll( newExpr->get_results(), tupleType->get_types() );
-				newType = tupleType;
-			} else {
-				newType = newExpr->get_results().front()->clone();
-			} // if
+			assert( newExpr->has_result() && ! newExpr->get_result()->isVoid() );
+			Type *newType = newExpr->get_result();
 			delete typeofType;
 			return newType;
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/Resolver.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -19,4 +19,5 @@
 #include "RenameVars.h"
 #include "ResolveTypeof.h"
+#include "typeops.h"
 #include "SynTree/Statement.h"
 #include "SynTree/Type.h"
@@ -68,6 +69,7 @@
 	  void resolveSingleAggrInit( Declaration *, InitIterator &, InitIterator & );
 	  void fallbackInit( ConstructorInit * ctorInit );
-		std::list< Type * > functionReturn;
-		Type *initContext;
+
+		Type * functionReturn = nullptr;
+		Type *initContext = nullptr;
 		bool inEnumDecl = false;
 	};
@@ -157,5 +159,5 @@
 			const TypeEnvironment *newEnv = 0;
 			for ( AltList::const_iterator i = finder.get_alternatives().begin(); i != finder.get_alternatives().end(); ++i ) {
-				if ( i->expr->get_results().size() == 1 && isIntegralType( i->expr->get_results().front() ) ) {
+				if ( i->expr->get_result()->size() == 1 && isIntegralType( i->expr->get_result() ) ) {
 					if ( newExpr ) {
 						throw SemanticError( "Too many interpretations for case control expression", untyped );
@@ -234,11 +236,7 @@
 		Type *new_type = resolveTypeof( functionDecl->get_type(), *this );
 		functionDecl->set_type( new_type );
-		std::list< Type * > oldFunctionReturn = functionReturn;
-		functionReturn.clear();
-		for ( std::list< DeclarationWithType * >::const_iterator i = functionDecl->get_functionType()->get_returnVals().begin(); i != functionDecl->get_functionType()->get_returnVals().end(); ++i ) {
-			functionReturn.push_back( (*i)->get_type() );
-		} // for
+		ValueGuard< Type * > oldFunctionReturn( functionReturn );
+		functionReturn = ResolvExpr::extractResultType( functionDecl->get_functionType() );
 		SymTab::Indexer::visit( functionDecl );
-		functionReturn = oldFunctionReturn;
 	}
 
@@ -338,6 +336,5 @@
 	void Resolver::visit( ReturnStmt *returnStmt ) {
 		if ( returnStmt->get_expr() ) {
-			CastExpr *castExpr = new CastExpr( returnStmt->get_expr() );
-			cloneAll( functionReturn, castExpr->get_results() );
+			CastExpr *castExpr = new CastExpr( returnStmt->get_expr(), functionReturn->clone() );
 			Expression *newExpr = findSingleExpression( castExpr, *this );
 			delete castExpr;
@@ -384,5 +381,5 @@
 				if ( isCharType( at->get_base() ) ) {
 					// check if the resolved type is char *
-					if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_results().front() ) ) {
+					if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {
 						if ( isCharType( pt->get_base() ) ) {
 							// strip cast if we're initializing a char[] with a char *, e.g.  char x[] = "hello";
@@ -446,4 +443,10 @@
 				(*iter)->accept( *this );
 			} // for
+		} else if ( TupleType * tt = dynamic_cast< TupleType * > ( initContext ) ) {
+			for ( Type * t : *tt ) {
+				if ( iter == end ) break;
+				initContext = t;
+				(*iter++)->accept( *this );
+			}
 		} else if ( StructInstType * st = dynamic_cast< StructInstType * >( initContext ) ) {
 			resolveAggrInit( st->get_baseStruct(), iter, end );
Index: src/ResolvExpr/TypeEnvironment.cc
===================================================================
--- src/ResolvExpr/TypeEnvironment.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/TypeEnvironment.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -158,6 +158,6 @@
 	}
 
-	void TypeEnvironment::add( const std::list< TypeDecl* > &tyDecls ) {
-		for ( std::list< TypeDecl* >::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) {
+	void TypeEnvironment::add( const Type::ForallList &tyDecls ) {
+		for ( Type::ForallList::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) {
 			EqvClass newClass;
 			newClass.vars.insert( (*i)->get_name() );
Index: src/ResolvExpr/TypeEnvironment.h
===================================================================
--- src/ResolvExpr/TypeEnvironment.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/TypeEnvironment.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -55,5 +55,5 @@
 		bool lookup( const std::string &var, EqvClass &eqvClass ) const;
 		void add( const EqvClass &eqvClass );
-		void add( const std::list< TypeDecl* > &tyDecls );
+		void add( const Type::ForallList &tyDecls );
 		template< typename SynTreeClass > int apply( SynTreeClass *&type ) const;
 		template< typename SynTreeClass > int applyFree( SynTreeClass *&type ) const;
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/Unify.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -597,4 +597,18 @@
 	}
 
+	// xxx - compute once and store in the FunctionType?
+	Type * extractResultType( FunctionType * function ) {
+		if ( function->get_returnVals().size() == 0 ) {
+			return new VoidType( Type::Qualifiers() );
+		} else if ( function->get_returnVals().size() == 1 ) {
+			return function->get_returnVals().front()->get_type()->clone();
+		} else {
+			TupleType * tupleType = new TupleType( Type::Qualifiers() );
+			for ( DeclarationWithType * decl : function->get_returnVals() ) {
+				tupleType->get_types().push_back( decl->get_type()->clone() );
+			} // for
+			return tupleType;
+		}
+	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/ResolvExpr/typeops.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// typeops.h -- 
+// typeops.h --
 //
 // Author           : Richard C. Bilson
@@ -30,10 +30,10 @@
 		typedef typename InputIterator::value_type SetType;
 		typedef typename std::list< typename SetType::value_type > ListType;
-  
+
 		if ( begin == end )	{
 			*out++ = ListType();
 			return;
 		} // if
-  
+
 		InputIterator current = begin;
 		begin++;
@@ -41,5 +41,5 @@
 		std::list< ListType > recursiveResult;
 		combos( begin, end, back_inserter( recursiveResult ) );
-  
+
 		for ( typename std::list< ListType >::const_iterator i = recursiveResult.begin(); i != recursiveResult.end(); ++i ) {
 			for ( typename ListType::const_iterator j = current->begin(); j != current->end(); ++j ) {
@@ -52,5 +52,5 @@
 		} // for
 	}
-  
+
 	// in AdjustExprType.cc
 	/// Replaces array types with the equivalent pointer, and function types with a pointer-to-function
@@ -144,4 +144,7 @@
 	}
 
+	/// creates the type represented by the list of returnVals in a FunctionType. The caller owns the return value.
+	Type * extractResultType( FunctionType * functionType );
+
 	// in CommonType.cc
 	Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
@@ -152,4 +155,16 @@
 	// in Occurs.cc
 	bool occurs( Type *type, std::string varName, const TypeEnvironment &env );
+
+	// flatten tuple type into list of types
+	template< typename OutputIterator >
+	void flatten( Type * type, OutputIterator out ) {
+		if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {
+			for ( Type * t : tupleType->get_types() ) {
+				flatten( t, out );
+			}
+		} else {
+			*out++ = type;
+		}
+	}
 } // namespace ResolvExpr
 
Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SymTab/Autogen.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -116,6 +116,7 @@
 		// This happens before function pointer type conversion, so need to do it manually here
 		VariableExpr * assignVarExpr = new VariableExpr( assignDecl );
-		Type *& assignVarExprType = assignVarExpr->get_results().front();
+		Type * assignVarExprType = assignVarExpr->get_result();
 		assignVarExprType = new PointerType( Type::Qualifiers(), assignVarExprType );
+		assignVarExpr->set_result( assignVarExprType );
 		ApplicationExpr * assignExpr = new ApplicationExpr( assignVarExpr );
 		assignExpr->get_args().push_back( new VariableExpr( dstParam ) );
Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SymTab/Indexer.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -40,8 +40,8 @@
 
 namespace SymTab {
-	template< typename Container, typename VisitorType >
-	inline void acceptAllNewScope( Container &container, VisitorType &visitor ) {
+	template< typename TreeType, typename VisitorType >
+	inline void acceptNewScope( TreeType *tree, VisitorType &visitor ) {
 		visitor.enterScope();
-		acceptAll( container, visitor );
+		maybeAccept( tree, visitor );
 		visitor.leaveScope();
 	}
@@ -143,5 +143,5 @@
 		for ( DeclarationWithType * decl : copy ) {
 			if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl ) ) {
-				std::list< DeclarationWithType * > params = function->get_functionType()->get_parameters();
+				std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
 				assert( ! params.empty() );
 				// use base type of pointer, so that qualifiers on the pointer type aren't considered.
@@ -337,5 +337,5 @@
 
 	void Indexer::visit( ApplicationExpr *applicationExpr ) {
-		acceptAllNewScope( applicationExpr->get_results(), *this );
+		acceptNewScope( applicationExpr->get_result(), *this );
 		maybeAccept( applicationExpr->get_function(), *this );
 		acceptAll( applicationExpr->get_args(), *this );
@@ -343,48 +343,48 @@
 
 	void Indexer::visit( UntypedExpr *untypedExpr ) {
-		acceptAllNewScope( untypedExpr->get_results(), *this );
+		acceptNewScope( untypedExpr->get_result(), *this );
 		acceptAll( untypedExpr->get_args(), *this );
 	}
 
 	void Indexer::visit( NameExpr *nameExpr ) {
-		acceptAllNewScope( nameExpr->get_results(), *this );
+		acceptNewScope( nameExpr->get_result(), *this );
 	}
 
 	void Indexer::visit( AddressExpr *addressExpr ) {
-		acceptAllNewScope( addressExpr->get_results(), *this );
+		acceptNewScope( addressExpr->get_result(), *this );
 		maybeAccept( addressExpr->get_arg(), *this );
 	}
 
 	void Indexer::visit( LabelAddressExpr *labAddressExpr ) {
-		acceptAllNewScope( labAddressExpr->get_results(), *this );
+		acceptNewScope( labAddressExpr->get_result(), *this );
 		maybeAccept( labAddressExpr->get_arg(), *this );
 	}
 
 	void Indexer::visit( CastExpr *castExpr ) {
-		acceptAllNewScope( castExpr->get_results(), *this );
+		acceptNewScope( castExpr->get_result(), *this );
 		maybeAccept( castExpr->get_arg(), *this );
 	}
 
 	void Indexer::visit( UntypedMemberExpr *memberExpr ) {
-		acceptAllNewScope( memberExpr->get_results(), *this );
+		acceptNewScope( memberExpr->get_result(), *this );
 		maybeAccept( memberExpr->get_aggregate(), *this );
 	}
 
 	void Indexer::visit( MemberExpr *memberExpr ) {
-		acceptAllNewScope( memberExpr->get_results(), *this );
+		acceptNewScope( memberExpr->get_result(), *this );
 		maybeAccept( memberExpr->get_aggregate(), *this );
 	}
 
 	void Indexer::visit( VariableExpr *variableExpr ) {
-		acceptAllNewScope( variableExpr->get_results(), *this );
+		acceptNewScope( variableExpr->get_result(), *this );
 	}
 
 	void Indexer::visit( ConstantExpr *constantExpr ) {
-		acceptAllNewScope( constantExpr->get_results(), *this );
+		acceptNewScope( constantExpr->get_result(), *this );
 		maybeAccept( constantExpr->get_constant(), *this );
 	}
 
 	void Indexer::visit( SizeofExpr *sizeofExpr ) {
-		acceptAllNewScope( sizeofExpr->get_results(), *this );
+		acceptNewScope( sizeofExpr->get_result(), *this );
 		if ( sizeofExpr->get_isType() ) {
 			maybeAccept( sizeofExpr->get_type(), *this );
@@ -395,5 +395,5 @@
 
 	void Indexer::visit( AlignofExpr *alignofExpr ) {
-		acceptAllNewScope( alignofExpr->get_results(), *this );
+		acceptNewScope( alignofExpr->get_result(), *this );
 		if ( alignofExpr->get_isType() ) {
 			maybeAccept( alignofExpr->get_type(), *this );
@@ -404,10 +404,10 @@
 
 	void Indexer::visit( UntypedOffsetofExpr *offsetofExpr ) {
-		acceptAllNewScope( offsetofExpr->get_results(), *this );
+		acceptNewScope( offsetofExpr->get_result(), *this );
 		maybeAccept( offsetofExpr->get_type(), *this );
 	}
 
 	void Indexer::visit( OffsetofExpr *offsetofExpr ) {
-		acceptAllNewScope( offsetofExpr->get_results(), *this );
+		acceptNewScope( offsetofExpr->get_result(), *this );
 		maybeAccept( offsetofExpr->get_type(), *this );
 		maybeAccept( offsetofExpr->get_member(), *this );
@@ -415,10 +415,10 @@
 
 	void Indexer::visit( OffsetPackExpr *offsetPackExpr ) {
-		acceptAllNewScope( offsetPackExpr->get_results(), *this );
+		acceptNewScope( offsetPackExpr->get_result(), *this );
 		maybeAccept( offsetPackExpr->get_type(), *this );
 	}
 
 	void Indexer::visit( AttrExpr *attrExpr ) {
-		acceptAllNewScope( attrExpr->get_results(), *this );
+		acceptNewScope( attrExpr->get_result(), *this );
 		if ( attrExpr->get_isType() ) {
 			maybeAccept( attrExpr->get_type(), *this );
@@ -429,5 +429,5 @@
 
 	void Indexer::visit( LogicalExpr *logicalExpr ) {
-		acceptAllNewScope( logicalExpr->get_results(), *this );
+		acceptNewScope( logicalExpr->get_result(), *this );
 		maybeAccept( logicalExpr->get_arg1(), *this );
 		maybeAccept( logicalExpr->get_arg2(), *this );
@@ -435,5 +435,5 @@
 
 	void Indexer::visit( ConditionalExpr *conditionalExpr ) {
-		acceptAllNewScope( conditionalExpr->get_results(), *this );
+		acceptNewScope( conditionalExpr->get_result(), *this );
 		maybeAccept( conditionalExpr->get_arg1(), *this );
 		maybeAccept( conditionalExpr->get_arg2(), *this );
@@ -442,5 +442,5 @@
 
 	void Indexer::visit( CommaExpr *commaExpr ) {
-		acceptAllNewScope( commaExpr->get_results(), *this );
+		acceptNewScope( commaExpr->get_result(), *this );
 		maybeAccept( commaExpr->get_arg1(), *this );
 		maybeAccept( commaExpr->get_arg2(), *this );
@@ -448,15 +448,18 @@
 
 	void Indexer::visit( TupleExpr *tupleExpr ) {
-		acceptAllNewScope( tupleExpr->get_results(), *this );
+		acceptNewScope( tupleExpr->get_result(), *this );
 		acceptAll( tupleExpr->get_exprs(), *this );
 	}
 
-	void Indexer::visit( SolvedTupleExpr *tupleExpr ) {
-		acceptAllNewScope( tupleExpr->get_results(), *this );
-		acceptAll( tupleExpr->get_exprs(), *this );
+	void Indexer::visit( TupleAssignExpr *tupleExpr ) {
+		acceptNewScope( tupleExpr->get_result(), *this );
+		enterScope();
+		acceptAll( tupleExpr->get_tempDecls(), *this );
+		acceptAll( tupleExpr->get_assigns(), *this );
+		leaveScope();
 	}
 
 	void Indexer::visit( TypeExpr *typeExpr ) {
-		acceptAllNewScope( typeExpr->get_results(), *this );
+		acceptNewScope( typeExpr->get_result(), *this );
 		maybeAccept( typeExpr->get_type(), *this );
 	}
@@ -469,5 +472,5 @@
 
 	void Indexer::visit( UntypedValofExpr *valofExpr ) {
-		acceptAllNewScope( valofExpr->get_results(), *this );
+		acceptNewScope( valofExpr->get_result(), *this );
 		maybeAccept( valofExpr->get_body(), *this );
 	}
Index: src/SymTab/Indexer.h
===================================================================
--- src/SymTab/Indexer.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SymTab/Indexer.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -64,9 +64,9 @@
 		virtual void visit( ConditionalExpr *conditionalExpr );
 		virtual void visit( CommaExpr *commaExpr );
-		virtual void visit( TupleExpr *tupleExpr );
-		virtual void visit( SolvedTupleExpr *tupleExpr );
 		virtual void visit( TypeExpr *typeExpr );
 		virtual void visit( AsmExpr *asmExpr );
 		virtual void visit( UntypedValofExpr *valofExpr );
+		virtual void visit( TupleExpr *tupleExpr );
+		virtual void visit( TupleAssignExpr *tupleExpr );
 
 		virtual void visit( TraitInstType *contextInst );
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SymTab/Mangler.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Mangler.cc -- 
+// Mangler.cc --
 //
 // Author           : Richard C. Bilson
@@ -35,8 +35,8 @@
 		return mangler.get_mangleName();
 	}
-	
+
 	Mangler::Mangler( bool mangleOverridable, bool typeMode )
 		: nextVarNum( 0 ), isTopLevel( true ), mangleOverridable( mangleOverridable ), typeMode( typeMode ) {}
-		
+
 	Mangler::Mangler( const Mangler &rhs ) : mangleName() {
 		varNums = rhs.varNums;
@@ -115,5 +115,5 @@
 			"Ir",	// LongDoubleImaginary
 		};
-  
+
 		printQualifiers( basicType );
 		mangleName << btLetter[ basicType->get_kind() ];
@@ -253,10 +253,10 @@
 		// skip if not including qualifiers
 		if ( typeMode ) return;
-		
+
 		if ( ! type->get_forall().empty() ) {
 			std::list< std::string > assertionNames;
 			int tcount = 0, dcount = 0, fcount = 0;
 			mangleName << "A";
-			for ( std::list< TypeDecl* >::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
+			for ( Type::ForallList::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
 				switch ( (*i)->get_kind() ) {
 				  case TypeDecl::Any:
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SymTab/Validate.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -23,6 +23,6 @@
 // - All enumeration constants have type EnumInstType.
 //
-// - The type "void" never occurs in lists of function parameter or return types; neither do tuple types.  A function
-//   taking no arguments has no argument types, and tuples are flattened.
+// - The type "void" never occurs in lists of function parameter or return types.  A function
+//   taking no arguments has no argument types.
 //
 // - No context instances exist; they are all replaced by the set of declarations signified by the context, instantiated
@@ -243,5 +243,5 @@
 		return dynamic_cast< StructDecl * >( decl ) || dynamic_cast< UnionDecl * >( decl );
 	}
-
+	// xxx - shouldn't this be declsToAddBefore?
 	template< typename AggDecl >
 	void HoistStruct::handleAggregate( AggDecl *aggregateDecl ) {
@@ -431,5 +431,5 @@
 	/// Fix up assertions
 	void forallFixer( Type *func ) {
-		for ( std::list< TypeDecl * >::iterator type = func->get_forall().begin(); type != func->get_forall().end(); ++type ) {
+		for ( Type::ForallList::iterator type = func->get_forall().begin(); type != func->get_forall().end(); ++type ) {
 			std::list< DeclarationWithType * > toBeDone, nextRound;
 			toBeDone.splice( toBeDone.end(), (*type )->get_assertions() );
Index: src/SynTree/AddressExpr.cc
===================================================================
--- src/SynTree/AddressExpr.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/AddressExpr.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -19,7 +19,7 @@
 
 AddressExpr::AddressExpr( Expression *arg, Expression *_aname ) : Expression( _aname ), arg( arg ) {
-	for ( std::list< Type* >::const_iterator i = arg->get_results().begin(); i != arg->get_results().end(); ++i ) {
-		get_results().push_back( new PointerType( Type::Qualifiers(), (*i)->clone() ) );
-	} // for
+	if ( arg->has_result() ) {
+		set_result( new PointerType( Type::Qualifiers(), arg->get_result()->clone() ) );
+	}
 }
 
@@ -35,5 +35,5 @@
 	if ( arg ) {
 		os << std::string( indent+2, ' ' );
-    arg->print( os, indent+2 );
+		arg->print( os, indent+2 );
 	} // if
 }
Index: src/SynTree/ApplicationExpr.cc
===================================================================
--- src/SynTree/ApplicationExpr.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/ApplicationExpr.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -21,5 +21,5 @@
 #include "TypeSubstitution.h"
 #include "Common/utility.h"
-
+#include "ResolvExpr/typeops.h"
 
 ParamEntry::ParamEntry( const ParamEntry &other ) :
@@ -43,12 +43,10 @@
 
 ApplicationExpr::ApplicationExpr( Expression *funcExpr ) : function( funcExpr ) {
-	PointerType *pointer = dynamic_cast< PointerType* >( funcExpr->get_results().front() );
-	assert( pointer );
-	FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() );
-	assert( function );
+	PointerType *pointer = safe_dynamic_cast< PointerType* >( funcExpr->get_result() );
+	FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
 
-	for ( std::list< DeclarationWithType* >::const_iterator i = function->get_returnVals().begin(); i != function->get_returnVals().end(); ++i ) {
-		get_results().push_back( (*i)->get_type()->clone() );
-	} // for
+	set_result( ResolvExpr::extractResultType( function ) );
+
+	assert( has_result() );
 }
 
Index: src/SynTree/CommaExpr.cc
===================================================================
--- src/SynTree/CommaExpr.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/CommaExpr.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -23,8 +23,6 @@
 	// to false on all result types. Actually doing this causes some strange things
 	// to happen in later passes (particularly, Specialize, Lvalue, and Box). This needs to be looked into.
-	cloneAll( arg2->get_results(), get_results() );
-	// for ( Type *& type : get_results() ) {
-	// 	type->set_isLvalue( false );
-	// }
+	set_result( maybeClone( arg2->get_result() ) );
+	// get_type->set_isLvalue( false );
 }
 
Index: src/SynTree/CompoundStmt.cc
===================================================================
--- src/SynTree/CompoundStmt.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/CompoundStmt.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -20,24 +20,8 @@
 #include "Expression.h"
 #include "Declaration.h"
+#include "SynTree/VarExprReplacer.h"
 
 using std::string;
 using std::endl;
-
-class VarExprReplacer : public Visitor {
-public:
-  typedef std::map< DeclarationWithType *, DeclarationWithType * > DeclMap;
-private:
-  const DeclMap & declMap;
-public:
-  VarExprReplacer( const DeclMap & declMap ) : declMap( declMap ) {}
-
-  // replace variable with new node from decl map
-  virtual void visit( VariableExpr * varExpr ) {
-    if ( declMap.count( varExpr->get_var() ) ) {
-      varExpr->set_var( declMap.at( varExpr->get_var() ) );
-    }
-  }
-};
-
 
 CompoundStmt::CompoundStmt( std::list<Label> labels ) : Statement( labels ) {
@@ -47,34 +31,36 @@
 	cloneAll( other.kids, kids );
 
-  // when cloning a compound statement, we may end up cloning declarations which
-  // are referred to by VariableExprs throughout the block. Cloning a VariableExpr
-  // does a shallow copy, so the VariableExpr will end up pointing to the original
-  // declaration. If the original declaration is deleted, e.g. because the original
-  // CompoundStmt is deleted, then we have a dangling pointer. To avoid this case,
-  // find all DeclarationWithType nodes (since a VariableExpr must point to a
-  // DeclarationWithType) in the original CompoundStmt and map them to the cloned
-  // node in the new CompoundStmt ('this'), then replace the Declarations referred to
-  // by each VariableExpr according to the constructed map. Note that only the declarations
-  // in the current level are collected into the map, because child CompoundStmts will
-  // recursively execute this routine. There may be more efficient ways of doing
-  // this.
-  VarExprReplacer::DeclMap declMap;
-  std::list< Statement * >::const_iterator origit = other.kids.begin();
-  for ( Statement * s : kids ) {
-    assert( origit != other.kids.end() );
-    if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( s ) ) {
-      DeclStmt * origDeclStmt = dynamic_cast< DeclStmt * >( *origit );
-      assert( origDeclStmt );
-      if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * > ( declStmt->get_decl() ) ) {
-        DeclarationWithType * origdwt = dynamic_cast< DeclarationWithType * > ( origDeclStmt->get_decl() );
-        assert( origdwt );
-        declMap[ origdwt ] = dwt;
-      }
-    }
-  }
-  if ( ! declMap.empty() ) {
-    VarExprReplacer replacer( declMap );
-    accept( replacer );
-  }
+	// when cloning a compound statement, we may end up cloning declarations which
+	// are referred to by VariableExprs throughout the block. Cloning a VariableExpr
+	// does a shallow copy, so the VariableExpr will end up pointing to the original
+	// declaration. If the original declaration is deleted, e.g. because the original
+	// CompoundStmt is deleted, then we have a dangling pointer. To avoid this case,
+	// find all DeclarationWithType nodes (since a VariableExpr must point to a
+	// DeclarationWithType) in the original CompoundStmt and map them to the cloned
+	// node in the new CompoundStmt ('this'), then replace the Declarations referred to
+	// by each VariableExpr according to the constructed map. Note that only the declarations
+	// in the current level are collected into the map, because child CompoundStmts will
+	// recursively execute this routine. There may be more efficient ways of doing
+	// this.
+	VarExprReplacer::DeclMap declMap;
+	std::list< Statement * >::const_iterator origit = other.kids.begin();
+	for ( Statement * s : kids ) {
+		assert( origit != other.kids.end() );
+		Statement * origStmt = *origit++;
+		if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( s ) ) {
+			DeclStmt * origDeclStmt = dynamic_cast< DeclStmt * >( origStmt );
+			assert( origDeclStmt );
+			if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * > ( declStmt->get_decl() ) ) {
+				DeclarationWithType * origdwt = dynamic_cast< DeclarationWithType * > ( origDeclStmt->get_decl() );
+				assert( origdwt );
+				assert( dwt->get_name() == origdwt->get_name() );
+				declMap[ origdwt ] = dwt;
+			}
+		}
+	}
+	if ( ! declMap.empty() ) {
+		VarExprReplacer replacer( declMap );
+		accept( replacer );
+	}
 }
 
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Expression.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -31,8 +31,7 @@
 
 
-Expression::Expression( Expression *_aname ) : env( 0 ), argName( _aname ) {}
-
-Expression::Expression( const Expression &other ) : env( maybeClone( other.env ) ), argName( maybeClone( other.get_argName() ) ), extension( other.extension ) {
-	cloneAll( other.results, results );
+Expression::Expression( Expression *_aname ) : result( 0 ), env( 0 ), argName( _aname ) {}
+
+Expression::Expression( const Expression &other ) : result( maybeClone( other.result ) ), env( maybeClone( other.env ) ), argName( maybeClone( other.get_argName() ) ), extension( other.extension ) {
 }
 
@@ -40,13 +39,5 @@
 	delete env;
 	delete argName;	// xxx -- there's a problem in cloning ConstantExpr I still don't know how to fix
-	deleteAll( results );
-}
-
-void Expression::add_result( Type *t ) {
-	if ( TupleType *tuple = dynamic_cast< TupleType* >( t ) ) {
-		std::copy( tuple->get_types().begin(), tuple->get_types().end(), back_inserter( results ) );
-	} else {
-		results.push_back(t);
-	} // if
+	delete result;
 }
 
@@ -68,5 +59,5 @@
 
 ConstantExpr::ConstantExpr( Constant _c, Expression *_aname ) : Expression( _aname ), constant( _c ) {
-	add_result( constant.get_type()->clone() );
+	set_result( constant.get_type()->clone() );
 }
 
@@ -85,8 +76,7 @@
 	assert( var );
 	assert( var->get_type() );
-	add_result( var->get_type()->clone() );
-	for ( std::list< Type* >::iterator i = get_results().begin(); i != get_results().end(); ++i ) {
-		(*i)->set_isLvalue( true );
-	} // for
+	Type * type = var->get_type()->clone();
+	type->set_isLvalue( true );
+	set_result( type );
 }
 
@@ -110,10 +100,10 @@
 SizeofExpr::SizeofExpr( Expression *expr_, Expression *_aname ) :
 		Expression( _aname ), expr(expr_), type(0), isType(false) {
-	add_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
+	set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
 }
 
 SizeofExpr::SizeofExpr( Type *type_, Expression *_aname ) :
 		Expression( _aname ), expr(0), type(type_), isType(true) {
-	add_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
+	set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
 }
 
@@ -141,10 +131,10 @@
 AlignofExpr::AlignofExpr( Expression *expr_, Expression *_aname ) :
 		Expression( _aname ), expr(expr_), type(0), isType(false) {
-	add_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
+	set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
 }
 
 AlignofExpr::AlignofExpr( Type *type_, Expression *_aname ) :
 		Expression( _aname ), expr(0), type(type_), isType(true) {
-	add_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
+	set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
 }
 
@@ -172,5 +162,5 @@
 UntypedOffsetofExpr::UntypedOffsetofExpr( Type *type_, const std::string &member_, Expression *_aname ) :
 		Expression( _aname ), type(type_), member(member_) {
-	add_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
+	set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
 }
 
@@ -197,5 +187,5 @@
 OffsetofExpr::OffsetofExpr( Type *type_, DeclarationWithType *member_, Expression *_aname ) :
 		Expression( _aname ), type(type_), member(member_) {
-	add_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
+	set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
 }
 
@@ -229,5 +219,5 @@
 
 OffsetPackExpr::OffsetPackExpr( StructInstType *type_, Expression *aname_ ) : Expression( aname_ ), type( type_ ) {
-	add_result( new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0, false, false ) );
+	set_result( new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0, false, false ) );
 }
 
@@ -284,8 +274,9 @@
 
 CastExpr::CastExpr( Expression *arg_, Type *toType, Expression *_aname ) : Expression( _aname ), arg(arg_) {
-	add_result(toType);
+	set_result(toType);
 }
 
 CastExpr::CastExpr( Expression *arg_, Expression *_aname ) : Expression( _aname ), arg(arg_) {
+	set_result( new VoidType( Type::Qualifiers() ) );
 }
 
@@ -303,31 +294,37 @@
 	arg->print(os, indent+2);
 	os << std::endl << std::string( indent, ' ' ) << "to:" << std::endl;
-	if ( results.empty() ) {
-		os << std::string( indent+2, ' ' ) << "nothing" << std::endl;
+	os << std::string( indent+2, ' ' );
+	if ( result->isVoid() ) {
+		os << "nothing";
 	} else {
-		printAll(results, os, indent+2);
+		result->print( os, indent+2 );
 	} // if
-	Expression::print( os, indent );
-}
-
-UntypedMemberExpr::UntypedMemberExpr( std::string _member, Expression *_aggregate, Expression *_aname ) :
+	os << std::endl;
+	Expression::print( os, indent );
+}
+
+UntypedMemberExpr::UntypedMemberExpr( Expression * _member, Expression *_aggregate, Expression *_aname ) :
 		Expression( _aname ), member(_member), aggregate(_aggregate) {}
 
 UntypedMemberExpr::UntypedMemberExpr( const UntypedMemberExpr &other ) :
-		Expression( other ), member( other.member ), aggregate( maybeClone( other.aggregate ) ) {
+		Expression( other ), member( maybeClone( other.member ) ), aggregate( maybeClone( other.aggregate ) ) {
 }
 
 UntypedMemberExpr::~UntypedMemberExpr() {
 	delete aggregate;
+	delete member;
 }
 
 void UntypedMemberExpr::print( std::ostream &os, int indent ) const {
-	os << "Untyped Member Expression, with field: " << get_member();
+	os << "Untyped Member Expression, with field: " << std::endl;
+	os << std::string( indent+2, ' ' );
+	get_member()->print(os, indent+4);
+	os << std::string( indent+2, ' ' );
 
 	Expression *agg = get_aggregate();
-	os << ", from aggregate: ";
+	os << "from aggregate: " << std::endl;
 	if (agg != 0) {
-		os << std::string( indent + 2, ' ' );
-		agg->print(os, indent + 2);
+		os << std::string( indent + 4, ' ' );
+		agg->print(os, indent + 4);
 	}
 	os << std::string( indent+2, ' ' );
@@ -338,8 +335,6 @@
 MemberExpr::MemberExpr( DeclarationWithType *_member, Expression *_aggregate, Expression *_aname ) :
 		Expression( _aname ), member(_member), aggregate(_aggregate) {
-	add_result( member->get_type()->clone() );
-	for ( std::list< Type* >::iterator i = get_results().begin(); i != get_results().end(); ++i ) {
-		(*i)->set_isLvalue( true );
-	} // for
+	set_result( member->get_type()->clone() );
+	get_result()->set_isLvalue( true );
 }
 
@@ -372,6 +367,6 @@
 }
 
-
-UntypedExpr::UntypedExpr( Expression *_function, Expression *_aname ) : Expression( _aname ), function( _function ) {}
+UntypedExpr::UntypedExpr( Expression *_function, const std::list<Expression *> &_args, Expression *_aname ) :
+		Expression( _aname ), function(_function), args(_args) {}
 
 UntypedExpr::UntypedExpr( const UntypedExpr &other ) :
@@ -380,11 +375,33 @@
 }
 
-UntypedExpr::UntypedExpr( Expression *_function, std::list<Expression *> &_args, Expression *_aname ) :
-		Expression( _aname ), function(_function), args(_args) {}
-
 UntypedExpr::~UntypedExpr() {
 	delete function;
 	deleteAll( args );
 }
+
+UntypedExpr * UntypedExpr::createDeref( Expression * expr ) {
+	UntypedExpr * ret = new UntypedExpr( new NameExpr("*?"), std::list< Expression * >{ expr } );
+	if ( Type * type = expr->get_result() ) {
+		Type * base = InitTweak::getPointerBase( type );
+		if ( ! base ) {
+			std::cerr << type << std::endl;
+		}
+		assertf( base, "expected pointer type in dereference\n" );
+		ret->set_result( maybeClone( base ) );
+	}
+	return ret;
+}
+
+UntypedExpr * UntypedExpr::createAssign( Expression * arg1, Expression * arg2 ) {
+	assert( arg1 && arg2 );
+	UntypedExpr * ret = new UntypedExpr( new NameExpr( "?=?" ), std::list< Expression * >{ arg1, arg2 } );
+	if ( arg1->get_result() && arg2->get_result() ) {
+		// if both expressions are typed, assumes that this assignment is a C bitwise assignment,
+		// so the result is the type of the RHS
+		ret->set_result( arg2->get_result()->clone() );
+	}
+	return ret;
+}
+
 
 void UntypedExpr::print( std::ostream &os, int indent ) const {
@@ -419,5 +436,5 @@
 LogicalExpr::LogicalExpr( Expression *arg1_, Expression *arg2_, bool andp, Expression *_aname ) :
 		Expression( _aname ), arg1(arg1_), arg2(arg2_), isAnd(andp) {
-	add_result( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
+	set_result( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
 }
 
@@ -454,9 +471,12 @@
 
 void ConditionalExpr::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Conditional expression on: " << std::endl;
+	os << "Conditional expression on: " << std::endl;
+	os << std::string( indent+2, ' ' );
 	arg1->print( os, indent+2 );
 	os << std::string( indent, ' ' ) << "First alternative:" << std::endl;
+	os << std::string( indent+2, ' ' );
 	arg2->print( os, indent+2 );
 	os << std::string( indent, ' ' ) << "Second alternative:" << std::endl;
+	os << std::string( indent+2, ' ' );
 	arg3->print( os, indent+2 );
 	os << std::endl;
@@ -477,5 +497,6 @@
 ImplicitCopyCtorExpr::ImplicitCopyCtorExpr( ApplicationExpr * callExpr ) : callExpr( callExpr ) {
 	assert( callExpr );
-	cloneAll( callExpr->get_results(), results );
+	assert( callExpr->has_result() );
+	set_result( callExpr->get_result()->clone() );
 }
 
@@ -510,5 +531,5 @@
 	Expression * arg = InitTweak::getCallArg( callExpr, 0 );
 	assert( arg );
-	cloneAll( arg->get_results(), results );
+	set_result( maybeClone( arg->get_result() ) );
 }
 
@@ -530,8 +551,9 @@
 
 CompoundLiteralExpr::CompoundLiteralExpr( Type * type, Initializer * initializer ) : type( type ), initializer( initializer ) {
-	add_result( type->clone() );
-}
-
-CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr &other ) : Expression( other ), type( maybeClone( other.type ) ), initializer( maybeClone( other.initializer ) ) {}
+	assert( type && initializer );
+	set_result( type->clone() );
+}
+
+CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr &other ) : Expression( other ), type( other.type->clone() ), initializer( other.initializer->clone() ) {}
 
 CompoundLiteralExpr::~CompoundLiteralExpr() {
@@ -542,6 +564,8 @@
 void CompoundLiteralExpr::print( std::ostream &os, int indent ) const {
 	os << "Compound Literal Expression: " << std::endl;
-	if ( type ) type->print( os, indent + 2 );
-	if ( initializer ) initializer->print( os, indent + 2 );
+	os << std::string( indent+2, ' ' );
+	type->print( os, indent + 2 );
+	os << std::string( indent+2, ' ' );
+	initializer->print( os, indent + 2 );
 }
 
@@ -557,10 +581,54 @@
 
 RangeExpr::RangeExpr( Expression *low, Expression *high ) : low( low ), high( high ) {}
-RangeExpr::RangeExpr( const RangeExpr &other ) : low( other.low->clone() ), high( other.high->clone() ) {}
+RangeExpr::RangeExpr( const RangeExpr &other ) : Expression( other ), low( other.low->clone() ), high( other.high->clone() ) {}
 void RangeExpr::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Range Expression: ";
+	os << "Range Expression: ";
 	low->print( os, indent );
 	os << " ... ";
 	high->print( os, indent );
+}
+
+StmtExpr::StmtExpr( CompoundStmt *statements ) : statements( statements ) {
+	assert( statements );
+	std::list< Statement * > & body = statements->get_kids();
+	if ( ! body.empty() ) {
+		if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( body.back() ) ) {
+			set_result( maybeClone( exprStmt->get_expr()->get_result() ) );
+		}
+	}
+}
+StmtExpr::StmtExpr( const StmtExpr &other ) : Expression( other ), statements( other.statements->clone() ) {}
+StmtExpr::~StmtExpr() {
+	delete statements;
+}
+void StmtExpr::print( std::ostream &os, int indent ) const {
+	os << "Statement Expression: " << std::endl << std::string( indent, ' ' );
+	statements->print( os, indent+2 );
+}
+
+
+long long UniqueExpr::count = 0;
+UniqueExpr::UniqueExpr( Expression *expr, long long idVal ) : expr( expr ), object( nullptr ), var( nullptr ), id( idVal ) {
+	assert( expr );
+	assert( count != -1 );
+	if ( id == -1 ) id = count++;
+	if ( expr->get_result() ) {
+		set_result( expr->get_result()->clone() );
+	}
+}
+UniqueExpr::UniqueExpr( const UniqueExpr &other ) : Expression( other ), expr( maybeClone( other.expr ) ), object( maybeClone( other.object ) ), var( maybeClone( other.var ) ), id( other.id ) {
+}
+UniqueExpr::~UniqueExpr() {
+	delete expr;
+	delete object;
+	delete var;
+}
+void UniqueExpr::print( std::ostream &os, int indent ) const {
+	os << "Unique Expression with id:" << id << std::endl << std::string( indent+2, ' ' );
+	get_expr()->print( os, indent+2 );
+	if ( get_object() ) {
+		os << " with decl: ";
+		get_object()->printShort( os, indent+2 );
+	}
 }
 
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Expression.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -32,6 +32,7 @@
 	virtual ~Expression();
 
-	std::list<Type *>& get_results() { return results; }
-	void add_result( Type *t );
+	Type *& get_result() { return result; }
+	void set_result( Type *newValue ) { result = newValue; }
+	bool has_result() const { return result != nullptr; }
 
 	TypeSubstitution *get_env() const { return env; }
@@ -47,5 +48,5 @@
 	virtual void print( std::ostream &os, int indent = 0 ) const;
   protected:
-	std::list<Type *> results;
+	Type * result;
 	TypeSubstitution *env;
 	Expression* argName; // if expression is used as an argument, it can be "designated" by this name
@@ -98,7 +99,6 @@
 class UntypedExpr : public Expression {
   public:
-	UntypedExpr( Expression *function, Expression *_aname = nullptr );
+	UntypedExpr( Expression *function, const std::list<Expression *> &args = std::list< Expression * >(), Expression *_aname = nullptr );
 	UntypedExpr( const UntypedExpr &other );
-	UntypedExpr( Expression *function, std::list<Expression *> &args, Expression *_aname = nullptr );
 	virtual ~UntypedExpr();
 
@@ -111,4 +111,7 @@
 	std::list<Expression*>& get_args() { return args; }
 
+	static UntypedExpr * createDeref( Expression * arg );
+	static UntypedExpr * createAssign( Expression * arg1, Expression * arg2 );
+
 	virtual UntypedExpr *clone() const { return new UntypedExpr( *this ); }
 	virtual void accept( Visitor &v ) { v.visit( this ); }
@@ -200,10 +203,10 @@
 class UntypedMemberExpr : public Expression {
   public:
-	UntypedMemberExpr( std::string member, Expression *aggregate, Expression *_aname = nullptr );
+	UntypedMemberExpr( Expression *member, Expression *aggregate, Expression *_aname = nullptr );
 	UntypedMemberExpr( const UntypedMemberExpr &other );
 	virtual ~UntypedMemberExpr();
 
-	std::string get_member() const { return member; }
-	void set_member( const std::string &newValue ) { member = newValue; }
+	Expression * get_member() const { return member; }
+	void set_member( Expression * newValue ) { member = newValue; }
 	Expression *get_aggregate() const { return aggregate; }
 	void set_aggregate( Expression *newValue ) { aggregate = newValue; }
@@ -214,5 +217,5 @@
 	virtual void print( std::ostream &os, int indent = 0 ) const;
   private:
-	std::string member;
+	Expression *member;
 	Expression *aggregate;
 };
@@ -483,40 +486,4 @@
 };
 
-/// TupleExpr represents a tuple expression ( [a, b, c] )
-class TupleExpr : public Expression {
-  public:
-	TupleExpr( Expression *_aname = nullptr );
-	TupleExpr( const TupleExpr &other );
-	virtual ~TupleExpr();
-
-	void set_exprs( std::list<Expression*> newValue ) { exprs = newValue; }
-	std::list<Expression*>& get_exprs() { return exprs; }
-
-	virtual TupleExpr *clone() const { return new TupleExpr( *this ); }
-	virtual void accept( Visitor &v ) { v.visit( this ); }
-	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
-	virtual void print( std::ostream &os, int indent = 0 ) const;
-  private:
-	std::list<Expression*> exprs;
-};
-
-/// SolvedTupleExpr represents a TupleExpr whose components have been type-resolved. It is effectively a shell for the code generator to work on
-class SolvedTupleExpr : public Expression {
-  public:
-	SolvedTupleExpr( Expression *_aname = nullptr ) : Expression( _aname ) {}
-	SolvedTupleExpr( std::list<Expression *> &, Expression *_aname = nullptr );
-	SolvedTupleExpr( const SolvedTupleExpr &other );
-	virtual ~SolvedTupleExpr() {}
-
-	std::list<Expression*> &get_exprs() { return exprs; }
-
-	virtual SolvedTupleExpr *clone() const { return new SolvedTupleExpr( *this ); }
-	virtual void accept( Visitor &v ) { v.visit( this ); }
-	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
-	virtual void print( std::ostream &os, int indent = 0 ) const;
-  private:
-	std::list<Expression*> exprs;
-};
-
 /// TypeExpr represents a type used in an expression (e.g. as a type generator parameter)
 class TypeExpr : public Expression {
@@ -618,5 +585,5 @@
 	CompoundLiteralExpr( Type * type, Initializer * initializer );
 	CompoundLiteralExpr( const CompoundLiteralExpr &other );
-	~CompoundLiteralExpr();
+	virtual ~CompoundLiteralExpr();
 
 	Type * get_type() const { return type; }
@@ -670,4 +637,130 @@
   private:
 	Expression *low, *high;
+};
+
+/// TupleExpr represents a tuple expression ( [a, b, c] )
+class TupleExpr : public Expression {
+  public:
+	TupleExpr( const std::list< Expression * > & exprs = std::list< Expression * >(), Expression *_aname = nullptr );
+	TupleExpr( const TupleExpr &other );
+	virtual ~TupleExpr();
+
+	void set_exprs( std::list<Expression*> newValue ) { exprs = newValue; }
+	std::list<Expression*>& get_exprs() { return exprs; }
+
+	virtual TupleExpr *clone() const { return new TupleExpr( *this ); }
+	virtual void accept( Visitor &v ) { v.visit( this ); }
+	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
+	virtual void print( std::ostream &os, int indent = 0 ) const;
+  private:
+	std::list<Expression*> exprs;
+};
+
+/// TupleIndexExpr represents an element selection operation on a tuple value, e.g. t.3 after processing by the expression analyzer
+class TupleIndexExpr : public Expression {
+  public:
+	TupleIndexExpr( Expression * tuple, unsigned int index );
+	TupleIndexExpr( const TupleIndexExpr &other );
+	virtual ~TupleIndexExpr();
+
+	Expression * get_tuple() const { return tuple; }
+	int get_index() const { return index; }
+	TupleIndexExpr * set_tuple( Expression *newValue ) { tuple = newValue; return this; }
+	TupleIndexExpr * set_index( unsigned int newValue ) { index = newValue; return this; }
+
+	virtual TupleIndexExpr *clone() const { return new TupleIndexExpr( *this ); }
+	virtual void accept( Visitor &v ) { v.visit( this ); }
+	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
+	virtual void print( std::ostream &os, int indent = 0 ) const;
+  private:
+	Expression * tuple;
+	unsigned int index;
+};
+
+/// MemberTupleExpr represents a tuple member selection operation on a struct type, e.g. s.[a, b, c] after processing by the expression analyzer
+class MemberTupleExpr : public Expression {
+  public:
+	MemberTupleExpr( Expression * member, Expression * aggregate, Expression * _aname = nullptr );
+	MemberTupleExpr( const MemberTupleExpr &other );
+	virtual ~MemberTupleExpr();
+
+	Expression * get_member() const { return member; }
+	Expression * get_aggregate() const { return aggregate; }
+	MemberTupleExpr * set_member( Expression *newValue ) { member = newValue; return this; }
+	MemberTupleExpr * set_aggregate( Expression *newValue ) { aggregate = newValue; return this; }
+
+	virtual MemberTupleExpr *clone() const { return new MemberTupleExpr( *this ); }
+	virtual void accept( Visitor &v ) { v.visit( this ); }
+	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
+	virtual void print( std::ostream &os, int indent = 0 ) const;
+  private:
+	Expression * member;
+	Expression * aggregate;
+};
+
+/// TupleAssignExpr represents a multiple assignment operation, where both sides of the assignment have tuple type, e.g. [a, b, c] = [d, e, f];, a mass assignment operation, where the left hand side has tuple type and the right hand side does not, e.g. [a, b, c] = 5.0;, or a tuple ctor/dtor expression
+class TupleAssignExpr : public Expression {
+  public:
+	TupleAssignExpr( const std::list< Expression * > & assigns, const std::list< ObjectDecl * > & tempDecls, Expression * _aname = nullptr );
+	TupleAssignExpr( const TupleAssignExpr &other );
+	virtual ~TupleAssignExpr();
+
+	std::list< Expression * > & get_assigns() { return assigns; }
+	std::list< ObjectDecl * > & get_tempDecls() { return tempDecls; }
+
+	virtual TupleAssignExpr *clone() const { return new TupleAssignExpr( *this ); }
+	virtual void accept( Visitor &v ) { v.visit( this ); }
+	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
+	virtual void print( std::ostream &os, int indent = 0 ) const;
+  private:
+	std::list< Expression * > assigns; // assignment expressions that use tempDecls
+	std::list< ObjectDecl * > tempDecls; // temporaries for address of lhs exprs
+};
+
+/// StmtExpr represents a GCC 'statement expression', e.g. ({ int x = 5; x; })
+class StmtExpr : public Expression {
+public:
+	StmtExpr( CompoundStmt *statements );
+	StmtExpr( const StmtExpr & other );
+	virtual ~StmtExpr();
+
+	CompoundStmt * get_statements() const { return statements; }
+	StmtExpr * set_statements( CompoundStmt * newValue ) { statements = newValue; return this; }
+
+	virtual StmtExpr *clone() const { return new StmtExpr( *this ); }
+	virtual void accept( Visitor &v ) { v.visit( this ); }
+	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
+	virtual void print( std::ostream &os, int indent = 0 ) const;
+private:
+	CompoundStmt * statements;
+};
+
+class UniqueExpr : public Expression {
+public:
+	UniqueExpr( Expression * expr, long long idVal = -1 );
+	UniqueExpr( const UniqueExpr & other );
+	~UniqueExpr();
+
+	Expression * get_expr() const { return expr; }
+	UniqueExpr * set_expr( Expression * newValue ) { expr = newValue; return this; }
+
+	ObjectDecl * get_object() const { return object; }
+	UniqueExpr * set_object( ObjectDecl * newValue ) { object = newValue; return this; }
+
+	VariableExpr * get_var() const { return var; }
+	UniqueExpr * set_var( VariableExpr * newValue ) { var = newValue; return this; }
+
+	int get_id() const { return id; }
+
+	virtual UniqueExpr *clone() const { return new UniqueExpr( *this ); }
+	virtual void accept( Visitor &v ) { v.visit( this ); }
+	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
+	virtual void print( std::ostream &os, int indent = 0 ) const;
+private:
+	Expression * expr;
+	ObjectDecl * object;
+	VariableExpr * var;
+	int id;
+	static long long count;
 };
 
Index: src/SynTree/Initializer.h
===================================================================
--- src/SynTree/Initializer.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Initializer.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -23,4 +23,6 @@
 
 #include <cassert>
+
+const std::list<Expression*> noDesignators;
 
 // Initializer: base class for object initializers (provide default values)
Index: src/SynTree/Mutator.cc
===================================================================
--- src/SynTree/Mutator.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Mutator.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -178,5 +178,5 @@
 
 Expression *Mutator::mutate( ApplicationExpr *applicationExpr ) {
-	mutateAll( applicationExpr->get_results(), *this );
+	applicationExpr->set_result( maybeMutate( applicationExpr->get_result(), *this ) );
 	applicationExpr->set_function( maybeMutate( applicationExpr->get_function(), *this ) );
 	mutateAll( applicationExpr->get_args(), *this );
@@ -185,5 +185,5 @@
 
 Expression *Mutator::mutate( UntypedExpr *untypedExpr ) {
-	mutateAll( untypedExpr->get_results(), *this );
+	untypedExpr->set_result( maybeMutate( untypedExpr->get_result(), *this ) );
 	mutateAll( untypedExpr->get_args(), *this );
 	return untypedExpr;
@@ -191,10 +191,10 @@
 
 Expression *Mutator::mutate( NameExpr *nameExpr ) {
-	mutateAll( nameExpr->get_results(), *this );
+	nameExpr->set_result( maybeMutate( nameExpr->get_result(), *this ) );
 	return nameExpr;
 }
 
 Expression *Mutator::mutate( AddressExpr *addressExpr ) {
-	mutateAll( addressExpr->get_results(), *this );
+	addressExpr->set_result( maybeMutate( addressExpr->get_result(), *this ) );
 	addressExpr->set_arg( maybeMutate( addressExpr->get_arg(), *this ) );
 	return addressExpr;
@@ -202,5 +202,5 @@
 
 Expression *Mutator::mutate( LabelAddressExpr *labelAddressExpr ) {
-	mutateAll( labelAddressExpr->get_results(), *this );
+	labelAddressExpr->set_result( maybeMutate( labelAddressExpr->get_result(), *this ) );
 	labelAddressExpr->set_arg( maybeMutate( labelAddressExpr->get_arg(), *this ) );
 	return labelAddressExpr;
@@ -208,5 +208,5 @@
 
 Expression *Mutator::mutate( CastExpr *castExpr ) {
-	mutateAll( castExpr->get_results(), *this );
+	castExpr->set_result( maybeMutate( castExpr->get_result(), *this ) );
 	castExpr->set_arg( maybeMutate( castExpr->get_arg(), *this ) );
 	return castExpr;
@@ -214,22 +214,23 @@
 
 Expression *Mutator::mutate( UntypedMemberExpr *memberExpr ) {
-	mutateAll( memberExpr->get_results(), *this );
+	memberExpr->set_result( maybeMutate( memberExpr->get_result(), *this ) );
+	memberExpr->set_aggregate( maybeMutate( memberExpr->get_aggregate(), *this ) );
+	memberExpr->set_member( maybeMutate( memberExpr->get_member(), *this ) );
+	return memberExpr;
+}
+
+Expression *Mutator::mutate( MemberExpr *memberExpr ) {
+	memberExpr->set_result( maybeMutate( memberExpr->get_result(), *this ) );
 	memberExpr->set_aggregate( maybeMutate( memberExpr->get_aggregate(), *this ) );
 	return memberExpr;
 }
 
-Expression *Mutator::mutate( MemberExpr *memberExpr ) {
-	mutateAll( memberExpr->get_results(), *this );
-	memberExpr->set_aggregate( maybeMutate( memberExpr->get_aggregate(), *this ) );
-	return memberExpr;
-}
-
 Expression *Mutator::mutate( VariableExpr *variableExpr ) {
-	mutateAll( variableExpr->get_results(), *this );
+	variableExpr->set_result( maybeMutate( variableExpr->get_result(), *this ) );
 	return variableExpr;
 }
 
 Expression *Mutator::mutate( ConstantExpr *constantExpr ) {
-	mutateAll( constantExpr->get_results(), *this );
+	constantExpr->set_result( maybeMutate( constantExpr->get_result(), *this ) );
 //  maybeMutate( constantExpr->get_constant(), *this )
 	return constantExpr;
@@ -237,5 +238,5 @@
 
 Expression *Mutator::mutate( SizeofExpr *sizeofExpr ) {
-	mutateAll( sizeofExpr->get_results(), *this );
+	sizeofExpr->set_result( maybeMutate( sizeofExpr->get_result(), *this ) );
 	if ( sizeofExpr->get_isType() ) {
 		sizeofExpr->set_type( maybeMutate( sizeofExpr->get_type(), *this ) );
@@ -247,5 +248,5 @@
 
 Expression *Mutator::mutate( AlignofExpr *alignofExpr ) {
-	mutateAll( alignofExpr->get_results(), *this );
+	alignofExpr->set_result( maybeMutate( alignofExpr->get_result(), *this ) );
 	if ( alignofExpr->get_isType() ) {
 		alignofExpr->set_type( maybeMutate( alignofExpr->get_type(), *this ) );
@@ -257,5 +258,5 @@
 
 Expression *Mutator::mutate( UntypedOffsetofExpr *offsetofExpr ) {
-	mutateAll( offsetofExpr->get_results(), *this );
+	offsetofExpr->set_result( maybeMutate( offsetofExpr->get_result(), *this ) );
 	offsetofExpr->set_type( maybeMutate( offsetofExpr->get_type(), *this ) );
 	return offsetofExpr;
@@ -263,5 +264,5 @@
 
 Expression *Mutator::mutate( OffsetofExpr *offsetofExpr ) {
-	mutateAll( offsetofExpr->get_results(), *this );
+	offsetofExpr->set_result( maybeMutate( offsetofExpr->get_result(), *this ) );
 	offsetofExpr->set_type( maybeMutate( offsetofExpr->get_type(), *this ) );
 	offsetofExpr->set_member( maybeMutate( offsetofExpr->get_member(), *this ) );
@@ -270,5 +271,5 @@
 
 Expression *Mutator::mutate( OffsetPackExpr *offsetPackExpr ) {
-	mutateAll( offsetPackExpr->get_results(), *this );
+	offsetPackExpr->set_result( maybeMutate( offsetPackExpr->get_result(), *this ) );
 	offsetPackExpr->set_type( maybeMutate( offsetPackExpr->get_type(), *this ) );
 	return offsetPackExpr;
@@ -276,5 +277,5 @@
 
 Expression *Mutator::mutate( AttrExpr *attrExpr ) {
-	mutateAll( attrExpr->get_results(), *this );
+	attrExpr->set_result( maybeMutate( attrExpr->get_result(), *this ) );
 	if ( attrExpr->get_isType() ) {
 		attrExpr->set_type( maybeMutate( attrExpr->get_type(), *this ) );
@@ -286,5 +287,5 @@
 
 Expression *Mutator::mutate( LogicalExpr *logicalExpr ) {
-	mutateAll( logicalExpr->get_results(), *this );
+	logicalExpr->set_result( maybeMutate( logicalExpr->get_result(), *this ) );
 	logicalExpr->set_arg1( maybeMutate( logicalExpr->get_arg1(), *this ) );
 	logicalExpr->set_arg2( maybeMutate( logicalExpr->get_arg2(), *this ) );
@@ -293,5 +294,5 @@
 
 Expression *Mutator::mutate( ConditionalExpr *conditionalExpr ) {
-	mutateAll( conditionalExpr->get_results(), *this );
+	conditionalExpr->set_result( maybeMutate( conditionalExpr->get_result(), *this ) );
 	conditionalExpr->set_arg1( maybeMutate( conditionalExpr->get_arg1(), *this ) );
 	conditionalExpr->set_arg2( maybeMutate( conditionalExpr->get_arg2(), *this ) );
@@ -301,5 +302,5 @@
 
 Expression *Mutator::mutate( CommaExpr *commaExpr ) {
-	mutateAll( commaExpr->get_results(), *this );
+	commaExpr->set_result( maybeMutate( commaExpr->get_result(), *this ) );
 	commaExpr->set_arg1( maybeMutate( commaExpr->get_arg1(), *this ) );
 	commaExpr->set_arg2( maybeMutate( commaExpr->get_arg2(), *this ) );
@@ -307,18 +308,6 @@
 }
 
-Expression *Mutator::mutate( TupleExpr *tupleExpr ) {
-	mutateAll( tupleExpr->get_results(), *this );
-	mutateAll( tupleExpr->get_exprs(), *this );
-	return tupleExpr;
-}
-
-Expression *Mutator::mutate( SolvedTupleExpr *tupleExpr ) {
-	mutateAll( tupleExpr->get_results(), *this );
-	mutateAll( tupleExpr->get_exprs(), *this );
-	return tupleExpr;
-}
-
 Expression *Mutator::mutate( TypeExpr *typeExpr ) {
-	mutateAll( typeExpr->get_results(), *this );
+	typeExpr->set_result( maybeMutate( typeExpr->get_result(), *this ) );
 	typeExpr->set_type( maybeMutate( typeExpr->get_type(), *this ) );
 	return typeExpr;
@@ -340,5 +329,5 @@
 
 Expression* Mutator::mutate( ConstructorExpr *ctorExpr ) {
-	mutateAll( ctorExpr->get_results(), *this );
+	ctorExpr->set_result( maybeMutate( ctorExpr->get_result(), *this ) );
 	ctorExpr->set_callExpr( maybeMutate( ctorExpr->get_callExpr(), *this ) );
 	return ctorExpr;
@@ -346,5 +335,5 @@
 
 Expression *Mutator::mutate( CompoundLiteralExpr *compLitExpr ) {
-	mutateAll( compLitExpr->get_results(), *this );
+	compLitExpr->set_result( maybeMutate( compLitExpr->get_result(), *this ) );
 	compLitExpr->set_type( maybeMutate( compLitExpr->get_type(), *this ) );
 	compLitExpr->set_initializer( maybeMutate( compLitExpr->get_initializer(), *this ) );
@@ -353,5 +342,5 @@
 
 Expression *Mutator::mutate( UntypedValofExpr *valofExpr ) {
-	mutateAll( valofExpr->get_results(), *this );
+	valofExpr->set_result( maybeMutate( valofExpr->get_result(), *this ) );
 	return valofExpr;
 }
@@ -361,4 +350,42 @@
 	rangeExpr->set_high( maybeMutate( rangeExpr->get_high(), *this ) );
 	return rangeExpr;
+}
+
+Expression *Mutator::mutate( TupleExpr *tupleExpr ) {
+	tupleExpr->set_result( maybeMutate( tupleExpr->get_result(), *this ) );
+	mutateAll( tupleExpr->get_exprs(), *this );
+	return tupleExpr;
+}
+
+Expression *Mutator::mutate( TupleIndexExpr *tupleExpr ) {
+	tupleExpr->set_result( maybeMutate( tupleExpr->get_result(), *this ) );
+	tupleExpr->set_tuple( maybeMutate( tupleExpr->get_tuple(), *this ) );
+	return tupleExpr;
+}
+
+Expression *Mutator::mutate( MemberTupleExpr *tupleExpr ) {
+	tupleExpr->set_result( maybeMutate( tupleExpr->get_result(), *this ) );
+	tupleExpr->set_member( maybeMutate( tupleExpr->get_member(), *this ) );
+	tupleExpr->set_aggregate( maybeMutate( tupleExpr->get_aggregate(), *this ) );
+	return tupleExpr;
+}
+
+Expression *Mutator::mutate( TupleAssignExpr *assignExpr ) {
+	assignExpr->set_result( maybeMutate( assignExpr->get_result(), *this ) );
+	mutateAll( assignExpr->get_tempDecls(), *this );
+	mutateAll( assignExpr->get_assigns(), *this );
+	return assignExpr;
+}
+
+Expression *Mutator::mutate( StmtExpr *stmtExpr ) {
+	stmtExpr->set_result( maybeMutate( stmtExpr->get_result(), *this ) );
+	stmtExpr->set_statements( maybeMutate( stmtExpr->get_statements(), *this ) );
+	return stmtExpr;
+}
+
+Expression *Mutator::mutate( UniqueExpr *uniqueExpr ) {
+	uniqueExpr->set_result( maybeMutate( uniqueExpr->get_result(), *this ) );
+	uniqueExpr->set_expr( maybeMutate( uniqueExpr->get_expr(), *this ) );
+	return uniqueExpr;
 }
 
Index: src/SynTree/Mutator.h
===================================================================
--- src/SynTree/Mutator.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Mutator.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -71,6 +71,4 @@
 	virtual Expression* mutate( ConditionalExpr *conditionalExpr );
 	virtual Expression* mutate( CommaExpr *commaExpr );
-	virtual Expression* mutate( TupleExpr *tupleExpr );
-	virtual Expression* mutate( SolvedTupleExpr *tupleExpr );
 	virtual Expression* mutate( TypeExpr *typeExpr );
 	virtual Expression* mutate( AsmExpr *asmExpr );
@@ -80,4 +78,10 @@
 	virtual Expression* mutate( UntypedValofExpr *valofExpr );
 	virtual Expression* mutate( RangeExpr *rangeExpr );
+	virtual Expression* mutate( TupleExpr *tupleExpr );
+	virtual Expression* mutate( TupleIndexExpr *tupleExpr );
+	virtual Expression* mutate( MemberTupleExpr *tupleExpr );
+	virtual Expression* mutate( TupleAssignExpr *assignExpr );
+	virtual Expression* mutate( StmtExpr * stmtExpr );
+	virtual Expression* mutate( UniqueExpr * uniqueExpr );
 
 	virtual Type* mutate( VoidType *basicType );
Index: src/SynTree/ReferenceToType.cc
===================================================================
--- src/SynTree/ReferenceToType.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/ReferenceToType.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -56,4 +56,6 @@
 	}
 } // namespace
+
+StructInstType::StructInstType( const Type::Qualifiers & tq, StructDecl * baseStruct ) : Parent( tq, baseStruct->get_name() ), baseStruct( baseStruct ) {}
 
 std::string StructInstType::typeString() const { return "struct"; }
Index: src/SynTree/SynTree.h
===================================================================
--- src/SynTree/SynTree.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/SynTree.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -76,6 +76,4 @@
 class ConditionalExpr;
 class CommaExpr;
-class TupleExpr;
-class SolvedTupleExpr;
 class TypeExpr;
 class AsmExpr;
@@ -85,4 +83,10 @@
 class UntypedValofExpr;
 class RangeExpr;
+class TupleExpr;
+class TupleIndexExpr;
+class MemberTupleExpr;
+class TupleAssignExpr;
+class StmtExpr;
+class UniqueExpr;
 
 class Type;
Index: src/SynTree/TupleExpr.cc
===================================================================
--- src/SynTree/TupleExpr.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/TupleExpr.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// TupleExpr.cc -- 
+// TupleExpr.cc --
 //
 // Author           : Richard C. Bilson
@@ -16,6 +16,15 @@
 #include "Expression.h"
 #include "Common/utility.h"
+#include "Type.h"
+#include "Declaration.h"
+#include "Tuples/Tuples.h"
+#include "VarExprReplacer.h"
 
-TupleExpr::TupleExpr( Expression *_aname ) : Expression( _aname ) {
+TupleExpr::TupleExpr( const std::list< Expression * > & exprs, Expression *_aname ) : Expression( _aname ), exprs( exprs ) {
+	if ( ! exprs.empty() ) {
+		if ( std::all_of( exprs.begin(), exprs.end(), [](Expression * expr) { return expr->get_result(); } ) ) {
+			set_result( Tuples::makeTupleType( exprs ) );
+		}
+	}
 }
 
@@ -29,22 +38,94 @@
 
 void TupleExpr::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Tuple:" << std::endl;
+	os << "Tuple:" << std::endl;
 	printAll( exprs, os, indent+2 );
 	Expression::print( os, indent );
 }
 
-SolvedTupleExpr::SolvedTupleExpr( std::list<Expression *> &_exprs, Expression *_aname ) : Expression( _aname ) {
-	std::copy(_exprs.begin(), _exprs.end(), back_inserter(exprs));
+TupleIndexExpr::TupleIndexExpr( Expression * tuple, unsigned int index ) : tuple( tuple ), index( index )  {
+	TupleType * type = safe_dynamic_cast< TupleType * >( tuple->get_result() );
+	assert( type->size() > index );
+	set_result( (*std::next( type->get_types().begin(), index ))->clone() );
+	get_result()->set_isLvalue( type->get_isLvalue() );
 }
 
-SolvedTupleExpr::SolvedTupleExpr( const SolvedTupleExpr &other ) : Expression( other ) {
-	cloneAll( other.exprs, exprs );
+TupleIndexExpr::TupleIndexExpr( const TupleIndexExpr &other ) : Expression( other ), tuple( other.tuple->clone() ), index( other.index ) {
 }
 
-void SolvedTupleExpr::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Solved Tuple:" << std::endl;
-	printAll( exprs, os, indent+2 );
+TupleIndexExpr::~TupleIndexExpr() {
+	delete tuple;
+}
+
+void TupleIndexExpr::print( std::ostream &os, int indent ) const {
+	os << "Tuple Index Expression, with tuple:" << std::endl;
+	os << std::string( indent+2, ' ' );
+	tuple->print( os, indent+2 );
+	os << std::string( indent+2, ' ' ) << "with index: " << index << std::endl;
 	Expression::print( os, indent );
 }
+
+MemberTupleExpr::MemberTupleExpr( Expression * member, Expression * aggregate, Expression * _aname ) : Expression( _aname ) {
+	set_result( maybeClone( member->get_result() ) ); // xxx - ???
+}
+
+MemberTupleExpr::MemberTupleExpr( const MemberTupleExpr &other ) : Expression( other ), member( other.member->clone() ), aggregate( other.aggregate->clone() ) {
+}
+
+MemberTupleExpr::~MemberTupleExpr() {
+	delete member;
+	delete aggregate;
+}
+
+void MemberTupleExpr::print( std::ostream &os, int indent ) const {
+	os << "Member Tuple Expression, with aggregate:" << std::endl;
+	os << std::string( indent+2, ' ' );
+	aggregate->print( os, indent+2 );
+	os << std::string( indent+2, ' ' ) << "with member: " << std::endl;
+	os << std::string( indent+2, ' ' );
+	member->print( os, indent+2 );
+	Expression::print( os, indent );
+}
+
+
+TupleAssignExpr::TupleAssignExpr( const std::list< Expression * > & assigns, const std::list< ObjectDecl * > & tempDecls, Expression * _aname ) : Expression( _aname ), assigns( assigns ), tempDecls( tempDecls ) {
+	set_result( Tuples::makeTupleType( assigns ) );
+}
+
+TupleAssignExpr::TupleAssignExpr( const TupleAssignExpr &other ) : Expression( other ) {
+	cloneAll( other.assigns, assigns );
+	cloneAll( other.tempDecls, tempDecls );
+
+	// clone needs to go into assigns and replace tempDecls
+	VarExprReplacer::DeclMap declMap;
+	std::list< ObjectDecl * >::const_iterator origit = other.tempDecls.begin();
+	for ( ObjectDecl * temp : tempDecls ) {
+		assert( origit != other.tempDecls.end() );
+		ObjectDecl * origTemp = *origit++;
+		assert( origTemp );
+		assert( temp->get_name() == origTemp->get_name() );
+		declMap[ origTemp ] = temp;
+	}
+	if ( ! declMap.empty() ) {
+		VarExprReplacer replacer( declMap );
+		for ( Expression * assn : assigns ) {
+			assn->accept( replacer );
+		}
+	}
+}
+
+TupleAssignExpr::~TupleAssignExpr() {
+	deleteAll( assigns );
+	// deleteAll( tempDecls );
+}
+
+void TupleAssignExpr::print( std::ostream &os, int indent ) const {
+	os << "Tuple Assignment Expression, with temporaries:" << std::endl;
+	printAll( tempDecls, os, indent+4 );
+	os << std::string( indent+2, ' ' ) << "with assignments: " << std::endl;
+	printAll( assigns, os, indent+4 );
+	Expression::print( os, indent );
+}
+
+
 
 // Local Variables: //
Index: src/SynTree/TupleType.cc
===================================================================
--- src/SynTree/TupleType.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/TupleType.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// TupleType.cc -- 
+// TupleType.cc --
 //
 // Author           : Richard C. Bilson
@@ -17,5 +17,5 @@
 #include "Common/utility.h"
 
-TupleType::TupleType( const Type::Qualifiers &tq ) : Type( tq ) {
+TupleType::TupleType( const Type::Qualifiers &tq, const std::list< Type * > & types ) : Type( tq ), types( types ) {
 }
 
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Type.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -20,4 +20,5 @@
 #include "Visitor.h"
 #include "Mutator.h"
+#include "Common/utility.h"
 
 class Type {
@@ -27,4 +28,5 @@
 		Qualifiers( bool isConst, bool isVolatile, bool isRestrict, bool isLvalue, bool isAtomic, bool isAttribute ): isConst( isConst ), isVolatile( isVolatile ), isRestrict( isRestrict ), isLvalue( isLvalue ), isAtomic( isAtomic ), isAttribute( isAttribute ) {}
 
+		Qualifiers &operator&=( const Qualifiers &other );
 		Qualifiers &operator+=( const Qualifiers &other );
 		Qualifiers &operator-=( const Qualifiers &other );
@@ -63,5 +65,11 @@
 	void set_isAtomic( bool newValue ) { tq.isAtomic = newValue; }
 	void set_isAttribute( bool newValue ) { tq.isAttribute = newValue; }
-	std::list<TypeDecl*>& get_forall() { return forall; }
+
+	typedef std::list<TypeDecl *> ForallList;
+	ForallList& get_forall() { return forall; }
+
+	/// How many elemental types are represented by this type
+	virtual unsigned size() const { return 1; };
+	virtual bool isVoid() const { return size() == 0; }
 
 	virtual Type *clone() const = 0;
@@ -71,5 +79,5 @@
   private:
 	Qualifiers tq;
-	std::list<TypeDecl*> forall;
+	ForallList forall;
 };
 
@@ -77,4 +85,6 @@
   public:
 	VoidType( const Type::Qualifiers &tq );
+
+	virtual unsigned size() const { return 0; };
 
 	virtual VoidType *clone() const { return new VoidType( *this ); }
@@ -234,4 +244,5 @@
   public:
 	StructInstType( const Type::Qualifiers &tq, const std::string &name ) : Parent( tq, name ), baseStruct( 0 ) {}
+	StructInstType( const Type::Qualifiers &tq, StructDecl * baseStruct );
 	StructInstType( const StructInstType &other ) : Parent( other ), baseStruct( other.baseStruct ) {}
 
@@ -348,9 +359,16 @@
 class TupleType : public Type {
   public:
-	TupleType( const Type::Qualifiers &tq );
+	TupleType( const Type::Qualifiers &tq, const std::list< Type * > & types = std::list< Type * >() );
 	TupleType( const TupleType& );
 	virtual ~TupleType();
 
+	typedef std::list<Type*> value_type;
+	typedef value_type::iterator iterator;
+
 	std::list<Type*>& get_types() { return types; }
+	virtual unsigned size() const { return types.size(); };
+
+	iterator begin() { return types.begin(); }
+	iterator end() { return types.end(); }
 
 	virtual TupleType *clone() const { return new TupleType( *this ); }
@@ -442,4 +460,13 @@
 };
 
+inline Type::Qualifiers &Type::Qualifiers::operator&=( const Type::Qualifiers &other ) {
+	isConst &= other.isConst;
+	isVolatile &= other.isVolatile;
+	isRestrict &= other.isRestrict;
+	isLvalue &= other.isLvalue;
+	isAtomic &= other.isAtomic;
+	return *this;
+}
+
 inline Type::Qualifiers &Type::Qualifiers::operator+=( const Type::Qualifiers &other ) {
 	isConst |= other.isConst;
Index: src/SynTree/TypeSubstitution.cc
===================================================================
--- src/SynTree/TypeSubstitution.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/TypeSubstitution.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -72,23 +72,23 @@
 Type *TypeSubstitution::lookup( std::string formalType ) const {
 	TypeEnvType::const_iterator i = typeEnv.find( formalType );
-	
+
 	// break on not in substitution set
 	if ( i == typeEnv.end() ) return 0;
-	
+
 	// attempt to transitively follow TypeInstType links.
 	while ( TypeInstType *actualType = dynamic_cast< TypeInstType* >( i->second ) ) {
 		const std::string& typeName = actualType->get_name();
-		
+
 		// break cycles in the transitive follow
 		if ( formalType == typeName ) break;
-		
+
 		// Look for the type this maps to, returning previous mapping if none-such
 		i = typeEnv.find( typeName );
 		if ( i == typeEnv.end() ) return actualType;
 	}
-	
+
 	// return type from substitution set
 	return i->second;
-	
+
 #if 0
 	if ( i == typeEnv.end() ) {
@@ -149,5 +149,5 @@
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
+		for ( Type::ForallList::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
 			boundVars.insert( (*tyvar )->get_name() );
 		} // for
@@ -163,5 +163,5 @@
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
+		for ( Type::ForallList::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
 			boundVars.insert( (*tyvar )->get_name() );
 		} // for
Index: src/SynTree/VarExprReplacer.cc
===================================================================
--- src/SynTree/VarExprReplacer.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/SynTree/VarExprReplacer.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,26 @@
+//
+// 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.
+//
+// VarExprReplacer.h --
+//
+// Author           : Rob Schluntz
+// Created On       : Wed Jan 13 16:29:30 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Fri May 13 11:27:52 2016
+// Update Count     : 5
+//
+
+#include "Expression.h"
+#include "VarExprReplacer.h"
+
+VarExprReplacer::VarExprReplacer( const DeclMap & declMap ) : declMap( declMap ) {}
+
+// replace variable with new node from decl map
+void VarExprReplacer::visit( VariableExpr * varExpr ) {
+  if ( declMap.count( varExpr->get_var() ) ) {
+    varExpr->set_var( declMap.at( varExpr->get_var() ) );
+  }
+}
Index: src/SynTree/VarExprReplacer.h
===================================================================
--- src/SynTree/VarExprReplacer.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/SynTree/VarExprReplacer.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,42 @@
+//
+// 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.
+//
+// VarExprReplacer.h --
+//
+// Author           : Rob Schluntz
+// Created On       : Wed Jan 13 16:29:30 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Fri May 13 11:27:52 2016
+// Update Count     : 5
+//
+
+#ifndef VAR_EXPR_REPLACER_H
+#define VAR_EXPR_REPLACER_H
+
+#include <map>
+
+#include "SynTree/SynTree.h"
+
+/// Visitor that replaces the declarations that VariableExprs refer to, according to the supplied mapping
+class VarExprReplacer : public Visitor {
+public:
+	typedef std::map< DeclarationWithType *, DeclarationWithType * > DeclMap;
+private:
+	const DeclMap & declMap;
+public:
+	VarExprReplacer( const DeclMap & declMap );
+
+	// replace variable with new node from decl map
+	virtual void visit( VariableExpr * varExpr );
+};
+
+#endif // VAR_EXPR_REPLACER_H
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SynTree/Visitor.cc
===================================================================
--- src/SynTree/Visitor.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Visitor.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -150,5 +150,5 @@
 
 void Visitor::visit( ApplicationExpr *applicationExpr ) {
-	acceptAll( applicationExpr->get_results(), *this );
+	maybeAccept( applicationExpr->get_result(), *this );
 	maybeAccept( applicationExpr->get_function(), *this );
 	acceptAll( applicationExpr->get_args(), *this );
@@ -156,48 +156,49 @@
 
 void Visitor::visit( UntypedExpr *untypedExpr ) {
-	acceptAll( untypedExpr->get_results(), *this );
+	maybeAccept( untypedExpr->get_result(), *this );
 	acceptAll( untypedExpr->get_args(), *this );
 }
 
 void Visitor::visit( NameExpr *nameExpr ) {
-	acceptAll( nameExpr->get_results(), *this );
+	maybeAccept( nameExpr->get_result(), *this );
 }
 
 void Visitor::visit( AddressExpr *addressExpr ) {
-	acceptAll( addressExpr->get_results(), *this );
+	maybeAccept( addressExpr->get_result(), *this );
 	maybeAccept( addressExpr->get_arg(), *this );
 }
 
 void Visitor::visit( LabelAddressExpr *labAddressExpr ) {
-	acceptAll( labAddressExpr->get_results(), *this );
+	maybeAccept( labAddressExpr->get_result(), *this );
 	maybeAccept( labAddressExpr->get_arg(), *this );
 }
 
 void Visitor::visit( CastExpr *castExpr ) {
-	acceptAll( castExpr->get_results(), *this );
+	maybeAccept( castExpr->get_result(), *this );
 	maybeAccept( castExpr->get_arg(), *this );
 }
 
 void Visitor::visit( UntypedMemberExpr *memberExpr ) {
-	acceptAll( memberExpr->get_results(), *this );
+	maybeAccept( memberExpr->get_result(), *this );
 	maybeAccept( memberExpr->get_aggregate(), *this );
+	maybeAccept( memberExpr->get_member(), *this );
 }
 
 void Visitor::visit( MemberExpr *memberExpr ) {
-	acceptAll( memberExpr->get_results(), *this );
+	maybeAccept( memberExpr->get_result(), *this );
 	maybeAccept( memberExpr->get_aggregate(), *this );
 }
 
 void Visitor::visit( VariableExpr *variableExpr ) {
-	acceptAll( variableExpr->get_results(), *this );
+	maybeAccept( variableExpr->get_result(), *this );
 }
 
 void Visitor::visit( ConstantExpr *constantExpr ) {
-	acceptAll( constantExpr->get_results(), *this );
+	maybeAccept( constantExpr->get_result(), *this );
 	maybeAccept( constantExpr->get_constant(), *this );
 }
 
 void Visitor::visit( SizeofExpr *sizeofExpr ) {
-	acceptAll( sizeofExpr->get_results(), *this );
+	maybeAccept( sizeofExpr->get_result(), *this );
 	if ( sizeofExpr->get_isType() ) {
 		maybeAccept( sizeofExpr->get_type(), *this );
@@ -208,5 +209,5 @@
 
 void Visitor::visit( AlignofExpr *alignofExpr ) {
-	acceptAll( alignofExpr->get_results(), *this );
+	maybeAccept( alignofExpr->get_result(), *this );
 	if ( alignofExpr->get_isType() ) {
 		maybeAccept( alignofExpr->get_type(), *this );
@@ -217,10 +218,10 @@
 
 void Visitor::visit( UntypedOffsetofExpr *offsetofExpr ) {
-	acceptAll( offsetofExpr->get_results(), *this );
+	maybeAccept( offsetofExpr->get_result(), *this );
 	maybeAccept( offsetofExpr->get_type(), *this );
 }
 
 void Visitor::visit( OffsetofExpr *offsetofExpr ) {
-	acceptAll( offsetofExpr->get_results(), *this );
+	maybeAccept( offsetofExpr->get_result(), *this );
 	maybeAccept( offsetofExpr->get_type(), *this );
 	maybeAccept( offsetofExpr->get_member(), *this );
@@ -228,10 +229,10 @@
 
 void Visitor::visit( OffsetPackExpr *offsetPackExpr ) {
-	acceptAll( offsetPackExpr->get_results(), *this );
+	maybeAccept( offsetPackExpr->get_result(), *this );
 	maybeAccept( offsetPackExpr->get_type(), *this );
 }
 
 void Visitor::visit( AttrExpr *attrExpr ) {
-	acceptAll( attrExpr->get_results(), *this );
+	maybeAccept( attrExpr->get_result(), *this );
 	if ( attrExpr->get_isType() ) {
 		maybeAccept( attrExpr->get_type(), *this );
@@ -242,5 +243,5 @@
 
 void Visitor::visit( LogicalExpr *logicalExpr ) {
-	acceptAll( logicalExpr->get_results(), *this );
+	maybeAccept( logicalExpr->get_result(), *this );
 	maybeAccept( logicalExpr->get_arg1(), *this );
 	maybeAccept( logicalExpr->get_arg2(), *this );
@@ -248,5 +249,5 @@
 
 void Visitor::visit( ConditionalExpr *conditionalExpr ) {
-	acceptAll( conditionalExpr->get_results(), *this );
+	maybeAccept( conditionalExpr->get_result(), *this );
 	maybeAccept( conditionalExpr->get_arg1(), *this );
 	maybeAccept( conditionalExpr->get_arg2(), *this );
@@ -255,21 +256,11 @@
 
 void Visitor::visit( CommaExpr *commaExpr ) {
-	acceptAll( commaExpr->get_results(), *this );
+	maybeAccept( commaExpr->get_result(), *this );
 	maybeAccept( commaExpr->get_arg1(), *this );
 	maybeAccept( commaExpr->get_arg2(), *this );
 }
 
-void Visitor::visit( TupleExpr *tupleExpr ) {
-	acceptAll( tupleExpr->get_results(), *this );
-	acceptAll( tupleExpr->get_exprs(), *this );
-}
-
-void Visitor::visit( SolvedTupleExpr *tupleExpr ) {
-	acceptAll( tupleExpr->get_results(), *this );
-	acceptAll( tupleExpr->get_exprs(), *this );
-}
-
 void Visitor::visit( TypeExpr *typeExpr ) {
-	acceptAll( typeExpr->get_results(), *this );
+	maybeAccept( typeExpr->get_result(), *this );
 	maybeAccept( typeExpr->get_type(), *this );
 }
@@ -288,10 +279,10 @@
 
 void Visitor::visit( ConstructorExpr * ctorExpr ) {
-	acceptAll( ctorExpr->get_results(), *this );
+	maybeAccept( ctorExpr->get_result(), *this );
 	maybeAccept( ctorExpr->get_callExpr(), *this );
 }
 
 void Visitor::visit( CompoundLiteralExpr *compLitExpr ) {
-	acceptAll( compLitExpr->get_results(), *this );
+	maybeAccept( compLitExpr->get_result(), *this );
 	maybeAccept( compLitExpr->get_type(), *this );
 	maybeAccept( compLitExpr->get_initializer(), *this );
@@ -299,5 +290,5 @@
 
 void Visitor::visit( UntypedValofExpr *valofExpr ) {
-	acceptAll( valofExpr->get_results(), *this );
+	maybeAccept( valofExpr->get_result(), *this );
 	maybeAccept( valofExpr->get_body(), *this );
 }
@@ -306,4 +297,36 @@
 	maybeAccept( rangeExpr->get_low(), *this );
 	maybeAccept( rangeExpr->get_high(), *this );
+}
+
+void Visitor::visit( TupleExpr *tupleExpr ) {
+	maybeAccept( tupleExpr->get_result(), *this );
+	acceptAll( tupleExpr->get_exprs(), *this );
+}
+
+void Visitor::visit( TupleIndexExpr *tupleExpr ) {
+	maybeAccept( tupleExpr->get_result(), *this );
+	maybeAccept( tupleExpr->get_tuple(), *this );
+}
+
+void Visitor::visit( MemberTupleExpr *tupleExpr ) {
+	maybeAccept( tupleExpr->get_result(), *this );
+	maybeAccept( tupleExpr->get_member(), *this );
+	maybeAccept( tupleExpr->get_aggregate(), *this );
+}
+
+void Visitor::visit( TupleAssignExpr *assignExpr ) {
+	maybeAccept( assignExpr->get_result(), *this );
+	acceptAll( assignExpr->get_tempDecls(), *this );
+	acceptAll( assignExpr->get_assigns(), *this );
+}
+
+void Visitor::visit( StmtExpr *stmtExpr ) {
+	maybeAccept( stmtExpr->get_result(), *this );
+	maybeAccept( stmtExpr->get_statements(), *this );
+}
+
+void Visitor::visit( UniqueExpr *uniqueExpr ) {
+	maybeAccept( uniqueExpr->get_result(), *this );
+	maybeAccept( uniqueExpr->get_expr(), *this );
 }
 
Index: src/SynTree/Visitor.h
===================================================================
--- src/SynTree/Visitor.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/Visitor.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -71,6 +71,4 @@
 	virtual void visit( ConditionalExpr *conditionalExpr );
 	virtual void visit( CommaExpr *commaExpr );
-	virtual void visit( TupleExpr *tupleExpr );
-	virtual void visit( SolvedTupleExpr *tupleExpr );
 	virtual void visit( TypeExpr *typeExpr );
 	virtual void visit( AsmExpr *asmExpr );
@@ -80,4 +78,10 @@
 	virtual void visit( UntypedValofExpr *valofExpr );
 	virtual void visit( RangeExpr *rangeExpr );
+	virtual void visit( TupleExpr *tupleExpr );
+	virtual void visit( TupleIndexExpr *tupleExpr );
+	virtual void visit( MemberTupleExpr *tupleExpr );
+	virtual void visit( TupleAssignExpr *assignExpr );
+	virtual void visit( StmtExpr * stmtExpr );
+	virtual void visit( UniqueExpr * uniqueExpr );
 
 	virtual void visit( VoidType *basicType );
Index: src/SynTree/module.mk
===================================================================
--- src/SynTree/module.mk	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/SynTree/module.mk	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -49,4 +49,5 @@
        SynTree/AddStmtVisitor.cc \
        SynTree/TypeSubstitution.cc \
-       SynTree/Attribute.cc
+       SynTree/Attribute.cc \
+       SynTree/VarExprReplacer.cc
 
Index: src/Tuples/Explode.cc
===================================================================
--- src/Tuples/Explode.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/Tuples/Explode.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,82 @@
+//
+// 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.
+//
+// Explode.cc --
+//
+// Author           : Rob Schluntz
+// Created On       : Wed Nov 9 13:12:24 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Wed Nov 9 13:20:24 2016
+// Update Count     : 2
+//
+
+#include "Explode.h"
+#include "SynTree/Mutator.h"
+
+namespace Tuples {
+	namespace {
+		struct AddrExploder : public Mutator {
+			bool foundUniqueExpr = false;
+			Expression * applyAddr( Expression * expr, bool first = true ) {
+				if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){
+					std::list< Expression * > exprs;
+					for ( Expression *& expr : tupleExpr->get_exprs() ) {
+						// move & into tuple exprs
+						exprs.push_back( applyAddr( expr, false ) );
+					}
+					// want the top-level expression to be address-taken, but not nested
+					// tuple expressions
+					if ( first ) {
+						return new AddressExpr( new TupleExpr( exprs ) );
+					} else {
+						return new TupleExpr( exprs );
+					}
+				}
+				// anything else should be address-taken as normal
+				return new AddressExpr( expr->clone() );
+			}
+
+			virtual Expression * mutate( UniqueExpr * uniqueExpr ) {
+				// move & into unique expr so that the unique expr has type T* rather than
+				// type T. In particular, this transformation helps with generating the
+				// correct code for address-taken member tuple expressions, since the result
+				// should now be a tuple of addresses rather than the address of a tuple.
+				// Still, this code is a bit awkward, and could use some improvement.
+				foundUniqueExpr = true;
+				UniqueExpr * newUniqueExpr = new UniqueExpr( applyAddr( uniqueExpr->get_expr() ), uniqueExpr->get_id() );
+				delete uniqueExpr;
+				UntypedExpr * deref = UntypedExpr::createDeref( Mutator::mutate( newUniqueExpr ) );
+				return deref;
+			}
+
+			virtual Expression * mutate( TupleIndexExpr * tupleExpr ) {
+				// tuple index expr needs to be rebuilt to ensure that the type of the
+				// field is consistent with the type of the tuple expr, since the field
+				// may have changed from type T to T*.
+				Expression * expr = tupleExpr->get_tuple()->acceptMutator( *this );
+				tupleExpr->set_tuple( nullptr );
+				TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );
+				delete tupleExpr;
+				return ret;
+			}
+		};
+	} // namespace
+
+	Expression * distributeAddr( Expression * expr ) {
+		AddrExploder addrExploder;
+		expr = expr->acceptMutator( addrExploder );
+		if ( ! addrExploder.foundUniqueExpr ) {
+			expr = new AddressExpr( expr );
+		}
+		return expr;
+	}
+} // namespace Tuples
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/Tuples/Explode.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,97 @@
+//
+// 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.
+//
+// Explode.h --
+//
+// Author           : Rob Schluntz
+// Created On       : Wed Nov 9 13:12:24 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Wed Nov 9 13:20:24 2016
+// Update Count     : 2
+//
+
+#ifndef _EXPLODE_H_
+#define _EXPLODE_H_
+
+#include "ResolvExpr/AlternativeFinder.h"
+#include "ResolvExpr/Resolver.h"
+
+#include "SynTree/Expression.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Type.h"
+
+#include "Tuples.h"
+
+namespace Tuples {
+	/// helper function used by explode to properly distribute
+	/// '&' across a tuple expression
+	Expression * distributeAddr( Expression * expr );
+
+	/// helper function used by explode
+	template< typename OutputIterator >
+	void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, const SymTab::Indexer & indexer, OutputIterator out ) {
+		Type * res = expr->get_result();
+		if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
+			ResolvExpr::AltList alts;
+			explodeUnique( addrExpr->get_arg(), alt, indexer, back_inserter( alts ) );
+			for ( ResolvExpr::Alternative & alt : alts ) {
+				// distribute '&' over all components
+				alt.expr = distributeAddr( alt.expr );
+				*out++ = alt;
+			}
+		} else if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
+			if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
+				// can open tuple expr and dump its exploded components
+				for ( Expression * expr : tupleExpr->get_exprs() ) {
+					explodeUnique( expr, alt, indexer, out );
+				}
+			} else {
+				// tuple type, but not tuple expr - recursively index into its components
+				Expression * arg = expr->clone();
+				if ( Tuples::maybeImpure( arg ) && ! dynamic_cast< UniqueExpr * >( arg ) ) {
+					// expressions which may contain side effects require a single unique instance of the expression.
+					arg = new UniqueExpr( arg );
+				}
+				for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
+					TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
+					explodeUnique( idx, alt, indexer, out );
+					delete idx;
+				}
+				delete arg;
+			}
+		} else {
+			// atomic (non-tuple) type - output a clone of the expression in a new alternative
+			*out++ = ResolvExpr::Alternative( expr->clone(), alt.env, alt.cost, alt.cvtCost );
+		}
+	}
+
+	/// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
+	template< typename OutputIterator >
+	void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer, OutputIterator out ) {
+		explodeUnique( alt.expr, alt, indexer, out );
+	}
+
+	// explode list of alternatives
+	template< typename AltIterator, typename OutputIterator >
+	void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer, OutputIterator out ) {
+		for ( ; altBegin != altEnd; ++altBegin ) {
+			explode( *altBegin, indexer, out );
+		}
+	}
+
+	template< typename OutputIterator >
+	void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, OutputIterator out ) {
+		explode( alts.begin(), alts.end(), indexer, out );
+	}
+} // namespace Tuples
+
+#endif // _TUPLE_ASSIGNMENT_H_
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: c/Tuples/NameMatcher.cc
===================================================================
--- src/Tuples/NameMatcher.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ 	(revision )
@@ -1,67 +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.
-//
-// NameMatcher.cc -- 
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon May 18 15:00:06 2015
-// Update Count     : 1
-//
-
-#include "NameMatcher.h"
-#include "NameMatcher.h"
-
-namespace Tuples {
-	NameMatcher::NameMatcher( std::list< DeclarationWithType* > &formals ) : current( 0 ) {
-		int cnt = 0;
-		for ( std::list< DeclarationWithType *>::const_iterator f = formals.begin(); f != formals.end(); ++f ) {
-			table.insert( std::pair< std::string, int >( (*f)->get_name(), cnt++ ) );
-			index.push_back(*f);
-		} // for
-		exprs.reserve( index.size() );
-	}
-
-	NameMatcher::~NameMatcher() {}
-
-	void NameMatcher::match( ResolvExpr::AltList &alternatives ) throw (NoMatch) {
-		if ( alternatives.size() != index.size() )
-			throw NoMatch("Length of actuals and formals differ");
-
-		for ( ResolvExpr::AltList::const_iterator a = alternatives.begin(); a != alternatives.end(); ++a ) {
-			if ( a->expr->get_argName() != 0 )
-				if ( NameExpr *name = dynamic_cast<NameExpr *>( a->expr->get_argName() ) ) {
-					if ( table.find( name->get_name() ) != table.end() ) {
-						std::cerr << "Rearranging to " << table[ name->get_name() ] << "position in the list." << std::endl;
-						exprs[ table[ name->get_name() ] ] = &(*a);
-					} else
-						throw NoMatch( name->get_name() + "no such  designation" );
-				} /*else if ( TupleExpr *tup = dynamic_cast<TupleExpr *>( a->expr->get_argName() ) )
-					std::cerr << "Designated expression" << std::endl; */
-			exprs.push_back( &(*a) );
-		} // for
-
-		/*std::cerr << "In matcher/match: ";
-		  if ( exprs.size() != index.size() )
-		  std::cerr << "exprs and index differ in length" << std::endl;
-		  else
-		  std::cerr << "is all good." << std::endl;
-		*/
-	}
-
-	ResolvExpr::Alternative &NameMatcher::get_next() throw (NoMoreElements) {
-		if ( current++ >= (int)(index.size()) )
-			throw NoMoreElements();
-		return *(new ResolvExpr::Alternative());
-	}
-} // namespace Tuples
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: c/Tuples/NameMatcher.h
===================================================================
--- src/Tuples/NameMatcher.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ 	(revision )
@@ -1,62 +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.
-//
-// NameMatcher.h -- 
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon May 18 15:01:37 2015
-// Update Count     : 3
-//
-
-#ifndef _NAMEMATCHER_H_
-#define _NAMEMATCHER_H_
-
-#include <map>
-#include <vector>
-#include <string>
-
-#include "SynTree/SynTree.h"
-#include "SynTree/Mutator.h"
-
-#include "SynTree/Type.h"
-#include "SynTree/Declaration.h"
-#include "SynTree/Expression.h"
-#include "SynTree/Statement.h"
-
-#include "ResolvExpr/Alternative.h"
-
-namespace Tuples {
-	struct NoMoreElements {};
-	struct NoMatch {
-		NoMatch( std::string msg ) : message( msg ) {}
-		std::string message;
-	};
-
-	class NameMatcher {
-	  public:
-		NameMatcher( std::list< DeclarationWithType* >& );
-		~NameMatcher();
-
-		void match( ResolvExpr::AltList &alternatives ) throw (NoMatch) ;
-		ResolvExpr::Alternative &get_next() throw (NoMoreElements);
-
-	  private:
-		int current;
-		std::vector< DeclarationWithType* > index;
-		std::vector< const ResolvExpr::Alternative * > exprs;
-		std::map< std::string, int> table;
-	};
-} // namespace Tuples
-
-#endif // _NAMEMATCHER_H_
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Tuples/TupleAssignment.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -9,6 +9,6 @@
 // Author           : Rodolfo G. Esteves
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon May 18 15:02:53 2015
+// Last Modified By : Rob Schluntz
+// Last Modified On : Wed Nov 9 13:48:42 2016
 // Update Count     : 2
 //
@@ -18,6 +18,9 @@
 #include "ResolvExpr/typeops.h"
 #include "SynTree/Expression.h"
-#include "TupleAssignment.h"
+#include "SynTree/Initializer.h"
+#include "Tuples.h"
+#include "Explode.h"
 #include "Common/SemanticError.h"
+#include "InitTweak/InitTweak.h"
 
 #include <functional>
@@ -27,383 +30,228 @@
 #include <cassert>
 #include <set>
+#include <unordered_set>
 
 namespace Tuples {
-	TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder *f )
-		: currentFinder(f), matcher(0), hasMatched( false ) {}
-
-	bool TupleAssignSpotter::pointsToTuple( Expression *expr ) {
+	class TupleAssignSpotter {
+	  public:
+		// dispatcher for Tuple (multiple and mass) assignment operations
+		TupleAssignSpotter( ResolvExpr::AlternativeFinder & );
+		void spot( UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities );
+
+	  private:
+		void match();
+
+		struct Matcher {
+		  public:
+			Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
+			virtual ~Matcher() {}
+			virtual void match( std::list< Expression * > &out ) = 0;
+			ResolvExpr::AltList lhs, rhs;
+			TupleAssignSpotter &spotter;
+			std::list< ObjectDecl * > tmpDecls;
+		};
+
+		struct MassAssignMatcher : public Matcher {
+		  public:
+			MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
+			virtual void match( std::list< Expression * > &out );
+		};
+
+		struct MultipleAssignMatcher : public Matcher {
+		  public:
+			MultipleAssignMatcher( TupleAssignSpotter &spot, const ResolvExpr::AltList & alts );
+			virtual void match( std::list< Expression * > &out );
+		};
+
+		ResolvExpr::AlternativeFinder &currentFinder;
+		std::string fname;
+		std::unique_ptr< Matcher > matcher;
+	};
+
+	/// true if expr is an expression of tuple type, i.e. a tuple expression, tuple variable, or MRV (multiple-return-value) function
+	bool isTuple( Expression *expr ) {
+		if ( ! expr ) return false;
+		assert( expr->has_result() );
+		return dynamic_cast<TupleExpr *>(expr) || expr->get_result()->size() > 1;
+	}
+
+	template< typename AltIter >
+	bool isMultAssign( AltIter begin, AltIter end ) {
+		// multiple assignment if more than one alternative in the range or if
+		// the alternative is a tuple
+		if ( begin == end ) return false;
+		if ( isTuple( begin->expr ) ) return true;
+		return ++begin != end;
+	}
+
+	bool pointsToTuple( Expression *expr ) {
 		// also check for function returning tuple of reference types
-		if (AddressExpr *addr = dynamic_cast<AddressExpr *>(expr) )
-			if ( isTuple(addr->get_arg() ) )
-				return true;
+		if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
+			return pointsToTuple( castExpr->get_arg() );
+		} else if ( AddressExpr *addr = dynamic_cast< AddressExpr * >( expr) ) {
+			return isTuple( addr->get_arg() );
+		}
 		return false;
 	}
 
-	bool TupleAssignSpotter::isTupleVar( DeclarationWithType *decl ) {
-		if ( dynamic_cast<TupleType *>(decl->get_type()) )
-			return true;
-		return false;
-	}
-
-	bool TupleAssignSpotter::isTuple( Expression *expr, bool isRight ) {
-		// true if `expr' is an expression returning a tuple: tuple, tuple variable or MRV function
-		if ( ! expr ) return false;
-
-		if ( dynamic_cast<TupleExpr *>(expr) )
-			return true;
-		else if ( VariableExpr *var = dynamic_cast<VariableExpr *>(expr) ) {
-			if ( isTupleVar(var->get_var()) )
-				return true;
-		}
-
-		return false;
-	}
-
-	bool TupleAssignSpotter::match() {
-		assert ( matcher != 0 );
-
-		std::list< Expression * > new_assigns;
-		if ( ! matcher->match(new_assigns) )
-			return false;
-
-		if ( new_assigns.empty() ) return false;
-		/*return */matcher->solve( new_assigns );
-		if ( dynamic_cast<TupleAssignSpotter::MultipleAssignMatcher *>( matcher ) ) {
-			// now resolve new assignments
-			std::list< Expression * > solved_assigns;
-			ResolvExpr::AltList solved_alts;
-			assert( currentFinder != 0 );
-
-			ResolvExpr::AltList current;
-			for ( std::list< Expression * >::iterator i = new_assigns.begin(); i != new_assigns.end(); ++i ) {
-				//try {
-				ResolvExpr::AlternativeFinder finder( currentFinder->get_indexer(), currentFinder->get_environ() );
-				finder.findWithAdjustment(*i);
-				// prune expressions that don't coincide with
-				ResolvExpr::AltList alts = finder.get_alternatives();
-				assert( alts.size() == 1 );
-				assert(alts.front().expr != 0 );
-				current.push_back( finder.get_alternatives().front() );
-				solved_assigns.push_back( alts.front().expr->clone() );
-				//solved_assigns.back()->print(std::cerr);
-				/*} catch( ... ) {
-				  continue; // no reasonable alternative found
-				  }*/
-			}
-			options.add_option( current );
-
-			return true;
-		} else { // mass assignment
-			//if ( new_assigns.empty() ) return false;
-			std::list< Expression * > solved_assigns;
-			ResolvExpr::AltList solved_alts;
-			assert( currentFinder != 0 );
-
-			ResolvExpr::AltList current;
-			if ( optMass.empty() ) {
-				for ( std::list< Expression * >::size_type i = 0; i != new_assigns.size(); ++i )
-					optMass.push_back( ResolvExpr::AltList() );
-			}
-			int cnt = 0;
-			for ( std::list< Expression * >::iterator i = new_assigns.begin(); i != new_assigns.end(); ++i, cnt++ ) {
-
-				ResolvExpr::AlternativeFinder finder( currentFinder->get_indexer(), currentFinder->get_environ() );
-				finder.findWithAdjustment(*i);
-				ResolvExpr::AltList alts = finder.get_alternatives();
-				assert( alts.size() == 1 );
-				assert(alts.front().expr != 0 );
-				current.push_back( finder.get_alternatives().front() );
-				optMass[cnt].push_back( finder.get_alternatives().front() );
-				solved_assigns.push_back( alts.front().expr->clone() );
-			}
-
-			return true;
-		}
-
-		return false;
-	}
-
-	bool TupleAssignSpotter::isMVR( Expression *expr ) {
-		if ( expr->get_results().size() > 1 ) {
-			// MVR processing
-			return true;
-		}
-		return false;
-	}
-
-	bool TupleAssignSpotter::isTupleAssignment( UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities ) {
-		if (  NameExpr *assgnop = dynamic_cast< NameExpr * >(expr->get_function()) ) {
-
-			if ( assgnop->get_name() == std::string("?=?") ) {
-
-				for ( std::list<ResolvExpr::AltList>::iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
-					assert( ali->size() == 2 );
-					ResolvExpr::AltList::iterator opit = ali->begin();
-					ResolvExpr::Alternative op1 = *opit, op2 = *(++opit);
-
-					if ( pointsToTuple(op1.expr) ) { // also handles tuple vars
-						if ( isTuple( op2.expr, true ) )
-							matcher = new MultipleAssignMatcher(op1.expr, op2.expr);
-						else if ( isMVR( op2.expr ) ) {
-							// handle MVR differently
-						} else
+	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities ) {
+		TupleAssignSpotter spotter( currentFinder );
+		spotter.spot( expr, possibilities );
+	}
+
+	TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )
+		: currentFinder(f) {}
+
+	void TupleAssignSpotter::spot( UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities ) {
+		if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
+			if ( InitTweak::isCtorDtorAssign( op->get_name() ) ) {
+				fname = op->get_name();
+				for ( std::list<ResolvExpr::AltList>::const_iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
+					if ( ali->size() == 0 ) continue; // AlternativeFinder will natrually handle this case, if it's legal
+					if ( ali->size() <= 1 && InitTweak::isAssignment( op->get_name() ) ) {
+						// what does it mean if an assignment takes 1 argument? maybe someone defined such a function, in which case AlternativeFinder will naturally handle it
+						continue;
+					}
+
+					assert( ! ali->empty() );
+					// grab args 2-N and group into a TupleExpr
+					const ResolvExpr::Alternative & alt1 = ali->front();
+					auto begin = std::next(ali->begin(), 1), end = ali->end();
+					if ( pointsToTuple(alt1.expr) ) {
+						if ( isMultAssign( begin, end ) ) {
+							matcher.reset( new MultipleAssignMatcher( *this, *ali ) );
+						} else {
 							// mass assignment
-							matcher = new MassAssignMatcher(op1.expr, op2.expr);
-
-						std::list< ResolvExpr::AltList > options;
-						if ( match() )
-							/*
-							  if ( hasMatched ) {
-							  // throw SemanticError("Ambiguous tuple assignment");
-							  } else {*/
-							// Matched for the first time
-							hasMatched = true;
-						/*} */
-					} /* else if ( isTuple( op2 ) )
-						 throw SemanticError("Inapplicable tuple assignment.");
-					  */
-				}
-
-				if ( hasMatched ) {
-					if ( dynamic_cast<TupleAssignSpotter::MultipleAssignMatcher *>( matcher ) ) {
-						//options.print( std::cerr );
-						std::list< ResolvExpr::AltList >best = options.get_best();
-						if ( best.size() == 1 ) {
-							std::list<Expression *> solved_assigns;
-							for ( ResolvExpr::AltList::iterator i = best.front().begin(); i != best.front().end(); ++i ) {
-								solved_assigns.push_back( i->expr );
-							}
-							/* assigning cost zero? */
-							currentFinder->get_alternatives().push_front( ResolvExpr::Alternative(new SolvedTupleExpr(solved_assigns/*, SolvedTupleExpr::MULTIPLE*/), currentFinder->get_environ(), ResolvExpr::Cost() ) );
+							matcher.reset( new MassAssignMatcher( *this,  *ali ) );
 						}
-					} else {
-						assert( ! optMass.empty() );
-						ResolvExpr::AltList winners;
-						for ( std::vector< ResolvExpr::AltList >::iterator i = optMass.begin(); i != optMass.end(); ++i )
-							findMinCostAlt( i->begin(), i->end(), back_inserter(winners) );
-
-						std::list< Expression *> solved_assigns;
-						for ( ResolvExpr::AltList::iterator i = winners.begin(); i != winners.end(); ++i )
-							solved_assigns.push_back( i->expr );
-						currentFinder->get_alternatives().push_front( ResolvExpr::Alternative(new SolvedTupleExpr(solved_assigns/*, SolvedTupleExpr::MASS*/), currentFinder->get_environ(), ResolvExpr::Cost() ) );
+						match();
 					}
 				}
 			}
 		}
-		return hasMatched;
-	}
-
-	void TupleAssignSpotter::Matcher::init( Expression *_lhs, Expression *_rhs ) {
-		lhs.clear();
-		if (AddressExpr *addr = dynamic_cast<AddressExpr *>(_lhs) )
-			if ( TupleExpr *tuple = dynamic_cast<TupleExpr *>(addr->get_arg()) )
-				std::copy( tuple->get_exprs().begin(), tuple->get_exprs().end(), back_inserter(lhs) );
-
-		rhs.clear();
-	}
-
-	TupleAssignSpotter::Matcher::Matcher( /*TupleAssignSpotter &spot,*/ Expression *_lhs, Expression *_rhs ) /*: own_spotter(spot) */{
-		init(_lhs,_rhs);
-	}
-
-	TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( Expression *_lhs, Expression *_rhs )/* : own_spotter(spot) */{
-		init(_lhs,_rhs);
-
-		if ( TupleExpr *tuple = dynamic_cast<TupleExpr *>(_rhs) )
-			std::copy( tuple->get_exprs().begin(), tuple->get_exprs().end(), back_inserter(rhs) );
-	}
-
-	UntypedExpr *TupleAssignSpotter::Matcher::createAssgn( Expression *left, Expression *right ) {
-		if ( left && right ) {
-			std::list< Expression * > args;
-			args.push_back(new AddressExpr(left->clone()));  args.push_back(right->clone());
-			return new UntypedExpr(new NameExpr("?=?"), args);
-		} else
-			throw 0; // xxx - diagnose the problem
-	}
-
-	bool TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
-		if ( lhs.empty() || (rhs.size() != 1) ) return false;
-
-		for ( std::list< Expression * >::iterator l = lhs.begin(); l != lhs.end(); l++ ) {
-			std::list< Expression * > args;
-			args.push_back( new AddressExpr(*l) );
-			args.push_back( rhs.front() );
-			out.push_back( new UntypedExpr(new NameExpr("?=?"), args) );
-		}
-
-		return true;
-	}
-
-	bool TupleAssignSpotter::MassAssignMatcher::solve( std::list< Expression * > &assigns ) {
-		/*
-		  std::list< Expression * > solved_assigns;
-		  ResolvExpr::AltList solved_alts;
-		  assert( currentFinder != 0 );
-
-		  ResolvExpr::AltList current;
-		  if ( optMass.empty() ) {
-		  for ( std::list< Expression * >::size_type i = 0; i != new_assigns.size(); ++i )
-		  optMass.push_back( ResolvExpr::AltList() );
-		  }
-		  int cnt = 0;
-		  for ( std::list< Expression * >::iterator i = new_assigns.begin(); i != new_assigns.end(); ++i, cnt++ ) {
-
-		  ResolvExpr::AlternativeFinder finder( currentFinder->get_indexer(), currentFinder->get_environ() );
-		  finder.findWithAdjustment(*i);
-		  ResolvExpr::AltList alts = finder.get_alternatives();
-		  assert( alts.size() == 1 );
-		  assert(alts.front().expr != 0 );
-		  current.push_back( finder.get_alternatives().front() );
-		  optMass[cnt].push_back( finder.get_alternatives().front() );
-		  solved_assigns.push_back( alts.front().expr->clone() );
-		  }
-		*/
-		return true;
-	}
-
-	bool TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
-		// need more complicated matching
+	}
+
+	void TupleAssignSpotter::match() {
+		assert ( matcher != 0 );
+
+		std::list< Expression * > new_assigns;
+		matcher->match( new_assigns );
+
+		if ( new_assigns.empty() ) return;
+		ResolvExpr::AltList current;
+		// now resolve new assignments
+		for ( std::list< Expression * >::iterator i = new_assigns.begin(); i != new_assigns.end(); ++i ) {
+			ResolvExpr::AlternativeFinder finder( currentFinder.get_indexer(), currentFinder.get_environ() );
+			try {
+				finder.findWithAdjustment(*i);
+			} catch (...) {
+				return; // xxx - no match should not mean failure, it just means this particular tuple assignment isn't valid
+			}
+			// prune expressions that don't coincide with
+			ResolvExpr::AltList alts = finder.get_alternatives();
+			assert( alts.size() == 1 );
+			assert( alts.front().expr != 0 );
+			current.push_back( alts.front() );
+		}
+
+		// extract expressions from the assignment alternatives to produce a list of assignments that
+		// together form a single alternative
+		std::list< Expression *> solved_assigns;
+		for ( ResolvExpr::Alternative & alt : current ) {
+			solved_assigns.push_back( alt.expr->clone() );
+		}
+		// xxx - need to do this??
+		ResolvExpr::TypeEnvironment compositeEnv;
+		simpleCombineEnvironments( current.begin(), current.end(), compositeEnv );
+		currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(new TupleAssignExpr(solved_assigns, matcher->tmpDecls), compositeEnv, ResolvExpr::sumCost( current ) ) );
+	}
+
+	TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList &alts ) : spotter(spotter) {
+		assert( ! alts.empty() );
+		ResolvExpr::Alternative lhsAlt = alts.front();
+		// peel off the cast that exists on ctor/dtor expressions
+		bool isCast = false;
+		if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( lhsAlt.expr ) ) {
+			lhsAlt.expr = castExpr->get_arg();
+			castExpr->set_arg( nullptr );
+			delete castExpr;
+			isCast = true;
+		}
+
+		// explode the lhs so that each field of the tuple-valued-expr is assigned.
+		explode( lhsAlt, spotter.currentFinder.get_indexer(), back_inserter(lhs) );
+
+		// and finally, re-add the cast to each lhs expr, so that qualified tuple fields can be constructed
+		if ( isCast ) {
+			for ( ResolvExpr::Alternative & alt : lhs ) {
+				Expression *& expr = alt.expr;
+				Type * castType = expr->get_result()->clone();
+				Type * type = InitTweak::getPointerBase( castType );
+				assert( type );
+				type->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true);
+				type->set_isLvalue( true ); // xxx - might not need this
+				expr = new CastExpr( expr, castType );
+			}
+		}
+	}
+
+	TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
+		assert( alts.size() == 1 || alts.size() == 2 );
+		if ( alts.size() == 2 ) {
+			rhs.push_back( alts.back() );
+		}
+	}
+
+	TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
+		// explode the rhs so that each field of the tuple-valued-expr is assigned.
+		explode( std::next(alts.begin(), 1), alts.end(), spotter.currentFinder.get_indexer(), back_inserter(rhs) );
+	}
+
+	UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
+		assert( left );
+		std::list< Expression * > args;
+		args.push_back( new AddressExpr( UntypedExpr::createDeref( new VariableExpr( left ) ) ) );
+		// args.push_back( new AddressExpr( new VariableExpr( left ) ) );
+		if ( right ) args.push_back( new VariableExpr( right ) );
+		return new UntypedExpr( new NameExpr( fname ), args );
+	}
+
+	ObjectDecl * newObject( UniqueName & namer, Expression * expr ) {
+		assert( expr->has_result() && ! expr->get_result()->isVoid() );
+		return new ObjectDecl( namer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, expr->get_result()->clone(), new SingleInit( expr->clone() ) );
+	}
+
+	void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
+		static UniqueName lhsNamer( "__massassign_L" );
+		static UniqueName rhsNamer( "__massassign_R" );
+		assert ( ! lhs.empty() && rhs.size() <= 1);
+
+		ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
+		for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
+			ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
+			out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
+			tmpDecls.push_back( ltmp );
+		}
+		if ( rtmp ) tmpDecls.push_back( rtmp );
+	}
+
+	void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
+		static UniqueName lhsNamer( "__multassign_L" );
+		static UniqueName rhsNamer( "__multassign_R" );
+
+		// xxx - need more complicated matching?
 		if ( lhs.size() == rhs.size() ) {
-			zipWith( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), back_inserter(out), TupleAssignSpotter::Matcher::createAssgn );
-			return true;
-		} //else
-		//std::cerr << "The length of (left, right) is: (" << lhs.size() << "," << rhs.size() << ")" << std::endl;*/
-		return false;
-	}
-
-	bool TupleAssignSpotter::MultipleAssignMatcher::solve( std::list< Expression * > &assigns ) {
-		/*
-		  std::list< Expression * > solved_assigns;
-		  ResolvExpr::AltList solved_alts;
-		  assert( currentFinder != 0 );
-
-		  ResolvExpr::AltList current;
-		  for ( std::list< Expression * >::iterator i = new_assigns.begin(); i != new_assigns.end(); ++i ) {
-		  //try {
-		  ResolvExpr::AlternativeFinder finder( currentFinder->get_indexer(), currentFinder->get_environ() );
-		  finder.findWithAdjustment(*i);
-		  // prune expressions that don't coincide with
-		  ResolvExpr::AltList alts = finder.get_alternatives();
-		  assert( alts.size() == 1 );
-		  assert(alts.front().expr != 0 );
-		  current.push_back( finder.get_alternatives().front() );
-		  solved_assigns.push_back( alts.front().expr->clone() );
-		  //solved_assigns.back()->print(std::cerr);
-		  //} catch( ... ) {
-		  //continue; // no reasonable alternative found
-		  //}
-		  }
-		  options.add_option( current );
-		*/
-
-		return true;
-	}
-
-	void TupleAssignSpotter::Options::add_option( ResolvExpr::AltList &opt ) {
-		using namespace std;
-
-		options.push_back( opt );
-		/*
-		  vector< Cost > costs;
-		  costs.reserve( opt.size() );
-		  transform( opt.begin(), opt.end(), back_inserter(costs), ptr_fun(extract_cost) );
-		*/
-		// transpose matrix
-		if ( costMatrix.empty() )
-			for ( unsigned int i = 0; i< opt.size(); ++i)
-				costMatrix.push_back( vector<ResolvExpr::Cost>() );
-
-		int cnt = 0;
-		for ( ResolvExpr::AltList::iterator i = opt.begin(); i != opt.end(); ++i, cnt++ )
-			costMatrix[cnt].push_back( i->cost );
-
-		return;
-	}
-
-	std::list< ResolvExpr::AltList > TupleAssignSpotter::Options::get_best() {
-		using namespace std;
-		using namespace ResolvExpr;
-		list< ResolvExpr::AltList > ret;
-		list< multiset<int> > solns;
-		for ( vector< vector<Cost> >::iterator i = costMatrix.begin(); i != costMatrix.end(); ++i ) {
-			list<int> current;
-			findMinCost( i->begin(), i->end(), back_inserter(current) );
-			solns.push_back( multiset<int>(current.begin(), current.end()) );
-		}
-		// need to combine
-		multiset<int> result;
-		lift_intersection( solns.begin(), solns.end(), inserter( result, result.begin() ) );
-		if ( result.size() != 1 )
-			throw SemanticError("Ambiguous tuple expression");
-		ret.push_back(get_option( *(result.begin() )));
-		return ret;
-	}
-
-	void TupleAssignSpotter::Options::print( std::ostream &ostr ) {
-		using namespace std;
-
-		for ( vector< vector < ResolvExpr::Cost > >::iterator i = costMatrix.begin(); i != costMatrix.end(); ++i ) {
-			for ( vector < ResolvExpr::Cost >::iterator j = i->begin(); j != i->end(); ++j )
-				ostr << *j << " " ;
-			ostr << std::endl;
-		} // for
-		return;
-	}
-
-	ResolvExpr::Cost extract_cost( ResolvExpr::Alternative &alt ) {
-		return alt.cost;
-	}
-
-	template< typename InputIterator, typename OutputIterator >
-	void TupleAssignSpotter::Options::findMinCost( InputIterator begin, InputIterator end, OutputIterator out ) {
-		using namespace ResolvExpr;
-		std::list<int> alternatives;
-
-		// select the alternatives that have the minimum parameter cost
-		Cost minCost = Cost::infinity;
-		unsigned int index = 0;
-		for ( InputIterator i = begin; i != end; ++i, index++ ) {
-			if ( *i < minCost ) {
-				minCost = *i;
-				alternatives.clear();
-				alternatives.push_back( index );
-			} else if ( *i == minCost ) {
-				alternatives.push_back( index );
-			}
-		}
-		std::copy( alternatives.begin(), alternatives.end(), out );
-	}
-
-	template< class InputIterator, class OutputIterator >
-	void TupleAssignSpotter::Options::lift_intersection( InputIterator begin, InputIterator end, OutputIterator out ) {
-		if ( begin == end ) return;
-		InputIterator test = begin;
-
-		if (++test == end)
-			{ copy(begin->begin(), begin->end(), out); return; }
-
-
-		std::multiset<int> cur; // InputIterator::value_type::value_type
-		copy( begin->begin(), begin->end(), inserter( cur, cur.begin() ) );
-
-		while ( test != end ) {
-			std::multiset<int> temp;
-			set_intersection( cur.begin(), cur.end(), test->begin(), test->end(), inserter(temp,temp.begin()) );
-			cur.clear();
-			copy( temp.begin(), temp.end(), inserter(cur,cur.begin()));
-			++test;
-		}
-
-		copy( cur.begin(), cur.end(), out );
-		return;
-	}
-
-	ResolvExpr::AltList TupleAssignSpotter::Options::get_option( std::list< ResolvExpr::AltList >::size_type index ) {
-		if ( index >= options.size() )
-			throw 0; // XXX
-		std::list< ResolvExpr::AltList >::iterator it = options.begin();
-		for ( std::list< ResolvExpr::AltList >::size_type i = 0; i < index; ++i, ++it );
-		return *it;
+			std::list< ObjectDecl * > ltmp;
+			std::list< ObjectDecl * > rtmp;
+			std::transform( lhs.begin(), lhs.end(), back_inserter( ltmp ), []( ResolvExpr::Alternative & alt ){
+				return newObject( lhsNamer, alt.expr );
+			});
+			std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), []( ResolvExpr::Alternative & alt ){
+				return newObject( rhsNamer, alt.expr );
+			});
+			zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), [&](ObjectDecl * obj1, ObjectDecl * obj2 ) { return createFunc(spotter.fname, obj1, obj2); } );
+			tmpDecls.splice( tmpDecls.end(), ltmp );
+			tmpDecls.splice( tmpDecls.end(), rtmp );
+		}
 	}
 } // namespace Tuples
Index: c/Tuples/TupleAssignment.h
===================================================================
--- src/Tuples/TupleAssignment.h	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ 	(revision )
@@ -1,136 +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.
-//
-// TupleAssignment.h --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon May 18 15:04:02 2015
-// Update Count     : 2
-//
-
-#ifndef _TUPLE_ASSIGNMENT_H_
-#define _TUPLE_ASSIGNMENT_H_
-
-#include <string>
-#include <vector>
-#include "ResolvExpr/AlternativeFinder.h"
-
-#include "SynTree/Expression.h"
-#include "SynTree/Declaration.h"
-#include "SynTree/Type.h"
-
-namespace Tuples {
-	class TupleAssignSpotter {
-	  public:
-		// dispatcher for Tuple (multiple and mass) assignment operations
-		TupleAssignSpotter( ResolvExpr::AlternativeFinder * = 0 );
-		~TupleAssignSpotter() { delete matcher; matcher = 0; }
-
-		bool pointsToTuple( Expression * );
-		static bool isTupleVar( DeclarationWithType * );
-		bool isTuple( Expression *, bool isRight = false );
-		bool isMVR( Expression * );
-		bool isTupleAssignment( UntypedExpr *, std::list<ResolvExpr::AltList> & );
-		bool match();
-	  private:
-		// records for assignment generation
-		class Options {
-		  public:
-			void add_option( ResolvExpr::AltList &opt );
-			std::list< ResolvExpr::AltList > get_best();
-			void print( std::ostream & );
-			int size() const { return options.size(); }
-			ResolvExpr::AltList get_option( std::list< ResolvExpr::AltList >::size_type index );
-
-			// should really use the one in ResolvExpr/AlternativeFinder, but it's too coupled with the object
-			template< typename InputIterator, typename OutputIterator >
-			void findMinCost( InputIterator begin, InputIterator end, OutputIterator out );
-
-			template< typename InputIterator, typename OutputIterator >
-			void lift_intersection( InputIterator begin, InputIterator end, OutputIterator out );
-		  private:
-			std::list< ResolvExpr::AltList > options;
-			std::vector< std::vector< ResolvExpr::Cost > > costMatrix;
-		};
-
-		class Matcher {
-		  public:
-			Matcher( /*TupleAssignSpotter &spot, */Expression *_lhs, Expression *_rhs );
-			virtual ~Matcher() {}
-			virtual bool match( std::list< Expression * > &out ) = 0;
-			virtual bool solve( std::list< Expression * > &assigns ) = 0;
-			static UntypedExpr *createAssgn( Expression *left, Expression *right );
-		  protected:
-			Matcher() /*: own_spotter( TupleAssignSpotter(0) ) */{}
-			void init(/* TupleAssignSpotter &, */Expression *_lhs, Expression *_rhs );
-			std::list< Expression * > lhs, rhs;
-			//TupleAssignSpotter &own_spotter;
-		};
-
-		class MassAssignMatcher : public Matcher {
-		  public:
-			MassAssignMatcher( Expression *_lhs, Expression *_rhs ) : Matcher( _lhs, _rhs ) {
-				rhs.push_back( _rhs );
-			}
-			virtual bool match( std::list< Expression * > &out );
-			virtual bool solve( std::list< Expression * > &assigns );
-		  private:
-			//std::vector< ResolvExpr::AltList > optMass;
-		};
-
-		class MultipleAssignMatcher : public Matcher {
-		  public:
-			MultipleAssignMatcher( Expression *_lhs, Expression *_rhs );
-			virtual bool match( std::list< Expression * > &out );
-			virtual bool solve( std::list< Expression * > &assigns );
-		  private:
-			//Options options;
-		};
-
-		friend class Matcher;
-
-		ResolvExpr::AlternativeFinder *currentFinder;
-		//std::list<Expression *> rhs, lhs;
-		// Expression *rhs, *lhs;
-		Matcher *matcher;
-		bool hasMatched;
-		Options options;
-		std::vector< ResolvExpr::AltList > optMass;
-	};
-
-	ResolvExpr::Cost extract_cost( ResolvExpr::Alternative & );
-
-	template< typename InputIterator, typename OutputIterator >
-	void findMinCostAlt( InputIterator begin, InputIterator end, OutputIterator out ) {
-		using namespace ResolvExpr;
-		AltList alternatives;
-
-		// select the alternatives that have the minimum parameter cost
-		Cost minCost = Cost::infinity;
-		for ( AltList::iterator i = begin; i != end; ++i ) {
-			if ( i->cost < minCost ) {
-				minCost = i->cost;
-				i->cost = i->cvtCost;
-				alternatives.clear();
-				alternatives.push_back( *i );
-			} else if ( i->cost == minCost ) {
-				i->cost = i->cvtCost;
-				alternatives.push_back( *i );
-			}
-		}
-		std::copy( alternatives.begin(), alternatives.end(), out );
-	}
-} // namespace Tuples
-
-#endif // _TUPLE_ASSIGNMENT_H_
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/Tuples/TupleExpansion.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,329 @@
+//
+// 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.
+//
+// TupleAssignment.cc --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon May 18 15:02:53 2015
+// Update Count     : 2
+//
+
+#include <iterator>
+#include <iostream>
+#include <cassert>
+#include "Tuples.h"
+#include "GenPoly/DeclMutator.h"
+#include "SynTree/Mutator.h"
+#include "SynTree/Statement.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Type.h"
+#include "SynTree/Expression.h"
+#include "SynTree/Initializer.h"
+#include "SymTab/Mangler.h"
+#include "Common/ScopedMap.h"
+#include "ResolvExpr/typeops.h"
+#include "InitTweak/GenInit.h"
+
+namespace Tuples {
+	namespace {
+		class MemberTupleExpander final : public Mutator {
+		public:
+			typedef Mutator Parent;
+			using Parent::mutate;
+
+			virtual Expression * mutate( UntypedMemberExpr * memberExpr ) override;
+		};
+
+		class UniqueExprExpander final : public GenPoly::DeclMutator {
+		public:
+			typedef GenPoly::DeclMutator Parent;
+			using Parent::mutate;
+
+			virtual Expression * mutate( UniqueExpr * unqExpr ) override;
+
+			std::map< int, Expression * > decls; // not vector, because order added may not be increasing order
+
+			~UniqueExprExpander() {
+				for ( std::pair<const int, Expression *> & p : decls ) {
+					delete p.second;
+				}
+			}
+		};
+
+		class TupleAssignExpander : public Mutator {
+		public:
+			typedef Mutator Parent;
+			using Parent::mutate;
+
+			virtual Expression * mutate( TupleAssignExpr * tupleExpr );
+		};
+
+		class TupleTypeReplacer : public GenPoly::DeclMutator {
+		  public:
+			typedef GenPoly::DeclMutator Parent;
+			using Parent::mutate;
+
+			virtual Type * mutate( TupleType * tupleType ) override;
+
+			virtual CompoundStmt * mutate( CompoundStmt * stmt ) override {
+				typeMap.beginScope();
+				stmt = Parent::mutate( stmt );
+				typeMap.endScope();
+				return stmt;
+			}
+		  private:
+			ScopedMap< std::string, StructDecl * > typeMap;
+		};
+
+		class TupleIndexExpander final : public Mutator {
+		public:
+			typedef Mutator Parent;
+			using Parent::mutate;
+
+			virtual Expression * mutate( TupleIndexExpr * tupleExpr ) override;
+		};
+
+		class TupleExprExpander final : public Mutator {
+		public:
+			typedef Mutator Parent;
+			using Parent::mutate;
+			
+			virtual Expression * mutate( TupleExpr * tupleExpr ) override;
+		};
+	}
+
+	void expandMemberTuples( std::list< Declaration * > & translationUnit ) {
+		MemberTupleExpander expander;
+		mutateAll( translationUnit, expander );
+	}
+
+	void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {
+		UniqueExprExpander unqExpander;
+		unqExpander.mutateDeclarationList( translationUnit );
+	}
+
+	void expandTuples( std::list< Declaration * > & translationUnit ) {
+		TupleAssignExpander assnExpander;
+		mutateAll( translationUnit, assnExpander );
+
+		TupleTypeReplacer replacer;
+		replacer.mutateDeclarationList( translationUnit );
+
+		TupleIndexExpander idxExpander;
+		mutateAll( translationUnit, idxExpander );
+
+		TupleExprExpander exprExpander;
+		mutateAll( translationUnit, exprExpander );
+	}
+
+	namespace {
+		/// given a expression representing the member and an expression representing the aggregate,
+		/// reconstructs a flattened UntypedMemberExpr with the right precedence
+		Expression * reconstructMemberExpr( Expression * member, Expression * aggr ) {
+			if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {
+				// construct a new UntypedMemberExpr with the correct structure , and recursively
+				// expand that member expression.
+				MemberTupleExpander expander;
+				UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->get_member(), new UntypedMemberExpr( memberExpr->get_aggregate(), aggr->clone() ) );
+
+				memberExpr->set_member(nullptr);
+				memberExpr->set_aggregate(nullptr);
+				delete memberExpr;
+				return newMemberExpr->acceptMutator( expander );
+			} else {
+				// not a member expression, so there is nothing to do but attach and return
+				return new UntypedMemberExpr( member, aggr->clone() );
+			}
+		}
+	}
+
+	Expression * MemberTupleExpander::mutate( UntypedMemberExpr * memberExpr ) {
+		if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( memberExpr->get_member() ) ) {
+			Expression * aggr = memberExpr->get_aggregate()->clone()->acceptMutator( *this );
+			// aggregate expressions which might be impure must be wrapped in unique expressions
+			// xxx - if there's a member-tuple expression nested in the aggregate, this currently generates the wrong code if a UniqueExpr is not used, and it's purely an optimization to remove the UniqueExpr
+			// if ( Tuples::maybeImpure( memberExpr->get_aggregate() ) ) aggr = new UniqueExpr( aggr );
+			aggr = new UniqueExpr( aggr );
+			for ( Expression *& expr : tupleExpr->get_exprs() ) {
+				expr = reconstructMemberExpr( expr, aggr );
+			}
+			delete aggr;
+			return tupleExpr;
+		} else {
+			// there may be a tuple expr buried in the aggregate
+			// xxx - this is a memory leak
+			return new UntypedMemberExpr( memberExpr->get_member()->clone(), memberExpr->get_aggregate()->acceptMutator( *this ) );
+		}
+	}
+
+	Expression * UniqueExprExpander::mutate( UniqueExpr * unqExpr ) {
+		unqExpr = safe_dynamic_cast< UniqueExpr * > ( Parent::mutate( unqExpr ) );
+		const int id = unqExpr->get_id();
+
+		// on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
+		// and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
+		if ( ! decls.count( id ) ) {
+			Expression * assignUnq;
+			Expression * var = unqExpr->get_var();
+			if ( unqExpr->get_object() ) {
+				// an object was generated to represent this unique expression -- it should be added to the list of declarations now
+				addDeclaration( unqExpr->get_object() );
+				unqExpr->set_object( nullptr );
+				// steal the expr from the unqExpr
+				assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );
+				unqExpr->set_expr( nullptr );
+			} else {
+				// steal the already generated assignment to var from the unqExpr - this has been generated by FixInit
+				Expression * expr = unqExpr->get_expr();
+				CommaExpr * commaExpr = safe_dynamic_cast< CommaExpr * >( expr );
+				assignUnq = commaExpr->get_arg1();
+				commaExpr->set_arg1( nullptr );
+			}
+			BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool );
+			ObjectDecl * finished = new ObjectDecl( toString( "_unq_expr_finished_", id ), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ), new SingleInit( new ConstantExpr( Constant( boolType->clone(), "0" ) ), noDesignators ) );
+			addDeclaration( finished );
+			// (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
+			// This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
+			Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant( boolType->clone(), "1" ) ) );
+			ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),
+				new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );
+			condExpr->set_result( var->get_result()->clone() );
+			decls[id] = condExpr;
+		}
+		delete unqExpr;
+		return decls[id]->clone();
+	}
+
+	Expression * TupleAssignExpander::mutate( TupleAssignExpr * assnExpr ) {
+		assnExpr = safe_dynamic_cast< TupleAssignExpr * >( Parent::mutate( assnExpr ) );
+		CompoundStmt * compoundStmt = new CompoundStmt( noLabels );
+		std::list< Statement * > & stmts = compoundStmt->get_kids();
+		for ( ObjectDecl * obj : assnExpr->get_tempDecls() ) {
+			stmts.push_back( new DeclStmt( noLabels, obj ) );
+		}
+		TupleExpr * tupleExpr = new TupleExpr( assnExpr->get_assigns() );
+		assert( tupleExpr->get_result() );
+		stmts.push_back( new ExprStmt( noLabels, tupleExpr ) );
+		assnExpr->get_tempDecls().clear();
+		assnExpr->get_assigns().clear();
+		delete assnExpr;
+		return new StmtExpr( compoundStmt );
+	}
+
+	Type * TupleTypeReplacer::mutate( TupleType * tupleType ) {
+		std::string mangleName = SymTab::Mangler::mangleType( tupleType );
+		TupleType * newType = safe_dynamic_cast< TupleType * > ( Parent::mutate( tupleType ) );
+		if ( ! typeMap.count( mangleName ) ) {
+			// generate struct type to replace tuple type
+			StructDecl * decl = new StructDecl( "_tuple_type_" + mangleName );
+			decl->set_body( true );
+			int cnt = 0;
+			for ( Type * t : *newType ) {
+				decl->get_members().push_back( new ObjectDecl( toString("field_", cnt++), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, t->clone(), nullptr ) );
+			}
+			typeMap[mangleName] = decl;
+			addDeclaration( decl );
+		}
+		Type::Qualifiers qualifiers = newType->get_qualifiers();
+		delete newType;
+		return new StructInstType( qualifiers, typeMap[mangleName] );
+	}
+
+	Expression * TupleIndexExpander::mutate( TupleIndexExpr * tupleExpr ) {
+		Expression * tuple = maybeMutate( tupleExpr->get_tuple(), *this );
+		assert( tuple );
+		tupleExpr->set_tuple( nullptr );
+		unsigned int idx = tupleExpr->get_index();
+		delete tupleExpr;
+
+		StructInstType * type = safe_dynamic_cast< StructInstType * >( tuple->get_result() );
+		StructDecl * structDecl = type->get_baseStruct();
+		assert( structDecl->get_members().size() > idx );
+		Declaration * member = *std::next(structDecl->get_members().begin(), idx);
+		return new MemberExpr( safe_dynamic_cast< DeclarationWithType * >( member ), tuple );
+	}
+
+	Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs ) {
+		if ( result->isVoid() ) {
+			// void result - don't need to produce a value for cascading - just output a chain of comma exprs
+			assert( ! exprs.empty() );
+			std::list< Expression * >::const_iterator iter = exprs.begin();
+			Expression * expr = *iter++;
+			for ( ; iter != exprs.end(); ++iter ) {
+				expr = new CommaExpr( expr, *iter );
+			}
+			return expr;
+		} else {
+			// typed tuple expression - produce a compound literal which performs each of the expressions
+			// as a distinct part of its initializer - the produced compound literal may be used as part of
+			// another expression
+			std::list< Initializer * > inits;
+			for ( Expression * expr : exprs ) {
+				inits.push_back( new SingleInit( expr ) );
+			}
+			return new CompoundLiteralExpr( result, new ListInit( inits ) );
+		}
+	}
+
+	Expression * TupleExprExpander::mutate( TupleExpr * tupleExpr ) {
+		// recursively expand sub-tuple-expressions
+		tupleExpr = safe_dynamic_cast<TupleExpr *>(Parent::mutate(tupleExpr));
+		Type * result = tupleExpr->get_result();
+		std::list< Expression * > exprs = tupleExpr->get_exprs();
+		assert( result );
+
+		// remove data from shell and delete it
+		tupleExpr->set_result( nullptr );
+		tupleExpr->get_exprs().clear();
+		delete tupleExpr;
+
+		return replaceTupleExpr( result, exprs );
+	}
+
+	Type * makeTupleType( const std::list< Expression * > & exprs ) {
+		// produce the TupleType which aggregates the types of the exprs
+		TupleType *tupleType = new TupleType( Type::Qualifiers(true, true, true, true, true, false) );
+		Type::Qualifiers &qualifiers = tupleType->get_qualifiers();
+		for ( Expression * expr : exprs ) {
+			assert( expr->get_result() );
+			if ( expr->get_result()->isVoid() ) {
+				// if the type of any expr is void, the type of the entire tuple is void
+				delete tupleType;
+				return new VoidType( Type::Qualifiers() );
+			}
+			Type * type = expr->get_result()->clone();
+			tupleType->get_types().push_back( type );
+			// the qualifiers on the tuple type are the qualifiers that exist on all component types
+			qualifiers &= type->get_qualifiers();
+		} // for
+		return tupleType;
+	}
+
+	namespace {
+		/// determines if impurity (read: side-effects) may exist in a piece of code. Currently gives a very crude approximation, wherein any function call expression means the code may be impure
+		class ImpurityDetector : public Visitor {
+		public:
+			typedef Visitor Parent;
+			virtual void visit( ApplicationExpr * appExpr ) { maybeImpure = true;	}
+			virtual void visit( UntypedExpr * untypedExpr ) { maybeImpure = true; }
+			bool maybeImpure = false;
+		};
+	} // namespace
+
+	bool maybeImpure( Expression * expr ) {
+		ImpurityDetector detector;
+		expr->accept( detector );
+		return detector.maybeImpure;
+	}
+} // namespace Tuples
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/Tuples/Tuples.h	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,54 @@
+//
+// 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.
+//
+// Tuples.h --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Rob Schluntz
+// Last Modified On : Wed Nov 9 13:17:58 2016
+// Update Count     : 15
+//
+
+#ifndef _TUPLES_H_
+#define _TUPLES_H_
+
+#include <string>
+
+#include "SynTree/Expression.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Type.h"
+
+#include "ResolvExpr/AlternativeFinder.h"
+
+namespace Tuples {
+	// TupleAssignment.cc
+	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, const std::list<ResolvExpr::AltList> & possibilities );
+
+	// TupleExpansion.cc
+	/// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
+	void expandMemberTuples( std::list< Declaration * > & translationUnit );
+
+	/// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
+	void expandTuples( std::list< Declaration * > & translationUnit );
+
+	/// replaces UniqueExprs with a temporary variable and one call
+	void expandUniqueExpr( std::list< Declaration * > & translationUnit );
+
+	/// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
+	Type * makeTupleType( const std::list< Expression * > & exprs );
+
+	/// returns true if the expression may contain side-effects.
+	bool maybeImpure( Expression * expr );
+} // namespace Tuples
+
+#endif // _TUPLE_ASSIGNMENT_H_
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Tuples/module.mk
===================================================================
--- src/Tuples/module.mk	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/Tuples/module.mk	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -6,5 +6,5 @@
 ## file "LICENCE" distributed with Cforall.
 ##
-## module.mk -- 
+## module.mk --
 ##
 ## Author           : Richard C. Bilson
@@ -16,3 +16,4 @@
 
 SRC += 	Tuples/TupleAssignment.cc \
-	Tuples/NameMatcher.cc
+	Tuples/TupleExpansion.cc \
+	Tuples/Explode.cc
Index: src/driver/cfa.cc
===================================================================
--- src/driver/cfa.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/driver/cfa.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -244,4 +244,6 @@
 		nargs += 1;
 	} // if
+	args[nargs] = "-I" CFA_INCDIR "/concurrency";
+	nargs += 1;
 	args[nargs] = "-I" CFA_INCDIR "/containers";
 	nargs += 1;
Index: src/examples/ArrayN.c
===================================================================
--- src/examples/ArrayN.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/examples/ArrayN.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,25 @@
+#include <fstream>
+
+// [unsigned, unsigned] offset_to_index(unsigned offset, unsigned sx, unsigned sy)
+// {
+//     return [offset / sx, offset % sy];
+// }
+
+forall(otype index_t)
+index_t offset_to_index(unsigned offset, index_t size)
+{
+    return [offset / size.0, offset % size.1];
+}
+
+int main(int argc, char* argv[])
+{
+    unsigned x = 0, y = 0, i = 0;
+    unsigned sx = 4, sy = 4;
+
+    i = 6;
+    [x, y] = offset_to_index(6, [sx, sy]);
+
+    sout | x | ' ' | y | endl;
+
+    return 0;
+}
Index: src/examples/coroutine.c
===================================================================
--- src/examples/coroutine.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/examples/coroutine.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,48 @@
+#include <fstream>
+#include <threads>
+
+struct Fibonacci {
+      coroutine c;
+      int fn; // used for communication
+};
+
+void ?{}(Fibonacci* this) {
+      this->fn = 0;
+}
+
+coroutine* this_coroutine(Fibonacci* this) {
+      return &this->c;
+}
+
+void co_main(Fibonacci* this) {
+      int fn1, fn2; 		// retained between resumes
+      this->fn = 0;
+      fn1 = this->fn;
+      suspend(); 		// return to last resume
+
+      this->fn = 1;
+      fn2 = fn1;
+      fn1 = this->fn;
+      suspend(); 		// return to last resume
+
+      for ( ;; ) {
+            this->fn = fn1 + fn2;
+            fn2 = fn1;
+            fn1 = this->fn;
+            suspend(); 	// return to last resume
+      }
+}
+
+int next(Fibonacci* this) {
+      resume(this); // transfer to last suspend
+      return this->fn;
+}
+
+int main() {
+      Fibonacci f1, f2;
+      for ( int i = 1; i <= 10; i += 1 ) {
+            sout | next(&f1) | ' ' | next(&f2) | endl;
+      }
+
+      return 0;
+}
Index: src/libcfa/Makefile.am
===================================================================
--- src/libcfa/Makefile.am	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/libcfa/Makefile.am	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -56,5 +56,6 @@
 CC = ${abs_top_srcdir}/src/driver/cfa
 
-headers = limits stdlib math iostream fstream iterator rational containers/vector
+headers = limits stdlib math iostream fstream iterator rational assert containers/vector concurrency/threads
+runtimehdrs = concurrency
 libobjs = ${headers:=.o}
 
Index: src/libcfa/Makefile.in
===================================================================
--- src/libcfa/Makefile.in	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/libcfa/Makefile.in	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -92,5 +92,6 @@
 am__objects_1 = limits.$(OBJEXT) stdlib.$(OBJEXT) math.$(OBJEXT) \
 	iostream.$(OBJEXT) fstream.$(OBJEXT) iterator.$(OBJEXT) \
-	rational.$(OBJEXT) containers/vector.$(OBJEXT)
+	rational.$(OBJEXT) assert.$(OBJEXT) \
+	containers/vector.$(OBJEXT) concurrency/threads.$(OBJEXT)
 am_libcfa_a_OBJECTS = libcfa-prelude.$(OBJEXT) $(am__objects_1)
 libcfa_a_OBJECTS = $(am_libcfa_a_OBJECTS)
@@ -234,5 +235,6 @@
 cfalib_DATA = builtins.cf extras.cf prelude.cf
 MAINTAINERCLEANFILES = builtins.cf extras.cf ${addprefix ${libdir}/,${cfalib_DATA}} ${addprefix ${libdir}/,${lib_LIBRARIES}}
-headers = limits stdlib math iostream fstream iterator rational containers/vector
+headers = limits stdlib math iostream fstream iterator rational assert containers/vector concurrency/threads
+runtimehdrs = concurrency
 libobjs = ${headers:=.o}
 libcfa_a_SOURCES = libcfa-prelude.c ${headers:=.c}
@@ -312,4 +314,12 @@
 containers/vector.$(OBJEXT): containers/$(am__dirstamp) \
 	containers/$(DEPDIR)/$(am__dirstamp)
+concurrency/$(am__dirstamp):
+	@$(MKDIR_P) concurrency
+	@: > concurrency/$(am__dirstamp)
+concurrency/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) concurrency/$(DEPDIR)
+	@: > concurrency/$(DEPDIR)/$(am__dirstamp)
+concurrency/threads.$(OBJEXT): concurrency/$(am__dirstamp) \
+	concurrency/$(DEPDIR)/$(am__dirstamp)
 libcfa.a: $(libcfa_a_OBJECTS) $(libcfa_a_DEPENDENCIES) $(EXTRA_libcfa_a_DEPENDENCIES) 
 	$(AM_V_at)-rm -f libcfa.a
@@ -319,4 +329,5 @@
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
+	-rm -f concurrency/threads.$(OBJEXT)
 	-rm -f containers/vector.$(OBJEXT)
 
@@ -324,4 +335,5 @@
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/assert.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fstream.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iostream.Po@am__quote@
@@ -332,4 +344,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rational.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stdlib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/threads.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@containers/$(DEPDIR)/vector.Po@am__quote@
 
@@ -505,4 +518,6 @@
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f concurrency/$(DEPDIR)/$(am__dirstamp)
+	-rm -f concurrency/$(am__dirstamp)
 	-rm -f containers/$(DEPDIR)/$(am__dirstamp)
 	-rm -f containers/$(am__dirstamp)
@@ -517,5 +532,5 @@
 
 distclean: distclean-am
-	-rm -rf ./$(DEPDIR) containers/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) concurrency/$(DEPDIR) containers/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
@@ -563,5 +578,5 @@
 
 maintainer-clean: maintainer-clean-am
-	-rm -rf ./$(DEPDIR) containers/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) concurrency/$(DEPDIR) containers/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic \
Index: src/libcfa/assert
===================================================================
--- src/libcfa/assert	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/libcfa/assert	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,34 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// assert --
+//
+// Author           : Thierry Delisle
+// Created On       : Mon Nov 28 12:27:26 2016
+// Last Modified By : Thierry Delisle
+// Last Modified On : Mon Nov 28 12:27:26 2016
+// Update Count     : 0
+//
+
+#ifndef __ASSERT_H__
+#define __ASSERT_H__
+
+extern "C" {
+	#include <assert.h>
+
+	#define __STRINGIFY__(str) #str
+	#define __VSTRINGIFY__(str) __STRINGIFY__(str)
+	#define assertf(expr, fmt, ...) ((expr) ? ((void)2) : __assert_fail_f(__VSTRINGIFY__(expr), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ## __VA_ARGS__ ))
+
+	void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) __attribute__((noreturn));
+}
+
+#endif // __ASSERT_H__
+
+// Local Variables: //
+// mode: c //
+// tab-width: 4 //
+// End: //
Index: src/libcfa/assert.c
===================================================================
--- src/libcfa/assert.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/libcfa/assert.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,47 @@
+//
+// 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.
+//
+// assert.c --
+//
+// Author           : Thierry Delisle
+// Created On       : Mon Nov 28 12:27:26 2016
+// Last Modified By : Thierry Delisle
+// Last Modified On : Mon Nov 28 12:27:26 2016
+// Update Count     : 0
+//
+
+#include "assert"
+#include "stdlib"										// abort
+
+extern "C" {
+	#include <stdarg.h>								// varargs
+	#include <stdio.h>								// fprintf
+
+	extern const char * __progname;						// global name of running executable (argv[0])
+
+	#define CFA_ASSERT_FMT "*CFA assertion error* from program \"%s\" in \"%s\" at line %d in file \"%s\""
+
+	// called by macro assert in assert.h
+	void __assert_fail( const char *assertion, const char *file, unsigned int line, const char *function ) {
+		fprintf( stderr, CFA_ASSERT_FMT ".\n", __progname, function, line, file );
+		abort();
+	}
+
+	// called by macro assertf
+	void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) {
+		fprintf( stderr, CFA_ASSERT_FMT ": ", __progname, function, line, file );
+		va_list args;
+		va_start( args, fmt );
+		vfprintf( stderr, fmt, args );
+		abort();
+	}
+
+}
+
+// Local Variables: //
+// mode: c //
+// tab-width: 4 //
+// End: //
Index: src/libcfa/concurrency/threads
===================================================================
--- src/libcfa/concurrency/threads	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/libcfa/concurrency/threads	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+// fstream --
+//
+// Author           : Peter A. Buhr
+// Created On       : Wed May 27 17:56:53 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Apr 28 08:08:04 2016
+// Update Count     : 88
+//
+
+#ifndef __THREADS_H__
+#define __THREADS_H__
+
+#include <stdbool.h>
+
+struct coroutine {
+      coroutine* last;
+      const char* name;
+      bool notHalted;
+};
+
+void ?{}(coroutine* this);
+
+trait coroutine_t(dtype T) {
+      coroutine* this_coroutine(T* this);
+};
+
+void suspend(void);
+
+forall(dtype T | coroutine_t(T))
+void resume(T* cor);
+
+#endif //__THREADS_H__
Index: src/libcfa/concurrency/threads.c
===================================================================
--- src/libcfa/concurrency/threads.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/libcfa/concurrency/threads.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,54 @@
+#include "threads"
+#include "assert"
+
+#include <stddef.h>
+
+#include <fstream>
+ 
+static coroutine main_coroutine;
+static coroutine* current_coroutine = &main_coroutine;
+
+void ctxSwitchDirect(void* src, void* dst) {
+	current_coroutine = dst;
+}
+
+coroutine* this_coroutine() {
+	return current_coroutine;
+}
+
+void ?{}(coroutine* this)
+{
+	this->last = NULL;
+      this->name = "A Coroutine";
+      this->notHalted = true;
+}
+
+void suspend() {
+      coroutine* src = this_coroutine();		// optimization
+
+	assertf( src->last == (coroutine*)0, 
+		"Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n"
+		"Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
+		src->name, src );
+	assertf( src->last->notHalted, 
+		"Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n"
+		"Possible cause is terminated coroutine's main routine has already returned.",
+		src->name, src, src->last->name, src->last );
+
+	ctxSwitchDirect( src, src->last );
+}
+
+forall(dtype T | coroutine_t(T))
+void resume(T* cor) {
+	coroutine* src = this_coroutine();		// optimization
+	coroutine* dst = this_coroutine(cor);
+
+	if ( src != dst ) {				// not resuming self ?
+		assertf( dst->notHalted , 
+			"Attempt by coroutine %.256s (%p) to resume terminated coroutine %.256s (%p).\n"
+			"Possible cause is terminated coroutine's main routine has already returned.",
+			src->name, src, dst->name, dst );
+		dst->last = src;					// set last resumer
+	} // if
+	ctxSwitchDirect( src, dst );				// always done for performance testing
+}
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 3a2128f5aaa77a03c76ff6198907b91256d8c603)
+++ src/main.cc	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -43,4 +43,5 @@
 #include "Common/UnimplementedError.h"
 #include "../config.h"
+#include "Tuples/Tuples.h"
 
 using namespace std;
@@ -236,5 +237,6 @@
 		OPTPRINT( "tweakInit" )
 		InitTweak::genInit( translationUnit );
-
+		OPTPRINT( "expandMemberTuples" );
+		Tuples::expandMemberTuples( translationUnit );
 		if ( libcfap ) {
 			// generate the bodies of cfa library functions
@@ -261,4 +263,7 @@
 			return 0;
 		} // if
+
+		OPTPRINT( "expandUniqueExpr" ); // xxx - is this the right place for this? want to expand ASAP so that subsequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
+		Tuples::expandUniqueExpr( translationUnit );
 
 		OPTPRINT("instantiateGenerics")
@@ -277,4 +282,6 @@
 		OPTPRINT( "box" )
 		GenPoly::box( translationUnit );
+		OPTPRINT( "expandTuples" ); // xxx - is this the right place for this?
+		Tuples::expandTuples( translationUnit );
 
 		// print tree right before code generation
Index: src/tests/.expect/tupleAssign.txt
===================================================================
--- src/tests/.expect/tupleAssign.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/tests/.expect/tupleAssign.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,6 @@
+u=5 v=6 x=10 y=11 z=[100, 200]
+u=11 v=10 x=11 y=10 z=[11, 10]
+u=10 v=11 z=[10, 11]
+u=123 v=456 z=[111, 222]
+d=-2153.12 i=-2153 c=-105 t=[-2153, -2153.12, -2153]
+d=-2153.12 i=-2153 c=-105 t=[-2153, -2153.12, -2153]
Index: src/tests/.expect/tupleFunction.txt
===================================================================
--- src/tests/.expect/tupleFunction.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/tests/.expect/tupleFunction.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,12 @@
+foo([123, 456, 999.123, {321, 654, Q, 3.14}])
+a=123 b=456 c=999.123 d={321, 654, Q, 3.14}
+X=[123, 456, 999.123, {321, 654, Q, 3.14}]
+foo(...)=456
+bar([777, 2.76, 8675])
+bar([123, 999.123, 456])
+baz(777, 2.76, 8675)
+baz(123, 999.123, 456)
+qux([777, 2.76], 8675)
+qux([123, 999.123], 456)
+x=[3, 5.254, 4]
+x1=3 x2=5.254 x3=4
Index: src/tests/.expect/tupleMember.txt
===================================================================
--- src/tests/.expect/tupleMember.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/tests/.expect/tupleMember.txt	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,4 @@
+called f!
+g(...)=13.5
+v.[f1, i.[f2, f3], f4]=[12, 11, 13, 3.14159]
+v.[f1, i.[f2, f3], f4]=[4, [987, 2], 6.28]
Index: src/tests/tupleAssign.c
===================================================================
--- src/tests/tupleAssign.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/tests/tupleAssign.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,40 @@
+int main() {
+	{
+		// test multiple assignment and cascading assignment
+		int u = 5, v = 6, x = 10, y = 11;
+		[int, int] z = [100, 200];
+
+		// swap x, y and store the new [x, y] in [u, v] and in z;
+		printf("u=%d v=%d x=%d y=%d z=[%d, %d]\n", u, v, x, y, z);
+		z = [u, v] = [x, y] = [y, x];
+		printf("u=%d v=%d x=%d y=%d z=[%d, %d]\n", u, v, x, y, z);
+
+		// shuffle elements -- v = z.0, z.0 = z.1, z.1 = u, u = v
+		[v, z, u] = [z, u, v];
+		printf("u=%d v=%d z=[%d, %d]\n", u, v, z);
+
+		// multiple assignment with tuple expression on right
+		z = [111, 222];
+		[u, v] = [123, 456];
+		printf("u=%d v=%d z=[%d, %d]\n", u, v, z);
+	}
+
+	{
+		// test mass assignment
+		double d = 0.0;
+		int i = 0;
+		char c = '\0';
+		struct X {
+			int z;
+		} x;
+		X ?=?(X * x, double d) {}
+		[int, double, int] t;
+
+		// no conversion from X to integral types, so this serves as a santiy
+		// check that as long as this compiles, ?=?(_, x) is not generated.
+		[t, x, d, i, c, x] = (double)-2153.12;
+		printf("d=%lg i=%d c=%d t=[%d, %lg, %d]\n", d, i, (int)c, t);
+		[x, c, i, d, x, t] = (double)-2153.12;
+		printf("d=%lg i=%d c=%d t=[%d, %lg, %d]\n", d, i, (int)c, t);
+	}
+}
Index: src/tests/tupleFunction.c
===================================================================
--- src/tests/tupleFunction.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/tests/tupleFunction.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,78 @@
+struct S {
+	int f1, f2;
+	char f3;
+	double f4;
+} v;
+
+[int] foo( [int, int, double, S] x ) {
+	printf("foo([%d, %d, %lg, {%d, %d, %c, %lg}])\n", x.0, x.1, x.2, x.3.[f1, f2, f3, f4]);
+	int a, b;
+	double c;
+	S d;
+	[a, b, c, d] = x;
+	[int, int, double, S] X = x;
+	printf("a=%d b=%d c=%lg d={%d, %d, %c, %lg}\n", a, b, c, d.[f1, f2, f3, f4]);
+	printf("X=[%d, %d, %lg, {%d, %d, %c, %lg}]\n", X.0, X.1, X.2, X.3.[f1, f2, f3, f4]);
+	return b;
+}
+
+[void] bar( [int, double, int] z ) {
+	printf("bar([%d, %lg, %d])\n", z);
+}
+
+[void] baz( int a, double b, int c ) {
+	printf("baz(%d, %lg, %d)\n", a, b, c);
+}
+
+[void] qux( [int, double] n, int m ) {
+	printf("qux([%d, %lg], %d)\n", n, m);
+}
+
+[int, double x, int] quux() {
+	return [3, 5.254, 4];
+}
+[[[int, double, int], [int, double]]] quuux() {
+	return [1, 2, 3, 4, 5];
+}
+
+// forall(otype T | { T ?+?(T, T); })
+// [T, T, T] ?+?([T, T, T] x, [T, T, T] y) {
+// 	T x1, x2, x3, y1, y2, y3;
+// 	[x1, x2, x3] = x;
+// 	[y1, y2, y3] = y;
+// 	return [x1+y1, x2+y2, x3+y3];
+// }
+
+int main() {
+  [int, double, int] x = [777, 2.76, 8675];
+  int x1 = 123, x3 = 456;
+  double x2 = 999.123;
+
+  printf("foo(...)=%d\n", foo(x1, x3, x2, (S){ 321, 654, 'Q', 3.14 }));
+
+	// call function with tuple parameter using tuple variable arg
+	bar(x);
+
+	// call function with tuple parameter using multiple values
+	bar(x1, x2, x3);
+
+	// call function with multiple parameters using tuple variable arg
+	baz(x);
+
+	// call function with multiple parameters using multiple args
+	baz(x1, x2, x3);
+
+	// call function with multiple parameters, one of which is a tuple using tuple variable arg
+	qux(x);
+
+	// call function with multiple parameters, one of which is a tuple using multiple args
+	qux(x1, x2, x3);
+
+	// call function with multiple return values and assign into a tuple variable
+	x = quux();
+	printf("x=[%d, %lg, %d]\n", x);
+
+	// call function with multiple return values and assign into a tuple expression
+	[x1, x2, x3] = quux();
+	printf("x1=%d x2=%lg x3=%d\n", x1, x2, x3);
+}
Index: src/tests/tupleMember.c
===================================================================
--- src/tests/tupleMember.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
+++ src/tests/tupleMember.c	(revision 1f44196dc72fd060b6183fe2bdc10f7b30f955d6)
@@ -0,0 +1,42 @@
+void f() {
+	printf("called f!\n");
+}
+
+double g(double x, char y, int z) {
+	return z-y+x;
+}
+
+struct V2	{
+	int f2, f3;
+};
+struct V {
+	int f1;
+	V2 i; // temporary
+	// struct V2 {
+	//   int f2, f3;
+	// } i;
+	double f4;
+} v;
+
+lvalue V h() {
+	static V local = { 111, { 222, 333 }, 444.5 };
+	return local;
+}
+
+int main() {
+	struct X {
+		int a;
+		double b;
+		char c;
+	} x = { 10, 12.5, '\x9' };
+
+	// should only call f once
+	printf("g(...)=%lg\n", g((f(), x).[b, c, a]));
+
+	v.[f1, i.[f2, f3], f4].[1.0, 2, 0, 1.1] = [11, 3.14159, 12, 13];
+
+	printf("v.[f1, i.[f2, f3], f4]=[%d, %d, %d, %lg]\n", v.[f1, i.[f2, f3], f4]);
+
+	h().[f1, i.[f2, f3], f4].[1.0, 2, 0, 1.1] = [987, 6.28, 4, 2];
+	printf("v.[f1, i.[f2, f3], f4]=[%d, [%d, %d], %lg]\n", h().[f1, i.[f2, f3], f4]);
+}
