Changeset 579263a


Ignore:
Timestamp:
Jun 26, 2017, 4:48:35 PM (6 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
bb1cd95
Parents:
e4d829b (diff), 2a7b3ca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into designations

Conflicts:

src/InitTweak/FixInit.cc
src/SymTab/Autogen.h
src/SynTree/Initializer.cc
src/SynTree/Initializer.h
src/Tuples/TupleExpansion.cc

Files:
22 added
6 deleted
89 edited
1 moved

Legend:

Unmodified
Added
Removed
  • .gitignore

    re4d829b r579263a  
    1313libcfa/Makefile
    1414src/Makefile
    15 version
     15/version
    1616
    1717# genereted by premake
  • configure

    re4d829b r579263a  
    62516251
    62526252
    6253 ac_config_files="$ac_config_files Makefile src/driver/Makefile src/Makefile src/benchmark/Makefile src/examples/Makefile src/tests/Makefile src/prelude/Makefile src/libcfa/Makefile"
     6253ac_config_files="$ac_config_files Makefile src/driver/Makefile src/Makefile src/benchmark/Makefile src/examples/Makefile src/tests/Makefile src/tests/preempt_longrun/Makefile src/prelude/Makefile src/libcfa/Makefile"
    62546254
    62556255
     
    70197019    "src/examples/Makefile") CONFIG_FILES="$CONFIG_FILES src/examples/Makefile" ;;
    70207020    "src/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/Makefile" ;;
     7021    "src/tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/preempt_longrun/Makefile" ;;
    70217022    "src/prelude/Makefile") CONFIG_FILES="$CONFIG_FILES src/prelude/Makefile" ;;
    70227023    "src/libcfa/Makefile") CONFIG_FILES="$CONFIG_FILES src/libcfa/Makefile" ;;
  • configure.ac

    re4d829b r579263a  
    235235        src/examples/Makefile
    236236        src/tests/Makefile
     237        src/tests/preempt_longrun/Makefile
    237238        src/prelude/Makefile
    238239        src/libcfa/Makefile
  • doc/LaTeXmacros/common.tex

    re4d829b r579263a  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon May 15 18:03:29 2017
    14 %% Update Count     : 302
     13%% Last Modified On : Sun Jun 18 20:32:32 2017
     14%% Update Count     : 319
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    3636% Names used in the document.
    3737
    38 \newcommand{\CFA}{\textrm{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}\xspace} % Cforall symbolic name
     38\newcommand{\CFAIcon}{\textrm{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}\xspace} % Cforall symbolic name
     39\newcommand{\CFA}{\protect\CFAIcon} % safe for section/caption
    3940\newcommand{\CFL}{\textrm{Cforall}\xspace} % Cforall symbolic name
    4041\newcommand{\Celeven}{\textrm{C11}\xspace} % C11 symbolic name
     
    241242belowskip=3pt,
    242243% replace/adjust listing characters that look bad in sanserif
    243 literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
     244literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
    244245        {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    245         {__}{\_\,\_}2 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2
    246         {___}{\_\,\_\,\_}3,
     246        {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2,
    247247moredelim=**[is][\color{red}]{®}{®},                                    % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
    248248moredelim=**[is][\color{blue}]{ß}{ß},                                   % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
  • doc/proposals/concurrency/Makefile

    re4d829b r579263a  
    1313annex/glossary \
    1414text/intro \
     15text/cforall \
    1516text/basics \
    1617text/concurrency \
  • doc/proposals/concurrency/build/bump_ver.sh

    re4d829b r579263a  
    11#!/bin/bash
    2 if [ ! -f build/version ]; then
    3     echo "0.0.0" > build/version
     2if [ ! -f version ]; then
     3    echo "0.0.0" > version
    44fi
    55
    6 sed -r 's/([0-9]+\.[0-9]+.)([0-9]+)/echo "\1\$((\2+1))" > version/ge' build/version > /dev/null
     6sed -r 's/([0-9]+\.[0-9]+.)([0-9]+)/echo "\1\$((\2+1))" > version/ge' version > /dev/null
  • doc/proposals/concurrency/text/basics.tex

    re4d829b r579263a  
    77
    88\section{Basics of concurrency}
    9 At its core, concurrency is based on having multiple call stacks and potentially multiple threads of execution for these stacks. Concurrency alone without parallelism only requires having multiple call stacks (or contexts) for a single thread of execution and switching between these call stacks on a regular basis. A minimal concurrency product can be achieved by creating coroutines which instead of context switching between each other, always ask an oracle where to context switch next. While coroutines do not technically require a stack, stackfull coroutines are the closest abstraction to a practical "naked"" call stack. When writing concurrency in terms of coroutines, the oracle effectively becomes a scheduler and the whole system now follows a cooperative threading model \cit. The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine but in any case a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to be present, the only feature missing is preemption. Indeed, concurrency challenges appear with the lack of determinism. Guaranteeing mutual-exclusion or synchronisation are simply ways of limiting the lack of determinism in the system. A scheduler introduces order of execution uncertainty while preemption introduces incertainty about when context-switches occur. Now it is important to understand that uncertainty is not necessarily undesireable, uncertainty can often be used by systems to significantly increase performance and is often the basis of giving the user the illusion that hundred of tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as little determinism as correctness will allow\cit.
     9At its core, concurrency is based on having call-stacks and potentially multiple threads of execution for these stacks. Concurrency without parallelism only requires having multiple call stacks (or contexts) for a single thread of execution, and switching between these call stacks on a regular basis. A minimal concurrency product can be achieved by creating coroutines, which instead of context switching between each other, always ask an oracle where to context switch next. While coroutines do not technically require a stack, stackfull coroutines are the closest abstraction to a practical "naked"" call stack. When writing concurrency in terms of coroutines, the oracle effectively becomes a scheduler and the whole system now follows a cooperative threading-model \cit. The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine. In any case, a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to occur, the only feature missing is preemption. Indeed, concurrency challenges appear with non-determinism. Guaranteeing mutual-exclusion or synchronisation are simply ways of limiting the lack of determinism in a system. A scheduler introduces order of execution uncertainty, while preemption introduces incertainty about where context-switches occur. Now it is important to understand that uncertainty is not necessarily undesireable; uncertainty can often be used by systems to significantly increase performance and is often the basis of giving a user the illusion that tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows\cit.
    1010
    1111\section{\protect\CFA 's Thread Building Blocks}
    12 % 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.
    13 One of the important features that is missing to C is threading. On modern architectures, the lack of threading is becoming less and less forgivable\cite{Sutter05, Sutter05b} and therefore any modern programming language should have the proper tools to allow users to write performant concurrent and/or parallel programs. As an extension of C, \CFA needs to express these concepts an a way that is as natural as possible to programmers used to imperative languages. And being a system level language means programmers will expect to be able to choose precisely which features they need and which cost they are willing to pay.
    14 
    15 \section{Coroutines A stepping stone}\label{coroutine}
    16 While the main focus of this proposal is concurrency and parallelism, as mentionned above 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 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. Furthermore, many design challenges of threads are at least partially present in designing coroutines, which makes the design effort that much more relevant. The core API of coroutines revolve around two features independent call stacks and \code{suspend}/\code{resume}.
     12One of the important features that is missing in C is threading. On modern architectures, a lack of threading is becoming less and less forgivable\cite{Sutter05, Sutter05b}, and therefore modern programming languages must have the proper tools to allow users to write performant concurrent and/or parallel programs. As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers used to imperative languages. And being a system-level language means programmers expect to choose precisely which features they need and which cost they are willing to pay.
     13
     14\section{Coroutines: A stepping stone}\label{coroutine}
     15While the main focus of this proposal is concurrency and parallelism, as mentionned above it is important to adress coroutines, which are actually a significant underlying aspect of a concurrency system. Indeed, while having nothing todo with parallelism and arguably 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. Furthermore, many design challenges of threads are at least partially present in designing coroutines, which makes the design effort that much more relevant. The core API of coroutines revolve around two features: independent call stacks and \code{suspend}/\code{resume}.
    1716
    1817Here is an example of a solution to the fibonnaci problem using \CFA coroutines:
     
    2625        }
    2726
     27        // main automacically called on first resume
    2828        void main(Fibonacci* this) {
    2929                int fn1, fn2;           // retained between resumes
     
    5959
    6060\subsection{Construction}
    61 One important design challenge for coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run some code after the user-constructor runs. In the case of the coroutines this challenge is simpler since there is no loss of determinism brough by preemption or scheduling, however, the underlying challenge remains the same for coroutines and threads.
    62 
    63 The runtime system needs to create the coroutine's stack and more importantly prepare it for the first resumption. The timing of the creation is non trivial since users both expect to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor (Obviously we only solve cases where these two statements don't conflict). There are several solutions to this problem but the chosen options effectively forces the design of the coroutine.
    64 
    65 Furthermore, \CFA faces an extra challenge which is that polymorphique routines rely on invisible thunks when casted to non-polymorphic routines and these thunks have function scope. For example, the following code, while looking benign, can run into undefined behaviour because of thunks:
     61One important design challenge for coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run code after the user-constructor runs. In the case of coroutines, this challenge is simpler since there is no non-determinism from preemption or scheduling. However, the underlying challenge remains the same for coroutines and threads.
     62
     63The runtime system needs to create the coroutine's stack and more importantly prepare it for the first resumption. The timing of the creation is non-trivial since users both expect to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor. Like for regular objects, constructors can still leak coroutines before they are ready. There are several solutions to this problem but the chosen options effectively forces the design of the coroutine.
     64
     65Furthermore, \CFA faces an extra challenge as polymorphic routines create invisible thunks when casted to non-polymorphic routines and these thunks have function scope. For example, the following code, while looking benign, can run into undefined behaviour because of thunks:
    6666
    6767\begin{cfacode}
     
    7878}
    7979\end{cfacode}
    80 Indeed, the generated C code\footnote{Code trimmed down for brevity} shows that a local thunk is created in order to hold type information:
     80The generated C code\footnote{Code trimmed down for brevity} creates a local thunk to hold type information:
    8181
    8282\begin{ccode}
     
    9595}
    9696\end{ccode}
    97 The problem in the this example is that there is a race condition between the start of the execution of \code{noop} on the other thread and the stack frame of \code{bar} being destroyed. This extra challenge limits which solutions are viable because storing the function pointer for too long only increases the chances that the race will end in undefined behavior; i.e. the stack based thunk being destroyed before it was used.
     97The problem in this example is a race condition between the start of the execution of \code{noop} on the other thread and the stack frame of \code{bar} being destroyed. This extra challenge limits which solutions are viable because storing the function pointer for too long only increases the chances that the race will end in undefined behavior; i.e. the stack based thunk being destroyed before it was used. This challenge is an extension of challenges that come with second-class routines. Indeed, GCC nested routines also have the limitation that the routines cannot be passed outside of the scope of the functions these were declared in. The case of coroutines and threads is simply an extension of this problem to multiple call-stacks.
    9898
    9999\subsection{Alternative: Composition}
    100 One solution to this challenge would be to use inheritence,
     100One solution to this challenge would be to use composition/containement,
    101101
    102102\begin{cfacode}
    103103        struct Fibonacci {
    104104              int fn; // used for communication
    105               coroutine c;
     105              coroutine c; //composition
    106106        };
    107107
     
    111111        }
    112112\end{cfacode}
    113 
    114 There are two downsides to this approach. The first, which is relatively minor, is that the base class needs to be made aware of the main routine pointer, regardless of whether we use a parameter or a virtual pointer, this means the coroutine data must be made larger to store a value that is actually a compile time constant (The address of the main routine). The second problem which is both subtle but significant, is that now users can get the initialisation order of there coroutines wrong. Indeed, every field of a \CFA struct will be constructed but in the order of declaration, unless users explicitly write otherwise. This means that users who forget to initialize a the coroutine at the right time may resume the coroutine with an uninitilized object. For coroutines, this is unlikely to be a problem, for threads however, this is a significant problem.
     113There are two downsides to this approach. The first, which is relatively minor, is that the base class needs to be made aware of the main routine pointer, regardless of whether a parameter or a virtual pointer is used, this means the coroutine data must be made larger to store a value that is actually a compile time constant (address of the main routine). The second problem, which is both subtle and significant, is that now users can get the initialisation order of there coroutines wrong. Indeed, every field of a \CFA struct is constructed but in declaration order, unless users explicitly write otherwise. This semantics means that users who forget to initialize a the coroutine may resume the coroutine with an uninitilized object. For coroutines, this is unlikely to be a problem, for threads however, this is a significant problem.
    115114
    116115\subsection{Alternative: Reserved keyword}
     
    122121        };
    123122\end{cfacode}
    124 
    125123This mean the compiler can solve problems by injecting code where needed. The downside of this approach is that it makes coroutine a special case in the language. Users who would want to extend coroutines or build their own for various reasons can only do so in ways offered by the language. Furthermore, implementing coroutines without language supports also displays the power of \CFA.
    126124While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can both be constructed by users without using the language support. The reserved keywords are only present to improve ease of use for the common cases.
     
    128126\subsection{Alternative: Lamda Objects}
    129127
    130 For coroutines as for threads, many implementations are based on routine pointers or function objects\cit. For example, Boost implements coroutines in terms of four functor object types \code{asymmetric_coroutine<>::pull_type}, \code{asymmetric_coroutine<>::push_type}, \code{symmetric_coroutine<>::call_type}, \code{symmetric_coroutine<>::yield_type}. Often, the canonical threading paradigm in languages is based on function pointers, pthread being one of the most well known example. The main problem of these approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type. Since the custom type is simple to write and \CFA and solves several issues, added support for routine/lambda based coroutines adds very little.
    131 
    132 \subsection{Trait based coroutines}
    133 
    134 Finally the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines. This approach defines a coroutine as \say{anything that \say{satisfies the trait \code{is_coroutine} and is used as a coroutine} is a coroutine}.
     128For coroutines as for threads, many implementations are based on routine pointers or function objects\cit. For example, Boost implements coroutines in terms of four functor object types:
     129\begin{cfacode}
     130asymmetric_coroutine<>::pull_type
     131asymmetric_coroutine<>::push_type
     132symmetric_coroutine<>::call_type
     133symmetric_coroutine<>::yield_type
     134\end{cfacode}
     135Often, the canonical threading paradigm in languages is based on function pointers, pthread being one of the most well known examples. The main problem of this approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type. Since the custom type is simple to write in \CFA and solves several issues, added support for routine/lambda based coroutines adds very little.
     136
     137A variation of this would be to use an simple function pointer in the same way pthread does for threads :
     138\begin{cfacode}
     139void foo( coroutine_t cid, void * arg ) {
     140        int * value = (int *)arg;
     141        //Coroutine body
     142}
     143
     144int main() {
     145        int value = 0;
     146        coroutine_t cid = coroutine_create( &foo, (void*)&value );
     147        coroutine_resume( &cid );
     148}
     149\end{cfacode}
     150This semantic is more common for thread interfaces than coroutines but would work equally well. As discussed in section \ref{threads}, this approach is superseeded by static approaches in terms of expressivity.
     151
     152\subsection{Alternative: Trait-based coroutines}
     153
     154Finally the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines. This approach defines a coroutine as anything that satisfies the trait \code{is_coroutine} and is used as a coroutine is a coroutine.
    135155
    136156\begin{cfacode}
     
    140160};
    141161\end{cfacode}
    142 
    143 This entails that an object is not a coroutine until \code{resume} (or \code{prime}) is called on the object. Correspondingly, any object that is passed to \code{resume} is a coroutine since it must satisfy the \code{is_coroutine} trait to compile. The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory foot print of a coroutine is trivial when implementing the \code{get_coroutine} routine. The \CFA keyword \code{coroutine} only has the effect of implementing the getter and forward declarations required for users to only have to implement the main routine.
     162This ensures an object is not a coroutine until \code{resume} (or \code{prime}) is called on the object. Correspondingly, any object that is passed to \code{resume} is a coroutine since it must satisfy the \code{is_coroutine} trait to compile. The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory foot print of a coroutine is trivial when implementing the \code{get_coroutine} routine. The \CFA keyword \code{coroutine} only has the effect of implementing the getter and forward declarations required for users to only have to implement the main routine.
     163
     164\begin{center}
     165\begin{tabular}{c c c}
     166\begin{cfacode}[tabsize=3]
     167coroutine MyCoroutine {
     168        int someValue;
     169};
     170\end{cfacode} & == & \begin{cfacode}[tabsize=3]
     171struct MyCoroutine {
     172        int someValue;
     173        coroutine_desc __cor;
     174};
     175
     176static inline
     177coroutine_desc * get_coroutine(
     178        struct MyCoroutine * this
     179) {
     180        return &this->__cor;
     181}
     182
     183void main(struct MyCoroutine * this);
     184\end{cfacode}
     185\end{tabular}
     186\end{center}
     187
    144188
    145189
    146190\section{Thread Interface}\label{threads}
    147 The basic building blocks of multi-threading in \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 SUE declaration \code{thread} as follows:
     191The basic building blocks of multi-threading in \CFA are \glspl{cfathread}. Both use and kernel threads are supported, where user threads are the concurrency mechanism and kernel threads are the parallel mechanism. User threads offer a flexible and lightweight interface. A thread can be declared using a struct declaration \code{thread} as follows:
    148192
    149193\begin{cfacode}
     
    151195\end{cfacode}
    152196
    153 Like for coroutines, the keyword is a thin wrapper arount a \CFA trait:
     197As for coroutines, the keyword is a thin wrapper arount a \CFA trait:
    154198
    155199\begin{cfacode}
     
    170214\end{cfacode}
    171215
    172 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 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
     216In this example, threads of type \code{foo} start execution in the \code{void main(foo*)} routine which prints \code{"Hello World!"}. While this proposoal encourages this approach to enforce strongly-typed 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
    173217\begin{cfacode}
    174218        typedef void (*voidFunc)(void);
     
    201245void main() {
    202246        World w;
    203         //Thread run forks here
    204 
    205         //Printing "Hello " and "World!" will be run concurrently
     247        //Thread forks here
     248
     249        //Printing "Hello " and "World!" are run concurrently
    206250        sout | "Hello " | endl;
    207251
     
    210254\end{cfacode}
    211255
    212 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, 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
     256This 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. Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple
     257
     258\begin{cfacode}
     259        thread MyThread {
     260                //...
     261        };
     262
     263        //main
     264        void main(MyThread* this) {
     265                //...
     266        }
     267
     268        void foo() {
     269                MyThread thrds[10];
     270                //Start 10 threads at the beginning of the scope
     271
     272                DoStuff();
     273
     274                //Wait for the 10 threads to finish
     275        }
     276\end{cfacode}
     277
     278However, 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 because of block structure. However, storage allocation os not limited to blocks; dynamic allocation can create threads that outlive the scope in which the thread is created much like dynamically allocating memory lets objects outlive the scope in which they are created
    213279
    214280\begin{cfacode}
     
    241307        }
    242308\end{cfacode}
    243 
    244 Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple
    245 
    246 \begin{cfacode}
    247         thread MyThread {
    248                 //...
    249         };
    250 
    251         //main
    252         void main(MyThread* this) {
    253                 //...
    254         }
    255 
    256         void foo() {
    257                 MyThread thrds[10];
    258                 //Start 10 threads at the beginning of the scope
    259 
    260                 DoStuff();
    261 
    262                 //Wait for the 10 threads to finish
    263         }
    264 \end{cfacode}
  • doc/proposals/concurrency/text/concurrency.tex

    re4d829b r579263a  
    44% ======================================================================
    55% ======================================================================
    6 Several tool can be used to solve concurrency challenges. Since many of these challenges 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). This distinction 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, 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 shared objects. At a lower level, non-concurrent paradigms are often 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.
     6Several tool can be used to solve concurrency challenges. Since many of these challenges 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). This distinction in turn means that, in order to be effective, programmers need to learn two sets of designs patterns. While this distinction can be hidden away in library code, effective use of the librairy still has to take both paradigms into account.
     7
     8Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects. At the lowest level, concurrent paradigms are implemented as atomic operations and locks. 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}.
     9
     10An 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 be the main concurrency paradigm for general purpose language, which is why it was rejected as the core paradigm for concurrency in \CFA.
     11
     12One 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.
    713
    814\section{Basics}
    9 The basic features that concurrency tools neet to offer is support for mutual-exclusion and synchronisation. Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is the group of instructions on an associated portion of data that requires the limited access. On the other hand, synchronization enforces relative ordering of execution and synchronization tools are used to guarantee that event \textit{X} always happens before \textit{Y}.
     15Non-determinism requires concurrent systems to offer support for mutual-exclusion and synchronisation. Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is a group of instructions on an associated portion of data that requires the restricted access. On the other hand, synchronization enforces relative ordering of execution and synchronization tools numerous mechanisms to establish timing relationships among threads.
    1016
    1117\subsection{Mutual-Exclusion}
    12 As mentionned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once. However, many solution exists for mutual exclusion which vary in terms of performance, flexibility and ease of use. Methods range from low level locks, which are fast and flexible but require significant attention to be correct, to  higher level mutual-exclusion methods, which sacrifice some performance in order to improve ease of use. Often by either guaranteeing some problems cannot occur (e.g. being deadlock free) or by offering a more explicit coupling between data and corresponding critical section. For example, the \CC \code{std::atomic<T>} which offer an easy way to express mutual-exclusion on a restricted set of features (.e.g: reading/writing large types atomically). Another challenge with low level locks is composability. Locks are said to not be composable because it takes careful organising for multiple locks to be used and once while preventing deadlocks. Easing composability is another feature higher-level mutual-exclusion mechanisms often offer.
     18As mentionned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once. However, many solution exists for mutual exclusion which vary in terms of performance, flexibility and ease of use. Methods range from low-level locks, which are fast and flexible but require significant attention to be correct, to  higher-level mutual-exclusion methods, which sacrifice some performance in order to improve ease of use. Ease of use comes by either guaranteeing some problems cannot occur (e.g., being deadlock free) or by offering a more explicit coupling between data and corresponding critical section. For example, the \CC \code{std::atomic<T>} which offer an easy way to express mutual-exclusion on a restricted set of operations (.e.g: reading/writing large types atomically). Another challenge with low-level locks is composability. Locks are not composable because it takes careful organising for multiple locks to be used while preventing deadlocks. Easing composability is another feature higher-level mutual-exclusion mechanisms often offer.
    1319
    1420\subsection{Synchronization}
    15 As for mutual-exclusion, low level synchronisation primitive often offer great performance and good flexibility at the cost of ease of use. Again, higher-level mechanism often simplify usage by adding better coupling between synchronization and data, for example message passing, or offering simple solution to otherwise involved challenges. An example of this is barging. As mentionned above synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}. Most of the time synchronisation happens around a critical section, where threads most acquire said critical section in a certain order. However, it may also be desired to be able to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}. This is called barging, where event \textit{X} tries to effect event \textit{Y} but anoter thread races to grab the critical section and emits \textit{Z} before \textit{Y}. Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs.
     21As for mutual-exclusion, low level synchronisation primitive often offer good performance and good flexibility at the cost of ease of use. Again, higher-level mechanism often simplify usage by adding better coupling between synchronization and data, .eg., message passing, or offering simple solution to otherwise involved challenges. An example of this is barging. As mentionned above synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}. Most of the time synchronisation happens around a critical section, where threads most acquire said critical section in a certain order. However, it may also be desired to be able to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}. This is called barging, where event \textit{X} tries to effect event \textit{Y} but anoter thread races to grab the critical section and emits \textit{Z} before \textit{Y}. Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs.
    1622
    1723% ======================================================================
     
    2026% ======================================================================
    2127% ======================================================================
    22 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 :
     28A 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 OO semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it :
    2329\begin{cfacode}
    2430        typedef /*some monitor type*/ monitor;
     
    3642% ======================================================================
    3743% ======================================================================
    38 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.
    39 
    40 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 :
     44The above monitor example displays some of the intrinsic characteristics. First, 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 objects.
     45
     46Another 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 occur for generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following to implement an atomic counter :
    4147
    4248\begin{cfacode}
     
    4652        size_t ++?(counter_t & mutex this); //increment
    4753
    48         //need for mutex is platform dependent here
     54        //need for mutex is platform dependent
    4955        void ?{}(size_t * this, counter_t & mutex cnt); //conversion
    5056\end{cfacode}
     
    5258Here, 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} keyword depending on whether or not reading an \code{size_t} is an atomic operation.
    5359
    54 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 qualifiers \code{void foo(counter_t & this)} then it is reasonable 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. In fact \code{nomutex} is the "normal" parameter behaviour, with the \code{nomutex} keyword effectively stating explicitly that "this routine is not 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 routines neither keyword. Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing. While there are several benefits to mandatory keywords, they do bring a few challenges. Mandatory keywords in \CFA would imply that the compiler must know without a doubt wheter or not a parameter is a monitor or not. Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred. For this reason, \CFA only has the \code{mutex} keyword.
     60Having both \code{mutex} and \code{nomutex} keywords is redundant based on the meaning of a routine having neither of these keywords. For example, given a routine without qualifiers \code{void foo(counter_t & this)}, then it is reasonable that it should default to the safest option \code{mutex}, whereas assuming \code{nomutex} is unsafe and may cause subtle errors. In fact, \code{nomutex} is the "normal" parameter behaviour, with the \code{nomutex} keyword effectively stating explicitly that "this routine is not 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 routines neither keyword. Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing. While there are several benefits to mandatory keywords, they do bring a few challenges. Mandatory keywords in \CFA would imply that the compiler must know without a doubt wheter or not a parameter is a monitor or not. Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred. For this reason, \CFA only has the \code{mutex} keyword.
    5561
    5662
     
    6066int f2(const monitor & mutex m);
    6167int f3(monitor ** mutex m);
    62 int f4(monitor *[] mutex m);
     68int f4(monitor * mutex m []);
    6369int f5(graph(monitor*) & mutex m);
    6470\end{cfacode}
     
    6874int f1(monitor & mutex m);   //Okay : recommanded case
    6975int f2(monitor * mutex m);   //Okay : could be an array but probably not
    70 int f3(monitor [] mutex m);  //Not Okay : Array of unkown length
     76int f3(monitor mutex m []);  //Not Okay : Array of unkown length
    7177int f4(monitor ** mutex m);  //Not Okay : Could be an array
    72 int f5(monitor *[] mutex m); //Not Okay : Array of unkown length
     78int f5(monitor * mutex m []); //Not Okay : Array of unkown length
    7379\end{cfacode}
    7480
  • doc/proposals/concurrency/text/intro.tex

    re4d829b r579263a  
    33% ======================================================================
    44
    5 This proposal provides a minimal concurrency API that is 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.
     5This proposal provides a minimal concurrency API that is simple, efficient and can be reused to build higher-level features. The simplest possible concurrency system 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. Therefore a high-level approach is adapted in \CFA
    66
    7 There are actually two problems that need to be solved in the design of 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 about performance, cost and resource utilization.
     7There are actually two problems that need to be solved in the design of concurrency for a programming language: which concurrency and which parallelism tools are available to the users. While these two concepts are often combined, they are in fact distinct concepts that require different tools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are about performance, cost and resource utilization.
  • doc/proposals/concurrency/thesis.tex

    re4d829b r579263a  
    7777\fancyhf{}
    7878\cfoot{\thepage}
    79 \rfoot{v\input{build/version}}
     79\rfoot{v\input{version}}
    8080
    8181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    9494
    9595\input{intro}
     96
     97\input{cforall}
    9698
    9799\input{basics}
  • doc/rob_thesis/intro.tex

    re4d829b r579263a  
    33%======================================================================
    44
    5 \section{\CFA Background}
     5\section{\protect\CFA Background}
    66\label{s:background}
    77\CFA \footnote{Pronounced ``C-for-all'', and written \CFA or Cforall.} is a modern non-object-oriented extension to the C programming language.
     
    370370    \end{tabular}
    371371  \end{center}
    372   \caption{\label{table:types} The different kinds of type parameters in \CFA}
     372  \caption{\label{table:types} The different kinds of type parameters in \protect\CFA}
    373373\end{table}
    374374
  • doc/rob_thesis/thesis.tex

    re4d829b r579263a  
    6666% ,monochrome % toggle black and white mode
    6767}{xcolor}
     68\PassOptionsToPackage{pdftex}{graphicx}
    6869\documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
    6970
  • doc/user/user.tex

    re4d829b r579263a  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Fri Jun  2 10:07:51 2017
    14 %% Update Count     : 2128
     13%% Last Modified On : Fri Jun 16 12:00:01 2017
     14%% Update Count     : 2433
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    4343\usepackage[pagewise]{lineno}
    4444\renewcommand{\linenumberfont}{\scriptsize\sffamily}
    45 \input{common}                                          % bespoke macros used in the document
     45\input{common}                                          % common CFA document macros
    4646\usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
    4747\usepackage{breakurl}
     
    110110\renewcommand{\subsectionmark}[1]{\markboth{\thesubsection\quad #1}{\thesubsection\quad #1}}
    111111\pagenumbering{roman}
    112 \linenumbers                                            % comment out to turn off line numbering
     112%\linenumbers                                            % comment out to turn off line numbering
    113113
    114114\maketitle
     
    454454the type suffixes ©U©, ©L©, etc. may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©.
    455455\end{enumerate}
    456 It is significantly easier to read and enter long constants when they are broken up into smaller groupings (most cultures use comma or period among digits for the same purpose).
     456It is significantly easier to read and enter long constants when they are broken up into smaller groupings (many cultures use comma and/or period among digits for the same purpose).
    457457This extension is backwards compatible, matches with the use of underscore in variable names, and appears in \Index*{Ada} and \Index*{Java} 8.
    458458
     
    464464\begin{cfa}
    465465int ®`®otype®`® = 3;                    §\C{// make keyword an identifier}§
    466 double ®`®choose®`® = 3.5;
    467 \end{cfa}
    468 Programs can be converted easily by enclosing keyword identifiers in backquotes, and the backquotes can be removed later when the identifier name is changed to a non-keyword name.
     466double ®`®forall®`® = 3.5;
     467\end{cfa}
     468Existing C programs with keyword clashes can be converted by enclosing keyword identifiers in backquotes, and eventually the identifier name can be changed to a non-keyword name.
    469469\VRef[Figure]{f:InterpositionHeaderFile} shows how clashes in C header files (see~\VRef{s:StandardHeaders}) can be handled using preprocessor \newterm{interposition}: ©#include_next© and ©-I filename©:
    470470
     
    473473// include file uses the CFA keyword "otype".
    474474#if ! defined( otype )                  §\C{// nesting ?}§
    475 #define otype `otype`
     475#define otype ®`®otype®`®               §\C{// make keyword an identifier}§
    476476#define __CFA_BFD_H__
    477477#endif // ! otype
     
    497497\begin{tabular}{@{}ll@{}}
    498498\begin{cfa}
    499 int *x[5]
     499int * x[5]
    500500\end{cfa}
    501501&
     
    508508For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way:
    509509\begin{cfa}
    510 int (*f())[5] {...};                    §\C{
    511 ... (*f())[3] += 1;
     510int ®(*®f®())[®5®]® {...};                              §\C{definition
     511 ... ®(*®f®())[®3®]® += 1;                              §\C{usage}§
    512512\end{cfa}
    513513Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
     
    516516\CFA provides its own type, variable and routine declarations, using a different syntax.
    517517The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type.
    518 In the following example, \R{red} is for the base type and \B{blue} is for the qualifiers.
     518In the following example, \R{red} is the base type and \B{blue} is qualifiers.
    519519The \CFA declarations move the qualifiers to the left of the base type, \ie move the blue to the left of the red, while the qualifiers have the same meaning but are ordered left to right to specify a variable's type.
    520520\begin{quote2}
     
    534534\end{tabular}
    535535\end{quote2}
    536 The only exception is bit field specification, which always appear to the right of the base type.
     536The only exception is \Index{bit field} specification, which always appear to the right of the base type.
    537537% Specifically, the character ©*© is used to indicate a pointer, square brackets ©[©\,©]© are used to represent an array or function return value, and parentheses ©()© are used to indicate a routine parameter.
    538538However, unlike C, \CFA type declaration tokens are distributed across all variables in the declaration list.
     
    583583\begin{cfa}
    584584int z[ 5 ];
    585 char *w[ 5 ];
    586 double (*v)[ 5 ];
     585char * w[ 5 ];
     586double (* v)[ 5 ];
    587587struct s {
    588588        int f0:3;
    589         int *f1;
    590         int *f2[ 5 ]
     589        int * f1;
     590        int * f2[ 5 ]
    591591};
    592592\end{cfa}
     
    637637\begin{cfa}
    638638int extern x[ 5 ];
    639 const int static *y;
     639const int static * y;
    640640\end{cfa}
    641641&
     
    658658\begin{cfa}
    659659y = (®int *®)x;
    660 i = sizeof(®int *[ 5 ]®);
     660i = sizeof(®int * [ 5 ]®);
    661661\end{cfa}
    662662\end{tabular}
     
    672672C provides a \newterm{pointer type};
    673673\CFA adds a \newterm{reference type}.
    674 These types may be derived from a object or routine type, called the \newterm{referenced type}.
     674These types may be derived from an object or routine type, called the \newterm{referenced type}.
    675675Objects of these types contain an \newterm{address}, which is normally a location in memory, but may also address memory-mapped registers in hardware devices.
    676676An integer constant expression with the value 0, or such an expression cast to type ©void *©, is called a \newterm{null-pointer constant}.\footnote{
     
    729729
    730730A \Index{pointer}/\Index{reference} object is a generalization of an object variable-name, \ie a mutable address that can point to more than one memory location during its lifetime.
    731 (Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage as the literal is embedded directly into instructions.)
     731(Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage if the literal is embedded directly into instructions.)
    732732Hence, a pointer occupies memory to store its current address, and the pointer's value is loaded by dereferencing, \eg:
    733733\begin{quote2}
     
    758758\begin{cfa}
    759759p1 = p2;                                                §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§
    760 p2 = p1 + x;                                    §\C{// p2 = p1 + x\ \ rather than\ \ *p1 = *p1 + x}§
     760p2 = p1 + x;                                    §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§
    761761\end{cfa}
    762762even though the assignment to ©p2© is likely incorrect, and the programmer probably meant:
     
    765765®*®p2 = ®*®p1 + x;                              §\C{// pointed-to value assignment / operation}§
    766766\end{cfa}
    767 The C semantics works well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).
     767The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).
    768768
    769769However, in most other situations, the pointed-to value is requested more often than the pointer address.
     
    799799For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}):
    800800\begin{cfa}
    801 (&®*®)r1 = &x;                                  §\C{// (\&*) cancel giving address of r1 not variable pointed-to by r1}§
     801(&®*®)r1 = &x;                                  §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§
    802802\end{cfa}
    803803Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}):
    804804\begin{cfa}
    805 (&(&®*®)®*®)r3 = &(&®*®)r2;             §\C{// (\&*) cancel giving address of r2, (\&(\&*)*) cancel giving address of r3}§
     805(&(&®*®)®*®)r3 = &(&®*®)r2;             §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§
    806806\end{cfa}
    807807Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth.
     
    824824As for a pointer type, a reference type may have qualifiers:
    825825\begin{cfa}
    826 const int cx = 5;                               §\C{// cannot change cx;}§
    827 const int & cr = cx;                    §\C{// cannot change what cr points to}§
    828 ®&®cr = &cx;                                    §\C{// can change cr}§
    829 cr = 7;                                                 §\C{// error, cannot change cx}§
    830 int & const rc = x;                             §\C{// must be initialized}§
    831 ®&®rc = &x;                                             §\C{// error, cannot change rc}§
    832 const int & const crc = cx;             §\C{// must be initialized}§
    833 crc = 7;                                                §\C{// error, cannot change cx}§
    834 ®&®crc = &cx;                                   §\C{// error, cannot change crc}§
    835 \end{cfa}
    836 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced into the reference}:
    837 \begin{cfa}
    838 int & const cr = *0;                    §\C{// where 0 is the int * zero}§
    839 \end{cfa}
    840 Note, constant reference-types do not prevent addressing errors because of explicit storage-management:
     826const int cx = 5;                                       §\C{// cannot change cx;}§
     827const int & cr = cx;                            §\C{// cannot change what cr points to}§
     828®&®cr = &cx;                                            §\C{// can change cr}§
     829cr = 7;                                                         §\C{// error, cannot change cx}§
     830int & const rc = x;                                     §\C{// must be initialized}§
     831®&®rc = &x;                                                     §\C{// error, cannot change rc}§
     832const int & const crc = cx;                     §\C{// must be initialized}§
     833crc = 7;                                                        §\C{// error, cannot change cx}§
     834®&®crc = &cx;                                           §\C{// error, cannot change crc}§
     835\end{cfa}
     836Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}:
     837\begin{cfa}
     838int & const cr = *0;                            §\C{// where 0 is the int * zero}§
     839\end{cfa}
     840Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management:
    841841\begin{cfa}
    842842int & const cr = *malloc();
    843843cr = 5;
    844 delete &cr;
    845 cr = 7;                                                 §\C{// unsound pointer dereference}§
    846 \end{cfa}
    847 
    848 Finally, the position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers.
     844free( &cr );
     845cr = 7;                                                         §\C{// unsound pointer dereference}§
     846\end{cfa}
     847
     848The position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers.
    849849The ©const© qualifier cannot be moved before the pointer/reference qualifier for C style-declarations;
    850 \CFA-style declarations attempt to address this issue:
     850\CFA-style declarations (see \VRef{s:Declarations}) attempt to address this issue:
    851851\begin{quote2}
    852852\begin{tabular}{@{}l@{\hspace{3em}}l@{}}
     
    863863\end{tabular}
    864864\end{quote2}
    865 where the \CFA declaration is read left-to-right (see \VRef{s:Declarations}).
     865where the \CFA declaration is read left-to-right.
     866
     867Finally, like pointers, references are usable and composable with other type operators and generators.
     868\begin{cfa}
     869int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§
     870&ar[1] = &w;                                            §\C{// change reference array element}§
     871typeof( ar[1] ) p;                                      §\C{// (gcc) is int, i.e., the type of referenced object}§
     872typeof( &ar[1] ) q;                                     §\C{// (gcc) is int \&, i.e., the type of reference}§
     873sizeof( ar[1] ) == sizeof( int );       §\C{// is true, i.e., the size of referenced object}§
     874sizeof( &ar[1] ) == sizeof( int *)      §\C{// is true, i.e., the size of a reference}§
     875\end{cfa}
    866876
    867877In contrast to \CFA reference types, \Index*[C++]{\CC{}}'s reference types are all ©const© references, preventing changes to the reference address, so only value assignment is possible, which eliminates half of the \Index{address duality}.
     878Also, \CC does not allow \Index{array}s\index{array!reference} of reference\footnote{
     879The reason for disallowing arrays of reference is unknown, but possibly comes from references being ethereal (like a textual macro), and hence, replaceable by the referant object.}
    868880\Index*{Java}'s reference types to objects (all Java objects are on the heap) are like C pointers, which always manipulate the address, and there is no (bit-wise) object assignment, so objects are explicitly cloned by shallow or deep copying, which eliminates half of the address duality.
     881
     882
     883\subsection{Initialization}
    869884
    870885\Index{Initialization} is different than \Index{assignment} because initialization occurs on the empty (uninitialized) storage on an object, while assignment occurs on possibly initialized storage of an object.
     
    872887Because the object being initialized has no value, there is only one meaningful semantics with respect to address duality: it must mean address as there is no pointed-to value.
    873888In contrast, the left-hand side of assignment has an address that has a duality.
    874 Therefore, for pointer/reference initialization, the initializing value must be an address (\Index{lvalue}) not a value (\Index{rvalue}).
    875 \begin{cfa}
    876 int * p = &x;                           §\C{// must have address of x}§
    877 int & r = x;                            §\C{// must have address of x}§
    878 \end{cfa}
    879 Therefore, it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect.
    880 Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match.
    881 Unfortunately, C allows ©p© to be assigned with ©&x© or ©x©, by value, but most compilers warn about the latter assignment as being potentially incorrect.
    882 (\CFA extends pointer initialization so a variable name is automatically referenced, eliminating the unsafe assignment.)
     889Therefore, for pointer/reference initialization, the initializing value must be an address not a value.
     890\begin{cfa}
     891int * p = &x;                                           §\C{// assign address of x}§
     892®int * p = x;®                                          §\C{// assign value of x}§
     893int & r = x;                                            §\C{// must have address of x}§
     894\end{cfa}
     895Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given).
     896Therefore, for safety, this context requires an address, so it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect.
     897Note, this is strictly a convenience and safety feature for a programmer.
     898Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match due to the implicit dereference.
     899Unfortunately, C allows ©p© to be assigned with ©&x© (address) or ©x© (value), but most compilers warn about the latter assignment as being potentially incorrect.
    883900Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason.
    884901\begin{cfa}
    885 int & f( int & r );                             §\C{// reference parameter and return}§
    886 z = f( x ) + f( y );                    §\C{// reference operator added, temporaries needed for call results}§
     902int & f( int & r );                                     §\C{// reference parameter and return}§
     903z = f( x ) + f( y );                            §\C{// reference operator added, temporaries needed for call results}§
    887904\end{cfa}
    888905Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©.
     
    892909z = temp1 + temp2;
    893910\end{cfa}
    894 This implicit referencing is crucial for reducing the syntactic burden for programmers when using references;
     911This \Index{implicit referencing} is crucial for reducing the syntactic burden for programmers when using references;
    895912otherwise references have the same syntactic  burden as pointers in these contexts.
    896913
     
    899916void f( ®const® int & cr );
    900917void g( ®const® int * cp );
    901 f( 3 );                   g( &3 );
    902 f( x + y );             g( &(x + y) );
     918f( 3 );                   g( ®&®3 );
     919f( x + y );             g( ®&®(x + y) );
    903920\end{cfa}
    904921Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter.
    905 (The ©&© is necessary for the pointer-type parameter to make the types match, and is a common requirement for a C programmer.)
     922The ©&© before the constant/expression for the pointer-type parameter (©g©) is a \CFA extension necessary to type match and is a common requirement before a variable in C (\eg ©scanf©).
     923Importantly, ©&3© may not be equal to ©&3©, where the references occur across calls because the temporaries maybe different on each call.
     924
    906925\CFA \emph{extends} this semantics to a mutable pointer/reference parameter, and the compiler implicitly creates the necessary temporary (copying the argument), which is subsequently pointed-to by the reference parameter and can be changed.\footnote{
    907926If whole program analysis is possible, and shows the parameter is not assigned, \ie it is ©const©, the temporary is unnecessary.}
     
    909928void f( int & r );
    910929void g( int * p );
    911 f( 3 );                   g( &3 );              §\C{// compiler implicit generates temporaries}§
    912 f( x + y );             g( &(x + y) );  §\C{// compiler implicit generates temporaries}§
     930f( 3 );                   g( ®&®3 );            §\C{// compiler implicit generates temporaries}§
     931f( x + y );             g( ®&®(x + y) );        §\C{// compiler implicit generates temporaries}§
    913932\end{cfa}
    914933Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{
     
    917936
    918937%\CFA attempts to handle pointers and references in a uniform, symmetric manner.
    919 However, C handles routine objects in an inconsistent way.
    920 A routine object is both a pointer and a reference (particle and wave).
     938Finally, C handles \Index{routine object}s in an inconsistent way.
     939A routine object is both a pointer and a reference (\Index{particle and wave}).
    921940\begin{cfa}
    922941void f( int i );
    923 void (*fp)( int );
    924 fp = f;                                                 §\C{// reference initialization}§
    925 fp = &f;                                                §\C{// pointer initialization}§
    926 fp = *f;                                                §\C{// reference initialization}§
    927 fp(3);                                                  §\C{// reference invocation}§
    928 (*fp)(3);                                               §\C{// pointer invocation}§
    929 \end{cfa}
    930 A routine object is best described by a ©const© reference:
    931 \begin{cfa}
    932 const void (&fr)( int ) = f;
    933 fr = ...                                                §\C{// error, cannot change code}§
    934 &fr = ...;                                              §\C{// changing routine reference}§
    935 fr( 3 );                                                §\C{// reference call to f}§
    936 (*fr)(3);                                               §\C{// error, incorrect type}§
     942void (*fp)( int );                                      §\C{// routine pointer}§
     943fp = f;                                                         §\C{// reference initialization}§
     944fp = &f;                                                        §\C{// pointer initialization}§
     945fp = *f;                                                        §\C{// reference initialization}§
     946fp(3);                                                          §\C{// reference invocation}§
     947(*fp)(3);                                                       §\C{// pointer invocation}§
     948\end{cfa}
     949While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type.
     950Instead, a routine object should be referenced by a ©const© reference:
     951\begin{cfa}
     952®const® void (®&® fr)( int ) = f;       §\C{// routine reference}§
     953fr = ...                                                        §\C{// error, cannot change code}§
     954&fr = ...;                                                      §\C{// changing routine reference}§
     955fr( 3 );                                                        §\C{// reference call to f}§
     956(*fr)(3);                                                       §\C{// error, incorrect type}§
    937957\end{cfa}
    938958because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{
     
    940960\CFA allows this additional use of references for routine objects in an attempt to give a more consistent meaning for them.
    941961
    942 This situation is different from inferring with reference type being used ...
    943 
     962
     963\subsection{Address-of Semantics}
     964
     965In C, ©&E© is an rvalue for any expression ©E©.
     966\CFA extends the ©&© (address-of) operator as follows:
     967\begin{itemize}
     968\item
     969if ©R© is an \Index{rvalue} of type ©T &$_1$...&$_r$© where $r \ge 1$ references (©&© symbols) than ©&R© has type ©T ®*®&$_{\color{red}2}$...&$_{\color{red}r}$©, \ie ©T© pointer with $r-1$ references (©&© symbols).
     970
     971\item
     972if ©L© is an \Index{lvalue} of type ©T &$_1$...&$_l$© where $l \ge 0$ references (©&© symbols) then ©&L© has type ©T ®*®&$_{\color{red}1}$...&$_{\color{red}l}$©, \ie ©T© pointer with $l$ references (©&© symbols).
     973\end{itemize}
     974The following example shows the first rule applied to different \Index{rvalue} contexts:
     975\begin{cfa}
     976int x, * px, ** ppx, *** pppx, **** ppppx;
     977int & rx = x, && rrx = rx, &&& rrrx = rrx ;
     978x = rrrx;               // rrrx is an lvalue with type int &&& (equivalent to x)
     979px = &rrrx;             // starting from rrrx, &rrrx is an rvalue with type int *&&& (&x)
     980ppx = &&rrrx;   // starting from &rrrx, &&rrrx is an rvalue with type int **&& (&rx)
     981pppx = &&&rrrx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (&rrx)
     982ppppx = &&&&rrrx; // starting from &&&rrrx, &&&&rrrx is an rvalue with type int **** (&rrrx)
     983\end{cfa}
     984The following example shows the second rule applied to different \Index{lvalue} contexts:
     985\begin{cfa}
     986int x, * px, ** ppx, *** pppx;
     987int & rx = x, && rrx = rx, &&& rrrx = rrx ;
     988rrrx = 2;               // rrrx is an lvalue with type int &&& (equivalent to x)
     989&rrrx = px;             // starting from rrrx, &rrrx is an rvalue with type int *&&& (rx)
     990&&rrrx = ppx;   // starting from &rrrx, &&rrrx is an rvalue with type int **&& (rrx)
     991&&&rrrx = pppx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (rrrx)
     992\end{cfa}
     993
     994
     995\subsection{Conversions}
     996
     997C provides a basic implicit conversion to simplify variable usage:
     998\begin{enumerate}
     999\setcounter{enumi}{-1}
     1000\item
     1001lvalue to rvalue conversion: ©cv T© converts to ©T©, which allows implicit variable dereferencing.
     1002\begin{cfa}
     1003int x;
     1004x + 1;                  // lvalue variable (int) converts to rvalue for expression
     1005\end{cfa}
     1006An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped.
     1007\end{enumerate}
     1008\CFA provides three new implicit conversion for reference types to simplify reference usage.
     1009\begin{enumerate}
     1010\item
     1011reference to rvalue conversion: ©cv T &© converts to ©T©, which allows implicit reference dereferencing.
     1012\begin{cfa}
     1013int x, &r = x, f( int p );
     1014x = ®r® + f( ®r® );  // lvalue reference converts to rvalue
     1015\end{cfa}
     1016An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped.
     1017
     1018\item
     1019lvalue to reference conversion: \lstinline[deletekeywords={lvalue}]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references.
     1020\begin{cfa}
     1021int x, &r = ®x®, f( int & p ); // lvalue variable (int) convert to reference (int &)
     1022f( ®x® );               // lvalue variable (int) convert to reference (int &)
     1023\end{cfa}
     1024Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.
     1025Conversion can expand a type, where ©cv1© $>$ ©cv2©, \eg passing a ©const volatile int© to an ©int &©, which has high cost (\Index{warning});
     1026furthermore, if ©cv1© has ©const© but not ©cv2©, a temporary variable is created to preserve the immutable lvalue.
     1027
     1028\item
     1029rvalue to reference conversion: ©T© converts to ©cv T &©, which allows binding references to temporaries.
     1030\begin{cfa}
     1031int x, & f( int & p );
     1032f( ®x + 3® );   // rvalue parameter (int) implicitly converts to lvalue temporary reference (int &)
     1033®&f®(...) = &x; // rvalue result (int &) implicitly converts to lvalue temporary reference (int &)
     1034\end{cfa}
     1035In both case, modifications to the temporary are inaccessible (\Index{warning}).
     1036Conversion expands the temporary-type with ©cv©, which is low cost since the temporary is inaccessible.
     1037\end{enumerate}
    9441038
    9451039
    9461040\begin{comment}
    947 \section{References}
    948 
    949 By introducing references in parameter types, users are given an easy way to pass a value by reference, without the need for NULL pointer checks.
    950 In structures, a reference can replace a pointer to an object that should always have a valid value.
    951 When a structure contains a reference, all of its constructors must initialize the reference and all instances of this structure must initialize it upon definition.
    952 
    953 The syntax for using references in \CFA is the same as \CC with the exception of reference initialization.
    954 Use ©&© to specify a reference, and access references just like regular objects, not like pointers (use dot notation to access fields).
    955 When initializing a reference, \CFA uses a different syntax which differentiates reference initialization from assignment to a reference.
    956 The ©&© is used on both sides of the expression to clarify that the address of the reference is being set to the address of the variable to which it refers.
    957 
    958 
    9591041From: Richard Bilson <rcbilson@gmail.com>
    9601042Date: Wed, 13 Jul 2016 01:58:58 +0000
     
    11181200\section{Routine Definition}
    11191201
    1120 \CFA also supports a new syntax for routine definition, as well as ISO C and K\&R routine syntax.
     1202\CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.
    11211203The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg:
    11221204\begin{cfa}
     
    11381220in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in:
    11391221\begin{cfa}
    1140 [§\,§] g();                                             §\C{// no input or output parameters}§
    1141 [ void ] g( void );                             §\C{// no input or output parameters}§
     1222[§\,§] g();                                                     §\C{// no input or output parameters}§
     1223[ void ] g( void );                                     §\C{// no input or output parameters}§
    11421224\end{cfa}
    11431225
     
    11571239\begin{cfa}
    11581240typedef int foo;
    1159 int f( int (* foo) );                   §\C{// foo is redefined as a parameter name}§
     1241int f( int (* foo) );                           §\C{// foo is redefined as a parameter name}§
    11601242\end{cfa}
    11611243The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo.
     
    11651247C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg:
    11661248\begin{cfa}
    1167 [ int ] f( * int, int * );              §\C{// returns an integer, accepts 2 pointers to integers}§
    1168 [ * int, int * ] f( int );              §\C{// returns 2 pointers to integers, accepts an integer}§
     1249[ int ] f( * int, int * );                      §\C{// returns an integer, accepts 2 pointers to integers}§
     1250[ * int, int * ] f( int );                      §\C{// returns 2 pointers to integers, accepts an integer}§
    11691251\end{cfa}
    11701252The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in:
    11711253\begin{cfa}
    11721254#define ptoa( n, d ) int (*n)[ d ]
    1173 int f( ptoa( p, 5 ) ) ...               §\C{// expands to int f( int (*p)[ 5 ] )}§
    1174 [ int ] f( ptoa( p, 5 ) ) ...   §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§
     1255int f( ptoa( p, 5 ) ) ...                       §\C{// expands to int f( int (*p)[ 5 ] )}§
     1256[ int ] f( ptoa( p, 5 ) ) ...           §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§
    11751257\end{cfa}
    11761258Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms.
     
    11941276        int z;
    11951277        ... x = 0; ... y = z; ...
    1196         ®return;® §\C{// implicitly return x, y}§
     1278        ®return;®                                                       §\C{// implicitly return x, y}§
    11971279}
    11981280\end{cfa}
     
    12041286[ int x, int y ] f() {
    12051287        ...
    1206 } §\C{// implicitly return x, y}§
     1288}                                                                               §\C{// implicitly return x, y}§
    12071289\end{cfa}
    12081290In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered.
     1291
     1292Named return values may be used in conjunction with named parameter values;
     1293specifically, a return and parameter can have the same name.
     1294\begin{cfa}
     1295[ int x, int y ] f( int, x, int y ) {
     1296        ...
     1297}                                                                               §\C{// implicitly return x, y}§
     1298\end{cfa}
     1299This notation allows the compiler to eliminate temporary variables in nested routine calls.
     1300\begin{cfa}
     1301[ int x, int y ] f( int, x, int y );    §\C{// prototype declaration}§
     1302int a, b;
     1303[a, b] = f( f( f( a, b ) ) );
     1304\end{cfa}
     1305While the compiler normally ignores parameters names in prototype declarations, here they are used to eliminate temporary return-values by inferring that the results of each call are the inputs of the next call, and ultimately, the left-hand side of the assignment.
     1306Hence, even without the body of routine ©f© (separate compilation), it is possible to perform a global optimization across routine calls.
     1307The compiler warns about naming inconsistencies between routine prototype and definition in this case, and behaviour is \Index{undefined} if the programmer is inconsistent.
    12091308
    12101309
     
    12141313as well, parameter names are optional, \eg:
    12151314\begin{cfa}
    1216 [ int x ] f ();                                 §\C{// returning int with no parameters}§
    1217 [ * int ] g (int y);                    §\C{// returning pointer to int with int parameter}§
    1218 [ ] h (int,char);                               §\C{// returning no result with int and char parameters}§
    1219 [ * int,int ] j (int);                  §\C{// returning pointer to int and int, with int parameter}§
     1315[ int x ] f ();                                                 §\C{// returning int with no parameters}§
     1316[ * int ] g (int y);                                    §\C{// returning pointer to int with int parameter}§
     1317[ ] h ( int, char );                                    §\C{// returning no result with int and char parameters}§
     1318[ * int, int ] j ( int );                               §\C{// returning pointer to int and int, with int parameter}§
    12201319\end{cfa}
    12211320This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa).
     
    12251324\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    12261325\begin{cfa}
    1227 [ int ] f(int), g;
     1326[ int ] f( int ), g;
    12281327\end{cfa}
    12291328&
    12301329\begin{cfa}
    1231 int f(int), g(int);
     1330int f( int ), g( int );
    12321331\end{cfa}
    12331332\end{tabular}
     
    12351334Declaration qualifiers can only appear at the start of a \CFA routine declaration,\footref{StorageClassSpecifier} \eg:
    12361335\begin{cfa}
    1237 extern [ int ] f (int);
    1238 static [ int ] g (int);
     1336extern [ int ] f ( int );
     1337static [ int ] g ( int );
    12391338\end{cfa}
    12401339
     
    12441343The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg:
    12451344\begin{cfa}
    1246 * [ int x ] () fp;                      §\C{// pointer to routine returning int with no parameters}§
    1247 * [ * int ] (int y) gp;         §\C{// pointer to routine returning pointer to int with int parameter}§
    1248 * [ ] (int,char) hp;            §\C{// pointer to routine returning no result with int and char parameters}§
    1249 * [ * int,int ] (int) jp;       §\C{// pointer to routine returning pointer to int and int, with int parameter}§
     1345* [ int x ] () fp;                                              §\C{// pointer to routine returning int with no parameters}§
     1346* [ * int ] (int y) gp;                                 §\C{// pointer to routine returning pointer to int with int parameter}§
     1347* [ ] (int,char) hp;                                    §\C{// pointer to routine returning no result with int and char parameters}§
     1348* [ * int,int ] ( int ) jp;                             §\C{// pointer to routine returning pointer to int and int, with int parameter}§
    12501349\end{cfa}
    12511350While parameter names are optional, \emph{a routine name cannot be specified};
    12521351for example, the following is incorrect:
    12531352\begin{cfa}
    1254 * [ int x ] f () fp;            §\C{// routine name "f" is not allowed}§
     1353* [ int x ] f () fp;                                    §\C{// routine name "f" is not allowed}§
    12551354\end{cfa}
    12561355
     
    12581357\section{Named and Default Arguments}
    12591358
    1260 Named and default arguments~\cite{Hardgrave76}\footnote{
     1359Named\index{named arguments}\index{arguments!named} and default\index{default arguments}\index{arguments!default} arguments~\cite{Hardgrave76}\footnote{
    12611360Francez~\cite{Francez77} proposed a further extension to the named-parameter passing style, which specifies what type of communication (by value, by reference, by name) the argument is passed to the routine.}
    12621361are two mechanisms to simplify routine call.
     
    14391538        int ;                                   §\C{// disallowed, unnamed field}§
    14401539        int *;                                  §\C{// disallowed, unnamed field}§
    1441         int (*)(int);                   §\C{// disallowed, unnamed field}§
     1540        int (*)( int );                 §\C{// disallowed, unnamed field}§
    14421541};
    14431542\end{cfa}
     
    15621661}
    15631662int main() {
    1564         * [int](int) fp = foo();        §\C{// int (*fp)(int)}§
     1663        * [int]( int ) fp = foo();      §\C{// int (*fp)( int )}§
    15651664        sout | fp( 3 ) | endl;
    15661665}
     
    26832782
    26842783
    2685 \subsection{Constructors and Destructors}
     2784\section{Constructors and Destructors}
    26862785
    26872786\CFA supports C initialization of structures, but it also adds constructors for more advanced initialization.
     
    30143113
    30153114
     3115\begin{comment}
    30163116\section{Generics}
    30173117
     
    32203320        }
    32213321\end{cfa}
     3322\end{comment}
    32223323
    32233324
     
    32793380        Complex *p3 = new(0.5, 1.0); // allocate + 2 param constructor
    32803381}
    3281 
    32823382\end{cfa}
    32833383
     
    32913391
    32923392
     3393\begin{comment}
    32933394\subsection{Unsafe C Constructs}
    32943395
     
    33013402The exact set of unsafe C constructs that will be disallowed in \CFA has not yet been decided, but is sure to include pointer arithmetic, pointer casting, etc.
    33023403Once the full set is decided, the rules will be listed here.
     3404\end{comment}
    33033405
    33043406
    33053407\section{Concurrency}
    3306 
    3307 Today's processors for nearly all use cases, ranging from embedded systems to large cloud computing servers, are composed of multiple cores, often heterogeneous.
    3308 As machines grow in complexity, it becomes more difficult for a program to make the most use of the hardware available.
    3309 \CFA includes built-in concurrency features to enable high performance and improve programmer productivity on these multi-/many-core machines.
    33103408
    33113409Concurrency support in \CFA is implemented on top of a highly efficient runtime system of light-weight, M:N, user level threads.
     
    33143412This enables a very familiar interface to all programmers, even those with no parallel programming experience.
    33153413It also allows the compiler to do static type checking of all communication, a very important safety feature.
    3316 This controlled communication with type safety has some similarities with channels in \Index*{Go}, and can actually implement
    3317 channels exactly, as well as create additional communication patterns that channels cannot.
     3414This controlled communication with type safety has some similarities with channels in \Index*{Go}, and can actually implement channels exactly, as well as create additional communication patterns that channels cannot.
    33183415Mutex objects, monitors, are used to contain mutual exclusion within an object and synchronization across concurrent threads.
    33193416
    3320 Three new keywords are added to support these features:
    3321 
    3322 monitor creates a structure with implicit locking when accessing fields
    3323 
    3324 mutex implies use of a monitor requiring the implicit locking
    3325 
    3326 task creates a type with implicit locking, separate stack, and a thread
     3417\begin{figure}
     3418\begin{cfa}
     3419#include <fstream>
     3420#include <coroutine>
     3421
     3422coroutine Fibonacci {
     3423        int fn;                                                         §\C{// used for communication}§
     3424};
     3425void ?{}( Fibonacci * this ) {
     3426        this->fn = 0;
     3427}
     3428void main( Fibonacci * this ) {
     3429        int fn1, fn2;                                           §\C{// retained between resumes}§
     3430        this->fn = 0;                                           §\C{// case 0}§
     3431        fn1 = this->fn;
     3432        suspend();                                                      §\C{// return to last resume}§
     3433
     3434        this->fn = 1;                                           §\C{// case 1}§
     3435        fn2 = fn1;
     3436        fn1 = this->fn;
     3437        suspend();                                                      §\C{// return to last resume}§
     3438
     3439        for ( ;; ) {                                            §\C{// general case}§
     3440                this->fn = fn1 + fn2;
     3441                fn2 = fn1;
     3442                fn1 = this->fn;
     3443                suspend();                                              §\C{// return to last resume}§
     3444        } // for
     3445}
     3446int next( Fibonacci * this ) {
     3447        resume( this );                                         §\C{// transfer to last suspend}§
     3448        return this->fn;
     3449}
     3450int main() {
     3451        Fibonacci f1, f2;
     3452        for ( int i = 1; i <= 10; i += 1 ) {
     3453                sout | next( &f1 ) | ' ' | next( &f2 ) | endl;
     3454        } // for
     3455}
     3456\end{cfa}
     3457\caption{Fibonacci Coroutine}
     3458\label{f:FibonacciCoroutine}
     3459\end{figure}
     3460
     3461
     3462\subsection{Coroutine}
     3463
     3464\Index{Coroutines} are the precursor to tasks.
     3465\VRef[Figure]{f:FibonacciCoroutine} shows a coroutine that computes the \Index*{Fibonacci} numbers.
    33273466
    33283467
     
    33393478\end{cfa}
    33403479
     3480\begin{figure}
     3481\begin{cfa}
     3482#include <fstream>
     3483#include <kernel>
     3484#include <monitor>
     3485#include <thread>
     3486
     3487monitor global_t {
     3488        int value;
     3489};
     3490
     3491void ?{}(global_t * this) {
     3492        this->value = 0;
     3493}
     3494
     3495static global_t global;
     3496
     3497void increment3( global_t * mutex this ) {
     3498        this->value += 1;
     3499}
     3500void increment2( global_t * mutex this ) {
     3501        increment3( this );
     3502}
     3503void increment( global_t * mutex this ) {
     3504        increment2( this );
     3505}
     3506
     3507thread MyThread {};
     3508
     3509void main( MyThread* this ) {
     3510        for(int i = 0; i < 1_000_000; i++) {
     3511                increment( &global );
     3512        }
     3513}
     3514int main(int argc, char* argv[]) {
     3515        processor p;
     3516        {
     3517                MyThread f[4];
     3518        }
     3519        sout | global.value | endl;
     3520}
     3521\end{cfa}
     3522\caption{Atomic-Counter Monitor}
     3523\caption{f:AtomicCounterMonitor}
     3524\end{figure}
     3525
     3526\begin{comment}
    33413527Since a monitor structure includes an implicit locking mechanism, it does not make sense to copy a monitor;
    33423528it is always passed by reference.
     
    33853571}
    33863572\end{cfa}
     3573\end{comment}
    33873574
    33883575
     
    33923579A task provides mutual exclusion like a monitor, and also has its own execution state and a thread of control.
    33933580Similar to a monitor, a task is defined like a structure:
     3581
     3582\begin{figure}
     3583\begin{cfa}
     3584#include <fstream>
     3585#include <kernel>
     3586#include <stdlib>
     3587#include <thread>
     3588
     3589thread First  { signal_once * lock; };
     3590thread Second { signal_once * lock; };
     3591
     3592void ?{}( First * this, signal_once* lock ) { this->lock = lock; }
     3593void ?{}( Second * this, signal_once* lock ) { this->lock = lock; }
     3594
     3595void main( First * this ) {
     3596        for ( int i = 0; i < 10; i += 1 ) {
     3597                sout | "First : Suspend No." | i + 1 | endl;
     3598                yield();
     3599        }
     3600        signal( this->lock );
     3601}
     3602
     3603void main( Second * this ) {
     3604        wait( this->lock );
     3605        for ( int i = 0; i < 10; i += 1 ) {
     3606                sout | "Second : Suspend No." | i + 1 | endl;
     3607                yield();
     3608        }
     3609}
     3610
     3611int main( void ) {
     3612        signal_once lock;
     3613        sout | "User main begin" | endl;
     3614        {
     3615                processor p;
     3616                {
     3617                        First  f = { &lock };
     3618                        Second s = { &lock };
     3619                }
     3620        }
     3621        sout | "User main end" | endl;
     3622}
     3623\end{cfa}
     3624\caption{Simple Tasks}
     3625\label{f:SimpleTasks}
     3626\end{figure}
     3627
     3628
     3629\begin{comment}
    33943630\begin{cfa}
    33953631type Adder = task {
     
    34453681\end{cfa}
    34463682
    3447 
    34483683\subsection{Cooperative Scheduling}
    34493684
     
    35583793}
    35593794\end{cfa}
    3560 
    3561 
     3795\end{comment}
     3796
     3797
     3798\begin{comment}
    35623799\section{Modules and Packages }
    35633800
    3564 \begin{comment}
    35653801High-level encapsulation is useful for organizing code into reusable units, and accelerating compilation speed.
    35663802\CFA provides a convenient mechanism for creating, building and sharing groups of functionality that enhances productivity and improves compile time.
     
    42264462
    42274463
     4464\begin{comment}
    42284465\subsection[Comparing Key Features of CFA]{Comparing Key Features of \CFA}
    42294466
     
    46034840
    46044841
    4605 \begin{comment}
    46064842\subsubsection{Modules / Packages}
    46074843
     
    46834919}
    46844920\end{cfa}
    4685 \end{comment}
    46864921
    46874922
     
    48445079
    48455080\subsection{Summary of Language Comparison}
    4846 
    4847 
    4848 \subsubsection[C++]{\CC}
     5081\end{comment}
     5082
     5083
     5084\subsection[C++]{\CC}
    48495085
    48505086\Index*[C++]{\CC{}} is a general-purpose programming language.
     
    48675103
    48685104
    4869 \subsubsection{Go}
     5105\subsection{Go}
    48705106
    48715107\Index*{Go}, also commonly referred to as golang, is a programming language developed at Google in 2007 [.].
     
    48835119
    48845120
    4885 \subsubsection{Rust}
     5121\subsection{Rust}
    48865122
    48875123\Index*{Rust} is a general-purpose, multi-paradigm, compiled programming language developed by Mozilla Research.
     
    48975133
    48985134
    4899 \subsubsection{D}
     5135\subsection{D}
    49005136
    49015137The \Index*{D} programming language is an object-oriented, imperative, multi-paradigm system programming
     
    50095245\item[Rationale:] keywords added to implement new semantics of \CFA.
    50105246\item[Effect on original feature:] change to semantics of well-defined feature. \\
    5011 Any ISO C programs using these keywords as identifiers are invalid \CFA programs.
     5247Any \Celeven programs using these keywords as identifiers are invalid \CFA programs.
    50125248\item[Difficulty of converting:] keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism (see~\VRef{s:BackquoteIdentifiers}).
    50135249\item[How widely used:] clashes among new \CFA keywords and existing identifiers are rare.
     
    52295465hence, names in these include files are not mangled\index{mangling!name} (see~\VRef{s:Interoperability}).
    52305466All other C header files must be explicitly wrapped in ©extern "C"© to prevent name mangling.
     5467For \Index*[C++]{\CC{}}, the name-mangling issue is handled implicitly because most C header-files are augmented with checks for preprocessor variable ©__cplusplus©, which adds appropriate ©extern "C"© qualifiers.
    52315468
    52325469
     
    53115548}
    53125549
    5313 // §\CFA§ safe initialization/copy
     5550// §\CFA§ safe initialization/copy, i.e., implicit size specification
    53145551forall( dtype T | sized(T) ) T * memset( T * dest, char c );§\indexc{memset}§
    53155552forall( dtype T | sized(T) ) T * memcpy( T * dest, const T * src );§\indexc{memcpy}§
     
    54215658\leavevmode
    54225659\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    5423 forall( otype T | { int ?<?( T, T ); } )
    5424 T min( T t1, T t2 );§\indexc{min}§
    5425 
    5426 forall( otype T | { int ?>?( T, T ); } )
    5427 T max( T t1, T t2 );§\indexc{max}§
    5428 
    5429 forall( otype T | { T min( T, T ); T max( T, T ); } )
    5430 T clamp( T value, T min_val, T max_val );§\indexc{clamp}§
    5431 
    5432 forall( otype T )
    5433 void swap( T * t1, T * t2 );§\indexc{swap}§
     5660forall( otype T | { int ?<?( T, T ); } ) T min( T t1, T t2 );§\indexc{min}§
     5661forall( otype T | { int ?>?( T, T ); } ) T max( T t1, T t2 );§\indexc{max}§
     5662forall( otype T | { T min( T, T ); T max( T, T ); } ) T clamp( T value, T min_val, T max_val );§\indexc{clamp}§
     5663forall( otype T ) void swap( T * t1, T * t2 );§\indexc{swap}§
    54345664\end{cfa}
    54355665
  • doc/working/exception/design.txt

    re4d829b r579263a  
    11Design of Exceptions and EHM in Cforall:
    22
    3 Currently this is a combination of ideas and big questions that still have to
    4 be addressed. It also includes some other error handling options, how they
    5 interact and compare to exceptions.
     3
     4Exception Instances:
     5Currently, exceptions are integers (like errno).
     6
     7They are planned to be the new "tagged structures", which allows them to
     8exist in a simple hierarchy which shared functionality throughout. However
     9the tagged structures are not yet implemented so that will wait.
     10
     11A single built in exception is at the top of the hierarchy and all other
     12exceptions are its children. When you match against an exception, you match
     13for an exception and its children, so the top of the hierarchy is used as a
     14catch-all option.
     15
     16The shared functionality across exceptions has not been finalized, but will
     17probably include things like human readable descriptions and default handlers.
    618
    719
    8 What is an Exception:
     20Throwing:
     21There are currently two kinds of throws, "throw" for termination and
     22"throwResume" for resumption. Both keywords can be used to create a throw
     23statement. The kind of throw decides what handlers may catch the exception
     24and weither control flow can return to the throw site.
    925
    10 In other words what do we throw? What is matched against, how does it carry
    11 data with it? A very important question that has not been answered.
     26Syntax
     27"throw" exception ";"
     28"throwResume" exception ";"
    1229
    13 Option 1: Strutures
     30Non-local throws are allowed for resumption only. A target is an object with
     31a stack, with which it may propagate and handle the exception.
    1432
    15 Considering the current state of Cforall the most natural form of the
    16 exception would likely be a struture, implementing a trait repersenting the
    17 minimum features of an exception. This has many advantages, including arbitray
    18 fields, some polymorphism and it matches exceptations of many current systems.
     33Syntax
     34"throwResume" exception "_At" target ";"
    1935
    20 The main issue with this is matching, without OOP inheritance there is no
    21 exception hierarchy. Meaning all handling has to happen on the exact exception
    22 without the ease of grouping parents. There are several ways to attempt to
    23 recover this.
    24 
    25 The first is with conditional matching (a check after the type has been
    26 matched) which allows for matching particular values of a known type. However
    27 this does not dynamically expand and requires an extra step (as opposed to
    28 mearly allowing one). I would not recomend this as the primary method.
    29 
    30 Second is to try and use type casts/conversions to create an implicate
    31 hierachy, so that a catch clause catches anything of the given type or
    32 anything that converts to the given type.
    33 
    34 Plan9 (from what I know of it) would be a powerful tool here. Even with it,
    35 creating a hierarchy of types at runtime might be too expencive. Esecially
    36 since they are less likely to be tree like at that point.
    37 
    38 Option 2: Tags
    39 
    40 The other option is to introduce a new construct into the language. A tag
    41 repersents a type of exception, it is not a structure or variable (or even
    42 a normal type). It may be usable in some of those contexts.
    43 
    44 Tags can declare an existing tag as its parent. Tags can be caught by handlers
    45 that catch their parents. (There is a single base_exception that all other
    46 exceptions are children of eventually.) This allows for grouping of exceptions
    47 that repersent similar errors.
    48 
    49 Tags should also have some assotiated data, where and on what did the error
    50 occur. Keeping with the otherness of exception tags and allowing them to be
    51 expanded, using a parameter list. Each exception can have a list of paramters
    52 given to it on a throw. Each tag would have a declared list of parameters
    53 (which could be treated more like a set of fields as well). Child tags must
    54 use their parent's list as a prefix to their own, so that the parameters can
    55 be accessed when the child tag is matched against the parent.
    56 
    57 Option N: ...
    58 
    59 This list is not complete.
     36Termination throws unwind the stack until a handler is reached, control moves
     37onwards from the end of the handler. Resumption throws do not unwind, if a
     38handler is found and control will return to the throw after the exception is
     39handled.
    6040
    6141
    62 Seperating Termination and Resumption:
     42Catching:
     43The catch and handle of an exception is preformed with a try statement, which
     44also can have finally clauses to exceute on exit from the scope.
    6345
    64 Differentating the types of exceptions based on exception would be hard with
    65 exceptions as structures. It is possible with exceptions as tags by having
    66 two base exceptions, one for each type of throw. However recompining them
    67 to dual types would be harder.
     46Syntax
     47"try"
     48        try-block
     49( ("catch" | "catchResume")
     50  "(" exception_type [identifier] [";" conditional_expression] ")"
     51        catch-block
     52)*
     53("finally"
     54        finally-block
     55)?
    6856
    69 Reguardless, using different keywords would also be useful for clarity, even
    70 if it does not add functality. Using the C++ like keywords would be a good
    71 base. Resumption exceptions could use a different set (ex. raise->handle) or
    72 use resume as a qualifier on the existing statements.
     57Either at least 1 handler clause or the finally clasue must be given on each
     58try block. Each handler clause handles 1 of the two types of throws. Each
     59handler also specifies a type of exception it handles, and will handle all
     60children exceptions as well. In addition, a conditional expression which, if
     61included, must be true for the handler to catch the exception.
     62
     63The two types of handlers may be intermixed. Multiple handlers catching the
     64same type may also be used, to allow for fallbacks on false conditionals.
    7365
    7466
    75 Conditional Matching:
     67Implementation Overview:
    7668
    77 A possible useful feature, it allows for arbitrary checks on a catch block
    78 instead of merely matching a type. However there are few use cases that
    79 cannot be avoided with proper use of a type hierarchy, and this shrinks even
    80 further with a good use of re-throws.
     69The implementation has two main parts. The first is just a collection of the
     70support definitions we need, the data types and functions used within the
     71exception handling code. Second is a translation from Cforall code to C code
     72that uses those definitions to throw, catch and handle exceptions.
    8173
    82 Also it assumes one sweep, that might also be a problem. But might also give
    83 it an advantage over re-throws.
     74Termination handlers call a specially annotated function, passing it inner
     75functions that act as the varius sub-blocks. Termination throws use the
     76unwind library that checks the underlying code for those annotations. Each
     77time one is found some magic is used to check for a matching handler, if one
     78is found control goes to the special function which excecutes the handler and
     79returns.
     80
     81Resumption handlers maintain a linked list of stack allocated nodes that have
     82the handler functions attached. Throwing a resumption exception traverses this
     83list, and calls each handler, the handlers handle the exception if they can
     84and return if they did or not.
     85
     86Finally clauses just use stack cleanup to force a nested function, which has
     87the code from the finally clause, to execute when we leave that section.
    8488
    8589
    86 Alternatives: Implicate Handlers & Return Unions
     90Alternative Error Handling: Return Unions
    8791
    88 Both act as a kind of local version of an exception. Implicate handlers act as
    89 resumption exceptions and return unions like termination exceptions. By local
    90 I mean they work well at one or two levels of calls, but do not cover N levels
    91 as cleanly.
     92Return unions (Maybe and Result), are types that can encode a success or
     93other result in a single value. Maybe stores a value or nothing, Result stores
     94a value or an error.
    9295
    93 Implicate handles require a growing number of function pointers (which should
    94 not be used very often) to be passed to functions, creating and additional
    95 preformance cost. Return unions have to be checked and handled at every level,
    96 which has some preformance cost, but also can significantly clutter code.
    97 Proper tools can help with the latter.
     96For errors that are usually handled quite close to where they occur, these
     97can replace exceptions.
    9898
    99 However, they may work better at that local level as they do not require stack
    100 walking or unwinding. In addition they are closer to regular control flow and
    101 are easier to staticly check. So even if they can't replace exceptions
    102 (directly) they may still be worth using together.
    103 
    104 For instance, consider the Python iterator interface. It uses a single
    105 function, __next__, to access the next value and to signal the end of the
    106 sequence. If a value is returned, it is the next value, if the StopIteration
    107 exception is thrown the sequence has finished.
    108 
    109 However almost every use of an iterator will add a try-except block around the
    110 call site (possibly through for or next) to catch and handle the exception
    111 immediately, ignoring the advantages of more distant exception handling.
    112 
    113 In this case it may be cleaner to use a Maybe for both cases (as in Rust)
    114 which gives similar results without having to jump to the exception handler.
    115 This will likely handle the error case more efficiently and the success case a
    116 bit less so.
    117 
    118 It also mixes the error and regular control flow, which can hurt readablity,
    119 but very little if the handling is simple, for instance providing a default
    120 value. Similarly, if the error (or alternate outcome) is common enough
    121 encoding it in the function signature may be good commuication.
     99They tend to be faster and require similar or less amounts of code to handle.
     100However they can slow down the normal path with some extra conditionals and
     101can mix the normal and exceptional control flow path. If handling the error
     102is simple, and happens relatively frequently, this might be prefered but in
     103other cases it just hurts speed and readability.
    122104
    123105In short, these errors seem to be more effective when errors are likely and
     
    125107be handled locally, might be better off using these instead of exceptions.
    126108
    127 Also the implicate handlers and return unions could use exceptions as well.
    128 For instance, a useful default might handler might be to throw an exception,
    129 seaching up the stack for a solution if one is not locally provided.
    130 
    131 Or here is a possible helper for unpacking a Result value:
     109Also the return unions could use exceptions as well. Getting the improper
     110side of a return union might throw an exception. Or we can provide helpers
     111for results withe exceptions as in:
    132112                forall(otype T, otype E | exception(E))
    133113                T get_or_throw (Result(T, E) * this) {
    134                         if (is_success(this)) {
    135                                 return get_success(this);
     114                        if (has_value(this)) {
     115                                return get_value(this);
    136116                        } else {
    137                                 throw get_failure(this);
     117                                throw get_error(this);
    138118                        }
    139119                }
    140 So they can feed off of each other.
  • src/CodeGen/CodeGenerator.cc

    re4d829b r579263a  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed May 10 14:45:00 2017
    13 // Update Count     : 484
     12// Last Modified On : Thu Jun  8 16:00:00 2017
     13// Update Count     : 485
    1414//
    1515
     
    112112
    113113        CodeGenerator::CodeGenerator( std::ostream & os, bool pretty, bool genC, bool lineMarks ) : indent( *this), cur_indent( 0 ), insideFunction( false ), output( os ), printLabels( *this ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ) {}
    114 
    115         CodeGenerator::CodeGenerator( std::ostream & os, std::string init, int indentation, bool infunp )
    116                         : indent( *this), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) {
    117                 //output << std::string( init );
    118         }
    119 
    120         CodeGenerator::CodeGenerator( std::ostream & os, char * init, int indentation, bool infunp )
    121                         : indent( *this ), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) {
    122                 //output << std::string( init );
    123         }
    124114
    125115        string CodeGenerator::mangleName( DeclarationWithType * decl ) {
     
    932922        }
    933923
     924        void CodeGenerator::visit( ThrowStmt * throwStmt ) {
     925                assertf( ! genC, "Throw statements should not reach code generation." );
     926
     927                output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
     928                           "throw" : "throwResume");
     929                if (throwStmt->get_expr()) {
     930                        output << " ";
     931                        throwStmt->get_expr()->accept( *this );
     932                }
     933                if (throwStmt->get_target()) {
     934                        output << " _At ";
     935                        throwStmt->get_target()->accept( *this );
     936                }
     937                output << ";";
     938        }
     939
    934940        void CodeGenerator::visit( WhileStmt * whileStmt ) {
    935941                if ( whileStmt->get_isDoWhile() ) {
  • src/CodeGen/CodeGenerator.h

    re4d829b r579263a  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed May 10 10:57:00 2017
    13 // Update Count     : 51
     12// Last Modified On : Thu Jun  8 15:48:00 2017
     13// Update Count     : 52
    1414//
    1515
     
    9292                virtual void visit( BranchStmt * );
    9393                virtual void visit( ReturnStmt * );
     94                virtual void visit( ThrowStmt * );
    9495                virtual void visit( WhileStmt * );
    9596                virtual void visit( ForStmt * );
  • src/CodeGen/FixNames.cc

    re4d829b r579263a  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 16 07:50:30 2017
    13 // Update Count     : 16
     12// Last Modified On : Wed Jun 21 14:22:59 2017
     13// Update Count     : 19
    1414//
    1515
     
    114114                                throw SemanticError("Main expected to have 0, 2 or 3 arguments\n", functionDecl);
    115115                        }
    116                         functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::SignedInt ), "0") ) ) );
     116                        functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new ConstantExpr( Constant::from_int( 0 ) ) ) );
    117117                        CodeGen::FixMain::registerMain( functionDecl );
    118118                }
  • src/Common/PassVisitor.h

    re4d829b r579263a  
    1212#include "SynTree/Expression.h"
    1313#include "SynTree/Constant.h"
     14#include "SynTree/TypeSubstitution.h"
    1415
    1516#include "PassVisitor.proto.h"
     
    1819// Templated visitor type
    1920// To use declare a PassVisitor< YOUR VISITOR TYPE >
    20 // The visitor type should specify the previsit/postvisit for types that are desired.
     21// The visitor type should specify the previsit/postvisit/premutate/postmutate for types that are desired.
     22// Note: previsit/postvisit/premutate/postmutate must be **public** members
     23//
     24// Several additional features are available through inheritance
     25// | WithTypeSubstitution - provides polymorphic TypeSubstitution * env for the current expression
     26// | WithStmtsToAdd       - provides the ability to insert statements before or after the current statement by adding new statements into
     27//                          stmtsToAddBefore or stmtsToAddAfter respectively.
     28// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children to false in pre{visit,mutate} to skip visiting children
     29// | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save, call GuardValue with the variable to save, the variable
     30//                          will automatically be restored to its previous value after the corresponding postvisit/postmutate teminates.
    2131//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    2232template< typename pass_type >
    2333class PassVisitor final : public Visitor, public Mutator {
    2434public:
    25         PassVisitor() = default;
    2635
    2736        template< typename... Args >
    2837        PassVisitor(Args &&... args)
    2938                : pass( std::forward<Args>( args )... )
    30         {}
     39        {
     40                typedef PassVisitor<pass_type> this_t;
     41                this_t * const * visitor = visitor_impl(pass, 0);
     42                if(visitor) {
     43                        *const_cast<this_t **>( visitor ) = this;
     44                }
     45        }
    3146
    3247        virtual ~PassVisitor() = default;
     
    5469        virtual void visit( BranchStmt *branchStmt ) override final;
    5570        virtual void visit( ReturnStmt *returnStmt ) override final;
     71        virtual void visit( ThrowStmt *throwStmt ) override final;
    5672        virtual void visit( TryStmt *tryStmt ) override final;
    5773        virtual void visit( CatchStmt *catchStmt ) override final;
     
    85101        virtual void visit( ConstructorExpr * ctorExpr ) override final;
    86102        virtual void visit( CompoundLiteralExpr *compLitExpr ) override final;
    87         virtual void visit( UntypedValofExpr *valofExpr ) override final;
    88103        virtual void visit( RangeExpr *rangeExpr ) override final;
    89104        virtual void visit( UntypedTupleExpr *tupleExpr ) override final;
    90105        virtual void visit( TupleExpr *tupleExpr ) override final;
    91106        virtual void visit( TupleIndexExpr *tupleExpr ) override final;
    92         virtual void visit( MemberTupleExpr *tupleExpr ) override final;
    93107        virtual void visit( TupleAssignExpr *assignExpr ) override final;
    94108        virtual void visit( StmtExpr * stmtExpr ) override final;
     
    140154        virtual Statement* mutate( BranchStmt *branchStmt ) override final;
    141155        virtual Statement* mutate( ReturnStmt *returnStmt ) override final;
     156        virtual Statement* mutate( ThrowStmt *throwStmt ) override final;
    142157        virtual Statement* mutate( TryStmt *returnStmt ) override final;
    143158        virtual Statement* mutate( CatchStmt *catchStmt ) override final;
     
    171186        virtual Expression* mutate( ConstructorExpr *ctorExpr ) override final;
    172187        virtual Expression* mutate( CompoundLiteralExpr *compLitExpr ) override final;
    173         virtual Expression* mutate( UntypedValofExpr *valofExpr ) override final;
    174188        virtual Expression* mutate( RangeExpr *rangeExpr ) override final;
    175189        virtual Expression* mutate( UntypedTupleExpr *tupleExpr ) override final;
    176190        virtual Expression* mutate( TupleExpr *tupleExpr ) override final;
    177191        virtual Expression* mutate( TupleIndexExpr *tupleExpr ) override final;
    178         virtual Expression* mutate( MemberTupleExpr *tupleExpr ) override final;
    179192        virtual Expression* mutate( TupleAssignExpr *assignExpr ) override final;
    180193        virtual Expression* mutate( StmtExpr * stmtExpr ) override final;
     
    207220
    208221private:
     222        template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor );
     223        template<typename pass_t> friend void mutateAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor );
     224
    209225        template<typename node_type> void call_previsit ( node_type * node ) { previsit_impl ( pass, node, 0 ); }
    210226        template<typename node_type> void call_postvisit( node_type * node ) { postvisit_impl( pass, node, 0 ); }
     
    218234        void set_env( TypeSubstitution * env ) { set_env_impl( pass, env, 0); }
    219235
    220         void visitStatementList( std::list< Statement* > &statements );
     236        template< typename func_t >
     237        void handleStatementList( std::list< Statement * > & statements, func_t func );
     238        void visitStatementList ( std::list< Statement* > &statements );
    221239        void mutateStatementList( std::list< Statement* > &statements );
    222240
    223         Statement * visitStatement( Statement * stmt );
     241        template< typename func_t >
     242        Statement * handleStatement( Statement * stmt, func_t func );
     243        Statement * visitStatement ( Statement * stmt );
    224244        Statement * mutateStatement( Statement * stmt );
    225245
    226         void visitExpression( Expression * expr );
     246        template< typename func_t >
     247        Expression * handleExpression( Expression * expr, func_t func );
     248        Expression * visitExpression ( Expression * expr );
    227249        Expression * mutateExpression( Expression * expr );
    228250
     
    231253        std::list< Statement* > *       get_beforeStmts() { return stmtsToAddBefore_impl( pass, 0); }
    232254        std::list< Statement* > *       get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); }
    233         bool visit_children() { bool* skip = skip_children_impl(pass, 0); return ! (skip && *skip); }
     255        std::list< Declaration* > *     get_beforeDecls() { return declsToAddBefore_impl( pass, 0); }
     256        std::list< Declaration* > *     get_afterDecls () { return declsToAddAfter_impl ( pass, 0); }
     257
     258        void set_visit_children( bool& ref ) { bool_ref * ptr = visit_children_impl(pass, 0); if(ptr) ptr->set( ref ); }
     259
     260        guard_value_impl init_guard() {
     261                guard_value_impl guard;
     262                auto at_cleanup = at_cleanup_impl(pass, 0);
     263                if( at_cleanup ) {
     264                        *at_cleanup = [&guard]( cleanup_func_t && func, void* val ) {
     265                                guard.push( std::move( func ), val );
     266                        };
     267                }
     268                return guard;
     269        }
     270};
     271
     272template<typename pass_type, typename T>
     273void GuardValue( pass_type * pass, T& val ) {
     274        pass->at_cleanup( [ val ]( void * newVal ) {
     275                * static_cast< T * >( newVal ) = val;
     276        }, static_cast< void * >( & val ) );
     277}
     278
     279class WithTypeSubstitution {
     280protected:
     281        WithTypeSubstitution() = default;
     282        ~WithTypeSubstitution() = default;
     283
     284public:
     285        TypeSubstitution * env = nullptr;
     286};
     287
     288class WithStmtsToAdd {
     289protected:
     290        WithStmtsToAdd() = default;
     291        ~WithStmtsToAdd() = default;
     292
     293public:
     294        std::list< Statement* > stmtsToAddBefore;
     295        std::list< Statement* > stmtsToAddAfter;
     296};
     297
     298class WithDeclsToAdd {
     299protected:
     300        WithDeclsToAdd() = default;
     301        ~WithDeclsToAdd() = default;
     302
     303public:
     304        std::list< Declaration* > declsToAddBefore;
     305        std::list< Declaration* > declsToAddAfter;
     306};
     307
     308class WithShortCircuiting {
     309protected:
     310        WithShortCircuiting() = default;
     311        ~WithShortCircuiting() = default;
     312
     313public:
     314        bool_ref visit_children;
     315};
     316
     317class WithGuards {
     318protected:
     319        WithGuards() = default;
     320        ~WithGuards() = default;
     321
     322public:
     323        at_cleanup_t at_cleanup;
     324
     325        template< typename T >
     326        void GuardValue( T& val ) {
     327                at_cleanup( [ val ]( void * newVal ) {
     328                        * static_cast< T * >( newVal ) = val;
     329                }, static_cast< void * >( & val ) );
     330        }
     331
     332        template< typename T >
     333        void GuardScope( T& val ) {
     334                val.beginScope();
     335                at_cleanup( []( void * val ) {
     336                        static_cast< T * >( val )->endScope();
     337                }, static_cast< void * >( & val ) );
     338        }
     339
     340        template< typename Func >
     341        void GuardAction( Func func ) {
     342                at_cleanup( [func](__attribute__((unused)) void *) { func(); }, nullptr );
     343        }
     344};
     345
     346template<typename pass_type>
     347class WithVisitorRef {
     348protected:
     349        WithVisitorRef() {}
     350        ~WithVisitorRef() {}
     351
     352public:
     353        PassVisitor<pass_type> * const visitor = nullptr;
    234354};
    235355
  • src/Common/PassVisitor.impl.h

    re4d829b r579263a  
    11#pragma once
    22
    3 #define VISIT_START( node )  \
    4         call_previsit( node ); \
    5         if( visit_children() ) { \
    6 
    7 #define VISIT_END( node )            \
    8         }                              \
    9         return call_postvisit( node ); \
    10 
    11 #define MUTATE_START( node )  \
    12         call_premutate( node ); \
    13         if( visit_children() ) { \
     3#define VISIT_START( node )                     \
     4        __attribute__((unused))                   \
     5        const auto & guard = init_guard();        \
     6        bool visit_children = true;               \
     7        set_visit_children( visit_children );   \
     8        call_previsit( node );                    \
     9        if( visit_children ) {                    \
     10
     11#define VISIT_END( node )                       \
     12        }                                         \
     13        call_postvisit( node );                   \
     14
     15#define MUTATE_START( node )                    \
     16        __attribute__((unused))                   \
     17        const auto & guard = init_guard();        \
     18        bool visit_children = true;               \
     19        set_visit_children( visit_children );   \
     20        call_premutate( node );                   \
     21        if( visit_children ) {                    \
    1422
    1523#define MUTATE_END( type, node )                \
     
    1826
    1927
    20 #define VISIT_BODY( node )    \
    21         VISIT_START( node );  \
    22         Visitor::visit( node ); \
    23         VISIT_END( node ); \
     28#define VISIT_BODY( node )        \
     29        VISIT_START( node );        \
     30        Visitor::visit( node );     \
     31        VISIT_END( node );          \
    2432
    2533
     
    3644}
    3745
    38 typedef std::list< Statement * > StmtList_t;
    39 
    40 template< typename pass_type >
    41 void PassVisitor< pass_type >::visitStatementList( std::list< Statement * > & statements ) {
     46typedef std::list< Statement   * > StmtList_t;
     47typedef std::list< Declaration * > DeclList_t;
     48
     49template<typename iterator_t>
     50static inline void splice( iterator_t it, DeclList_t * decls ) {
     51        std::transform(
     52                decls->begin(),
     53                decls->end(),
     54                it,
     55                [](Declaration * decl) -> auto {
     56                        return new DeclStmt( noLabels, decl );
     57                }
     58        );
     59        decls->clear();
     60}
     61
     62template< typename pass_type >
     63static inline void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_type >& visitor ) {
     64
     65        DeclList_t* beforeDecls = visitor.get_beforeDecls();
     66        DeclList_t* afterDecls  = visitor.get_afterDecls();
     67
     68        for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
     69                // splice in new declarations after previous decl
     70                if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); }
     71
     72                if ( i == decls.end() ) break;
     73
     74                // run mutator on declaration
     75                maybeAccept( *i, visitor );
     76
     77                // splice in new declarations before current decl
     78                if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
     79        }
     80}
     81
     82template< typename pass_type >
     83static inline void mutateAll( std::list< Declaration* > &decls, PassVisitor< pass_type >& mutator ) {
     84
     85        DeclList_t* beforeDecls = mutator.get_beforeDecls();
     86        DeclList_t* afterDecls  = mutator.get_afterDecls();
     87
     88        for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
     89                // splice in new declarations after previous decl
     90                if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); }
     91
     92                if ( i == decls.end() ) break;
     93
     94                // run mutator on declaration
     95                *i = maybeMutate( *i, mutator );
     96
     97                // splice in new declarations before current decl
     98                if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
     99        }
     100}
     101
     102template< typename pass_type >
     103template< typename func_t >
     104void PassVisitor< pass_type >::handleStatementList( std::list< Statement * > & statements, func_t func ) {
    42105        SemanticError errors;
     106
     107        // don't want statements from outer CompoundStmts to be added to this CompoundStmt
     108        ValueGuardPtr< StmtList_t > oldBeforeStmts( get_beforeStmts() );
     109        ValueGuardPtr< StmtList_t > oldAfterStmts ( get_afterStmts () );
     110        ValueGuardPtr< DeclList_t > oldBeforeDecls( get_beforeDecls() );
     111        ValueGuardPtr< DeclList_t > oldAfterDecls ( get_afterDecls () );
    43112
    44113        StmtList_t* beforeStmts = get_beforeStmts();
    45114        StmtList_t* afterStmts  = get_afterStmts();
     115        DeclList_t* beforeDecls = get_beforeDecls();
     116        DeclList_t* afterDecls  = get_afterDecls();
    46117
    47118        for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
     119
     120                if ( !empty( afterDecls ) ) { splice( std::inserter( statements, i ), afterDecls ); }
    48121                if ( !empty( afterStmts ) ) { statements.splice( i, *afterStmts ); }
     122
    49123                try {
    50                         (*i)->accept( *this );
     124                        func( *i );
     125                        assert(( empty( beforeStmts ) && empty( afterStmts ))
     126                            || ( empty( beforeDecls ) && empty( afterDecls )) );
     127
    51128                } catch ( SemanticError &e ) {
    52129                        errors.append( e );
    53130                }
     131
     132                if ( !empty( beforeDecls ) ) { splice( std::inserter( statements, i ), beforeDecls ); }
    54133                if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); }
    55134        }
    56135
     136        if ( !empty( afterDecls ) ) { splice( std::back_inserter( statements ), afterDecls); }
    57137        if ( !empty( afterStmts ) ) { statements.splice( statements.end(), *afterStmts ); }
    58138        if ( !errors.isEmpty() ) { throw errors; }
     
    60140
    61141template< typename pass_type >
     142void PassVisitor< pass_type >::visitStatementList( std::list< Statement * > & statements ) {
     143        handleStatementList( statements, [this]( Statement * stmt) {
     144                stmt->accept( *this );
     145        });
     146}
     147
     148template< typename pass_type >
    62149void PassVisitor< pass_type >::mutateStatementList( std::list< Statement * > & statements ) {
    63         SemanticError errors;
     150        handleStatementList( statements, [this]( Statement *& stmt) {
     151                stmt = stmt->acceptMutator( *this );
     152        });
     153}
     154
     155
     156template< typename pass_type >
     157template< typename func_t >
     158Statement * PassVisitor< pass_type >::handleStatement( Statement * stmt, func_t func ) {
     159        // don't want statements from outer CompoundStmts to be added to this CompoundStmt
     160        ValueGuardPtr< TypeSubstitution * >  oldEnv        ( get_env_ptr    () );
     161        ValueGuardPtr< DeclList_t >          oldBeforeDecls( get_beforeDecls() );
     162        ValueGuardPtr< DeclList_t >          oldAfterDecls ( get_afterDecls () );
     163        ValueGuardPtr< StmtList_t >          oldBeforeStmts( get_beforeStmts() );
     164        ValueGuardPtr< StmtList_t >          oldAfterStmts ( get_afterStmts () );
     165
     166        Statement *newStmt = func( stmt );
    64167
    65168        StmtList_t* beforeStmts = get_beforeStmts();
    66169        StmtList_t* afterStmts  = get_afterStmts();
    67 
    68         for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
    69                 if ( !empty( afterStmts ) ) { statements.splice( i, *afterStmts ); }
    70                 try {
    71                         *i = (*i)->acceptMutator( *this );
    72                 } catch ( SemanticError &e ) {
    73                         errors.append( e );
    74                 }
    75                 if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); }
    76         }
    77 
    78         if ( !empty( afterStmts ) ) { statements.splice( statements.end(), *afterStmts ); }
    79         if ( !errors.isEmpty() ) { throw errors; }
    80 }
    81 
    82 template< typename pass_type >
    83 Statement * PassVisitor< pass_type >::visitStatement( Statement * stmt ) {
    84         // don't want statements from outer CompoundStmts to be added to this CompoundStmt
    85         ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
    86         ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
    87         ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
    88 
    89         maybeAccept( stmt, *this );
    90 
    91         StmtList_t* beforeStmts = get_beforeStmts();
    92         StmtList_t* afterStmts  = get_afterStmts();
    93 
    94         if( empty(beforeStmts) && empty(afterStmts) ) { return stmt; }
     170        DeclList_t* beforeDecls = get_beforeDecls();
     171        DeclList_t* afterDecls  = get_afterDecls();
     172
     173        if( empty(beforeStmts) && empty(afterStmts) && empty(beforeDecls) && empty(afterDecls) ) { return newStmt; }
     174        assert(( empty( beforeStmts ) && empty( afterStmts ))
     175            || ( empty( beforeDecls ) && empty( afterDecls )) );
    95176
    96177        CompoundStmt *compound = new CompoundStmt( noLabels );
     178        if( !empty(beforeDecls) ) { splice( std::back_inserter( compound->get_kids() ), beforeDecls ); }
    97179        if( !empty(beforeStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *beforeStmts ); }
    98         compound->get_kids().push_back( stmt );
     180        compound->get_kids().push_back( newStmt );
     181        if( !empty(afterDecls) ) { splice( std::back_inserter( compound->get_kids() ), afterDecls ); }
    99182        if( !empty(afterStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *afterStmts ); }
    100183        return compound;
     
    102185
    103186template< typename pass_type >
     187Statement * PassVisitor< pass_type >::visitStatement( Statement * stmt ) {
     188        return handleStatement( stmt, [this]( Statement * stmt ) {
     189                maybeAccept( stmt, *this );
     190                return stmt;
     191        });
     192}
     193
     194template< typename pass_type >
    104195Statement * PassVisitor< pass_type >::mutateStatement( Statement * stmt ) {
    105         // don't want statements from outer CompoundStmts to be added to this CompoundStmt
    106         ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
    107         ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
    108         ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
    109 
    110         Statement *newStmt = maybeMutate( stmt, *this );
    111 
    112         StmtList_t* beforeStmts = get_beforeStmts();
    113         StmtList_t* afterStmts  = get_afterStmts();
    114 
    115         if( empty(beforeStmts) && empty(afterStmts) ) { return newStmt; }
    116 
    117         CompoundStmt *compound = new CompoundStmt( noLabels );
    118         if( !empty(beforeStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *beforeStmts ); }
    119         compound->get_kids().push_back( newStmt );
    120         if( !empty(afterStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *afterStmts ); }
    121         return compound;
    122 }
    123 
    124 
    125 
    126 template< typename pass_type >
    127 void PassVisitor< pass_type >::visitExpression( Expression * expr ) {
    128         if( !expr ) return;
     196        return handleStatement( stmt, [this]( Statement * stmt ) {
     197                return maybeMutate( stmt, *this );
     198        });
     199}
     200
     201template< typename pass_type >
     202template< typename func_t >
     203Expression * PassVisitor< pass_type >::handleExpression( Expression * expr, func_t func ) {
     204        if( !expr ) return nullptr;
    129205
    130206        auto env_ptr = get_env_ptr();
     
    132208                *env_ptr = expr->get_env();
    133209        }
    134         // xxx - should env be cloned (or moved) onto the result of the mutate?
    135         expr->accept( *this );
     210
     211        // should env be cloned (or moved) onto the result of the mutate?
     212        return func( expr );
     213}
     214
     215template< typename pass_type >
     216Expression * PassVisitor< pass_type >::visitExpression( Expression * expr ) {
     217        return handleExpression(expr, [this]( Expression * expr ) {
     218                expr->accept( *this );
     219                return expr;
     220        });
    136221}
    137222
    138223template< typename pass_type >
    139224Expression * PassVisitor< pass_type >::mutateExpression( Expression * expr ) {
    140         if( !expr ) return nullptr;
    141 
    142         auto env_ptr = get_env_ptr();
    143         if ( env_ptr && expr->get_env() ) {
    144                 *env_ptr = expr->get_env();
    145         }
    146         // xxx - should env be cloned (or moved) onto the result of the mutate?
    147         return expr->acceptMutator( *this );
    148 }
    149 
     225        return handleExpression(expr, [this]( Expression * expr ) {
     226                return expr->acceptMutator( *this );
     227        });
     228}
    150229
    151230//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    153232template< typename pass_type >
    154233void PassVisitor< pass_type >::visit( ObjectDecl * node ) {
    155         VISIT_BODY( node ); 
     234        VISIT_BODY( node );
    156235}
    157236
    158237template< typename pass_type >
    159238void PassVisitor< pass_type >::visit( FunctionDecl * node ) {
    160         VISIT_BODY( node ); 
     239        VISIT_BODY( node );
    161240}
    162241
    163242template< typename pass_type >
    164243void PassVisitor< pass_type >::visit( StructDecl * node ) {
    165         VISIT_BODY( node ); 
     244        VISIT_BODY( node );
    166245}
    167246
    168247template< typename pass_type >
    169248void PassVisitor< pass_type >::visit( UnionDecl * node ) {
    170         VISIT_BODY( node ); 
     249        VISIT_BODY( node );
    171250}
    172251
    173252template< typename pass_type >
    174253void PassVisitor< pass_type >::visit( EnumDecl * node ) {
    175         VISIT_BODY( node ); 
     254        VISIT_BODY( node );
    176255}
    177256
    178257template< typename pass_type >
    179258void PassVisitor< pass_type >::visit( TraitDecl * node ) {
    180         VISIT_BODY( node ); 
     259        VISIT_BODY( node );
    181260}
    182261
    183262template< typename pass_type >
    184263void PassVisitor< pass_type >::visit( TypeDecl * node ) {
    185         VISIT_BODY( node ); 
     264        VISIT_BODY( node );
    186265}
    187266
    188267template< typename pass_type >
    189268void PassVisitor< pass_type >::visit( TypedefDecl * node ) {
    190         VISIT_BODY( node ); 
     269        VISIT_BODY( node );
    191270}
    192271
    193272template< typename pass_type >
    194273void PassVisitor< pass_type >::visit( AsmDecl * node ) {
    195         VISIT_BODY( node ); 
     274        VISIT_BODY( node );
    196275}
    197276
     
    225304void PassVisitor< pass_type >::visit( ExprStmt * node ) {
    226305        VISIT_START( node );
    227         call_beginScope();
    228306
    229307        visitExpression( node->get_expr() );
    230308
    231         call_endScope();
    232309        VISIT_END( node );
    233310}
     
    242319}
    243320
     321//--------------------------------------------------------------------------
     322// AsmStmt
    244323template< typename pass_type >
    245324void PassVisitor< pass_type >::visit( AsmStmt * node ) {
    246         VISIT_BODY( node );
     325        VISIT_BODY( node );
     326}
     327
     328template< typename pass_type >
     329Statement * PassVisitor< pass_type >::mutate( AsmStmt * node ) {
     330        MUTATE_BODY( Statement, node );
    247331}
    248332
     
    251335template< typename pass_type >
    252336void PassVisitor< pass_type >::visit( IfStmt * node ) {
    253         VISIT_START( node ); 
     337        VISIT_START( node );
    254338
    255339        visitExpression( node->get_condition() );
     
    262346template< typename pass_type >
    263347Statement * PassVisitor< pass_type >::mutate( IfStmt * node ) {
    264         MUTATE_START( node ); 
     348        MUTATE_START( node );
    265349
    266350        node->set_condition( mutateExpression( node->get_condition() ) );
     
    275359template< typename pass_type >
    276360void PassVisitor< pass_type >::visit( WhileStmt * node ) {
    277         VISIT_START( node ); 
     361        VISIT_START( node );
    278362
    279363        visitExpression( node->get_condition() );
     
    285369template< typename pass_type >
    286370Statement * PassVisitor< pass_type >::mutate( WhileStmt * node ) {
    287         MUTATE_START( node ); 
     371        MUTATE_START( node );
    288372
    289373        node->set_condition( mutateExpression( node->get_condition() ) );
     
    294378
    295379//--------------------------------------------------------------------------
    296 // WhileStmt
     380// ForStmt
    297381template< typename pass_type >
    298382void PassVisitor< pass_type >::visit( ForStmt * node ) {
    299         VISIT_START( node ); 
     383        VISIT_START( node );
    300384
    301385        acceptAll( node->get_initialization(), *this );
     
    309393template< typename pass_type >
    310394Statement * PassVisitor< pass_type >::mutate( ForStmt * node ) {
    311         MUTATE_START( node ); 
     395        MUTATE_START( node );
    312396
    313397        mutateAll( node->get_initialization(), *this );
     
    323407template< typename pass_type >
    324408void PassVisitor< pass_type >::visit( SwitchStmt * node ) {
    325         VISIT_START( node ); 
     409        VISIT_START( node );
    326410
    327411        visitExpression( node->get_condition() );
     
    333417template< typename pass_type >
    334418Statement * PassVisitor< pass_type >::mutate( SwitchStmt * node ) {
    335         MUTATE_START( node ); 
    336        
     419        MUTATE_START( node );
     420
    337421        node->set_condition( mutateExpression( node->get_condition() ) );
    338422        mutateStatementList( node->get_statements() );
    339        
     423
    340424        MUTATE_END( Statement, node );
    341425}
    342426
    343427//--------------------------------------------------------------------------
    344 // SwitchStmt
     428// CaseStmt
    345429template< typename pass_type >
    346430void PassVisitor< pass_type >::visit( CaseStmt * node ) {
    347         VISIT_START( node ); 
    348        
     431        VISIT_START( node );
     432
    349433        visitExpression( node->get_condition() );
    350434        visitStatementList( node->get_statements() );
    351        
     435
    352436        VISIT_END( node );
    353437}
     
    355439template< typename pass_type >
    356440Statement * PassVisitor< pass_type >::mutate( CaseStmt * node ) {
    357         MUTATE_START( node ); 
    358        
     441        MUTATE_START( node );
     442
    359443        node->set_condition(  mutateExpression( node->get_condition() ) );
    360444        mutateStatementList( node->get_statements() );
    361        
     445
    362446        MUTATE_END( Statement, node );
    363447}
    364448
     449//--------------------------------------------------------------------------
     450// BranchStmt
    365451template< typename pass_type >
    366452void PassVisitor< pass_type >::visit( BranchStmt * node ) {
    367         VISIT_BODY( node );
     453        VISIT_BODY( node );
     454}
     455
     456template< typename pass_type >
     457Statement * PassVisitor< pass_type >::mutate( BranchStmt * node ) {
     458        MUTATE_BODY( Statement, node );
    368459}
    369460
     
    386477
    387478        MUTATE_END( Statement, node );
     479}
     480
     481//--------------------------------------------------------------------------
     482// ThrowStmt
     483
     484template< typename pass_type >
     485void PassVisitor< pass_type >::visit( ThrowStmt * node ) {
     486        VISIT_BODY( node );
     487}
     488
     489template< typename pass_type >
     490Statement * PassVisitor< pass_type >::mutate( ThrowStmt * node ) {
     491        MUTATE_BODY( Statement, node );
    388492}
    389493
     
    396500        maybeAccept( node->get_block(), *this );
    397501        acceptAll( node->get_catchers(), *this );
     502        maybeAccept( node->get_finally(), *this );
    398503
    399504        VISIT_END( node );
     
    406511        node->set_block(  maybeMutate( node->get_block(), *this ) );
    407512        mutateAll( node->get_catchers(), *this );
    408        
     513        node->set_finally( maybeMutate( node->get_finally(), *this ) );
     514
    409515        MUTATE_END( Statement, node );
    410516}
     
    416522        VISIT_START( node );
    417523
     524        maybeAccept( node->get_decl(), *this );
     525        node->set_cond( visitExpression( node->get_cond() ) );
    418526        node->set_body( visitStatement( node->get_body() ) );
    419         maybeAccept( node->get_decl(), *this );
    420527
    421528        VISIT_END( node );
     
    425532Statement * PassVisitor< pass_type >::mutate( CatchStmt * node ) {
    426533        MUTATE_START( node );
    427        
    428         node->set_body(  mutateStatement( node->get_body() ) );
    429         node->set_decl(  maybeMutate( node->get_decl(), *this ) );
    430        
     534
     535        node->set_decl( maybeMutate( node->get_decl(), *this ) );
     536        node->set_cond( mutateExpression( node->get_cond() ) );
     537        node->set_body( mutateStatement( node->get_body() ) );
     538
    431539        MUTATE_END( Statement, node );
    432540}
     
    434542template< typename pass_type >
    435543void PassVisitor< pass_type >::visit( FinallyStmt * node ) {
    436         VISIT_BODY( node ); 
     544        VISIT_BODY( node );
    437545}
    438546
    439547template< typename pass_type >
    440548void PassVisitor< pass_type >::visit( NullStmt * node ) {
    441         VISIT_BODY( node ); 
     549        VISIT_BODY( node );
    442550}
    443551
    444552template< typename pass_type >
    445553void PassVisitor< pass_type >::visit( DeclStmt * node ) {
    446         VISIT_BODY( node ); 
     554        VISIT_BODY( node );
    447555}
    448556
    449557template< typename pass_type >
    450558void PassVisitor< pass_type >::visit( ImplicitCtorDtorStmt * node ) {
    451         VISIT_BODY( node ); 
     559        VISIT_BODY( node );
    452560}
    453561
    454562template< typename pass_type >
    455563void PassVisitor< pass_type >::visit( ApplicationExpr * node ) {
    456         VISIT_BODY( node ); 
     564        VISIT_BODY( node );
    457565}
    458566
     
    462570void PassVisitor< pass_type >::visit( UntypedExpr * node ) {
    463571        VISIT_START( node );
     572
     573        // maybeAccept( node->get_env(), *this );
     574        maybeAccept( node->get_result(), *this );
    464575
    465576        for ( auto expr : node->get_args() ) {
     
    474585        MUTATE_START( node );
    475586
     587        node->set_env( maybeMutate( node->get_env(), *this ) );
     588        node->set_result( maybeMutate( node->get_result(), *this ) );
     589
    476590        for ( auto& expr : node->get_args() ) {
    477591                expr = mutateExpression( expr );
     
    483597template< typename pass_type >
    484598void PassVisitor< pass_type >::visit( NameExpr * node ) {
    485         VISIT_BODY( node ); 
     599        VISIT_BODY( node );
    486600}
    487601
    488602template< typename pass_type >
    489603void PassVisitor< pass_type >::visit( CastExpr * node ) {
    490         VISIT_BODY( node ); 
     604        VISIT_BODY( node );
    491605}
    492606
    493607template< typename pass_type >
    494608void PassVisitor< pass_type >::visit( AddressExpr * node ) {
    495         VISIT_BODY( node ); 
     609        VISIT_BODY( node );
    496610}
    497611
    498612template< typename pass_type >
    499613void PassVisitor< pass_type >::visit( LabelAddressExpr * node ) {
    500         VISIT_BODY( node ); 
     614        VISIT_BODY( node );
    501615}
    502616
    503617template< typename pass_type >
    504618void PassVisitor< pass_type >::visit( UntypedMemberExpr * node ) {
    505         VISIT_BODY( node ); 
     619        VISIT_BODY( node );
    506620}
    507621
    508622template< typename pass_type >
    509623void PassVisitor< pass_type >::visit( MemberExpr * node ) {
    510         VISIT_BODY( node ); 
     624        VISIT_BODY( node );
    511625}
    512626
    513627template< typename pass_type >
    514628void PassVisitor< pass_type >::visit( VariableExpr * node ) {
    515         VISIT_BODY( node ); 
     629        VISIT_BODY( node );
    516630}
    517631
    518632template< typename pass_type >
    519633void PassVisitor< pass_type >::visit( ConstantExpr * node ) {
    520         VISIT_BODY( node ); 
     634        VISIT_BODY( node );
    521635}
    522636
    523637template< typename pass_type >
    524638void PassVisitor< pass_type >::visit( SizeofExpr * node ) {
    525         VISIT_BODY( node ); 
     639        VISIT_BODY( node );
    526640}
    527641
    528642template< typename pass_type >
    529643void PassVisitor< pass_type >::visit( AlignofExpr * node ) {
    530         VISIT_BODY( node ); 
     644        VISIT_BODY( node );
    531645}
    532646
    533647template< typename pass_type >
    534648void PassVisitor< pass_type >::visit( UntypedOffsetofExpr * node ) {
    535         VISIT_BODY( node ); 
     649        VISIT_BODY( node );
    536650}
    537651
    538652template< typename pass_type >
    539653void PassVisitor< pass_type >::visit( OffsetofExpr * node ) {
    540         VISIT_BODY( node ); 
     654        VISIT_BODY( node );
    541655}
    542656
    543657template< typename pass_type >
    544658void PassVisitor< pass_type >::visit( OffsetPackExpr * node ) {
    545         VISIT_BODY( node ); 
     659        VISIT_BODY( node );
    546660}
    547661
    548662template< typename pass_type >
    549663void PassVisitor< pass_type >::visit( AttrExpr * node ) {
    550         VISIT_BODY( node ); 
     664        VISIT_BODY( node );
    551665}
    552666
    553667template< typename pass_type >
    554668void PassVisitor< pass_type >::visit( LogicalExpr * node ) {
    555         VISIT_BODY( node ); 
     669        VISIT_BODY( node );
    556670}
    557671
    558672template< typename pass_type >
    559673void PassVisitor< pass_type >::visit( ConditionalExpr * node ) {
    560         VISIT_BODY( node ); 
     674        VISIT_BODY( node );
    561675}
    562676
    563677template< typename pass_type >
    564678void PassVisitor< pass_type >::visit( CommaExpr * node ) {
    565         VISIT_BODY( node ); 
     679        VISIT_BODY( node );
    566680}
    567681
    568682template< typename pass_type >
    569683void PassVisitor< pass_type >::visit( TypeExpr * node ) {
    570         VISIT_BODY( node ); 
     684        VISIT_BODY( node );
    571685}
    572686
    573687template< typename pass_type >
    574688void PassVisitor< pass_type >::visit( AsmExpr * node ) {
    575         VISIT_BODY( node ); 
     689        VISIT_BODY( node );
    576690}
    577691
    578692template< typename pass_type >
    579693void PassVisitor< pass_type >::visit( ImplicitCopyCtorExpr * node ) {
    580         VISIT_BODY( node ); 
     694        VISIT_BODY( node );
    581695}
    582696
    583697template< typename pass_type >
    584698void PassVisitor< pass_type >::visit( ConstructorExpr * node ) {
    585         VISIT_BODY( node ); 
     699        VISIT_BODY( node );
    586700}
    587701
    588702template< typename pass_type >
    589703void PassVisitor< pass_type >::visit( CompoundLiteralExpr * node ) {
    590         VISIT_BODY( node );
    591 }
    592 
    593 template< typename pass_type >
    594 void PassVisitor< pass_type >::visit( UntypedValofExpr * node ) {
    595         VISIT_BODY( node );
     704        VISIT_BODY( node );
    596705}
    597706
    598707template< typename pass_type >
    599708void PassVisitor< pass_type >::visit( RangeExpr * node ) {
    600         VISIT_BODY( node ); 
     709        VISIT_BODY( node );
    601710}
    602711
    603712template< typename pass_type >
    604713void PassVisitor< pass_type >::visit( UntypedTupleExpr * node ) {
    605         VISIT_BODY( node ); 
     714        VISIT_BODY( node );
    606715}
    607716
    608717template< typename pass_type >
    609718void PassVisitor< pass_type >::visit( TupleExpr * node ) {
    610         VISIT_BODY( node ); 
     719        VISIT_BODY( node );
    611720}
    612721
    613722template< typename pass_type >
    614723void PassVisitor< pass_type >::visit( TupleIndexExpr * node ) {
    615         VISIT_BODY( node );
    616 }
    617 
    618 template< typename pass_type >
    619 void PassVisitor< pass_type >::visit( MemberTupleExpr * node ) {
    620         VISIT_BODY( node );
     724        VISIT_BODY( node );
    621725}
    622726
    623727template< typename pass_type >
    624728void PassVisitor< pass_type >::visit( TupleAssignExpr * node ) {
    625         VISIT_BODY( node ); 
     729        VISIT_BODY( node );
    626730}
    627731
     
    645749Expression * PassVisitor< pass_type >::mutate( StmtExpr * node ) {
    646750        MUTATE_START( node );
    647        
     751
    648752        // don't want statements from outer CompoundStmts to be added to this StmtExpr
    649753        ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
     
    658762template< typename pass_type >
    659763void PassVisitor< pass_type >::visit( UniqueExpr * node ) {
    660         VISIT_BODY( node ); 
     764        VISIT_BODY( node );
    661765}
    662766
    663767template< typename pass_type >
    664768void PassVisitor< pass_type >::visit( VoidType * node ) {
    665         VISIT_BODY( node ); 
     769        VISIT_BODY( node );
    666770}
    667771
    668772template< typename pass_type >
    669773void PassVisitor< pass_type >::visit( BasicType * node ) {
    670         VISIT_BODY( node ); 
     774        VISIT_BODY( node );
    671775}
    672776
    673777template< typename pass_type >
    674778void PassVisitor< pass_type >::visit( PointerType * node ) {
    675         VISIT_BODY( node ); 
     779        VISIT_BODY( node );
    676780}
    677781
    678782template< typename pass_type >
    679783void PassVisitor< pass_type >::visit( ArrayType * node ) {
    680         VISIT_BODY( node ); 
     784        VISIT_BODY( node );
    681785}
    682786
    683787template< typename pass_type >
    684788void PassVisitor< pass_type >::visit( FunctionType * node ) {
    685         VISIT_BODY( node ); 
     789        VISIT_BODY( node );
    686790}
    687791
    688792template< typename pass_type >
    689793void PassVisitor< pass_type >::visit( StructInstType * node ) {
    690         VISIT_BODY( node ); 
     794        VISIT_BODY( node );
    691795}
    692796
    693797template< typename pass_type >
    694798void PassVisitor< pass_type >::visit( UnionInstType * node ) {
    695         VISIT_BODY( node ); 
     799        VISIT_BODY( node );
    696800}
    697801
    698802template< typename pass_type >
    699803void PassVisitor< pass_type >::visit( EnumInstType * node ) {
    700         VISIT_BODY( node ); 
     804        VISIT_BODY( node );
    701805}
    702806
    703807template< typename pass_type >
    704808void PassVisitor< pass_type >::visit( TraitInstType * node ) {
    705         VISIT_BODY( node ); 
     809        VISIT_BODY( node );
    706810}
    707811
    708812template< typename pass_type >
    709813void PassVisitor< pass_type >::visit( TypeInstType * node ) {
    710         VISIT_BODY( node ); 
     814        VISIT_BODY( node );
    711815}
    712816
    713817template< typename pass_type >
    714818void PassVisitor< pass_type >::visit( TupleType * node ) {
    715         VISIT_BODY( node ); 
     819        VISIT_BODY( node );
    716820}
    717821
    718822template< typename pass_type >
    719823void PassVisitor< pass_type >::visit( TypeofType * node ) {
    720         VISIT_BODY( node ); 
     824        VISIT_BODY( node );
    721825}
    722826
    723827template< typename pass_type >
    724828void PassVisitor< pass_type >::visit( AttrType * node ) {
    725         VISIT_BODY( node ); 
     829        VISIT_BODY( node );
    726830}
    727831
    728832template< typename pass_type >
    729833void PassVisitor< pass_type >::visit( VarArgsType * node ) {
    730         VISIT_BODY( node ); 
     834        VISIT_BODY( node );
    731835}
    732836
    733837template< typename pass_type >
    734838void PassVisitor< pass_type >::visit( ZeroType * node ) {
    735         VISIT_BODY( node ); 
     839        VISIT_BODY( node );
    736840}
    737841
    738842template< typename pass_type >
    739843void PassVisitor< pass_type >::visit( OneType * node ) {
    740         VISIT_BODY( node ); 
     844        VISIT_BODY( node );
    741845}
    742846
     
    763867template< typename pass_type >
    764868void PassVisitor< pass_type >::visit( ListInit * node ) {
    765         VISIT_BODY( node ); 
     869        VISIT_BODY( node );
    766870}
    767871
    768872template< typename pass_type >
    769873void PassVisitor< pass_type >::visit( ConstructorInit * node ) {
    770         VISIT_BODY( node ); 
     874        VISIT_BODY( node );
    771875}
    772876
    773877template< typename pass_type >
    774878void PassVisitor< pass_type >::visit( Subrange * node ) {
    775         VISIT_BODY( node ); 
     879        VISIT_BODY( node );
    776880}
    777881
    778882template< typename pass_type >
    779883void PassVisitor< pass_type >::visit( Constant * node ) {
    780         VISIT_BODY( node ); 
     884        VISIT_BODY( node );
    781885}
    782886
     
    829933
    830934template< typename pass_type >
    831 Statement * PassVisitor< pass_type >::mutate( AsmStmt * node ) {
    832         MUTATE_BODY( Statement, node );
    833 }
    834 
    835 template< typename pass_type >
    836 Statement * PassVisitor< pass_type >::mutate( BranchStmt * node ) {
    837         MUTATE_BODY( Statement, node );
    838 }
    839 
    840 template< typename pass_type >
    841935Statement * PassVisitor< pass_type >::mutate( FinallyStmt * node ) {
    842936        MUTATE_BODY( Statement, node );
     
    9741068
    9751069template< typename pass_type >
    976 Expression * PassVisitor< pass_type >::mutate( UntypedValofExpr * node ) {
    977         MUTATE_BODY( Expression, node );
    978 }
    979 
    980 template< typename pass_type >
    9811070Expression * PassVisitor< pass_type >::mutate( RangeExpr * node ) {
    9821071        MUTATE_BODY( Expression, node );
     
    9951084template< typename pass_type >
    9961085Expression * PassVisitor< pass_type >::mutate( TupleIndexExpr * node ) {
    997         MUTATE_BODY( Expression, node );
    998 }
    999 
    1000 template< typename pass_type >
    1001 Expression * PassVisitor< pass_type >::mutate( MemberTupleExpr * node ) {
    10021086        MUTATE_BODY( Expression, node );
    10031087}
  • src/Common/PassVisitor.proto.h

    re4d829b r579263a  
    11#pragma once
     2
     3template<typename pass_type>
     4class PassVisitor;
     5
     6typedef std::function<void( void * )> cleanup_func_t;
     7
     8class guard_value_impl {
     9public:
     10        guard_value_impl() = default;
     11
     12        ~guard_value_impl() {
     13                while( !cleanups.empty() ) {
     14                        auto& cleanup = cleanups.top();
     15                        cleanup.func( cleanup.val );
     16                        cleanups.pop();
     17                }
     18        }
     19
     20        void push( cleanup_func_t && func, void* val ) {
     21                cleanups.emplace( std::move(func), val );
     22        }
     23
     24private:
     25        struct cleanup_t {
     26                cleanup_func_t func;
     27                void * val;
     28
     29                cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
     30        };
     31
     32        std::stack< cleanup_t > cleanups;
     33};
     34
     35typedef std::function< void( cleanup_func_t, void * ) > at_cleanup_t;
     36
     37class bool_ref {
     38public:
     39        bool_ref() = default;
     40        ~bool_ref() = default;
     41
     42        operator bool() { return *m_ref; }
     43        bool operator=( bool val ) { return *m_ref = val; }
     44
     45private:
     46
     47        template<typename pass>
     48        friend class PassVisitor;
     49
     50        void set( bool & val ) { m_ref = &val; };
     51
     52        bool * m_ref;
     53};
    254
    355//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    456// Deep magic (a.k.a template meta programming) to make the templated visitor work
    557// Basically the goal is to make 2 previsit_impl
    6 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 
     58// 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
    759//     'pass.previsit( node )' that compiles will be used for that node for that type
    860//     This requires that this option only compile for passes that actually define an appropriate visit.
     
    1870// Visit
    1971template<typename pass_type, typename node_type>
    20 static inline auto previsit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.previsit( node ), void() ) {
     72static inline auto previsit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.previsit( node ), void() ) {
    2173        pass.previsit( node );
    2274}
     
    2779
    2880template<typename pass_type, typename node_type>
    29 static inline auto postvisit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.postvisit( node ), void() ) {
     81static inline auto postvisit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postvisit( node ), void() ) {
    3082        pass.postvisit( node );
    3183}
     
    3688// Mutate
    3789template<typename pass_type, typename node_type>
    38 static inline auto premutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.premutate( node ), void() ) {
     90static inline auto premutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.premutate( node ), void() ) {
    3991        return pass.premutate( node );
    4092}
     
    4597
    4698template<typename return_type, typename pass_type, typename node_type>
    47 static inline auto postmutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.postmutate( node ) ) {
     99static inline auto postmutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postmutate( node ) ) {
    48100        return pass.postmutate( node );
    49101}
     
    54106// Begin/End scope
    55107template<typename pass_type>
    56 static inline auto begin_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) ->decltype( pass.beginScope(), void() ) {
     108static inline auto begin_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.beginScope(), void() ) {
    57109        pass.beginScope();
    58110}
     
    63115
    64116template<typename pass_type>
    65 static inline auto end_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) ->decltype( pass.endScope(), void() ) {
     117static inline auto end_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.endScope(), void() ) {
    66118        pass.endScope();
    67119}
     
    73125#define FIELD_PTR( type, name )                                                                                                        \
    74126template<typename pass_type>                                                                                                           \
    75 static inline auto name##_impl( pass_type& pass, __attribute__((unused)) int unused ) ->decltype( &pass.name ) { return &pass.name; } \
     127static inline auto name##_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( &pass.name ) { return &pass.name; } \
    76128                                                                                                                                       \
    77129template<typename pass_type>                                                                                                           \
     
    81133FIELD_PTR( std::list< Statement* >, stmtsToAddBefore )
    82134FIELD_PTR( std::list< Statement* >, stmtsToAddAfter  )
    83 FIELD_PTR( bool, skip_children )
     135FIELD_PTR( std::list< Declaration* >, declsToAddBefore )
     136FIELD_PTR( std::list< Declaration* >, declsToAddAfter  )
     137FIELD_PTR( bool_ref, visit_children )
     138FIELD_PTR( at_cleanup_t, at_cleanup )
     139FIELD_PTR( PassVisitor<pass_type> * const, visitor )
  • src/GenPoly/Box.cc

    re4d829b r579263a  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 13 09:26:38 2017
    13 // Update Count     : 341
     12// Last Modified On : Wed Jun 21 15:49:59 2017
     13// Update Count     : 346
    1414//
    1515
     
    108108                        Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true );
    109109                        /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value
    110                         Expression *addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *polyType, std::list< Expression *>::iterator &arg );
     110                        Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType, std::list< Expression *>::iterator &arg );
    111111                        Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
    112112                        void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars );
     
    341341        Statement *makeAlignTo( Expression *lhs, Expression *rhs ) {
    342342                // check that the lhs is zeroed out to the level of rhs
    343                 Expression *ifCond = makeOp( "?&?", lhs, makeOp( "?-?", rhs, new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), "1" ) ) ) );
     343                Expression *ifCond = makeOp( "?&?", lhs, makeOp( "?-?", rhs, new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    344344                // if not aligned, increment to alignment
    345345                Expression *ifExpr = makeOp( "?+=?", lhs->clone(), makeOp( "?-?", rhs->clone(), ifCond->clone() ) );
     
    384384
    385385                // initialize size and alignment to 0 and 1 (will have at least one member to re-edit size)
    386                 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant( sizeAlignType->clone(), "0" ) ) ) );
    387                 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant( sizeAlignType->clone(), "1" ) ) ) );
     386                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 0 ) ) ) );
     387                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    388388                unsigned long n_members = 0;
    389389                bool firstMember = true;
     
    441441
    442442                // calculate union layout in function body
    443                 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant( sizeAlignType->clone(), "1" ) ) ) );
    444                 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant( sizeAlignType->clone(), "1" ) ) ) );
     443                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
     444                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    445445                for ( std::list< Declaration* >::const_iterator member = unionDecl->get_members().begin(); member != unionDecl->get_members().end(); ++member ) {
    446446                        DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( *member );
     
    504504                DeclarationWithType *Pass1::mutate( FunctionDecl *functionDecl ) {
    505505                        if ( functionDecl->get_statements() ) {         // empty routine body ?
     506                                // std::cerr << "mutating function: " << functionDecl->get_mangleName() << std::endl;
    506507                                doBeginScope();
    507508                                scopeTyVars.beginScope();
     
    548549                                retval = oldRetval;
    549550                                doEndScope();
     551                                // std::cerr << "end function: " << functionDecl->get_mangleName() << std::endl;
    550552                        } // if
    551553                        return functionDecl;
     
    726728                }
    727729
    728                 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *dynType, std::list< Expression *>::iterator &arg ) {
     730                Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType, std::list< Expression *>::iterator &arg ) {
    729731                        assert( env );
    730732                        Type *concrete = replaceWithConcrete( appExpr, dynType );
     
    11161118
    11171119                Expression *Pass1::mutate( ApplicationExpr *appExpr ) {
    1118                         // std::cerr << "mutate appExpr: ";
     1120                        // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl;
    11191121                        // for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i ) {
    11201122                        //      std::cerr << i->first << " ";
     
    11411143                        ReferenceToType *dynRetType = isDynRet( function, exprTyVars );
    11421144
     1145                        // std::cerr << function << std::endl;
     1146                        // std::cerr << "scopeTyVars: ";
     1147                        // printTyVarMap( std::cerr, scopeTyVars );
     1148                        // std::cerr << "exprTyVars: ";
     1149                        // printTyVarMap( std::cerr, exprTyVars );
     1150                        // std::cerr << "env: " << *env << std::endl;
     1151                        // std::cerr << needsAdapter( function, scopeTyVars ) << ! needsAdapter( function, exprTyVars) << std::endl;
     1152
    11431153                        // NOTE: addDynRetParam needs to know the actual (generated) return type so it can make a temp variable, so pass the result type from the appExpr
    11441154                        // passTypeVars needs to know the program-text return type (i.e. the distinction between _conc_T30 and T3(int))
    11451155                        // concRetType may not be a good name in one or both of these places. A more appropriate name change is welcome.
    11461156                        if ( dynRetType ) {
     1157                                // std::cerr << "dynRetType: " << dynRetType << std::endl;
    11471158                                Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result();
    1148                                 ret = addDynRetParam( appExpr, function, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType
     1159                                ret = addDynRetParam( appExpr, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType
    11491160                        } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...?
    11501161                                // xxx - the ! needsAdapter check may be incorrect. It seems there is some situation where an adapter is applied where it shouldn't be, and this fixes it for some cases. More investigation is needed.
     
    15641575                /// Returns an index expression into the offset array for a type
    15651576                Expression *makeOffsetIndex( Type *objectType, long i ) {
    1566                         std::stringstream offset_namer;
    1567                         offset_namer << i;
    1568                         ConstantExpr *fieldIndex = new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), offset_namer.str() ) );
     1577                        ConstantExpr *fieldIndex = new ConstantExpr( Constant::from_ulong( i ) );
    15691578                        UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) );
    15701579                        fieldOffset->get_args().push_back( new NameExpr( offsetofName( mangleType( objectType ) ) ) );
     
    17791788                                // all union members are at offset zero
    17801789                                delete offsetofExpr;
    1781                                 return new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), "0" ) );
     1790                                return new ConstantExpr( Constant::from_ulong( 0 ) );
    17821791                        } else return offsetofExpr;
    17831792                }
  • src/GenPoly/DeclMutator.cc

    re4d829b r579263a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Fri Nov 27 14:44:00 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug  4 11:16:43 2016
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jun 22 13:49:00 2017
     13// Update Count     : 4
    1414//
    1515
     
    178178        Statement* DeclMutator::mutate(CatchStmt *catchStmt) {
    179179                catchStmt->set_decl( maybeMutate( catchStmt->get_decl(), *this ) );
     180                catchStmt->set_cond( maybeMutate( catchStmt->get_cond(), *this ) );
    180181                catchStmt->set_body( mutateStatement( catchStmt->get_body() ) );
    181182                return catchStmt;
  • src/GenPoly/InstantiateGeneric.cc

    re4d829b r579263a  
    2222#include "InstantiateGeneric.h"
    2323
    24 #include "DeclMutator.h"
    2524#include "GenPoly.h"
    2625#include "ScopedSet.h"
    2726#include "ScrubTyVars.h"
    28 #include "PolyMutator.h"
     27
     28#include "Common/PassVisitor.h"
     29#include "Common/ScopedMap.h"
     30#include "Common/UniqueName.h"
     31#include "Common/utility.h"
    2932
    3033#include "ResolvExpr/typeops.h"
     
    3437#include "SynTree/Type.h"
    3538
    36 #include "Common/ScopedMap.h"
    37 #include "Common/UniqueName.h"
    38 #include "Common/utility.h"
     39
     40#include "InitTweak/InitTweak.h"
     41
    3942
    4043namespace GenPoly {
     
    153156        }
    154157
    155         // collect the environments of each TypeInstType so that type variables can be replaced
    156         // xxx - possibly temporary solution. Access to type environments is required in GenericInstantiator, but it needs to be a DeclMutator which does not provide easy access to the type environments.
    157         class EnvFinder final : public GenPoly::PolyMutator {
    158         public:
    159                 using GenPoly::PolyMutator::mutate;
    160                 virtual Type * mutate( TypeInstType * inst ) override {
    161                         if ( env ) envMap[inst] = env;
    162                         return inst;
    163                 }
    164 
    165                 // don't want to associate an environment with TypeInstTypes that occur in function types - this may actually only apply to function types belonging to DeclarationWithTypes (or even just FunctionDecl)?
    166                 virtual Type * mutate( FunctionType * ftype ) override {
    167                         return ftype;
    168                 }
    169                 std::unordered_map< ReferenceToType *, TypeSubstitution * > envMap;
    170         };
    171 
    172158        /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
    173         class GenericInstantiator final : public DeclMutator {
     159        struct GenericInstantiator final : public WithTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {
    174160                /// Map of (generic type, parameter list) pairs to concrete type instantiations
    175161                InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
     
    178164                /// Namer for concrete types
    179165                UniqueName typeNamer;
    180                 /// Reference to mapping of environments
    181                 const std::unordered_map< ReferenceToType *, TypeSubstitution * > & envMap;
    182         public:
    183                 GenericInstantiator( const std::unordered_map< ReferenceToType *, TypeSubstitution * > & envMap ) : DeclMutator(), instantiations(), dtypeStatics(), typeNamer("_conc_"), envMap( envMap ) {}
    184 
    185                 using DeclMutator::mutate;
    186                 virtual Type* mutate( StructInstType *inst ) override;
    187                 virtual Type* mutate( UnionInstType *inst ) override;
    188 
    189                 virtual void doBeginScope() override;
    190                 virtual void doEndScope() override;
     166                /// Should not make use of type environment to replace types of function parameter and return values.
     167                bool inFunctionType = false;
     168                GenericInstantiator() : instantiations(), dtypeStatics(), typeNamer("_conc_") {}
     169
     170                Type* postmutate( StructInstType *inst );
     171                Type* postmutate( UnionInstType *inst );
     172
     173                void premutate( FunctionType * ftype ) {
     174                        GuardValue( inFunctionType );
     175                        inFunctionType = true;
     176                }
     177
     178                void beginScope();
     179                void endScope();
    191180        private:
    192181                /// Wrap instantiation lookup for structs
     
    207196
    208197        void instantiateGeneric( std::list< Declaration* > &translationUnit ) {
    209                 EnvFinder finder;
    210                 mutateAll( translationUnit, finder );
    211                 GenericInstantiator instantiator( finder.envMap );
    212                 instantiator.mutateDeclarationList( translationUnit );
     198                PassVisitor<GenericInstantiator> instantiator;
     199                mutateAll( translationUnit, instantiator );
    213200        }
    214201
     
    306293        Type *GenericInstantiator::replaceWithConcrete( Type *type, bool doClone ) {
    307294                if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    308                         if ( envMap.count( typeInst ) ) {
    309                                 TypeSubstitution * env = envMap.at( typeInst );
     295                        if ( env && ! inFunctionType ) {
    310296                                Type *concrete = env->lookup( typeInst->get_name() );
    311297                                if ( concrete ) {
     
    331317
    332318
    333         Type* GenericInstantiator::mutate( StructInstType *inst ) {
    334                 // mutate subtypes
    335                 Type *mutated = Mutator::mutate( inst );
    336                 inst = dynamic_cast< StructInstType* >( mutated );
    337                 if ( ! inst ) return mutated;
    338 
     319        Type* GenericInstantiator::postmutate( StructInstType *inst ) {
    339320                // exit early if no need for further mutation
    340321                if ( inst->get_parameters().empty() ) return inst;
     
    368349                                substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
    369350                                insert( inst, typeSubs, concDecl ); // must insert before recursion
    370                                 concDecl->acceptMutator( *this ); // recursively instantiate members
    371                                 DeclMutator::addDeclaration( concDecl ); // must occur before declaration is added so that member instantiations appear first
     351                                concDecl->acceptMutator( *visitor ); // recursively instantiate members
     352                                declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
    372353                        }
    373354                        StructInstType *newInst = new StructInstType( inst->get_qualifiers(), concDecl->get_name() );
     
    388369        }
    389370
    390         Type* GenericInstantiator::mutate( UnionInstType *inst ) {
    391                 // mutate subtypes
    392                 Type *mutated = Mutator::mutate( inst );
    393                 inst = dynamic_cast< UnionInstType* >( mutated );
    394                 if ( ! inst ) return mutated;
    395 
     371        Type* GenericInstantiator::postmutate( UnionInstType *inst ) {
    396372                // exit early if no need for further mutation
    397373                if ( inst->get_parameters().empty() ) return inst;
     
    423399                                substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
    424400                                insert( inst, typeSubs, concDecl ); // must insert before recursion
    425                                 concDecl->acceptMutator( *this ); // recursively instantiate members
    426                                 DeclMutator::addDeclaration( concDecl ); // must occur before declaration is added so that member instantiations appear first
     401                                concDecl->acceptMutator( *visitor ); // recursively instantiate members
     402                                declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
    427403                        }
    428404                        UnionInstType *newInst = new UnionInstType( inst->get_qualifiers(), concDecl->get_name() );
     
    442418        }
    443419
    444         void GenericInstantiator::doBeginScope() {
    445                 DeclMutator::doBeginScope();
     420        void GenericInstantiator::beginScope() {
    446421                instantiations.beginScope();
    447422                dtypeStatics.beginScope();
    448423        }
    449424
    450         void GenericInstantiator::doEndScope() {
    451                 DeclMutator::doEndScope();
     425        void GenericInstantiator::endScope() {
    452426                instantiations.endScope();
    453427                dtypeStatics.endScope();
  • src/GenPoly/PolyMutator.cc

    re4d829b r579263a  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug  4 11:26:22 2016
    13 // Update Count     : 16
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jun 22 13:47:00 2017
     13// Update Count     : 17
    1414//
    1515
     
    123123
    124124        Statement * PolyMutator::mutate(TryStmt *tryStmt) {
    125                 tryStmt->set_block(  maybeMutate( tryStmt->get_block(), *this ) );
     125                tryStmt->set_block( maybeMutate( tryStmt->get_block(), *this ) );
    126126                mutateAll( tryStmt->get_catchers(), *this );
     127                tryStmt->set_finally( maybeMutate( tryStmt->get_finally(), *this ) );
    127128                return tryStmt;
    128129        }
    129130
    130131        Statement * PolyMutator::mutate(CatchStmt *cathStmt) {
    131                 cathStmt->set_body(  mutateStatement( cathStmt->get_body() ) );
    132                 cathStmt->set_decl(  maybeMutate( cathStmt->get_decl(), *this ) );
     132                cathStmt->set_body( mutateStatement( cathStmt->get_body() ) );
     133                cathStmt->set_cond( maybeMutate( cathStmt->get_cond(), *this ) );
     134                cathStmt->set_decl( maybeMutate( cathStmt->get_decl(), *this ) );
    133135                return cathStmt;
    134136        }
  • src/GenPoly/Specialize.cc

    re4d829b r579263a  
    9393        }
    9494
    95         bool needsTupleSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     95        bool needsTupleSpecialization( Type *formalType, Type *actualType ) {
    9696                // Needs tuple specialization if the structure of the formal type and actual type do not match.
    9797                // This is the case if the formal type has ttype polymorphism, or if the structure  of tuple types
     
    9999                if ( FunctionType * fftype = getFunctionType( formalType ) ) {
    100100                        if ( fftype->isTtype() ) return true;
     101                        // conversion of 0 (null) to function type does not require tuple specialization
     102                        if ( dynamic_cast< ZeroType * >( actualType ) ) return false;
    101103                        FunctionType * aftype = getFunctionType( actualType );
    102104                        assertf( aftype, "formal type is a function type, but actual type is not." );
     
    112114
    113115        bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    114                 return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType, env );
     116                return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType );
    115117        }
    116118
  • src/InitTweak/FixInit.cc

    re4d829b r579263a  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 17 09:13:47 2017
    13 // Update Count     : 71
     12// Last Modified On : Wed Jun 21 17:35:05 2017
     13// Update Count     : 74
    1414//
    1515
     
    5656                typedef std::unordered_map< int, int > UnqCount;
    5757
    58                 class InsertImplicitCalls {
     58                class InsertImplicitCalls : public WithTypeSubstitution {
    5959                public:
    6060                        /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
     
    6969                        // collects environments for relevant nodes
    7070                        EnvMap & envMap;
    71                         TypeSubstitution * env; //Magically populated by the PassVisitor
    7271                };
    7372
     
    192191                };
    193192
    194                 class FixInit {
     193                class FixInit : public WithStmtsToAdd {
    195194                  public:
    196195                        /// expand each object declaration to use its constructor after it is declared.
     
    200199
    201200                        std::list< Declaration * > staticDtorDecls;
    202                         std::list< Statement * > stmtsToAddAfter; // found by PassVisitor
    203201                };
    204202
     
    726724                                                // static bool __objName_uninitialized = true
    727725                                                BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool );
    728                                                 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ) );
     726                                                SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant::from_int( 1 ) ) );
    729727                                                ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", Type::StorageClasses( Type::Static ), LinkageSpec::Cforall, 0, boolType, boolInitExpr );
    730728                                                isUninitializedVar->fixUniqueId();
     
    733731                                                UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) );
    734732                                                setTrue->get_args().push_back( new VariableExpr( isUninitializedVar ) );
    735                                                 setTrue->get_args().push_back( new ConstantExpr( Constant( boolType->clone(), "0" ) ) );
     733                                                setTrue->get_args().push_back( new ConstantExpr( Constant::from_int( 0 ) ) );
    736734
    737735                                                // generate body of if
     
    902900                }
    903901
    904                 void InsertDtors::visit( ReturnStmt * returnStmt ) {
     902                void InsertDtors::visit( __attribute((unused)) ReturnStmt * returnStmt ) {
    905903                        // return exits all scopes, so dump destructors for all scopes
    906904                        for ( OrderedDecls & od : reverseDeclOrder ) {
  • src/InitTweak/GenInit.cc

    re4d829b r579263a  
    3939
    4040namespace InitTweak {
    41         class ReturnFixer final : public GenPoly::PolyMutator {
    42           public:
     41        namespace {
     42                const std::list<Label> noLabels;
     43                const std::list<Expression *> noDesignators;
     44        }
     45
     46        struct ReturnFixer : public WithStmtsToAdd, public WithGuards {
    4347                /// consistently allocates a temporary variable for the return value
    4448                /// of a function so that anything which the resolver decides can be constructed
     
    4650                static void makeReturnTemp( std::list< Declaration * > &translationUnit );
    4751
    48                 typedef GenPoly::PolyMutator Parent;
    49                 using Parent::mutate;
    50                 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override;
    51                 virtual Statement * mutate( ReturnStmt * returnStmt ) override;
     52                void premutate( FunctionDecl *functionDecl );
     53                void premutate( ReturnStmt * returnStmt );
    5254
    5355          protected:
     
    5658        };
    5759
    58         class CtorDtor final : public GenPoly::PolyMutator {
    59           public:
    60                 typedef GenPoly::PolyMutator Parent;
    61                 using Parent::mutate;
     60        struct CtorDtor : public WithGuards, public WithShortCircuiting  {
    6261                /// create constructor and destructor statements for object declarations.
    6362                /// the actual call statements will be added in after the resolver has run
     
    6665                static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    6766
    68                 virtual DeclarationWithType * mutate( ObjectDecl * ) override;
    69                 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override;
     67                void previsit( ObjectDecl * );
     68                void previsit( FunctionDecl *functionDecl );
     69
    7070                // should not traverse into any of these declarations to find objects
    7171                // that need to be constructed or destructed
    72                 virtual Declaration* mutate( StructDecl *aggregateDecl ) override;
    73                 virtual Declaration* mutate( UnionDecl *aggregateDecl ) override { return aggregateDecl; }
    74                 virtual Declaration* mutate( EnumDecl *aggregateDecl ) override { return aggregateDecl; }
    75                 virtual Declaration* mutate( TraitDecl *aggregateDecl ) override { return aggregateDecl; }
    76                 virtual TypeDecl* mutate( TypeDecl *typeDecl ) override { return typeDecl; }
    77                 virtual Declaration* mutate( TypedefDecl *typeDecl ) override { return typeDecl; }
    78 
    79                 virtual Type * mutate( FunctionType *funcType ) override { return funcType; }
    80 
    81                 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) override;
     72                void previsit( StructDecl *aggregateDecl );
     73                void previsit( UnionDecl *aggregateDecl ) { visit_children = false; }
     74                void previsit( EnumDecl *aggregateDecl ) { visit_children = false; }
     75                void previsit( TraitDecl *aggregateDecl ) { visit_children = false; }
     76                void previsit( TypeDecl *typeDecl ) { visit_children = false; }
     77                void previsit( TypedefDecl *typeDecl ) { visit_children = false; }
     78
     79                void previsit( FunctionType *funcType ) { visit_children = false; }
     80
     81                void previsit( CompoundStmt * compoundStmt );
    8282
    8383          private:
     
    131131
    132132        void ReturnFixer::makeReturnTemp( std::list< Declaration * > & translationUnit ) {
    133                 ReturnFixer fixer;
     133                PassVisitor<ReturnFixer> fixer;
    134134                mutateAll( translationUnit, fixer );
    135135        }
    136136
    137         Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) {
     137        void ReturnFixer::premutate( ReturnStmt *returnStmt ) {
    138138                std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    139139                assert( returnVals.size() == 0 || returnVals.size() == 1 );
     
    146146                        construct->get_args().push_back( new AddressExpr( new VariableExpr( returnVals.front() ) ) );
    147147                        construct->get_args().push_back( returnStmt->get_expr() );
    148                         stmtsToAdd.push_back(new ExprStmt(noLabels, construct));
     148                        stmtsToAddBefore.push_back(new ExprStmt(noLabels, construct));
    149149
    150150                        // return the retVal object
    151151                        returnStmt->set_expr( new VariableExpr( returnVals.front() ) );
    152152                } // if
    153                 return returnStmt;
    154         }
    155 
    156         DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
    157                 ValueGuard< FunctionType * > oldFtype( ftype );
    158                 ValueGuard< std::string > oldFuncName( funcName );
     153        }
     154
     155        void ReturnFixer::premutate( FunctionDecl *functionDecl ) {
     156                GuardValue( ftype );
     157                GuardValue( funcName );
    159158
    160159                ftype = functionDecl->get_functionType();
    161160                funcName = functionDecl->get_name();
    162                 return Parent::mutate( functionDecl );
    163161        }
    164162
     
    210208
    211209        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
    212                 CtorDtor ctordtor;
    213                 mutateAll( translationUnit, ctordtor );
     210                PassVisitor<CtorDtor> ctordtor;
     211                acceptAll( translationUnit, ctordtor );
    214212        }
    215213
     
    288286        }
    289287
    290         DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) {
     288        void CtorDtor::previsit( ObjectDecl * objDecl ) {
    291289                handleDWT( objDecl );
    292290                // hands off if @=, extern, builtin, etc.
     
    300298                        objDecl->set_init( genCtorInit( objDecl ) );
    301299                }
    302                 return Parent::mutate( objDecl );
    303         }
    304 
    305         DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) {
    306                 ValueGuard< bool > oldInFunc = inFunction;
     300        }
     301
     302        void CtorDtor::previsit( FunctionDecl *functionDecl ) {
     303                GuardValue( inFunction );
    307304                inFunction = true;
    308305
    309306                handleDWT( functionDecl );
    310307
    311                 managedTypes.beginScope();
     308                GuardScope( managedTypes );
    312309                // go through assertions and recursively add seen ctor/dtors
    313310                for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
     
    316313                        }
    317314                }
    318                 // parameters should not be constructed and destructed, so don't mutate FunctionType
    319                 functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
    320 
    321                 managedTypes.endScope();
    322                 return functionDecl;
    323         }
    324 
    325         Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) {
     315
     316                PassVisitor<CtorDtor> newCtorDtor;
     317                newCtorDtor.pass = *this;
     318                maybeAccept( functionDecl->get_statements(), newCtorDtor );
     319                visit_children = false;  // do not try and construct parameters or forall parameters - must happen after maybeAccept
     320        }
     321
     322        void CtorDtor::previsit( StructDecl *aggregateDecl ) {
     323                visit_children = false; // do not try to construct and destruct aggregate members
     324
    326325                // don't construct members, but need to take note if there is a managed member,
    327326                // because that means that this type is also managed
     
    335334                        }
    336335                }
    337                 return aggregateDecl;
    338         }
    339 
    340         CompoundStmt * CtorDtor::mutate( CompoundStmt * compoundStmt ) {
    341                 managedTypes.beginScope();
    342                 CompoundStmt * stmt = Parent::mutate( compoundStmt );
    343                 managedTypes.endScope();
    344                 return stmt;
    345         }
    346 
     336        }
     337
     338        void CtorDtor::previsit( CompoundStmt * compoundStmt ) {
     339                GuardScope( managedTypes );
     340        }
    347341} // namespace InitTweak
    348342
  • src/InitTweak/InitTweak.cc

    re4d829b r579263a  
    471471        public:
    472472                ConstExprChecker() : isConstExpr( true ) {}
     473
     474                using Visitor::visit;
    473475
    474476                virtual void visit( __attribute((unused)) ApplicationExpr *applicationExpr ) { isConstExpr = false; }
  • src/Parser/ExpressionNode.cc

    re4d829b r579263a  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May 17 21:31:01 2017
    13 // Update Count     : 527
     12// Last Modified On : Wed Jun 21 16:44:46 2017
     13// Update Count     : 541
    1414//
    1515
     
    6262        bool dec = true, Unsigned = false;                                      // decimal, unsigned constant
    6363        int size;                                                                                       // 0 => int, 1 => long, 2 => long long
    64         unsigned long long v;                                                           // converted integral value
     64        unsigned long long int v;                                                               // converted integral value
    6565        size_t last = str.length() - 1;                                         // last character of constant
    6666
     
    118118        } // if
    119119
    120         Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[Unsigned][size] ), str ) );
     120        Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[Unsigned][size] ), str, v ) );
    121121        delete &str;                                                                            // created by lex
    122122        return ret;
     
    133133        // floating-point constant has minimum of 2 characters: 1. or .1
    134134        size_t last = str.length() - 1;
     135        double v;
     136
     137        sscanf( str.c_str(), "%lg", &v );
    135138
    136139        if ( checkI( str[last] ) ) {                                            // imaginary ?
     
    150153        } // if
    151154
    152         Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[complx][size] ), str ) );
     155        Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[complx][size] ), str, v ) );
    153156        delete &str;                                                                            // created by lex
    154157        return ret;
     
    156159
    157160Expression *build_constantChar( const std::string & str ) {
    158         Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::Char ), str ) );
     161        Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::Char ), str, (unsigned long long int)(unsigned char)str[1] ) );
    159162        delete &str;                                                                            // created by lex
    160163        return ret;
     
    164167        // string should probably be a primitive type
    165168        ArrayType *at = new ArrayType( emptyQualifiers, new BasicType( Type::Qualifiers( Type::Const ), BasicType::Char ),
    166                                 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::UnsignedInt ),
    167                                                                                         toString( str.size()+1-2 ) ) ),  // +1 for '\0' and -2 for '"'
     169                                                                   new ConstantExpr( Constant::from_ulong( str.size() + 1 - 2 ) ),  // +1 for '\0' and -2 for '"'
    168170                                                                   false, false );
    169         ConstantExpr * ret = new ConstantExpr( Constant( at, str ) );
     171        // constant 0 is ignored for pure string value
     172        ConstantExpr * ret = new ConstantExpr( Constant( at, str, (unsigned long long int)0 ) );
    170173        delete &str;                                                                            // created by lex
    171174        return ret;
     
    173176
    174177Expression *build_constantZeroOne( const std::string & str ) {
    175         Expression * ret = new ConstantExpr( Constant( str == "0" ? (Type *)new ZeroType( emptyQualifiers ) : (Type*)new OneType( emptyQualifiers ), str ) );
     178        Expression * ret = new ConstantExpr( Constant( str == "0" ? (Type *)new ZeroType( emptyQualifiers ) : (Type*)new OneType( emptyQualifiers ), str,
     179                                                                                                   str == "0" ? (unsigned long long int)0 : (unsigned long long int)1 ) );
    176180        delete &str;                                                                            // created by lex
    177181        return ret;
     
    184188        std::stringstream ss( str );
    185189        ss >> a >> dot >> b;
    186         UntypedMemberExpr * ret = new UntypedMemberExpr(
    187                 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( b ) ) ),
    188                 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( a ) ) ) );
     190        UntypedMemberExpr * ret = new UntypedMemberExpr( new ConstantExpr( Constant::from_int( b ) ), new ConstantExpr( Constant::from_int( a ) ) );
    189191        delete &str;
    190192        return ret;
     
    223225} // build_field_name_REALDECIMALconstant
    224226
    225 NameExpr * build_varref( const string *name, bool labelp ) {
     227NameExpr * build_varref( const string *name ) {
    226228        NameExpr *expr = new NameExpr( *name, nullptr );
    227229        delete name;
     
    346348
    347349Expression *build_valexpr( StatementNode *s ) {
    348         return new UntypedValofExpr( maybeMoveBuild< Statement >(s), nullptr );
     350        return new StmtExpr( dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(s) ) );
    349351}
    350352Expression *build_typevalue( DeclarationNode *decl ) {
  • src/Parser/ParseNode.h

    re4d829b r579263a  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:28:16 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 17 15:42:18 2017
    13 // Update Count     : 777
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Jun 12 13:00:00 2017
     13// Update Count     : 779
    1414//
    1515
     
    166166Expression * build_field_name_REALDECIMALconstant( const std::string & str );
    167167
    168 NameExpr * build_varref( const std::string * name, bool labelp = false );
     168NameExpr * build_varref( const std::string * name );
    169169Expression * build_typevalue( DeclarationNode * decl );
    170170
     
    393393Statement * build_return( ExpressionNode * ctl );
    394394Statement * build_throw( ExpressionNode * ctl );
     395Statement * build_resume( ExpressionNode * ctl );
     396Statement * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
    395397Statement * build_try( StatementNode * try_stmt, StatementNode * catch_stmt, StatementNode * finally_stmt );
    396 Statement * build_catch( DeclarationNode * decl, StatementNode * stmt, bool catchAny = false );
     398Statement * build_catch( CatchStmt::Kind kind, DeclarationNode *decl, ExpressionNode *cond, StatementNode *body );
    397399Statement * build_finally( StatementNode * stmt );
    398400Statement * build_compound( StatementNode * first );
     
    413415                                result->location = cur->location;
    414416                                * out++ = result;
     417                        } else {
     418                                assertf(false, "buildList unknown type");
    415419                        } // if
    416420                } catch( SemanticError &e ) {
  • src/Parser/StatementNode.cc

    re4d829b r579263a  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 14:59:41 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  2 22:16:40 2017
    13 // Update Count     : 327
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Jun 12 13:03:00 2017
     13// Update Count     : 329
    1414//
    1515
     
    152152        return new ReturnStmt( noLabels, exps.size() > 0 ? exps.back() : nullptr );
    153153}
     154
    154155Statement *build_throw( ExpressionNode *ctl ) {
    155156        std::list< Expression * > exps;
    156157        buildMoveList( ctl, exps );
    157158        assertf( exps.size() < 2, "This means we are leaking memory");
    158         return new ReturnStmt( noLabels, !exps.empty() ? exps.back() : nullptr, true );
     159        return new ThrowStmt( noLabels, ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr );
     160}
     161
     162Statement *build_resume( ExpressionNode *ctl ) {
     163        std::list< Expression * > exps;
     164        buildMoveList( ctl, exps );
     165        assertf( exps.size() < 2, "This means we are leaking memory");
     166        return new ThrowStmt( noLabels, ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr );
     167}
     168
     169Statement *build_resume_at( ExpressionNode *ctl, ExpressionNode *target ) {
     170        (void)ctl;
     171        (void)target;
     172        assertf( false, "resume at (non-local throw) is not yet supported," );
    159173}
    160174
    161175Statement *build_try( StatementNode *try_stmt, StatementNode *catch_stmt, StatementNode *finally_stmt ) {
    162         std::list< Statement * > branches;
    163         buildMoveList< Statement, StatementNode >( catch_stmt, branches );
     176        std::list< CatchStmt * > branches;
     177        buildMoveList< CatchStmt, StatementNode >( catch_stmt, branches );
    164178        CompoundStmt *tryBlock = safe_dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(try_stmt));
    165179        FinallyStmt *finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_stmt) );
    166180        return new TryStmt( noLabels, tryBlock, branches, finallyBlock );
    167181}
    168 Statement *build_catch( DeclarationNode *decl, StatementNode *stmt, bool catchAny ) {
    169         std::list< Statement * > branches;
    170         buildMoveList< Statement, StatementNode >( stmt, branches );
    171         assert( branches.size() == 1 );
    172         return new CatchStmt( noLabels, maybeMoveBuild< Declaration >(decl), branches.front(), catchAny );
     182Statement *build_catch( CatchStmt::Kind kind, DeclarationNode *decl, ExpressionNode *cond, StatementNode *body ) {
     183        std::list< Statement * > branches;
     184        buildMoveList< Statement, StatementNode >( body, branches );
     185        assert( branches.size() == 1 );
     186        return new CatchStmt( noLabels, kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), branches.front() );
    173187}
    174188Statement *build_finally( StatementNode *stmt ) {
  • src/Parser/parser.yy

    re4d829b r579263a  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu May 25 15:21:59 2017
    13 // Update Count     : 2398
     12// Last Modified On : Mon Jun 12 12:59:00 2017
     13// Update Count     : 2402
    1414//
    1515
     
    193193%type<sn> case_value_list                               case_label                                      case_label_list
    194194%type<sn> switch_clause_list_opt                switch_clause_list                      choose_clause_list_opt          choose_clause_list
    195 %type<sn> handler_list                                  handler_clause                          finally_clause
     195%type<sn> /* handler_list */                    handler_clause                          finally_clause
    196196
    197197// declarations
     
    547547                { $$ = new ExpressionNode( build_attrtype( build_varref( $1 ), $3 ) ); }
    548548//      | ANDAND IDENTIFIER                                                                     // GCC, address of label
    549 //              { $$ = new ExpressionNode( new OperatorNode( OperKinds::LabelAddress ), new ExpressionNode( build_varref( $2, true ) ); }
     549//              { $$ = new ExpressionNode( new OperatorNode( OperKinds::LabelAddress ), new ExpressionNode( build_varref( $2 ) ); }
    550550        ;
    551551
     
    931931                { $$ = new StatementNode( build_throw( $2 ) ); }
    932932        | THROWRESUME assignment_expression_opt ';'                     // handles reresume
    933                 { $$ = new StatementNode( build_throw( $2 ) ); }
     933                { $$ = new StatementNode( build_resume( $2 ) ); }
    934934        | THROWRESUME assignment_expression_opt AT assignment_expression ';' // handles reresume
    935                 { $$ = new StatementNode( build_throw( $2 ) ); }
     935                { $$ = new StatementNode( build_resume_at( $2, $4 ) ); }
    936936        ;
    937937
    938938exception_statement:
    939         TRY compound_statement handler_list
     939        TRY compound_statement handler_clause
    940940                { $$ = new StatementNode( build_try( $2, $3, 0 ) ); }
    941941        | TRY compound_statement finally_clause
    942942                { $$ = new StatementNode( build_try( $2, 0, $3 ) ); }
    943         | TRY compound_statement handler_list finally_clause
     943        | TRY compound_statement handler_clause finally_clause
    944944                { $$ = new StatementNode( build_try( $2, $3, $4 ) ); }
    945945        ;
    946946
    947 handler_list:
    948         handler_clause
    949                 // ISO/IEC 9899:1999 Section 15.3(6 ) If present, a "..." handler shall be the last handler for its try block.
    950         | CATCH '(' ELLIPSIS ')' compound_statement
    951                 { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
    952         | handler_clause CATCH '(' ELLIPSIS ')' compound_statement
    953                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
    954         | CATCHRESUME '(' ELLIPSIS ')' compound_statement
    955                 { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
    956         | handler_clause CATCHRESUME '(' ELLIPSIS ')' compound_statement
    957                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
    958         ;
     947//handler_list:
     948//      handler_clause
     949//              // ISO/IEC 9899:1999 Section 15.3(6 ) If present, a "..." handler shall be the last handler for its try block.
     950//      | CATCH '(' ELLIPSIS ')' compound_statement
     951//              { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
     952//      | handler_clause CATCH '(' ELLIPSIS ')' compound_statement
     953//              { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
     954//      | CATCHRESUME '(' ELLIPSIS ')' compound_statement
     955//              { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
     956//      | handler_clause CATCHRESUME '(' ELLIPSIS ')' compound_statement
     957//              { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
     958//      ;
    959959
    960960handler_clause:
    961961        CATCH '(' push push exception_declaration pop ')' compound_statement pop
    962                 { $$ = new StatementNode( build_catch( $5, $8 ) ); }
     962                { $$ = new StatementNode( build_catch( CatchStmt::Terminate, $5, nullptr, $8 ) ); }
    963963        | handler_clause CATCH '(' push push exception_declaration pop ')' compound_statement pop
    964                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $6, $9 ) ) ); }
     964                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Terminate, $6, nullptr, $9 ) ) ); }
    965965        | CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop
    966                 { $$ = new StatementNode( build_catch( $5, $8 ) ); }
     966                { $$ = new StatementNode( build_catch( CatchStmt::Resume, $5, nullptr, $8 ) ); }
    967967        | handler_clause CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop
    968                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $6, $9 ) ) ); }
     968                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Resume, $6, nullptr, $9 ) ) ); }
    969969        ;
    970970
  • src/Parser/parseutility.cc

    re4d829b r579263a  
    1010// Created On       : Sat May 16 15:30:39 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug 14 23:45:03 2016
    13 // Update Count     : 3
     12// Last Modified On : Wed Jun 21 15:33:41 2017
     13// Update Count     : 5
    1414//
    1515
     
    2626        UntypedExpr *comparison = new UntypedExpr( new NameExpr( "?!=?" ) );
    2727        comparison->get_args().push_back( orig );
    28         comparison->get_args().push_back( new ConstantExpr( Constant( new ZeroType( emptyQualifiers ), "0" ) ) );
     28        comparison->get_args().push_back( new ConstantExpr( Constant( new ZeroType( emptyQualifiers ), "0", (unsigned long long int)0 ) ) );
    2929        return new CastExpr( comparison, new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    3030}
  • src/ResolvExpr/AlternativeFinder.cc

    re4d829b r579263a  
    9797                /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
    9898                template< typename InputIterator, typename OutputIterator >
    99                 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out, const SymTab::Indexer &indexer ) {
     99                void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
    100100                        // select the alternatives that have the minimum conversion cost for a particular set of result types
    101101                        std::map< std::string, PruneStruct > selected;
     
    183183                        )
    184184                        AltList::iterator oldBegin = alternatives.begin();
    185                         pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ), indexer );
     185                        pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) );
    186186                        if ( alternatives.begin() == oldBegin ) {
    187187                                std::ostringstream stream;
  • src/ResolvExpr/CommonType.cc

    re4d829b r579263a  
    157157        void CommonType::visit( PointerType *pointerType ) {
    158158                if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
    159                         if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base(), indexer) ) {
     159                        if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
    160160                                getCommonWithVoidPointer( otherPointer, pointerType );
    161                         } else if ( widenSecond && dynamic_cast< VoidType* >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base(), indexer) ) {
     161                        } else if ( widenSecond && dynamic_cast< VoidType* >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {
    162162                                getCommonWithVoidPointer( pointerType, otherPointer );
    163163                        } else if ( ( pointerType->get_base()->get_qualifiers() >= otherPointer->get_base()->get_qualifiers() || widenFirst )
  • src/ResolvExpr/PtrsCastable.cc

    re4d829b r579263a  
    135135        }
    136136
    137         void PtrsCastable::visit(TraitInstType *inst) {
    138                 // I definitely don't think we should be doing anything here
    139         }
     137        void PtrsCastable::visit( __attribute__((unused)) TraitInstType *inst ) {}
    140138
    141139        void PtrsCastable::visit(TypeInstType *inst) {
  • src/ResolvExpr/Unify.cc

    re4d829b r579263a  
    114114        }
    115115
    116         bool isFtype( Type *type, const SymTab::Indexer &indexer ) {
     116        bool isFtype( Type *type ) {
    117117                if ( dynamic_cast< FunctionType* >( type ) ) {
    118118                        return true;
     
    123123        }
    124124
    125         bool tyVarCompatible( const TypeDecl::Data & data, Type *type, const SymTab::Indexer &indexer ) {
     125        bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
    126126                switch ( data.kind ) {
    127127                  case TypeDecl::Any:
     
    131131                        // type must also be complete
    132132                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
    133                         return ! isFtype( type, indexer ) && (! data.isComplete || type->isComplete() );
     133                        return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
    134134                  case TypeDecl::Ftype:
    135                         return isFtype( type, indexer );
     135                        return isFtype( type );
    136136                  case TypeDecl::Ttype:
    137137                        // ttype unifies with any tuple type
     
    144144                OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
    145145                assert( tyvar != openVars.end() );
    146                 if ( ! tyVarCompatible( tyvar->second, other, indexer ) ) {
     146                if ( ! tyVarCompatible( tyvar->second, other ) ) {
    147147                        return false;
    148148                } // if
     
    388388        }
    389389
    390         void Unify::visit(VoidType *voidType) {
     390        void Unify::visit( __attribute__((unused)) VoidType *voidType) {
    391391                result = dynamic_cast< VoidType* >( type2 );
    392392        }
     
    683683
    684684        template< typename Iterator1, typename Iterator2 >
    685         bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     685        bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    686686                auto get_type = [](Type * t) { return t; };
    687687                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     
    733733                        flatten( flat2.get(), back_inserter( types2 ) );
    734734
    735                         result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, widenMode, indexer );
    736                 } // if
    737         }
    738 
    739         void Unify::visit(VarArgsType *varArgsType) {
     735                        result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );
     736                } // if
     737        }
     738
     739        void Unify::visit( __attribute__((unused)) VarArgsType *varArgsType ) {
    740740                result = dynamic_cast< VarArgsType* >( type2 );
    741741        }
    742742
    743         void Unify::visit(ZeroType *zeroType) {
     743        void Unify::visit( __attribute__((unused)) ZeroType *zeroType ) {
    744744                result = dynamic_cast< ZeroType* >( type2 );
    745745        }
    746746
    747         void Unify::visit(OneType *oneType) {
     747        void Unify::visit( __attribute__((unused)) OneType *oneType ) {
    748748                result = dynamic_cast< OneType* >( type2 );
    749749        }
  • src/ResolvExpr/typeops.h

    re4d829b r579263a  
    118118
    119119        // in Unify.cc
    120         bool isFtype( Type *type, const SymTab::Indexer &indexer );
     120        bool isFtype( Type *type );
    121121        bool typesCompatible( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );
    122122        bool typesCompatibleIgnoreQualifiers( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );
  • src/SymTab/Autogen.cc

    re4d829b r579263a  
    262262        // E ?=?(E volatile*, int),
    263263        //   ?=?(E _Atomic volatile*, int);
    264         void makeEnumFunctions( EnumDecl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
     264        void makeEnumFunctions( EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
    265265
    266266                // T ?=?(E *, E);
     
    486486
    487487        /// generates the body of a union assignment/copy constructor/field constructor
    488         void makeUnionAssignBody( FunctionDecl * funcDecl, bool isDynamicLayout ) {
     488        void makeUnionAssignBody( FunctionDecl * funcDecl ) {
    489489                FunctionType * ftype = funcDecl->get_functionType();
    490490                assert( ftype->get_parameters().size() == 2 );
     
    506506                // Make function polymorphic in same parameters as generic union, if applicable
    507507                const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
    508                 bool isDynamicLayout = hasDynamicLayout( aggregateDecl );  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct)
    509 
     508               
    510509                // default ctor/dtor need only first parameter
    511510                // void ?{}(T *); void ^?{}(T *);
     
    533532                FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
    534533
    535                 makeUnionAssignBody( assignDecl, isDynamicLayout );
     534                makeUnionAssignBody( assignDecl );
    536535
    537536                // body of assignment and copy ctor is the same
    538                 makeUnionAssignBody( copyCtorDecl, isDynamicLayout );
     537                makeUnionAssignBody( copyCtorDecl );
    539538
    540539                // create a constructor which takes the first member type as a parameter.
     
    551550                                FunctionDecl * ctor = genFunc( "?{}", memCtorType, functionNesting );
    552551
    553                                 makeUnionAssignBody( ctor, isDynamicLayout );
     552                                makeUnionAssignBody( ctor );
    554553                                memCtors.push_back( ctor );
    555554                                // only generate a ctor for the first field
     
    578577                        EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() );
    579578                        // enumInst->set_baseEnum( enumDecl );
    580                         makeEnumFunctions( enumDecl, enumInst, functionNesting, declsToAddAfter );
     579                        makeEnumFunctions( enumInst, functionNesting, declsToAddAfter );
    581580                }
    582581        }
  • src/SymTab/Autogen.h

    re4d829b r579263a  
    1010// Created On       : Sun May 17 21:53:34 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 17 09:10:41 2017
    13 // Update Count     : 9
     12// Last Modified On : Wed Jun 21 17:25:26 2017
     13// Update Count     : 14
    1414//
    1515
     
    4343        template< typename OutputIterator >
    4444        Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false ) {
    45                 // want to be able to generate assignment, ctor, and dtor generically,
    46                 // so fname is either ?=?, ?{}, or ^?{}
    47                 UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
     45        // want to be able to generate assignment, ctor, and dtor generically,
     46        // so fname is either ?=?, ?{}, or ^?{}
     47        UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
    4848
    49                 // do something special for unnamed members
    50                 dstParam = new AddressExpr( dstParam );
    51                 if ( addCast ) {
    52                         // cast to T* with qualifiers removed, so that qualified objects can be constructed
    53                         // and destructed with the same functions as non-qualified objects.
    54                         // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
    55                         // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
    56                         // remove lvalue as a qualifier, this can change to
    57                         //   type->get_qualifiers() = Type::Qualifiers();
    58                         assert( type );
    59                         Type * castType = type->clone();
    60 //                      castType->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, false);
    61                         castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
    62                         castType->set_lvalue( true ); // xxx - might not need this
    63                         dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) );
    64                 }
    65                 fExpr->get_args().push_back( dstParam );
     49        // do something special for unnamed members
     50        dstParam = new AddressExpr( dstParam );
     51        if ( addCast ) {
     52                // cast to T* with qualifiers removed, so that qualified objects can be constructed
     53                // and destructed with the same functions as non-qualified objects.
     54                // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
     55                // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
     56                // remove lvalue as a qualifier, this can change to
     57                //   type->get_qualifiers() = Type::Qualifiers();
     58                assert( type );
     59                Type * castType = type->clone();
     60                castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
     61                castType->set_lvalue( true ); // xxx - might not need this
     62                dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) );
     63        }
     64        fExpr->get_args().push_back( dstParam );
    6665
    67                 Statement * listInit = srcParam.buildListInit( fExpr );
     66        Statement * listInit = srcParam.buildListInit( fExpr );
    6867
    69                 std::list< Expression * > args = *++srcParam;
    70                 fExpr->get_args().splice( fExpr->get_args().end(), args );
     68        std::list< Expression * > args = *++srcParam;
     69        fExpr->get_args().splice( fExpr->get_args().end(), args );
    7170
    72                 *out++ = new ExprStmt( noLabels, fExpr );
     71        *out++ = new ExprStmt( noLabels, fExpr );
    7372
    74                 srcParam.clearArrayIndices();
     73        srcParam.clearArrayIndices();
    7574
    76                 return listInit;
     75        return listInit;
    7776        }
    7877
     
    8887                Expression * begin, * end, * update, * cmp;
    8988                if ( forward ) {
    90                         // generate: for ( int i = 0; i < 0; ++i )
    91                         begin = new ConstantExpr( Constant( new ZeroType( emptyQualifiers ), "0" ) );
     89                        // generate: for ( int i = 0; i < N; ++i )
     90                        begin = new ConstantExpr( Constant::from_int( 0 ) );
    9291                        end = array->get_dimension()->clone();
    9392                        cmp = new NameExpr( "?<?" );
     
    9796                        begin = new UntypedExpr( new NameExpr( "?-?" ) );
    9897                        ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() );
    99                         ((UntypedExpr*)begin)->get_args().push_back( new ConstantExpr( Constant( new OneType( emptyQualifiers ), "1" ) ) );
    100                         end = new ConstantExpr( Constant( new ZeroType( emptyQualifiers ), "0" ) );
     98                        ((UntypedExpr*)begin)->get_args().push_back( new ConstantExpr( Constant::from_int( 1 ) ) );
     99                        end = new ConstantExpr( Constant::from_int( 0 ) );
    101100                        cmp = new NameExpr( "?>=?" );
    102101                        update = new NameExpr( "--?" );
  • src/SymTab/ImplementationType.cc

    re4d829b r579263a  
    7676        }
    7777
    78         void ImplementationType::visit(FunctionType *functionType) {
    79 ///   FunctionType *newType = functionType->clone();
    80 ///   for ( std::list< DeclarationWithType* >::iterator i = newType->get_parameters().begin(); i != newType->get_parameters().end(); ++i ) {
    81 ///     i->set_type( implementationType( i->get_type(), indexer ) );
    82 ///   }
    83 ///   for ( std::list< DeclarationWithType* >::iterator i = newType->get_parameters().begin(); i != newType->get_parameters().end(); ++i ) {
    84 ///     i->set_type( implementationType( i->get_type(), indexer ) );
    85 ///   }
    86         }
    87 
     78        void ImplementationType::visit( __attribute__((unused)) FunctionType *functionType ) {}
    8879        void ImplementationType::visit( __attribute__((unused)) StructInstType * aggregateUseType ) {}
    8980        void ImplementationType::visit( __attribute__((unused)) UnionInstType * aggregateUseType ) {}
  • src/SymTab/Indexer.cc

    re4d829b r579263a  
    495495        }
    496496
    497         void Indexer::visit( UntypedValofExpr *valofExpr ) {
    498                 acceptNewScope( valofExpr->get_result(), *this );
    499                 maybeAccept( valofExpr->get_body(), *this );
    500         }
    501 
    502497        void Indexer::visit( RangeExpr *rangeExpr ) {
    503498                maybeAccept( rangeExpr->get_low(), *this );
     
    518513                acceptNewScope( tupleExpr->get_result(), *this );
    519514                maybeAccept( tupleExpr->get_tuple(), *this );
    520         }
    521 
    522         void Indexer::visit( MemberTupleExpr *tupleExpr ) {
    523                 acceptNewScope( tupleExpr->get_result(), *this );
    524                 maybeAccept( tupleExpr->get_member(), *this );
    525                 maybeAccept( tupleExpr->get_aggregate(), *this );
    526515        }
    527516
  • src/SymTab/Indexer.h

    re4d829b r579263a  
    6969                virtual void visit( ConstructorExpr * ctorExpr );
    7070                virtual void visit( CompoundLiteralExpr *compLitExpr );
    71                 virtual void visit( UntypedValofExpr *valofExpr );
    7271                virtual void visit( RangeExpr *rangeExpr );
    7372                virtual void visit( UntypedTupleExpr *tupleExpr );
    7473                virtual void visit( TupleExpr *tupleExpr );
    7574                virtual void visit( TupleIndexExpr *tupleExpr );
    76                 virtual void visit( MemberTupleExpr *tupleExpr );
    7775                virtual void visit( TupleAssignExpr *tupleExpr );
    7876                virtual void visit( StmtExpr * stmtExpr );
  • src/SymTab/Mangler.cc

    re4d829b r579263a  
    236236        }
    237237
    238         void Mangler::visit( ZeroType *zeroType ) {
     238        void Mangler::visit( __attribute__((unused)) ZeroType *zeroType ) {
    239239                mangleName << "Z";
    240240        }
    241241
    242         void Mangler::visit( OneType *oneType ) {
     242        void Mangler::visit( __attribute__((unused)) OneType *oneType ) {
    243243                mangleName << "O";
    244244        }
  • src/SymTab/Validate.cc

    re4d829b r579263a  
    106106
    107107        /// Fix return types so that every function returns exactly one value
    108         class ReturnTypeFixer {
    109           public:
     108        struct ReturnTypeFixer {
    110109                static void fix( std::list< Declaration * > &translationUnit );
    111110
     
    115114
    116115        /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers.
    117         class EnumAndPointerDecayPass final : public Visitor {
    118                 typedef Visitor Parent;
    119                 virtual void visit( EnumDecl *aggregateDecl );
    120                 virtual void visit( FunctionType *func );
     116        struct EnumAndPointerDecay {
     117                void previsit( EnumDecl *aggregateDecl );
     118                void previsit( FunctionType *func );
    121119        };
    122120
     
    126124          public:
    127125                LinkReferenceToTypes( bool doDebug, const Indexer *indexer );
    128           private:
    129126                using Parent::visit;
    130127                void visit( EnumInstType *enumInst ) final;
     
    136133                void visit( UnionDecl *unionDecl ) final;
    137134                void visit( TypeInstType *typeInst ) final;
    138 
     135          private:
    139136                const Indexer *indexer;
    140137
     
    147144        };
    148145
    149         /// Replaces array and function types in forall lists by appropriate pointer type
    150         class Pass3 final : public Indexer {
     146        /// Replaces array and function types in forall lists by appropriate pointer type and assigns each Object and Function declaration a unique ID.
     147        class ForallPointerDecay final : public Indexer {
    151148                typedef Indexer Parent;
    152149          public:
    153150                using Parent::visit;
    154                 Pass3( const Indexer *indexer );
    155           private:
     151                ForallPointerDecay( const Indexer *indexer );
     152
    156153                virtual void visit( ObjectDecl *object ) override;
    157154                virtual void visit( FunctionDecl *func ) override;
     
    160157        };
    161158
    162         class ReturnChecker {
    163           public:
     159        struct ReturnChecker : public WithGuards {
    164160                /// Checks that return statements return nothing if their return type is void
    165161                /// and return something if the return type is non-void.
    166162                static void checkFunctionReturns( std::list< Declaration * > & translationUnit );
    167           private:
     163
    168164                void previsit( FunctionDecl * functionDecl );
    169                 void postvisit( FunctionDecl * functionDecl );
    170165                void previsit( ReturnStmt * returnStmt );
    171166
    172167                typedef std::list< DeclarationWithType * > ReturnVals;
    173168                ReturnVals returnVals;
    174                 std::stack< ReturnVals > returnValsStack;
    175169        };
    176170
     
    208202        };
    209203
    210         class VerifyCtorDtorAssign {
    211         public:
     204        struct VerifyCtorDtorAssign {
    212205                /// ensure that constructors, destructors, and assignment have at least one
    213206                /// parameter, the first of which must be a pointer, and that ctor/dtors have no
     
    219212
    220213        /// ensure that generic types have the correct number of type arguments
    221         class ValidateGenericParameters {
    222         public:
     214        struct ValidateGenericParameters {
    223215                void previsit( StructInstType * inst );
    224216                void previsit( UnionInstType * inst );
    225217        };
    226218
    227         class ArrayLength {
    228         public:
     219        struct ArrayLength {
    229220                /// for array types without an explicit length, compute the length and store it so that it
    230221                /// is known to the rest of the phases. For example,
     
    239230        };
    240231
    241         class CompoundLiteral final : public GenPoly::DeclMutator {
     232        struct CompoundLiteral final : public WithDeclsToAdd, public WithVisitorRef<CompoundLiteral> {
    242233                Type::StorageClasses storageClasses;
    243234
    244                 using GenPoly::DeclMutator::mutate;
    245                 DeclarationWithType * mutate( ObjectDecl *objectDecl ) final;
    246                 Expression *mutate( CompoundLiteralExpr *compLitExpr ) final;
     235                void premutate( ObjectDecl *objectDecl );
     236                Expression * postmutate( CompoundLiteralExpr *compLitExpr );
    247237        };
    248238
    249239        void validate( std::list< Declaration * > &translationUnit, bool doDebug ) {
    250                 EnumAndPointerDecayPass epc;
     240                PassVisitor<EnumAndPointerDecay> epc;
    251241                LinkReferenceToTypes lrt( doDebug, 0 );
    252                 Pass3 pass3( 0 );
    253                 CompoundLiteral compoundliteral;
     242                ForallPointerDecay fpd( 0 );
     243                PassVisitor<CompoundLiteral> compoundliteral;
    254244                PassVisitor<ValidateGenericParameters> genericParams;
    255245
     
    262252                VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    263253                Concurrency::applyKeywords( translationUnit );
    264                 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecayPass
     254                autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay
    265255                Concurrency::implementMutexFuncs( translationUnit );
    266256                Concurrency::implementThreadStarter( translationUnit );
    267257                ReturnChecker::checkFunctionReturns( translationUnit );
    268                 compoundliteral.mutateDeclarationList( translationUnit );
    269                 acceptAll( translationUnit, pass3 );
     258                mutateAll( translationUnit, compoundliteral );
     259                acceptAll( translationUnit, fpd );
    270260                ArrayLength::computeLength( translationUnit );
    271261        }
    272262
    273263        void validateType( Type *type, const Indexer *indexer ) {
    274                 EnumAndPointerDecayPass epc;
     264                PassVisitor<EnumAndPointerDecay> epc;
    275265                LinkReferenceToTypes lrt( false, indexer );
    276                 Pass3 pass3( indexer );
     266                ForallPointerDecay fpd( indexer );
    277267                type->accept( epc );
    278268                type->accept( lrt );
    279                 type->accept( pass3 );
     269                type->accept( fpd );
    280270        }
    281271
     
    356346        }
    357347
    358         void EnumAndPointerDecayPass::visit( EnumDecl *enumDecl ) {
     348        void EnumAndPointerDecay::previsit( EnumDecl *enumDecl ) {
    359349                // Set the type of each member of the enumeration to be EnumConstant
    360350                for ( std::list< Declaration * >::iterator i = enumDecl->get_members().begin(); i != enumDecl->get_members().end(); ++i ) {
     
    363353                        obj->set_type( new EnumInstType( Type::Qualifiers( Type::Const ), enumDecl->get_name() ) );
    364354                } // for
    365                 Parent::visit( enumDecl );
    366355        }
    367356
     
    370359                void fixFunctionList( DWTList & dwts, FunctionType * func ) {
    371360                        // the only case in which "void" is valid is where it is the only one in the list; then it should be removed
    372                         // entirely other fix ups are handled by the FixFunction class
     361                        // entirely. other fix ups are handled by the FixFunction class
    373362                        typedef typename DWTList::iterator DWTIterator;
    374363                        DWTIterator begin( dwts.begin() ), end( dwts.end() );
     
    389378                                for ( ; i != end; ++i ) {
    390379                                        FixFunction fixer;
    391                                         *i = (*i )->acceptMutator( fixer );
     380                                        *i = (*i)->acceptMutator( fixer );
    392381                                        if ( fixer.get_isVoid() ) {
    393382                                                throw SemanticError( "invalid type void in function type ", func );
     
    398387        }
    399388
    400         void EnumAndPointerDecayPass::visit( FunctionType *func ) {
     389        void EnumAndPointerDecay::previsit( FunctionType *func ) {
    401390                // Fix up parameters and return types
    402391                fixFunctionList( func->get_parameters(), func );
    403392                fixFunctionList( func->get_returnVals(), func );
    404                 Visitor::visit( func );
    405393        }
    406394
     
    549537        }
    550538
    551         Pass3::Pass3( const Indexer *other_indexer ) :  Indexer( false ) {
     539        ForallPointerDecay::ForallPointerDecay( const Indexer *other_indexer ) :  Indexer( false ) {
    552540                if ( other_indexer ) {
    553541                        indexer = other_indexer;
     
    587575        }
    588576
    589         void Pass3::visit( ObjectDecl *object ) {
     577        void ForallPointerDecay::visit( ObjectDecl *object ) {
    590578                forallFixer( object->get_type() );
    591579                if ( PointerType *pointer = dynamic_cast< PointerType * >( object->get_type() ) ) {
     
    596584        }
    597585
    598         void Pass3::visit( FunctionDecl *func ) {
     586        void ForallPointerDecay::visit( FunctionDecl *func ) {