Changes in / [b110bcc:2ed94a9]


Ignore:
Files:
5 added
227 deleted
179 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/Promote

    rb110bcc r2ed94a9  
    3636                dir (BuildDir) {
    3737                    sh 'rm -rf *'
    38                         sshagent (credentials: ['git_key_mar27']) {
     38                        sshagent (credentials: ['github_key_jun1']) {
    3939                                sh "git clone --bare ${RemoteRepo} repo"
    4040                        }
     
    6969                        sh "git status"
    7070                        sh "git diff-index --quiet HEAD || git commit -m 'Push from build machine: ${name}'"
    71                         sshagent (credentials: ['git_key_mar27']) {
     71                        sshagent (credentials: ['github_key_jun1']) {
    7272                                sh "git push origin master"
    7373                        }
  • doc/LaTeXmacros/common.sty

    rb110bcc r2ed94a9  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Tue Apr  4 12:03:19 2023
    14 %% Update Count     : 585
     13%% Last Modified On : Sat Apr  2 17:35:23 2022
     14%% Update Count     : 570
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    3030\setlist[itemize,1]{label=\textbullet}% local
    3131%\renewcommand{\labelitemi}{{\raisebox{0.25ex}{\footnotesize$\bullet$}}}
    32 \setlist[enumerate]{topsep=0.5ex,parsep=0.25ex,itemsep=0.25ex,listparindent=\parindent}% global
     32\setlist[enumerate]{listparindent=\parindent}% global
    3333\setlist[enumerate,2]{leftmargin=\parindent,labelsep=*,align=parleft,label=\alph*.}% local
    3434\setlist[description]{topsep=0.5ex,itemsep=0pt,listparindent=\parindent,leftmargin=\parindent,labelsep=1.5ex}
     
    4949\newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace}   % C++17 symbolic name
    5050\newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace}              % C++20 symbolic name
    51 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name
     51\newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}\xspace} % C# symbolic name
    5252
    5353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    5454
    55 \usepackage[scaled=0.85]{helvet}                                                % descent Helvetica font and scale to times size
    56 \usepackage[T1]{fontenc}
     55\usepackage{pslatex}                                                                    % reduce size of san serif font
    5756\usepackage{relsize}                                                                    % must be after change to small or selects old size
    5857\usepackage{rotating}
     
    196195\newcommand{\viz}{\VIZ\CheckPeriod}
    197196
    198 \newcommand{\VS}{\abbrevFont{vs}}
    199 \newcommand{\vs}{\VS\CheckPeriod}
    200 
    201197\newenvironment{cquote}{%
    202198        \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
     
    248244\renewcommand{\reftextpagerange}[2]{\unskip, pp.~\pageref{#1}--\pageref{#2}}
    249245\newcommand{\VRef}[2][Section]{\ifx#1\@empty\else{#1}\nobreakspace\fi\vref{#2}}
    250 \newcommand{\VRefrange}[3][Sections]{\ifx#1\@empty\else{#1}\nobreakspace\fi\vrefrange{#2}{#3}}
    251246\newcommand{\VPageref}[2][page]{\ifx#1\@empty\else{#1}\nobreakspace\fi\pageref{#2}}
    252 \newcommand{\VPagerefrange}[3][pages]{\ifx#1\@empty\else{#1}\nobreakspace\fi\pageref{#2}{#3}}
    253247
    254248\let\Oldthebibliography\thebibliography
     
    266260\newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
    267261\newcommand{\LstStringStyle}[1]{{\lst@basicstyle{\lst@stringstyle{#1}}}}
    268 \newcommand{\LstNumberStyle}[1]{{\lst@basicstyle{\lst@numberstyle{#1}}}}
    269262
    270263\newlength{\gcolumnposn}                                % temporary hack because lstlisting does not handle tabs correctly
     
    287280columns=fullflexible,
    288281basicstyle=\linespread{0.9}\sf,                 % reduce line spacing and use sanserif font
    289 stringstyle=\small\tt,                                  % use typewriter font
     282stringstyle=\tt,                                                % use typewriter font
    290283tabsize=5,                                                              % N space tabbing
    291284xleftmargin=\parindentlnth,                             % indent code to paragraph indentation
  • doc/LaTeXmacros/common.tex

    rb110bcc r2ed94a9  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Tue Apr  4 12:03:18 2023
    14 %% Update Count     : 567
     13%% Last Modified On : Tue Apr 26 16:02:48 2022
     14%% Update Count     : 558
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    4949\newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace}   % C++17 symbolic name
    5050\newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace}              % C++20 symbolic name
    51 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name
     51\newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}\xspace} % C# symbolic name
    5252
    5353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    5454
    55 \usepackage[scaled=0.85]{helvet}                                                % descent Helvetica font and scale to times size
    56 \usepackage[T1]{fontenc}
     55\usepackage{pslatex}                                                                    % reduce size of san serif font
    5756\usepackage{relsize}                                                                    % must be after change to small or selects old size
    5857\usepackage{rotating}
     
    197196\newcommand{\viz}{\VIZ\CheckPeriod}
    198197
    199 \newcommand{\VS}{\abbrevFont{vs}}
    200 \newcommand{\vs}{\VS\CheckPeriod}
    201198\makeatother
    202199
     
    269266\newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
    270267\newcommand{\LstStringStyle}[1]{{\lst@basicstyle{\lst@stringstyle{#1}}}}
    271 \newcommand{\LstNumberStyle}[1]{{\lst@basicstyle{\lst@numberstyle{#1}}}}
    272268
    273269\newlength{\gcolumnposn}                                % temporary hack because lstlisting does not handle tabs correctly
     
    291287columns=fullflexible,
    292288basicstyle=\linespread{0.9}\sf,                 % reduce line spacing and use sanserif font
    293 stringstyle=\small\tt,                                  % use typewriter font
     289stringstyle=\tt,                                                % use typewriter font
    294290tabsize=5,                                                              % N space tabbing
    295291xleftmargin=\parindentlnth,                             % indent code to paragraph indentation
  • doc/bibliography/pl.bib

    rb110bcc r2ed94a9  
    147147    author      = {Zhang, Yizhou and Salvaneschi, Guido and Beightol, Quinn and Liskov, Barbara and Myers, Andrew C.},
    148148    title       = {Accepting Blame for Safe Tunneled Exceptions},
    149     organization= {Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation},
     149    booktitle   = {Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation},
    150150    series      = {PLDI'16},
    151151    year        = {2016},
     
    196196   },
    197197   comment      = {Mentions Thoth in reference to delegation}
    198 }
    199 
    200 @misc{ActorBenchmarks,
    201     keywords    = {Actors, microbenchmarks, uC++. CAF, AkkaC, AkkaT, ProtoActor},
    202     contributer = {pabuhr@plg},
    203     key         = {ActorBenchmarks},
    204     title       = {Actor Benchmarks},
    205     author      = {Peter A. Buhr and Colby A. Parsons},
    206     howpublished= {\href{https://github.com/pabuhr/ActorExperiments}{https://\-github.com/\-pabuhr/\-ActorExperiments}},
    207     year        = 2022,
    208198}
    209199
     
    255245}
    256246
    257 @manual{Ada95,
    258     keywords    = {Ada},
    259     contributer = {pabuhr@plg},
    260     title       = {{A}da Reference Manual},
    261     edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
    262     organization= {Intermetrics, Inc.},
    263     month       = dec,
    264     year        = 1995,
    265     note        = {Language and Standards Libraries}
    266 }
    267 
    268 @manual{Ada12,
    269     keywords    = {ISO/IEC Ada},
    270     contributer = {pabuhr@plg},
    271     author      = {Ada12},
    272     title       = {Programming languages -- {Ada} ISO/IEC 8652:2012},
    273     edition     = {3rd},
    274     organization= {International Standard Organization},
    275     address     = {Geneva, Switzerland},
    276     year        = 2012,
    277     note        = {\href{https://www.iso.org/standard/61507.html}{https://\-www.iso.org/\-standard/\-61507.html}},
    278 }
    279 
    280 @manual{Ada95:annotated,
    281     keywords    = {Ada},
    282     contributer = {pabuhr@plg},
    283     title       = {Annotated {A}da Reference Manual},
    284     edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
    285     organization= {Intermetrics, Inc.},
    286     month       = dec,
    287     year        = 1995,
    288     note        = {Language and Standards Libraries}
    289 }
    290 
    291247@article{dim:ada,
    292248    keywords    = {Dimensional Analysis, Ada},
     
    300256    number      = 2,
    301257    pages       = {189-203},
    302 }
    303 
    304 @article{Agrawal08,
    305     keywords    = {Adaptive scheduling, adversary, instantaneous parallelism, job scheduling, multiprocessing, multiprogramming, parallel computation, parallelism feedback, processor allocation, randomized algorithm, space sharing, span, thread scheduling, trim analysis, two-level scheduling, work, work-stealing},
    306     author      = {Agrawal, Kunal and Leiserson, Charles E. and He, Yuxiong and Hsu, Wen Jing},
    307     title       = {Adaptive Work-stealing with Parallelism Feedback},
    308     journal     = {ACM Trans. Comput. Syst.},
    309     issue_date  = {September 2008},
    310     volume      = {26},
    311     number      = {3},
    312     month       = sep,
    313     year        = {2008},
    314     pages       = {7:1-7:32},
    315     publisher   = {ACM},
    316     address     = {New York, NY, USA},
    317258}
    318259
     
    436377    year        = 2016,
    437378    note        = {\href{http://doc.akka.io/docs/akka/2.4/AkkaScala.pdf}{http://\-doc.akka.io/\-docs/\-akka/\-2.4/\-AkkaScala.pdf}},
    438 }
    439 
    440 @misc{AkkaFuture,
    441     contributer = {pabuhr@plg},
    442     key         = {AkkaFuture},
    443     title       = {Akka Futures},
    444     author      = {{Lightbend}},
    445     howpublished= {\href{https://doc.akka.io/docs/akka/2.5/futures.html}{https://\-doc.akka.io/\-docs/\-akka/\-2.5/\-futures.html}},
    446     year        = 2022,
    447379}
    448380
     
    616548}
    617549
    618 @inproceedings{Mitzenmacher98,
    619     author      = {Mitzenmacher, Michael},
    620     title       = {Analyses of Load Stealing Models Based on Differential Equations},
    621     organization= {Proceedings of the Tenth Annual ACM Symposium on Parallel Algorithms and Architectures},
    622     series      = {SPAA '98},
    623     year        = {1998},
    624     isbn        = {0-89791-989-0},
    625     location    = {Puerto Vallarta, Mexico},
    626     pages       = {212-221},
    627     publisher   = {ACM},
    628     address     = {New York, NY, USA},
    629 }
    630 
    631 @inproceedings{Squillante91,
    632     author      = {Squillante, Mark S. and Nelson, Randolph D.},
    633     title       = {Analysis of Task Migration in Shared-memory Multiprocessor Scheduling},
    634     organization= {Proceedings of the 1991 ACM SIGMETRICS Conference on Measurement and Modeling of Computer Systems},
    635     series      = {SIGMETRICS '91},
    636     year        = {1991},
    637     isbn        = {0-89791-392-2},
    638     location    = {San Diego, California, USA},
    639     pages       = {143-155},
    640     publisher   = {ACM},
    641     address     = {New York, NY, USA},
    642 }
    643 
    644550@article{Sinha00,
    645551    author      = {Saurabh Sinha and Mary Jean Harrold},
     
    656562    author      = {Martin P. Robillard and Gail C. Murphy},
    657563    title       = {Analyzing Exception Flow in {J}ava Programs},
    658     organization= {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly
     564    booktitle   = {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly
    659565                   with the 7th ACM SIGSOFT International Symposium on Foundations of Software Engineering},
    660566    year        = 1999,
     
    698604    author      = {Henry Qin and Qian Li and Jacqueline Speiser and Peter Kraft and John Ousterhout},
    699605    title       = {Arachne: Core-Aware Thread Management},
    700     organization= {13th {USENIX} Symp. on Oper. Sys. Design and Impl. ({OSDI} 18)},
     606    booktitle   = {13th {USENIX} Symp. on Oper. Sys. Design and Impl. ({OSDI} 18)},
    701607    year        = {2018},
    702608    address     = {Carlsbad, CA},
     
    755661    author      = {Jaewoong Chung and Luke Yen and Stephan Diestelhorst and Martin Pohlack and Michael Hohmuth and David Christie and Dan Grossman},
    756662    title       = {ASF: AMD64 Extension for Lock-Free Data Structures and Transactional Memory},
    757     organization= {Proceedings of the 2010 43rd Annual IEEE/ACM International Symposium on Microarchitecture},
     663    booktitle   = {Proceedings of the 2010 43rd Annual IEEE/ACM International Symposium on Microarchitecture},
    758664    series      = {MICRO '43},
    759665    year        = 2010,
     
    776682}
    777683
    778 @misc{AsyncAwait,
    779     contributer = {pabuhr@plg},
    780     key         = {AsyncAwait},
    781     title       = {Async Await},
    782     author      = {{WikipediA}},
    783     howpublished= {\href{https://en.wikipedia.org/wiki/Async/await}{https://\-en.wikipedia.org/\-wiki/\-Async/\-await}},
    784     year        = 2022,
    785 }
    786 
    787684@inproceedings{Krischer08,
    788685    keywords    = {exception handling, asynchronous, blocked tasks},
     
    790687    author      = {Roy Krischer and Peter A. Buhr},
    791688    title       = {Asynchronous Exception Propagation in Blocked Tasks},
    792     organization= {4th International Workshop on Exception Handling (WEH.08)},
     689    booktitle   = {4th International Workshop on Exception Handling (WEH.08)},
    793690    optorganization= {16th International Symposium on the Foundations of Software Engineering (FSE 16)},
    794691    address     = {Atlanta, U.S.A},
     
    799696
    800697@article{Joung00,
    801     keywords    = {group mutual exclusion, congenial talking philosophers, resource allocation, shared-memory algorithms},
    802698    author      = {Joung, Yuh-Jzer},
    803699    title       = {Asynchronous group mutual exclusion},
     
    863759    publisher   = {ACM},
    864760    address     = {New York, NY, USA},
    865 }
    866 
    867 @techreport{Neill09,
    868     author      = {Daniel Neill and Adam Wierman},
    869     title       = {On the Benefits of Work Stealing in Shared-Memory Multiprocessors},
    870     institution = {Carnegie Mellon University},
    871     address     = {California Institute of Technology, Pasadena, CA, USA},
    872     note        = {\href{http://www.cs.cmu.edu/~acw/15740/paper.pdf}{http://\-www.cs.cmu.edu/\-$\sim$acw/\-15740/\-paper.pdf}, Accessed May 2014},
    873     year        = 2009,
    874761}
    875762
     
    1029916}
    1030917
    1031 @inproceedings{Ding12,
    1032     keywords    = {fairness, multicore, time sharing, work stealing},
    1033     author      = {Ding, Xiaoning and Wang, Kaibo and Gibbons, Phillip B. and Zhang, Xiaodong},
    1034     title       = {BWS: Balanced Work Stealing for Time-sharing Multicores},
    1035     organization= {Proceedings of the 7th ACM European Conference on Computer Systems},
    1036     series      = {EuroSys '12},
    1037     year        = {2012},
    1038     location    = {Bern, Switzerland},
    1039     pages       = {365-378},
    1040     publisher   = {ACM},
    1041     address     = {New York, NY, USA},
    1042 }
    1043 
    1044918% C
    1045919
     
    1114988    year        = 2015,
    1115989    note        = {\href{https://www.iso.org/standard/64031.html}{https://\-www.iso.org/\-standard/\-64031.html}},
    1116 }
    1117 
    1118 @inproceedings{CAF,
    1119     keywords    = {performance measurement, actor model, c++, message-oriented middleware, distributed debugging},
    1120     author      = {Charousset, Dominik and Hiesgen, Raphael and Schmidt, Thomas C.},
    1121     title       = {{CAF} - the {C}++ Actor Framework for Scalable and Resource-Efficient Applications},
    1122     publisher   = {ACM},
    1123     address     = {New York, NY, USA},
    1124     organization= {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
    1125     pages       = {15-28},
    1126     numpages    = {14},
    1127     location    = {Portland, Oregon, USA},
    1128     series      = {AGERE'14},
    1129     year        = {2014},
    1130990}
    1131991
     
    13121172@techreport{Prokopec11,
    13131173    keywords    = {ctrie, concurrent map},
    1314     contributer = {a3moss@uwaterloo.ca},
     1174    contributer = {a3moss@uwaterloo.ca},
    13151175    title       = {Cache-aware lock-free concurrent hash tries},
    13161176    author      = {Prokopec, Aleksandar and Bagwell, Phil and Odersky, Martin},
     
    16361496    author      = {Emery D. Berger and Benjamin G. Zorn and Kathryn S. McKinley},
    16371497    title       = {Composing High-Performance Memory Allocators},
    1638     organization= {{SIGPLAN} Conference on Programming Language Design and Implementation},
     1498    booktitle   = {{SIGPLAN} Conference on Programming Language Design and Implementation},
    16391499    pages       = {114-124},
    16401500    year        = 2001,
     
    21361996    address     = {Eindhoven, Neth.},
    21371997    year        = 1965,
    2138     optnote     = {Reprinted in \cite{Genuys68} pp. 43--112.},
    2139     note        = {\url{https://pure.tue.nl/ws/files/4279816/344354178746665.pdf}},
     1998    note        = {Reprinted in \cite{Genuys68} pp. 43--112.}
    21401999}
    21412000
     
    21442003    author      = {Adya, Atul and Howell, Jon and Theimer, Marvin and Bolosky, William J. and Douceur, John R.},
    21452004    title       = {Cooperative Task Management Without Manual Stack Management},
    2146     organization= {Proc. of the General Track USENIX Tech. Conf.},
     2005    booktitle   = {Proc. of the General Track USENIX Tech. Conf.},
    21472006    series      = {ATEC '02},
    21482007    year        = {2002},
     
    22522111    year        = 2016,
    22532112    note        = {\href{http://dlang.org/spec/spec.html}{http://\-dlang.org/\-spec/\-spec.html}},
    2254 }
    2255 
    2256 @article{Acar02,
    2257     author      = {Acar, Umut A. and Blelloch, Guy E. and Blumofe, Robert D.},
    2258     title       = {The Data Locality of Work Stealing},
    2259     journal     = {Theory of Computing Systems},
    2260     volume      = {35},
    2261     number      = {3},
    2262     year        = {2002},
    2263     publisher   = {Springer-Verlag},
    2264     pages       = {321-347},
    22652113}
    22662114
     
    25222370    editor      = {R. E. A. Mason},
    25232371    organization= {IFIP},
    2524     publisher   = {North-Holland},
    2525     summary     = {
     2372    publisher = {North-Holland},
     2373    summary = {
    25262374        Packages group related declarations or subprograms, and encapsulate
    25272375        data types.  Separate interfaces and bodies promotes information
     
    27502598    address     = {Waterview Corporate Center, 20 Waterview Boulevard, Parsippany, NJ 07054},
    27512599    year        = {1993}
    2752 }
    2753 
    2754 @inproceedings{Chen14,
    2755     keywords    = {Core allocation, Multi-programmed, Work-stealing},
    2756     author      = {Chen, Quan and Zheng, Long and Guo, Minyi},
    2757     title       = {DWS: Demand-aware Work-Stealing in Multi-programmed Multi-core Architectures},
    2758     organization= {Proceedings of Programming Models and Applications on Multicores and Manycores},
    2759     series      = {PMAM'14},
    2760     year        = {2007},
    2761     location    = {Orlando, FL, USA},
    2762     pages       = {131:131-131:139},
    2763     articleno   = {131},
    2764     numpages    = {9},
    2765     publisher   = {ACM},
    2766     address     = {New York, NY, USA},
    27672600}
    27682601
     
    27982631    year        = 2003,
    27992632    pages       = {29-35},
    2800 }
    2801 
    2802 @inproceedings{Hamidzadeh96,
    2803     keywords    = {processor scheduling, resource allocation, shared memory systems, average memory referencing delay},
    2804     author      = {Hamidzadeh, B. and Lilja, D.J.},
    2805     booktitle   = {Distributed Computing Systems, 1996., Proceedings of the 16th International Conference on},
    2806     title       = {Dynamic scheduling strategies for shared-memory multiprocessors},
    2807     year        = {1996},
    2808     month       = {May},
    2809     pages       = {208-215},
    2810 }
    2811 
    2812 @article{Hendler06,
    2813     keywords    = {Concurrent programming; Load balancing; Work stealing; Lock-free; Data structures},
    2814     author      = {Hendler, Danny and Lev, Yossi and Moir, Mark and Shavit, Nir},
    2815     title       = {A dynamic-sized nonblocking work stealing deque},
    2816     journal     = {Distributed Computing},
    2817     volume      = {18},
    2818     number      = {3},
    2819     year        = {2006},
    2820     publisher   = {Springer-Verlag},
    2821     pages       = {189-207},
    28222633}
    28232634
     
    29232734}
    29242735
    2925 @inproceedings{Blelloch04,
    2926     keywords    = {chip multiprocessors, multithreaded architectures, scheduling algorithms, shared cache},
    2927     author      = {Blelloch, Guy E. and Gibbons, Phillip B.},
    2928     title       = {Effectively Sharing a Cache Among Threads},
    2929     organization= {Proceedings of the Sixteenth Annual ACM Symposium on Parallelism in Algorithms and Architectures},
    2930     series      = {SPAA '04},
    2931     year        = {2004},
    2932     location    = {Barcelona, Spain},
    2933     pages       = {235-244},
    2934     publisher   = {ACM},
    2935     address     = {New York, NY, USA},
    2936 }
    2937 
    29382736@techreport{Habermann80,
    29392737    keywords    = {Ada, threads},
     
    30102808    title       = {Encapsulation and Inheritance in Object-Oriented Programming Languages},
    30112809    journal     = sigplan,
    3012     volume      = {21},
    3013     number      = {11},
     2810    volume      = {21},    number = {11},
    30142811    pages       = {38-45},
    3015     month       = nov,
    3016     year        = 1986,
     2812    month       = nov, year = 1986,
    30172813    comment     = {
    30182814        Client, child interfaces should be distinct.  Child interface
     
    30702866}
    30712867
    3072 @inproceedings{Ribic14,
    3073     keywords    = {dvfs, energy efficiency, language runtimes, thread management, work stealing},
    3074     author      = {Ribic, Haris and Liu, Yu David},
    3075     title       = {Energy-efficient Work-stealing Language Runtimes},
    3076     organization= {Proceedings of the 19th International Conference on Architectural Support for Programming Languages and Operating Systems},
    3077     series      = {ASPLOS '14},
    3078     year        = {2014},
    3079     location    = {Salt Lake City, Utah, USA},
    3080     pages       = {513-528},
    3081     publisher   = {ACM},
    3082     address     = {New York, NY, USA},
    3083 }
    3084 
    30852868@manual{EPT,
    30862869    keywords    = {concurrency, light-weight threads},
     
    31202903    publisher   = {North Oxford Academic},
    31212904    year        = 1985
    3122 }
    3123 
    3124 @article{Torrellas95,
    3125     author      = {J. Torrellas and A. Tucker and A. Gupta},
    3126     title       = {Evaluating the Performance of Cache-Affinity Scheduling in Shared-Memory Multiprocessors},
    3127     journal     = {Journal of Parallel and Distributed Computing},
    3128     volume      = {24},
    3129     number      = {2},
    3130     pages       = {139-151},
    3131     year        = {1995},
    31322905}
    31332906
     
    38413614    author      = {Robert Griesemer and Rob Pike and Ken Thompson},
    38423615    title       = {{Go} Programming Language},
    3843     address     = {Mountain View, CA, USA},
    38443616    organization= {Google},
    38453617    year        = 2009,
     
    39533725@article{Michael04a,
    39543726    keywords    = {Lock-free, synchronization, concurrent programming, memory management, multiprogramming, dynamic data structures},
    3955     contributer = {pabuhr@plg},
    39563727    author      = {Maged M. Michael},
    39573728    title       = {Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects},
     
    39643735    publisher   = {IEEE Press},
    39653736    address     = {Piscataway, NJ, USA},
    3966 }
    3967 
    3968 @inproceedings{Johansson02,
    3969     keywords    = {concurrent languages, erlang, garbage collection, message passing, runtime systems},
    3970     contributer = {pabuhr@plg},
    3971     author      = {Erik Johansson and Konstantinos Sagonas and Jesper Wilhelmsson},
    3972     title       = {Heap Architectures for Concurrent Languages Using Message Passing},
    3973     year        = {2002},
    3974     isbn        = {1581135394},
    3975     publisher   = {ACM},
    3976     address     = {New York, NY, USA},
    3977     organization= {Proceedings of the 3rd International Symposium on Memory Management},
    3978     pages       = {88-99},
    3979     location    = {Berlin, Germany},
    39803737}
    39813738
     
    41603917    year        = {1994},
    41613918    pages       = {64-69},
    4162 }
    4163 
    4164 @inproceedings{Halstead84,
    4165     author      = {Halstead,Jr., Robert H.},
    4166     title       = {Implementation of Multilisp: Lisp on a Multiprocessor},
    4167     organization= {Proceedings of the 1984 ACM Symposium on LISP and Functional Programming},
    4168     series      = {LFP '84},
    4169     year        = {1984},
    4170     location    = {Austin, Texas, USA},
    4171     pages       = {9-17},
    4172     publisher   = {ACM},
    4173     address     = {New York, NY, USA},
    41743919}
    41753920
     
    49504695    contributer = {pabuhr@plg},
    49514696    author      = {Lua},
    4952     title       = {Lua 5.4 Reference Manual},
    4953     organization= {Pontifical Catholic University},
    4954     address     = {\href{https://www.lua.org/manual/5.4}{https://\-www.lua.org/\-manual/\-5.4}},
    4955     year        = 2020,
     4697    title       = {Lua 5.3 Reference Manual},
     4698    address     = {\href{https://www.lua.org/manual/5.3}{https://\-www.lua.org/\-manual/\-5.3}},
     4699    year        = 2018,
    49564700}
    49574701
     
    55335277        Programming Language},
    55345278    year        = 1980,
    5535     month       = dec,
    5536     pages       = {139-145},
     5279    month       = dec, pages = {139-145},
    55375280    note        = {SIGPLAN Notices, v. 15, n. 11},
    55385281    abstract    = {
     
    56555398    year        = 2005,
    56565399    pages       = {146-196},
    5657     publisher   = {ACM},
    5658     address     = {New York, NY, USA},
    5659 }
    5660 
    5661 @inproceedings{Hendler02,
    5662     author      = {Hendler, Danny and Shavit, Nir},
    5663     title       = {Non-blocking Steal-half Work Queues},
    5664     organization= {Proceedings of the Twenty-first Annual Symposium on Principles of Distributed Computing},
    5665     series      = {PODC '02},
    5666     year        = {2002},
    5667     location    = {Monterey, California},
    5668     pages       = {280-289},
    56695400    publisher   = {ACM},
    56705401    address     = {New York, NY, USA},
     
    59155646}
    59165647
    5917 @misc{OpenTelemetry,
    5918     contributer = {pabuhr@plg},
    5919     key         = {OpenTelemetry},
    5920     title       = {OpenTelemetry},
    5921     author      = {{Asynkron AB}},
    5922     howpublished= {\href{https://proto.actor/docs/tracing}{https://\-proto.actor/\-docs/\-tracing}},
    5923     year        = 2022,
    5924 }
    5925 
    59265648@inproceedings{Krebbers14,
    59275649    keywords    = {c formalization},
     
    61615883}
    61625884
    6163 @article{Nigro21,
    6164     keywords    = {Actors, Asynchronous messages, Reflective control on message passing, Lock-free parallel computing, Java, Scalable multi-agent systems, Parallel matrix multiplication, Iterated Prisoner's Dilemma},
    6165     contributer = {pabuhr@plg},
    6166     author      = {Libero Nigro},
    6167     title       = {Parallel Theatre: An actor framework in {Java} for high performance computing},
    6168     journal     = {Simulation Modelling Practice and Theory},
    6169     volume      = {106},
    6170     number      = {102189},
    6171     year        = {2021},
    6172 }
    6173 
    61745885@incollection{Stroustrup96,
    61755886    keywords    = {concurrency, C++},
     
    62065917    journal     = ieeese,
    62075918    year        = 1984,
    6208     month       = sep,
    6209     volume      = "SE-10",
    6210     number      = 5,
    6211     pages       = {528-543},
     5919    month       = sep, volume = "SE-10", number = 5, pages = {528-543},
    62125920    abstract    = {
    62135921        Parameterized programming is a powerful technique for the reliable
     
    62415949    booktitle   = {USENIX {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Conference},
    62425950    organization= {USENIX Association},
    6243     year        = 1988,
    6244     pages       = {1-18},
     5951    year        = 1988, pages = {1-18}
    62455952}
    62465953
     
    63306037}
    63316038
    6332 @incollection{Kazempour08,
    6333     keywords    = {multicore processors; cache affinity; performance evaluation; scheduling},
    6334     author      = {Kazempour, Vahid and Fedorova, Alexandra and Alagheband, Pouya},
    6335     title       = {Performance Implications of Cache Affinity on Multicore Processors},
    6336     organization= {Euro-Par 2008 -- Parallel Processing},
    6337     series      = {Lecture Notes in Computer Science},
    6338     editor      = {Luque, Emilio and Margalef, Tomas and Benitez, Domingo},
    6339     year        = {2008},
    6340     volume      = {5168},
    6341     pages       = {151-161},
    6342     publisher   = {Springer Berlin Heidelberg},
    6343 }
    6344 
    6345 @article{Anderson89,
    6346     keywords    = {data structures, multiprocessing systems, operating systems (computers), performance evaluation, critical resource waiting},
    6347     author      = {Anderson, T.E. and Lazowska, E.D. and Levy, H.M.},
    6348     journal     = {Computers, IEEE Transactions on},
    6349     title       = {The Performance Implications of Thread Management Alternatives for Shared-Memory Multiprocessors},
    6350     year        = {1989},
    6351     month       = {Dec},
    6352     volume      = {38},
    6353     number      = {12},
    6354     pages       = {1631-1644},
    6355 }
    6356 
    63576039@article{Anderson90,
    63586040    keywords    = {spin locks, back off, performance},
     
    63666048    number      = 1,
    63676049    pages       = {6-16},
    6368 }
    6369 
    6370 @article{Blumofe98,
    6371     author      = {Blumofe, Robert D. and Papadopoulos, Dionisios},
    6372     title       = {The Performance of Work Stealing in Multiprogrammed Environments (Extended Abstract)},
    6373     journal     = {SIGMETRICS Perform. Eval. Rev.},
    6374     volume      = {26},
    6375     number      = {1},
    6376     month       = jun,
    6377     year        = {1998},
    6378     issn        = {0163-5999},
    6379     pages       = {266-267},
    6380     publisher   = {ACM},
    6381     address     = {New York, NY, USA},
    63826050}
    63836051
     
    70926760}
    70936761
    7094 @inproceedings{Bacon03,
    7095     keywords    = {utilization, real-time scheduling, read barrier, defragmentation},
    7096     contributer = {pabuhr@plg},
    7097     author      = {David F. Bacon and Perry Cheng and V. T. Rajan},
    7098     title       = {A Real-Time Garbage Collector with Low Overhead and Consistent Utilization},
    7099     year        = {2003},
    7100     organization= {Proceedings of the 30th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages},
    7101     publisher   = {ACM},
    7102     address     = {New York, NY, USA},
    7103     pages       = {285-298},
    7104     location    = {New Orleans, Louisiana, USA},
     6762@manual{Ada95,
     6763    keywords    = {Ada},
     6764    contributer = {pabuhr@plg},
     6765    title       = {{A}da Reference Manual},
     6766    edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
     6767    organization= {Intermetrics, Inc.},
     6768    month       = dec,
     6769    year        = 1995,
     6770    note        = {Language and Standards Libraries}
     6771}
     6772
     6773@manual{Ada12,
     6774    keywords    = {ISO/IEC Ada},
     6775    contributer = {pabuhr@plg},
     6776    author      = {Ada12},
     6777    title       = {Programming languages -- {Ada} ISO/IEC 8652:2012},
     6778    edition     = {3rd},
     6779    organization= {International Standard Organization},
     6780    address     = {Geneva, Switzerland},
     6781    year        = 2012,
     6782    note        = {\href{https://www.iso.org/standard/61507.html}{https://\-www.iso.org/\-standard/\-61507.html}},
     6783}
     6784
     6785@manual{Ada95:annotated,
     6786    keywords    = {Ada},
     6787    contributer = {pabuhr@plg},
     6788    title       = {Annotated {A}da Reference Manual},
     6789    edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
     6790    organization = {Intermetrics, Inc.},
     6791    month       = dec,
     6792    year        = 1995,
     6793    note        = {Language and Standards Libraries}
    71056794}
    71066795
     
    72386927    journal     = sigplan,
    72396928    year        = 1991,
    7240     month       = oct,
    7241     volume      = 26,
    7242     number      = 10,
    7243     pages       = {29-43},
     6929    month       = oct, volume = 26, number = 10, pages = {29-43},
    72446930    abstract    = {
    72456931        {\tt lcc} is a new retargetable compiler for ANSI C.  Versions for
     
    73317017    publisher   = {ACM},
    73327018    address     = {New York, NY, USA},
    7333     organization= {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
     7019    booktitle   = {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
    73347020    pages       = {67-80},
    73357021    numpages    = {14},
     
    73637049}
    73647050
    7365 @article{Nickolls08,
    7366     author      = {Nickolls, John and Buck, Ian and Garland, Michael and Skadron, Kevin},
    7367     title       = {Scalable Parallel Programming with CUDA},
    7368     journal     = {Queue},
    7369     volume      = {6},
    7370     number      = {2},
    7371     month       = mar,
    7372     year        = 2008,
    7373     pages       = {40-53},
    7374     publisher   = {ACM},
    7375     address     = {New York, NY, USA},
    7376 }
    7377 
    73787051@article{Anderson92,
    73797052    keywords    = {light-weight tasks},
     
    73897062}
    73907063
    7391 @article{Blumofe99,
    7392     keywords    = {critical-path length, multiprocessor, multithreading, randomized algorithm, thread scheduling, work stealing},
    7393     author      = {Blumofe, Robert D. and Leiserson, Charles E.},
    7394     title       = {Scheduling Multithreaded Computations by Work Stealing},
    7395     journal     = {Journal of the ACM},
    7396     volume      = {46},
    7397     number      = {5},
    7398     month       = sep,
    7399     year        = {1999},
    7400     pages       = {720-748},
    7401     publisher   = {ACM},
    7402     address     = {New York, NY, USA},
    7403 }
    7404 
    7405 @inproceedings{Acar13,
    7406     keywords    = {dynamic load balancing, nested parallelism, work stealing},
    7407     author      = {Acar, Umut A. and Chargueraud, Arthur and Rainey, Mike},
    7408     title       = {Scheduling Parallel Programs by Work Stealing with Private Deques},
    7409     organization= {Proceedings of the 18th ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming},
    7410     series      = {PPoPP '13},
    7411     year        = {2013},
    7412     location    = {Shenzhen, China},
    7413     pages       = {219-228},
    7414     publisher   = {ACM},
    7415     address     = {New York, NY, USA},
    7416 }
    7417 
    7418 @inproceedings{Chen07,
    7419     keywords    = {chip multiprocessors, constructive cache sharing, parallel depth first, scheduling algorithms, thread granularity, work stealing, working set profiling},
    7420     author      = {Chen, Shimin and Gibbons, Phillip B. and Kozuch, Michael and Liaskovitis, Vasileios and Ailamaki, Anastassia and Blelloch, Guy E. and Falsafi, Babak and Fix, Limor and Hardavellas, Nikos and Mowry, Todd C. and Wilkerson, Chris},
    7421     title       = {Scheduling Threads for Constructive Cache Sharing on CMPs},
    7422     organization= {Proceedings of the Nineteenth Annual ACM Symposium on Parallel Algorithms and Architectures},
    7423     series      = {SPAA '07},
    7424     year        = {2007},
    7425     location    = {San Diego, California, USA},
    7426     pages       = {105-115},
    7427     numpages    = {11},
    7428     publisher   = {ACM},
    7429     address     = {New York, NY, USA},
    7430 }
    7431 
    74327064@manual{SELF,
    74337065    keywords    = {programming language, obect-oriented, polymorphism},
     
    74517083    publisher   = {Springer},
    74527084    note        = {Lecture Notes in Computer Science v. 173},
    7453 }
    7454 
    7455 @inproceedings{Kahn74,
    7456     keywords    = {programming language, obect-oriented, polymorphism},
    7457     contributer = {pabuhr@plg},
    7458     title       = {The Semantics of a Simple Language for Parallel Programming},
    7459     author      = {Gilles Kahn},
    7460     booktitle   = {IFIP Congress},
    7461     year        = 1974,
    74627085}
    74637086
     
    75277150    publisher   = {Morgan \& Claypool},
    75287151    year        = 2013,
    7529 }
    7530 
    7531 @inproceedings{Leissa14,
    7532     title       = {{S}ierra: a {SIMD} extension for {C}++},
    7533     author      = {Lei{\ss}a, Roland and Haffner, Immanuel and Hack, Sebastian},
    7534     booktitle   = {Proceedings of the 2014 Workshop on Workshop on programming models for SIMD/Vector processing},
    7535     pages       = {17-24},
    7536     year        = {2014},
    7537     organization= {ACM}
    75387152}
    75397153
     
    82197833}
    82207834
    8221 @article{Arora01,
    8222     author      = {Arora, N. S. and Blumofe, R. D. and Plaxton, C. G.},
    8223     title       = {Thread Scheduling for Multiprogrammed Multiprocessors},
    8224     journal     = {Theory of Computing Systems},
    8225     year        = {2001},
    8226     volume      = {34},
    8227     number      = {2},
    8228     pages       = {115-144},
    8229     publisher   = {Springer-Verlag},
    8230 }
    8231 
    82327835@article{Boehm05,
    82337836    keywords    = {concurrency, C++},
     
    84578060}
    84588061
    8459 @misc{AkkaBecome,
    8460     contributer = {pabuhr@plg},
    8461     key         = {AkkaBecome},
    8462     title       = {Typed Actors},
    8463     author      = {{Lightbend}},
    8464     howpublished= {\href{https://doc.akka.io/docs/akka/2.5/typed-actors.html}{https://\-doc.akka.io/\-docs/\-akka/\-2.5/\-typed-actors.html}},
    8465     year        = 2022,
    8466 }
    8467 
    84688062@article{concatenation,
    84698063    keywords    = {record concatenation, isa},
     
    85308124    author      = {Paul R. Wilson},
    85318125    title       = {Uniprocessor Garbage Collection Techniques},
    8532     organization= {Proceedings of the International Workshop on Memory Management},
     8126    booktitle   = {Proceedings of the International Workshop on Memory Management},
    85338127    location    = {St. Malo, France},
    85348128    publisher   = {Springer},
     
    85438137    author      = {Carl Hewitt and Peter Bishop and Richard Steiger},
    85448138    title       = {A Universal Modular {ACTOR} Formalism for Artificial Intelligence},
    8545     organization= {Proceedings of the 3rd International Joint Conference on Artificial Intelligence},
     8139    booktitle   = {Proceedings of the 3rd International Joint Conference on Artificial Intelligence},
    85468140    address     = {Standford, California, U.S.A.},
    85478141    pages       = {235-245},
    8548     location    = {Stanford, USA},
    8549     series      = {IJCAI'73},
    85508142    month       = aug,
    85518143    year        = 1973,
     
    85798171@article{Karsten20,
    85808172    author      = {Karsten, Martin and Barghi, Saman},
    8581     title       = {User-level Threading: Have Your Cake and Eat It Too},
     8173    title       = {{User-level Threading: Have Your Cake and Eat It Too}},
    85828174    year        = {2020},
    85838175    issue_date  = {March 2020},
     
    86048196}
    86058197
    8606 @article{Squillante93,
    8607     keywords    = {buffer storage, performance evaluation, queueing theory, scheduling, shared memory systems, processor-cache affinity},
    8608     author      = {Squillante, M.S. and Lazowska, E.D.},
    8609     title       = {Using Processor-Cache Affinity Information in Shared-Memory Multiprocessor Scheduling},
    8610     journal     = {Parallel and Distributed Systems, IEEE Transactions on},
    8611     year        = {1993},
    8612     month       = {Feb},
    8613     volume      = {4},
    8614     number      = {2},
    8615     pages       = {131-143},
    8616 }
    8617 
    86188198@article{delegation,
    86198199    keywords    = {delegation, inheritance, actors},
     
    87658345    year        = 2003,
    87668346    pages       = {19-24},
    8767 }
    8768 
    8769 @inproceedings{Saman18,
    8770     keywords    = {actors, scheduling, NUMA, locality},
    8771     contributer = {pabuhr@plg},
    8772     author      = {Saman Barghi and Martin Karsten},
    8773     organization= {2018 IEEE International Parallel and Distributed Processing Symposium (IPDPS)},
    8774     title       = {Work-Stealing, Locality-Aware Actor Scheduling},
    8775     year        = {2018},
    8776     address     = {Vancouver, BC, Canada},
    8777     pages       = {484-494},
    8778 }
    8779 
    8780 @article{Wimmer13,
    8781     keywords    = {priorities, scheduler hints, strategies, work-stealing},
    8782     author      = {Wimmer, Martin and Cederman, Daniel and Tr\"{a}ff, Jesper Larsson and Tsigas, Philippas},
    8783     title       = {Work-stealing with Configurable Scheduling Strategies},
    8784     journal     = {SIGPLAN Not.},
    8785     issue_date  = {August 2013},
    8786     volume      = {48},
    8787     number      = {8},
    8788     month       = feb,
    8789     year        = {2013},
    8790     issn        = {0362-1340},
    8791     pages       = {315-316},
    8792     publisher   = {ACM},
    8793     address     = {New York, NY, USA},
    87948347}
    87958348
  • doc/theses/mike_brooks_MMath/Makefile

    rb110bcc r2ed94a9  
    88PicSRC = ${notdir ${wildcard ${Pictures}/*.png}}
    99DemoSRC = ${notdir ${wildcard ${Programs}/*-demo.cfa}}
    10 PgmSRC = ${notdir ${wildcard ${Programs}/*}}
    11 RunPgmSRC = ${notdir ${wildcard ${Programs}/*.run.*}}
     10PgmSRC = ${notdir ${wildcard ${Programs}/*.cfa}}
    1211BibSRC = ${wildcard *.bib}
    1312
     
    1514BibLIB = .:../../bibliography                   # common citation repository
    1615
    17 #MAKEFLAGS = --no-print-directory # --silent
     16MAKEFLAGS = --no-print-directory # --silent
    1817VPATH = ${Build} ${Pictures} ${Programs} # extra search path for file names used in document
    1918
     
    2120BASE = ${basename ${DOCUMENT}}                  # remove suffix
    2221
    23 DemoTex = ${DemoSRC:%.cfa=${Build}/%.tex}
    24 RunPgmExe = ${addprefix ${Build}/,${basename ${basename ${RunPgmSRC}}}}
    25 RunPgmOut = ${RunPgmExe:%=%.out}
    26 
    2722# Commands
    2823
    2924LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && pdflatex -halt-on-error -output-directory=${Build}
    3025BibTeX = BIBINPUTS=${BibLIB} && export BIBINPUTS && bibtex
    31 CFA = cfa -O0 -g
    32 CC  = gcc -O0 -g
    33 CXX = g++-11 --std=c++20 -O0 -g
     26CFA = cfa
    3427
    3528# Rules and Recipes
    3629
    37 .PHONY : all fragments_ran clean                        # not file names
    38 .PRECIOUS : ${Build}/% ${Build}/%-demo      # don't delete intermediates
     30.PHONY : all clean                              # not file names
    3931.ONESHELL :
    4032
    41 all : fragments_ran ${DOCUMENT}
    42 
    43 fragments_ran : $(RunPgmOut)
     33all : ${DOCUMENT}
    4434
    4535clean :
     
    4838# File Dependencies
    4939
    50 %.pdf : ${TeXSRC} ${DemoTex} ${PicSRC} ${PgmSRC} ${BibSRC} Makefile | ${Build}
     40%.pdf : ${TeXSRC} ${DemoSRC:%.cfa=%.tex} ${PicSRC} ${PgmSRC} ${BibSRC} Makefile | ${Build}
    5141        ${LaTeX} ${BASE}
    5242        ${BibTeX} ${Build}/${BASE}
     
    6252
    6353%-demo.tex: %-demo | ${Build}
    64         $< > $@
     54        ${Build}/$< > ${Build}/$@
    6555
    66 ${Build}/%-demo: ${Programs}/%-demo.cfa | ${Build}
    67         ${CFA} $< -o $@
     56%-demo: %-demo.cfa
     57        ${CFA} $< -o ${Build}/$@
    6858
    69 ${Build}/%: ${Programs}/%.run.cfa | ${Build}
    70         ${CFA} $< -o $@
    71 
    72 ${Build}/%: ${Programs}/%.run.c | ${Build}
    73         ${CC}  $< -o $@
    74 
    75 ${Build}/%: ${Programs}/%.run.cpp | ${Build}
    76         ${CXX} -MMD $< -o $@
    77 
    78 ${Build}/%.out: ${Build}/% | ${Build}
    79         $< > $@
    80 
    81 -include ${Build}/*.d
  • doc/theses/mike_brooks_MMath/uw-ethesis.bib

    rb110bcc r2ed94a9  
    6565  bibsource = {dblp computer science bibliography, https://dblp.org}
    6666}
    67 
    68 % --------------------------------------------------
    69 % Linked-list prior work
    70 
    71 @misc{CFAStackEvaluation,
    72     contributer = {a3moss@plg},
    73     author      = {Aaron Moss},
    74     title       = {\textsf{C}$\mathbf{\forall}$ Stack Evaluation Programs},
    75     year        = 2018,
    76     howpublished= {\href{https://cforall.uwaterloo.ca/CFAStackEvaluation.zip}{https://cforall.uwaterloo.ca/\-CFAStackEvaluation.zip}},
    77 }
    78 
    79 @misc{lst:linuxq,
    80   title     = {queue(7) — Linux manual page},
    81   howpublished= {\href{https://man7.org/linux/man-pages/man3/queue.3.html}{https://man7.org/linux/man-pages/man3/queue.3.html}},
    82 }
    83   % see also https://man7.org/linux/man-pages/man7/queue.7.license.html
    84   %          https://man7.org/tlpi/
    85   %          https://www.kernel.org/doc/man-pages/
    86 
    87 @misc{lst:stl,
    88   title     = {std::list},
    89   howpublished= {\href{https://en.cppreference.com/w/cpp/container/list}{https://en.cppreference.com/w/cpp/container/list}},
    90 }
    91 
  • doc/theses/mike_brooks_MMath/uw-ethesis.tex

    rb110bcc r2ed94a9  
    6060% For hyperlinked PDF, suitable for viewing on a computer, use this:
    6161\documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
    62 \usepackage{times}
    6362\usepackage[T1]{fontenc}        % Latin-1 => 256-bit characters, => | not dash, <> not Spanish question marks
    6463
     
    8887\usepackage{comment} % Removes large sections of the document.
    8988\usepackage{tabularx}
    90 \usepackage[labelformat=simple,aboveskip=0pt,farskip=0pt,font=normalsize]{subfig}
    91 \renewcommand\thesubfigure{(\alph{subfigure})}
     89\usepackage{subfigure}
    9290
    9391\usepackage{algorithm}
     
    117115    citecolor=blue,        % color of links to bibliography
    118116    filecolor=magenta,      % color of file links
    119     urlcolor=blue,           % color of external links
    120     breaklinks=true
     117    urlcolor=blue           % color of external links
    121118}
    122119\ifthenelse{\boolean{PrintVersion}}{   % for improved print quality, change some hyperref options
     
    132129% although it's supposed to be in both the TeX Live and MikTeX distributions. There are also documentation and
    133130% installation instructions there.
    134 
    135 % Customizing tabularx
    136 \newcolumntype{Y}{>{\centering\arraybackslash}X}
    137131
    138132% Setting up the page margins...
     
    181175\CFAStyle                                               % CFA code-style
    182176\lstset{language=CFA}                                   % default language
    183 \lstset{basicstyle=\linespread{0.9}\sf}                 % CFA typewriter font
     177\lstset{basicstyle=\linespread{0.9}\tt}                 % CFA typewriter font
    184178\lstset{inputpath={programs}}
    185179\newcommand{\PAB}[1]{{\color{red}PAB: #1}}
    186 
    187 \newcommand{\uCpp}{$\mu$\CC}
    188180
    189181%======================================================================
     
    209201%----------------------------------------------------------------------
    210202\begin{sloppypar}
     203
    211204\input{intro}
    212205\input{background}
    213 \input{list}
    214206\input{array}
    215207\input{string}
  • driver/cfa.cc

    rb110bcc r2ed94a9  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 21:16:00 2023
    13 // Update Count     : 476
     12// Last Modified On : Wed Jul 14 21:55:12 2021
     13// Update Count     : 467
    1414//
    1515
     
    4444        static int flags = 0;
    4545
    46     // This allocation 'leaks' memory from the program to the execution
    47     // environment, as putenv does not manage the storage of the string used
    48     // as an environment variable. This leak is necessary to ensure the
    49     // underlying C string is allocated long enough.
    5046        if ( putenv( (char *)( *new string( string( __CFA_FLAGPREFIX__ + to_string( flags++ ) + "__=" ) + arg ) ).c_str() ) ) {
    5147                cerr << argv[0] << " error, cannot set environment variable." << endl;
     
    202198                                } // if
    203199                        } else if ( arg == "-CFA" ) {
    204                                 CFA_flag = true;                                                // strip -CFA flag
     200                                CFA_flag = true;                                                // strip the -CFA flag
    205201                                link = false;
    206202                                args[nargs++] = "-fsyntax-only";                // stop after stage 2
    207203                        } else if ( arg == "-debug" ) {
    208                                 debug = true;                                                   // strip debug flag
     204                                debug = true;                                                   // strip the debug flag
    209205                        } else if ( arg == "-nodebug" ) {
    210                                 debug = false;                                                  // strip nodebug flag
     206                                debug = false;                                                  // strip the nodebug flag
    211207                        } else if ( arg == "-quiet" ) {
    212                                 quiet = true;                                                   // strip quiet flag
     208                                quiet = true;                                                   // strip the quiet flag
    213209                        } else if ( arg == "-noquiet" ) {
    214                                 quiet = false;                                                  // strip noquiet flag
    215                         } else if ( arg == "-invariant" ) {
    216                                 Putenv( argv, "-" + arg );
    217                         } else if ( arg == "--invariant" ) {
    218                                 Putenv( argv, arg );
     210                                quiet = false;                                                  // strip the noquiet flag
    219211                        } else if ( arg == "-no-include-stdhdr" ) {
    220                                 noincstd_flag = true;                                   // strip no-include-stdhdr flag
     212                                noincstd_flag = true;                                   // strip the no-include-stdhdr flag
    221213                        } else if ( arg == "-nolib" ) {
    222                                 nolib = true;                                                   // strip nolib flag
     214                                nolib = true;                                                   // strip the nolib flag
    223215                        } else if ( arg == "-help" ) {
    224                                 help = true;                                                    // strip help flag
     216                                help = true;                                                    // strip the help flag
    225217                        } else if ( arg == "-nohelp" ) {
    226                                 help = false;                                                   // strip nohelp flag
     218                                help = false;                                                   // strip the nohelp flag
    227219                        } else if ( arg == "-cfalib") {
    228220                                compiling_libs = true;
     
    282274                                } // if
    283275                        } else if ( prefix( arg, "-B" ) ) {
    284                                 bprefix = arg.substr(2);                                // strip -B flag
     276                                bprefix = arg.substr(2);                                // strip the -B flag
    285277                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    286278                                args[nargs++] = argv[i];                                // pass flag along
     
    452444
    453445        args[nargs++] = "-fexceptions";                                         // add exception flags (unconditionally)
    454         args[nargs++] = "-D_GNU_SOURCE";                                        // force gnu libraries
    455446
    456447        // add flags based on the type of compile
  • libcfa/src/Makefile.am

    rb110bcc r2ed94a9  
    4848        math.hfa \
    4949        time_t.hfa \
    50         virtual_dtor.hfa \
    5150        bits/algorithm.hfa \
    5251        bits/align.hfa \
  • libcfa/src/algorithms/range_iterator.hfa

    rb110bcc r2ed94a9  
    99// Author           : Thierry Delisle
    1010// Created On       : Tue Nov 30 13:06:22 2021
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 13 23:10:35 2023
    13 // Update Count     : 1
     11// Last Modified By :
     12// Last Modified On :
     13// Update Count     :
    1414//
    15 
    16 #pragma once
    1715
    1816generator RangeIter {
  • libcfa/src/bitmanip.hfa

    rb110bcc r2ed94a9  
    1111// Created On       : Sat Mar 14 18:12:27 2020
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Mon Jan  9 09:02:43 2023
    14 // Update Count     : 144
     13// Last Modified On : Sat Oct  8 08:28:15 2022
     14// Update Count     : 142
    1515//
    1616
    1717#pragma once
    18 
    19 #include "bits/debug.hfa"                                                               // verify
    2018
    2119// Reference: Bit Twiddling Hacks: http://graphics.stanford.edu/%7Eseander/bithacks.html#CountBitsSetNaive
  • libcfa/src/bits/random.hfa

    rb110bcc r2ed94a9  
    1010// Created On       : Fri Jan 14 07:18:11 2022
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 20 21:45:24 2023
    13 // Update Count     : 186
     12// Last Modified On : Thu Dec 22 20:54:22 2022
     13// Update Count     : 178
    1414//
    1515
     
    2828        #define XOSHIRO256PP
    2929        //#define KISS_64
    30     // #define SPLITMIX_64
    3130
    3231        // 32-bit generators
    3332        //#define XORSHIFT_6_21_7
    3433        #define XOSHIRO128PP
    35     // #define SPLITMIX_32
    3634#else                                                                                                   // 32-bit architecture
    3735        // 64-bit generators
    3836        //#define XORSHIFT_13_7_17
    3937        #define XOSHIRO256PP
    40     // #define SPLITMIX_64
    4138
    4239        // 32-bit generators
    4340        //#define XORSHIFT_6_21_7
    4441        #define XOSHIRO128PP
    45     // #define SPLITMIX_32
    4642#endif // __x86_64__
    4743
    4844// Define C/CFA PRNG name and random-state.
     45
     46// SKULLDUGGERY: typedefs name struct and typedef with the same name to deal with CFA typedef numbering problem.
    4947
    5048#ifdef XOSHIRO256PP
    5149#define PRNG_NAME_64 xoshiro256pp
    5250#define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t)
    53 typedef struct { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T;
     51typedef struct PRNG_STATE_64_T { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T;
    5452#endif // XOSHIRO256PP
    5553
     
    5755#define PRNG_NAME_32 xoshiro128pp
    5856#define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t)
    59 typedef struct { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T;
     57typedef struct PRNG_STATE_32_T { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T;
    6058#endif // XOSHIRO128PP
    6159
     
    8583#endif // XORSHIFT_12_25_27
    8684
    87 #ifdef SPLITMIX_64
    88 #define PRNG_NAME_64 splitmix64
    89 #define PRNG_STATE_64_T uint64_t
    90 #endif // SPLITMIX32
    91 
    92 #ifdef SPLITMIX_32
    93 #define PRNG_NAME_32 splitmix32
    94 #define PRNG_STATE_32_T uint32_t
    95 #endif // SPLITMIX32
    96 
    9785#ifdef KISS_64
    9886#define PRNG_NAME_64 kiss_64
    9987#define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t)
    100 typedef struct { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;
     88typedef struct PRNG_STATE_64_T { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;
    10189#endif // KISS_^64
    10290
     
    10492#define PRNG_NAME_32 xorwow
    10593#define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t)
    106 typedef struct { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;
     94typedef struct PRNG_STATE_32_T { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;
    10795#endif // XOSHIRO128PP
    10896
     
    131119#ifdef __cforall                                                                                // don't include in C code (invoke.h)
    132120
    133 // https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
    134 //
    135 // Splitmix64 is not recommended for demanding random number requirements, but is often used to calculate initial states
    136 // for other more complex pseudo-random number generators (see https://prng.di.unimi.it).
    137 // Also https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64.
    138 static inline uint64_t splitmix64( uint64_t & state ) {
    139     state += 0x9e3779b97f4a7c15;
    140     uint64_t z = state;
    141     z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
    142     z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
    143     return z ^ (z >> 31);
    144 } // splitmix64
    145 
    146 static inline void splitmix64_set_seed( uint64_t & state , uint64_t seed ) {
    147     state = seed;
    148     splitmix64( state );                                                                // prime
    149 } // splitmix64_set_seed
    150 
    151 // https://github.com/bryc/code/blob/master/jshash/PRNGs.md#splitmix32
    152 //
    153 // Splitmix32 is not recommended for demanding random number requirements, but is often used to calculate initial states
    154 // for other more complex pseudo-random number generators (see https://prng.di.unimi.it).
    155 
    156 static inline uint32_t splitmix32( uint32_t & state ) {
    157     state += 0x9e3779b9;
    158     uint64_t z = state;
    159     z = (z ^ (z >> 15)) * 0x85ebca6b;
    160     z = (z ^ (z >> 13)) * 0xc2b2ae35;
    161     return z ^ (z >> 16);
    162 } // splitmix32
    163 
    164 static inline void splitmix32_set_seed( uint32_t & state, uint64_t seed ) {
    165     state = seed;
    166     splitmix32( state );                                                                // prime
    167 } // splitmix32_set_seed
    168 
    169 #ifdef __SIZEOF_INT128__
    170 //--------------------------------------------------
    171 static inline uint64_t lehmer64( __uint128_t & state ) {
    172         __uint128_t ret = state;
    173         state *= 0x_da94_2042_e4dd_58b5;
    174         return ret >> 64;
    175 } // lehmer64
    176 
    177 static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) {
    178         // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed.
    179         state = splitmix64( seed );                                                     // prime
    180 } // lehmer64_set_seed
    181 
    182 //--------------------------------------------------
    183 static inline uint64_t wyhash64( uint64_t & state ) {
    184         uint64_t ret = state;
    185         state += 0x_60be_e2be_e120_fc15;
    186         __uint128_t tmp;
    187         tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d;
    188         uint64_t m1 = (tmp >> 64) ^ tmp;
    189         tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9;
    190         uint64_t m2 = (tmp >> 64) ^ tmp;
    191         return m2;
    192 } // wyhash64
    193 
    194 static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {
    195         state = splitmix64( seed );                                                     // prime
    196 } // wyhash64_set_seed
    197 #endif // __SIZEOF_INT128__
    198 
    199121// https://prng.di.unimi.it/xoshiro256starstar.c
    200122//
     
    208130
    209131#ifndef XOSHIRO256PP
    210 typedef struct { uint64_t s0, s1, s2, s3; } xoshiro256pp_t;
     132typedef struct xoshiro256pp_t { uint64_t s0, s1, s2, s3; } xoshiro256pp_t;
    211133#endif // ! XOSHIRO256PP
    212134
     
    229151
    230152static inline void xoshiro256pp_set_seed( xoshiro256pp_t & state, uint64_t seed ) {
    231     // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
    232     uint64_t seed1 = splitmix64( seed );                                // prime
    233     uint64_t seed2 = splitmix64( seed );
    234     uint64_t seed3 = splitmix64( seed );
    235     uint64_t seed4 = splitmix64( seed );
    236         state = (xoshiro256pp_t){ seed1, seed2, seed3, seed4 };
     153        state = (xoshiro256pp_t){ seed, seed, seed, seed };
     154        xoshiro256pp( state );
    237155} // xoshiro256pp_set_seed
    238156
     
    247165
    248166#ifndef XOSHIRO128PP
    249 typedef struct { uint32_t s0, s1, s2, s3; } xoshiro128pp_t;
     167typedef struct xoshiro128pp_t { uint32_t s0, s1, s2, s3; } xoshiro128pp_t;
    250168#endif // ! XOSHIRO128PP
    251169
     
    268186
    269187static inline void xoshiro128pp_set_seed( xoshiro128pp_t & state, uint32_t seed ) {
    270     // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
    271     uint32_t seed1 = splitmix32( seed );                                // prime
    272     uint32_t seed2 = splitmix32( seed );
    273     uint32_t seed3 = splitmix32( seed );
    274     uint32_t seed4 = splitmix32( seed );
    275         state = (xoshiro128pp_t){ seed1, seed2, seed3, seed4 };
     188        state = (xoshiro128pp_t){ seed, seed, seed, seed };
     189        xoshiro128pp( state );                                                          // prime
    276190} // xoshiro128pp_set_seed
     191
     192#ifdef __SIZEOF_INT128__
     193        //--------------------------------------------------
     194        static inline uint64_t lehmer64( __uint128_t & state ) {
     195                __uint128_t ret = state;
     196                state *= 0x_da94_2042_e4dd_58b5;
     197                return ret >> 64;
     198        } // lehmer64
     199
     200        static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) {
     201                // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed.
     202                state = seed;
     203                lehmer64( state );                                                              // prime
     204        } // lehmer64_set_seed
     205
     206        //--------------------------------------------------
     207        static inline uint64_t wyhash64( uint64_t & state ) {
     208                uint64_t ret = state;
     209                state += 0x_60be_e2be_e120_fc15;
     210                __uint128_t tmp;
     211                tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d;
     212                uint64_t m1 = (tmp >> 64) ^ tmp;
     213                tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9;
     214                uint64_t m2 = (tmp >> 64) ^ tmp;
     215                return m2;
     216        } // wyhash64
     217
     218        static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {
     219                state = seed;
     220                wyhash64( state );                                                              // prime
     221        } // wyhash64_set_seed
     222#endif // __SIZEOF_INT128__
    277223
    278224//--------------------------------------------------
     
    286232
    287233static inline void xorshift_13_7_17_set_seed( uint64_t & state, uint64_t seed ) {
    288         state = splitmix64( seed );                                                     // prime
     234        state = seed;
     235        xorshift_13_7_17( state );                                                      // prime
    289236} // xorshift_13_7_17_set_seed
    290237
     
    303250
    304251static inline void xorshift_6_21_7_set_seed( uint32_t & state, uint32_t seed ) {
    305     state = splitmix32( seed );                                                 // prime
     252        state = seed;
     253        xorshift_6_21_7( state );                                                       // prime
    306254} // xorshift_6_21_7_set_seed
    307255
     
    317265
    318266static inline void xorshift_12_25_27_set_seed( uint64_t & state, uint64_t seed ) {
    319         state = splitmix64( seed );                                                     // prime
     267        state = seed;
     268        xorshift_12_25_27( state );                                                     // prime
    320269} // xorshift_12_25_27_set_seed
    321270
     
    323272// The state must be seeded with a nonzero value.
    324273#ifndef KISS_64
    325 typedef struct { uint64_t z, w, jsr, jcong; } kiss_64_t;
     274typedef struct kiss_64_t { uint64_t z, w, jsr, jcong; } kiss_64_t;
    326275#endif // ! KISS_64
    327276
     
    338287
    339288static inline void kiss_64_set_seed( kiss_64_t & rs, uint64_t seed ) with(rs) {
    340         z = 1; w = 1; jsr = 4; jcong = splitmix64( seed );      // prime
     289        z = 1; w = 1; jsr = 4; jcong = seed;
     290        kiss_64( rs );                                                                          // prime
    341291} // kiss_64_set_seed
    342292
     
    344294// The state array must be initialized to non-zero in the first four words.
    345295#ifndef XORWOW
    346 typedef struct { uint32_t a, b, c, d, counter; } xorwow_t;
     296typedef struct xorwow_t { uint32_t a, b, c, d, counter; } xorwow_t;
    347297#endif // ! XORWOW
    348298
     
    366316
    367317static inline void xorwow_set_seed( xorwow_t & rs, uint32_t seed ) {
    368     // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
    369     uint32_t seed1 = splitmix32( seed );                                // prime
    370     uint32_t seed2 = splitmix32( seed );
    371     uint32_t seed3 = splitmix32( seed );
    372     uint32_t seed4 = splitmix32( seed );
    373         rs = (xorwow_t){ seed1, seed2, seed3, seed4, 0 };
     318        rs = (xorwow_t){ seed, seed, seed, seed, 0 };
     319        xorwow( rs );                                                                           // prime
    374320} // xorwow_set_seed
    375321
     
    377323// Used in __tls_rand_fwd
    378324#define M  (1_l64u << 48_l64u)
    379 #define A  (25_214_903_917_l64u)
    380 #define AI (18_446_708_753_438_544_741_l64u)
     325#define A  (25214903917_l64u)
     326#define AI (18446708753438544741_l64u)
    381327#define C  (11_l64u)
    382328#define D  (16_l64u)
  • libcfa/src/concurrency/actor.hfa

    rb110bcc r2ed94a9  
    33#include <locks.hfa>
    44#include <limits.hfa>
     5#include <list.hfa>
    56#include <kernel.hfa>
    6 #include <iofwd.hfa>
    7 #include <virtual_dtor.hfa>
    87
    98#ifdef __CFA_DEBUG__
     
    2120// Define the default number of executor request-queues (mailboxes) written to by actors and serviced by the
    2221// actor-executor threads. Must be greater than 0.
    23 #define __DEFAULT_EXECUTOR_RQUEUES__ 4
     22#define __DEFAULT_EXECUTOR_RQUEUES__ 2
    2423
    2524// Define if executor is created in a separate cluster
    2625#define __DEFAULT_EXECUTOR_SEPCLUS__ false
    2726
    28 #define __DEFAULT_EXECUTOR_BUFSIZE__ 10
    29 
    30 #define __STEAL 0 // workstealing toggle. Disjoint from toggles above
    31 
    32 // workstealing heuristic selection (only set one to be 1)
    33 // #define RAND 0
    34 #define SEARCH 1
    35 
    36 // show stats
    37 // #define ACTOR_STATS
     27// when you flip this make sure to recompile compiler and flip the appropriate flag there too in Actors.cpp
     28#define __ALLOC 0
    3829
    3930// forward decls
    4031struct actor;
    4132struct message;
    42 struct executor;
    4333
    4434enum Allocation { Nodelete, Delete, Destroy, Finished }; // allocation status
     
    5040    __receive_fn fn;
    5141    bool stop;
    52 };
     42    inline dlink(request);
     43};
     44P9_EMBEDDED( request, dlink(request) )
    5345
    5446static inline void ?{}( request & this ) { this.stop = true; } // default ctor makes a sentinel
     
    6658}
    6759
    68 // Vector-like data structure that supports O(1) queue operations with no bound on size
    69 // assumes gulping behaviour (once a remove occurs, removes happen until empty beforw next insert)
     60// hybrid data structure. Copies until buffer is full and then allocates for intrusive list
    7061struct copy_queue {
     62    dlist( request ) list;
     63    #if ! __ALLOC
    7164    request * buffer;
    72     size_t count, buffer_size, index, utilized, last_size;
     65    size_t count, buffer_size, index;
     66    #endif
    7367};
    7468static inline void ?{}( copy_queue & this ) {}
    7569static inline void ?{}( copy_queue & this, size_t buf_size ) with(this) {
     70    list{};
     71    #if ! __ALLOC
    7672    buffer_size = buf_size;
    7773    buffer = aalloc( buffer_size );
    7874    count = 0;
    79     utilized = 0;
    8075    index = 0;
    81     last_size = 0;
    82 }
    83 static inline void ^?{}( copy_queue & this ) with(this) { adelete(buffer); }
     76    #endif
     77}
     78static inline void ^?{}( copy_queue & this ) with(this) {
     79    #if ! __ALLOC
     80    adelete(buffer);
     81    #endif
     82}
    8483
    8584static inline void insert( copy_queue & this, request & elem ) with(this) {
    86     if ( count >= buffer_size ) { // increase arr size
    87         last_size = buffer_size;
    88         buffer_size = 2 * buffer_size;
    89         buffer = realloc( buffer, sizeof( request ) * buffer_size );
    90         /* paranoid */ verify( buffer );
     85    #if ! __ALLOC
     86    if ( count < buffer_size ) { // fast path ( no alloc )
     87        buffer[count]{ elem };
     88        count++;
     89        return;
    9190    }
    92     memcpy( &buffer[count], &elem, sizeof(request) );
    93     count++;
     91    request * new_elem = alloc();
     92    (*new_elem){ elem };
     93    insert_last( list, *new_elem );
     94    #else
     95    insert_last( list, elem );
     96    #endif
    9497}
    9598
    9699// once you start removing you need to remove all elements
    97 // it is not supported to call insert() before the array is fully empty
    98 static inline request & remove( copy_queue & this ) with(this) {
     100// it is not supported to call insert() before the list is fully empty
     101// should_delete is an output param
     102static inline request & remove( copy_queue & this, bool & should_delete ) with(this) {
     103    #if ! __ALLOC
    99104    if ( count > 0 ) {
    100105        count--;
     106        should_delete = false;
    101107        size_t old_idx = index;
    102108        index = count == 0 ? 0 : index + 1;
    103109        return buffer[old_idx];
    104110    }
    105     request * ret = 0p;
    106     return *0p;
    107 }
    108 
    109 // try to reclaim some memory if less than half of buffer is utilized
    110 static inline void reclaim( copy_queue & this ) with(this) {
    111     if ( utilized >= last_size || buffer_size <= 4 ) { utilized = 0; return; }
    112     utilized = 0;
    113     buffer_size--;
    114     buffer = realloc( buffer, sizeof( request ) * buffer_size ); // try to reclaim some memory
    115 }
    116 
    117 static inline bool isEmpty( copy_queue & this ) with(this) { return count == 0; }
    118 
     111    #endif
     112    should_delete = true;
     113    return try_pop_front( list );
     114}
     115
     116static inline bool isEmpty( copy_queue & this ) with(this) {
     117    #if ! __ALLOC
     118    return count == 0 && list`isEmpty;
     119    #else
     120    return list`isEmpty;
     121    #endif
     122}
     123
     124static size_t __buffer_size = 10; // C_TODO: rework this to be passed from executor through ctors (no need for global)
    119125struct work_queue {
    120126    __spinlock_t mutex_lock;
    121     copy_queue * owned_queue;       // copy queue allocated and cleaned up by this work_queue
    122     copy_queue * c_queue;           // current queue
    123     volatile bool being_processed;  // flag to prevent concurrent processing
    124     #ifdef ACTOR_STATS
    125     unsigned int id;
    126     size_t missed;                  // transfers skipped due to being_processed flag being up
    127     #endif
     127    copy_queue owned_queue;
     128    copy_queue * c_queue; // C_TODO: try putting this on the stack with ptr juggling
     129
    128130}; // work_queue
    129 static inline void ?{}( work_queue & this, size_t buf_size, unsigned int i ) with(this) {
    130     owned_queue = alloc();      // allocated separately to avoid false sharing
    131     (*owned_queue){ buf_size };
    132     c_queue = owned_queue;
    133     being_processed = false;
    134     #ifdef ACTOR_STATS
    135     id = i;
    136     missed = 0;
    137     #endif
    138 }
    139 
    140 // clean up copy_queue owned by this work_queue
    141 static inline void ^?{}( work_queue & this ) with(this) { delete( owned_queue ); }
     131static inline void ?{}( work_queue & this ) with(this) {
     132    // c_queue = alloc();
     133    // (*c_queue){ __buffer_size };
     134    owned_queue{ __buffer_size };
     135    c_queue = &owned_queue;
     136}
     137// static inline void ^?{}( work_queue & this ) with(this) { delete( c_queue ); }
    142138
    143139static inline void insert( work_queue & this, request & elem ) with(this) {
     
    149145static inline void transfer( work_queue & this, copy_queue ** transfer_to ) with(this) {
    150146    lock( mutex_lock __cfaabi_dbg_ctx2 );
    151     #ifdef __STEAL
    152 
    153     // check if queue is being processed elsewhere
    154     if ( unlikely( being_processed ) ) {
    155         #ifdef ACTOR_STATS
    156         missed++;
    157         #endif
    158         unlock( mutex_lock );
    159         return;
    160     }
    161 
    162     being_processed = c_queue->count != 0;
    163     #endif // __STEAL
    164 
    165     c_queue->utilized = c_queue->count;
    166 
    167147    // swap copy queue ptrs
    168148    copy_queue * temp = *transfer_to;
     
    172152} // transfer
    173153
    174 // needed since some info needs to persist past worker lifetimes
    175 struct worker_info {
    176     volatile unsigned long long stamp;
    177     #ifdef ACTOR_STATS
    178     size_t stolen_from, try_steal, stolen, failed_swaps, msgs_stolen;
    179     unsigned long long processed;
    180     size_t gulps;
    181     #endif
    182 };
    183 static inline void ?{}( worker_info & this ) {
    184     #ifdef ACTOR_STATS
    185     this.stolen_from = 0;
    186     this.try_steal = 0;                             // attempts to steal
    187     this.stolen = 0;                                // successful steals
    188     this.processed = 0;                             // requests processed
    189     this.gulps = 0;                                 // number of gulps
    190     this.failed_swaps = 0;                          // steal swap failures
    191     this.msgs_stolen = 0;                           // number of messages stolen
    192     #endif
    193     this.stamp = rdtscl();
    194 }
    195 
    196 // #ifdef ACTOR_STATS
    197 // unsigned int * stolen_arr;
    198 // unsigned int * replaced_queue;
    199 // #endif
    200154thread worker {
    201     work_queue ** request_queues;
     155    copy_queue owned_queue;
     156    work_queue * request_queues;
    202157    copy_queue * current_queue;
    203     executor * executor_;
     158        request & req;
    204159    unsigned int start, range;
    205     int id;
    206 };
    207 
    208 #ifdef ACTOR_STATS
    209 // aggregate counters for statistics
    210 size_t __total_tries = 0, __total_stolen = 0, __total_workers, __all_gulps = 0,
    211     __total_failed_swaps = 0, __all_processed = 0, __num_actors_stats = 0, __all_msgs_stolen = 0;
    212 #endif
    213 static inline void ?{}( worker & this, cluster & clu, work_queue ** request_queues, copy_queue * current_queue, executor * executor_,
    214     unsigned int start, unsigned int range, int id ) {
     160};
     161
     162static inline void ?{}( worker & this, cluster & clu, work_queue * request_queues, unsigned int start, unsigned int range ) {
    215163    ((thread &)this){ clu };
    216     this.request_queues = request_queues;           // array of all queues
    217     this.current_queue = current_queue;             // currently gulped queue (start with empty queue to use in swap later)
    218     this.executor_ = executor_;                     // pointer to current executor
    219     this.start = start;                             // start of worker's subrange of request_queues
    220     this.range = range;                             // size of worker's subrange of request_queues
    221     this.id = id;                                   // worker's id and index in array of workers
    222 }
    223 
    224 static bool no_steal = false;
     164    this.request_queues = request_queues;
     165    // this.current_queue = alloc();
     166    // (*this.current_queue){ __buffer_size };
     167    this.owned_queue{ __buffer_size };
     168    this.current_queue = &this.owned_queue;
     169    this.start = start;
     170    this.range = range;
     171}
     172// static inline void ^?{}( worker & mutex this ) with(this) { delete( current_queue ); }
     173
    225174struct executor {
    226175    cluster * cluster;                                                      // if workers execute on separate cluster
    227176        processor ** processors;                                            // array of virtual processors adding parallelism for workers
    228         work_queue * request_queues;                                // master array of work request queues
    229     copy_queue * local_queues;                      // array of all worker local queues to avoid deletion race
    230         work_queue ** worker_req_queues;                // secondary array of work queues to allow for swapping
    231     worker ** workers;                                                          // array of workers executing work requests
    232     worker_info * w_infos;                          // array of info about each worker
     177        work_queue * request_queues;                                // master list of work request queues
     178        worker ** workers;                                                              // array of workers executing work requests
    233179        unsigned int nprocessors, nworkers, nrqueues;   // number of processors/threads/request queues
    234180        bool seperate_clus;                                                             // use same or separate cluster for executor
    235181}; // executor
    236182
    237 // #ifdef ACTOR_STATS
    238 // __spinlock_t out_lock;
    239 // #endif
    240 static inline void ^?{}( worker & mutex this ) with(this) {
    241     #ifdef ACTOR_STATS
    242     __atomic_add_fetch(&__all_gulps, executor_->w_infos[id].gulps,__ATOMIC_SEQ_CST);
    243     __atomic_add_fetch(&__all_processed, executor_->w_infos[id].processed,__ATOMIC_SEQ_CST);
    244     __atomic_add_fetch(&__all_msgs_stolen, executor_->w_infos[id].msgs_stolen,__ATOMIC_SEQ_CST);
    245     __atomic_add_fetch(&__total_tries, executor_->w_infos[id].try_steal, __ATOMIC_SEQ_CST);
    246     __atomic_add_fetch(&__total_stolen, executor_->w_infos[id].stolen, __ATOMIC_SEQ_CST);
    247     __atomic_add_fetch(&__total_failed_swaps, executor_->w_infos[id].failed_swaps, __ATOMIC_SEQ_CST);
    248 
    249     // per worker steal stats (uncomment alongside the lock above this routine to print)
    250     // lock( out_lock __cfaabi_dbg_ctx2 );
    251     // printf("Worker id: %d, processed: %llu messages, attempted %lu, stole: %lu, stolen from: %lu\n", id, processed, try_steal, stolen, __atomic_add_fetch(&executor_->w_infos[id].stolen_from, 0, __ATOMIC_SEQ_CST) );
    252     // int count = 0;
    253     // int count2 = 0;
    254     // for ( i; range ) {
    255     //     if ( replaced_queue[start + i] > 0 ){
    256     //         count++;
    257     //         // printf("%d: %u, ",i, replaced_queue[i]);
    258     //     }
    259     //     if (__atomic_add_fetch(&stolen_arr[start + i],0,__ATOMIC_SEQ_CST) > 0)
    260     //         count2++;
    261     // }
    262     // printf("swapped with: %d of %u indices\n", count, executor_->nrqueues / executor_->nworkers );
    263     // printf("%d of %u indices were stolen\n", count2, executor_->nrqueues / executor_->nworkers );
    264     // unlock( out_lock );
    265     #endif
    266 }
    267 
    268183static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus, size_t buf_size ) with(this) {
    269184    if ( nrqueues < nworkers ) abort( "nrqueues needs to be >= nworkers\n" );
     185    __buffer_size = buf_size;
    270186    this.nprocessors = nprocessors;
    271187    this.nworkers = nworkers;
     
    273189    this.seperate_clus = seperate_clus;
    274190
    275     if ( nworkers == nrqueues )
    276         no_steal = true;
    277    
    278     #ifdef ACTOR_STATS
    279     // stolen_arr = aalloc( nrqueues );
    280     // replaced_queue = aalloc( nrqueues );
    281     __total_workers = nworkers;
    282     #endif
    283 
    284191    if ( seperate_clus ) {
    285192        cluster = alloc();
     
    288195
    289196    request_queues = aalloc( nrqueues );
    290     worker_req_queues = aalloc( nrqueues );
    291     for ( i; nrqueues ) {
    292         request_queues[i]{ buf_size, i };
    293         worker_req_queues[i] = &request_queues[i];
    294     }
     197    for ( i; nrqueues )
     198        request_queues[i]{};
    295199   
    296200    processors = aalloc( nprocessors );
     
    298202        (*(processors[i] = alloc())){ *cluster };
    299203
    300     local_queues = aalloc( nworkers );
    301     workers = aalloc( nworkers );
    302     w_infos = aalloc( nworkers );
     204    workers = alloc( nworkers );
    303205    unsigned int reqPerWorker = nrqueues / nworkers, extras = nrqueues % nworkers;
    304 
    305     for ( i; nworkers ) {
    306         w_infos[i]{};
    307         local_queues[i]{ buf_size };
    308     }
    309 
    310206    for ( unsigned int i = 0, start = 0, range; i < nworkers; i += 1, start += range ) {
    311207        range = reqPerWorker + ( i < extras ? 1 : 0 );
    312         (*(workers[i] = alloc())){ *cluster, worker_req_queues, &local_queues[i], &this, start, range, i };
     208        (*(workers[i] = alloc())){ *cluster, request_queues, start, range };
    313209    } // for
    314210}
    315 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus ) { this{ nprocessors, nworkers, nrqueues, seperate_clus, __DEFAULT_EXECUTOR_BUFSIZE__ }; }
     211static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus ) { this{ nprocessors, nworkers, nrqueues, seperate_clus, __buffer_size }; }
    316212static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues ) { this{ nprocessors, nworkers, nrqueues, __DEFAULT_EXECUTOR_SEPCLUS__ }; }
    317213static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers ) { this{ nprocessors, nworkers, __DEFAULT_EXECUTOR_RQUEUES__ }; }
     
    320216
    321217static inline void ^?{}( executor & this ) with(this) {
    322     #ifdef __STEAL
    323     request sentinels[nrqueues];
    324     for ( unsigned int i = 0; i < nrqueues; i++ ) {
    325         insert( request_queues[i], sentinels[i] );              // force eventually termination
    326     } // for
    327     #else
    328218    request sentinels[nworkers];
    329     unsigned int reqPerWorker = nrqueues / nworkers, extras = nrqueues % nworkers;
    330     for ( unsigned int i = 0, step = 0, range; i < nworkers; i += 1, step += range ) {
    331         range = reqPerWorker + ( i < extras ? 1 : 0 );
     219    unsigned int reqPerWorker = nrqueues / nworkers;
     220    for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker ) {
    332221        insert( request_queues[step], sentinels[i] );           // force eventually termination
    333222    } // for
    334     #endif
    335223
    336224    for ( i; nworkers )
     
    341229    } // for
    342230
    343     #ifdef ACTOR_STATS
    344     size_t misses = 0;
    345     for ( i; nrqueues ) {
    346         misses += worker_req_queues[i]->missed;
    347     }
    348     // adelete( stolen_arr );
    349     // adelete( replaced_queue );
    350     #endif
    351 
    352231    adelete( workers );
    353     adelete( w_infos );
    354     adelete( local_queues );
    355232    adelete( request_queues );
    356     adelete( worker_req_queues );
    357233    adelete( processors );
    358234    if ( seperate_clus ) delete( cluster );
    359 
    360     #ifdef ACTOR_STATS // print formatted stats
    361     printf("    Actor System Stats:\n");
    362     printf("\tActors Created:\t\t\t\t%lu\n\tMessages Sent:\t\t\t\t%lu\n", __num_actors_stats, __all_processed);
    363     size_t avg_gulps = __all_gulps == 0 ? 0 : __all_processed / __all_gulps;
    364     printf("\tGulps:\t\t\t\t\t%lu\n\tAverage Gulp Size:\t\t\t%lu\n\tMissed gulps:\t\t\t\t%lu\n", __all_gulps, avg_gulps, misses);
    365     printf("\tSteal attempts:\t\t\t\t%lu\n\tSteals:\t\t\t\t\t%lu\n\tSteal failures (no candidates):\t\t%lu\n\tSteal failures (failed swaps):\t\t%lu\n",
    366         __total_tries, __total_stolen, __total_tries - __total_stolen - __total_failed_swaps, __total_failed_swaps);
    367     size_t avg_steal = __total_stolen == 0 ? 0 : __all_msgs_stolen / __total_stolen;
    368     printf("\tMessages stolen:\t\t\t%lu\n\tAverage steal size:\t\t\t%lu\n", __all_msgs_stolen, avg_steal);
    369     #endif
    370        
    371235}
    372236
    373237// this is a static field of executor but have to forward decl for get_next_ticket
    374 static size_t __next_ticket = 0;
    375 
    376 static inline size_t __get_next_ticket( executor & this ) with(this) {
    377     #ifdef __CFA_DEBUG__
    378     size_t temp = __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues;
    379 
    380     // reserve MAX for dead actors
    381     if ( unlikely( temp == MAX ) ) temp = __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues;
    382     return temp;
    383     #else
    384     return __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_RELAXED) % nrqueues;
    385     #endif
     238static unsigned int __next_ticket = 0;
     239
     240static inline unsigned int get_next_ticket( executor & this ) with(this) {
     241    return __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues;
    386242} // tickets
    387243
    388 // TODO: update globals in this file to be static fields once the static fields project is done
     244// C_TODO: update globals in this file to be static fields once the project is done
    389245static executor * __actor_executor_ = 0p;
    390 static bool __actor_executor_passed = false;            // was an executor passed to start_actor_system
    391 static size_t __num_actors_ = 0;                                        // number of actor objects in system
     246static bool __actor_executor_passed = false;        // was an executor passed to start_actor_system
     247static unsigned long int __num_actors_;                         // number of actor objects in system
    392248static struct thread$ * __actor_executor_thd = 0p;              // used to wake executor after actors finish
    393249struct actor {
    394     size_t ticket;                                          // executor-queue handle
    395     Allocation allocation_;                                         // allocation action
    396     inline virtual_dtor;
    397 };
    398 
    399 static inline void ?{}( actor & this ) with(this) {
     250    unsigned long int ticket;           // executor-queue handle to provide FIFO message execution
     251    Allocation allocation_;                     // allocation action
     252};
     253
     254static inline void ?{}( actor & this ) {
    400255    // Once an actor is allocated it must be sent a message or the actor system cannot stop. Hence, its receive
    401256    // member must be called to end it
    402     verifyf( __actor_executor_, "Creating actor before calling start_actor_system() can cause undefined behaviour.\n" );
    403     allocation_ = Nodelete;
    404     ticket = __get_next_ticket( *__actor_executor_ );
    405     __atomic_fetch_add( &__num_actors_, 1, __ATOMIC_RELAXED );
    406     #ifdef ACTOR_STATS
    407     __atomic_fetch_add( &__num_actors_stats, 1, __ATOMIC_SEQ_CST );
    408     #endif
    409 }
     257    verifyf( __actor_executor_, "Creating actor before calling start_actor_system()." );
     258    this.allocation_ = Nodelete;
     259    this.ticket = get_next_ticket( *__actor_executor_ );
     260    __atomic_fetch_add( &__num_actors_, 1, __ATOMIC_SEQ_CST );
     261}
     262static inline void ^?{}( actor & this ) {}
    410263
    411264static inline void check_actor( actor & this ) {
     
    423276        }
    424277
    425         if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_RELAXED ) == 0 ) ) { // all actors have terminated
     278        if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_SEQ_CST ) == 0 ) ) { // all actors have terminated
    426279            unpark( __actor_executor_thd );
    427280        }
     
    431284struct message {
    432285    Allocation allocation_;                     // allocation action
    433     inline virtual_dtor;
    434 };
    435 
    436 static inline void ?{}( message & this ) {
    437     this.allocation_ = Nodelete;
    438 }
    439 static inline void ?{}( message & this, Allocation allocation ) {
    440     memcpy( &this.allocation_, &allocation, sizeof(allocation) ); // optimization to elide ctor
    441     verifyf( this.allocation_ != Finished, "The Finished Allocation status is not supported for message types.\n");
    442 }
    443 static inline void ^?{}( message & this ) with(this) {
    444     CFA_DEBUG( if ( allocation_ == Nodelete ) printf("A message at location %p was allocated but never sent.\n", &this); )
    445 }
     286};
     287
     288static inline void ?{}( message & this ) { this.allocation_ = Nodelete; }
     289static inline void ?{}( message & this, Allocation allocation ) { this.allocation_ = allocation; }
     290static inline void ^?{}( message & this ) {}
    446291
    447292static inline void check_message( message & this ) {
    448293    switch ( this.allocation_ ) {                                               // analyze message status
    449         case Nodelete: CFA_DEBUG(this.allocation_ = Finished); break;
     294        case Nodelete: break;
    450295        case Delete: delete( &this ); break;
    451296        case Destroy: ^?{}(this); break;
     
    453298    } // switch
    454299}
    455 static inline void set_allocation( message & this, Allocation state ) {
    456     this.allocation_ = state;
    457 }
    458300
    459301static inline void deliver_request( request & this ) {
    460     this.receiver->allocation_ = this.fn( *this.receiver, *this.msg );
     302    Allocation actor_allocation = this.fn( *this.receiver, *this.msg );
     303    this.receiver->allocation_ = actor_allocation;
     304    check_actor( *this.receiver );
    461305    check_message( *this.msg );
    462     check_actor( *this.receiver );
    463 }
    464 
    465 // tries to atomically swap two queues and returns 0p if the swap failed
    466 // returns ptr to newly owned queue if swap succeeds
    467 static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) {
    468     work_queue * my_queue = request_queues[my_idx];
    469     work_queue * other_queue = request_queues[victim_idx];
    470 
    471     // if either queue is 0p then they are in the process of being stolen
    472     if ( other_queue == 0p ) return 0p;
    473 
    474     // try to set our queue ptr to be 0p. If it fails someone moved our queue so return false
    475     if ( !__atomic_compare_exchange_n( &request_queues[my_idx], &my_queue, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) )
    476         return 0p;
    477 
    478     // try to set other queue ptr to be our queue ptr. If it fails someone moved the other queue so fix up then return false
    479     if ( !__atomic_compare_exchange_n( &request_queues[victim_idx], &other_queue, my_queue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) {
    480         /* paranoid */ verify( request_queues[my_idx] == 0p );
    481         request_queues[my_idx] = my_queue; // reset my queue ptr back to appropriate val
    482         return 0p;
    483     }
    484 
    485     // we have successfully swapped and since our queue is 0p no one will touch it so write back new queue ptr non atomically
    486     request_queues[my_idx] = other_queue; // last write does not need to be atomic
    487     return other_queue;
    488 }
    489 
    490 // once a worker to steal from has been chosen, choose queue to steal from
    491 static inline void choose_queue( worker & this, unsigned int victim_id, unsigned int swap_idx ) with(this) {
    492     // have to calculate victim start and range since victim may be deleted before us in shutdown
    493     const unsigned int queues_per_worker = executor_->nrqueues / executor_->nworkers;
    494     const unsigned int extras = executor_->nrqueues % executor_->nworkers;
    495     unsigned int vic_start, vic_range;
    496     if ( extras > victim_id  ) {
    497         vic_range = queues_per_worker + 1;
    498         vic_start = vic_range * victim_id;
    499     } else {
    500         vic_start = extras + victim_id * queues_per_worker;
    501         vic_range = queues_per_worker;
    502     }
    503     unsigned int start_idx = prng( vic_range );
    504 
    505     unsigned int tries = 0;
    506     work_queue * curr_steal_queue;
    507 
    508     for ( unsigned int i = start_idx; tries < vic_range; i = (i + 1) % vic_range ) {
    509         tries++;
    510         curr_steal_queue = request_queues[ i + vic_start ];
    511         // avoid empty queues and queues that are being operated on
    512         if ( curr_steal_queue == 0p || curr_steal_queue->being_processed || isEmpty( *curr_steal_queue->c_queue ) )
    513             continue;
    514 
    515         #ifdef ACTOR_STATS
    516         curr_steal_queue = try_swap_queues( this, i + vic_start, swap_idx );
    517         if ( curr_steal_queue ) {
    518             executor_->w_infos[id].msgs_stolen += curr_steal_queue->c_queue->count;
    519             executor_->w_infos[id].stolen++;
    520             // __atomic_add_fetch(&executor_->w_infos[victim_id].stolen_from, 1, __ATOMIC_RELAXED);
    521             // replaced_queue[swap_idx]++;
    522             // __atomic_add_fetch(&stolen_arr[ i + vic_start ], 1, __ATOMIC_RELAXED);
    523         } else {
    524             executor_->w_infos[id].failed_swaps++;
    525         }
    526         #else
    527         curr_steal_queue = try_swap_queues( this, i + vic_start, swap_idx );
    528         #endif // ACTOR_STATS
    529 
    530         return;
    531     }
    532 
    533     return;
    534 }
    535 
    536 // choose a worker to steal from
    537 static inline void steal_work( worker & this, unsigned int swap_idx ) with(this) {
    538     #if RAND
    539     unsigned int victim = prng( executor_->nworkers );
    540     if ( victim == id ) victim = ( victim + 1 ) % executor_->nworkers;
    541     choose_queue( this, victim, swap_idx );
    542     #elif SEARCH
    543     unsigned long long min = MAX; // smaller timestamp means longer since service
    544     int min_id = 0; // use ints not uints to avoid integer underflow without hacky math
    545     int n_workers = executor_->nworkers;
    546     unsigned long long curr_stamp;
    547     int scount = 1;
    548     for ( int i = (id + 1) % n_workers; scount < n_workers; i = (i + 1) % n_workers, scount++ ) {
    549         curr_stamp = executor_->w_infos[i].stamp;
    550         if ( curr_stamp < min ) {
    551             min = curr_stamp;
    552             min_id = i;
    553         }
    554     }
    555     choose_queue( this, min_id, swap_idx );
    556     #endif
    557306}
    558307
    559308void main( worker & this ) with(this) {
    560     // #ifdef ACTOR_STATS
    561     // for ( i; executor_->nrqueues ) {
    562     //     replaced_queue[i] = 0;
    563     //     __atomic_store_n( &stolen_arr[i], 0, __ATOMIC_SEQ_CST );
    564     // }
    565     // #endif
    566 
    567     // threshold of empty queues we see before we go stealing
    568     const unsigned int steal_threshold = 2 * range;
    569 
    570     // Store variable data here instead of worker struct to avoid any potential false sharing
    571     unsigned int empty_count = 0;
    572     request & req;
    573     work_queue * curr_work_queue;
    574 
     309    bool should_delete;
    575310    Exit:
    576311    for ( unsigned int i = 0;; i = (i + 1) % range ) { // cycle through set of request buffers
    577         curr_work_queue = request_queues[i + start];
    578        
    579         // check if queue is empty before trying to gulp it
    580         if ( isEmpty( *curr_work_queue->c_queue ) ) {
    581             #ifdef __STEAL
    582             empty_count++;
    583             if ( empty_count < steal_threshold ) continue;
    584             #else
    585             continue;
    586             #endif
    587         }
    588         transfer( *curr_work_queue, &current_queue );
    589         #ifdef ACTOR_STATS
    590         executor_->w_infos[id].gulps++;
    591         #endif // ACTOR_STATS
    592         #ifdef __STEAL
    593         if ( isEmpty( *current_queue ) ) {
    594             if ( unlikely( no_steal ) ) continue;
    595             empty_count++;
    596             if ( empty_count < steal_threshold ) continue;
    597             empty_count = 0;
    598 
    599             __atomic_store_n( &executor_->w_infos[id].stamp, rdtscl(), __ATOMIC_RELAXED );
    600            
    601             #ifdef ACTOR_STATS
    602             executor_->w_infos[id].try_steal++;
    603             #endif // ACTOR_STATS
    604            
    605             steal_work( this, start + prng( range ) );
    606             continue;
    607         }
    608         #endif // __STEAL
     312        // C_TODO: potentially check queue count instead of immediately trying to transfer
     313        transfer( request_queues[i + start], &current_queue );
    609314        while ( ! isEmpty( *current_queue ) ) {
    610             #ifdef ACTOR_STATS
    611             executor_->w_infos[id].processed++;
    612             #endif
    613             &req = &remove( *current_queue );
    614             if ( !&req ) continue;
     315            &req = &remove( *current_queue, should_delete );
     316            if ( !&req ) continue; // possibly add some work stealing/idle sleep here
    615317            if ( req.stop ) break Exit;
    616318            deliver_request( req );
    617         }
    618         #ifdef __STEAL
    619         curr_work_queue->being_processed = false; // set done processing
    620         empty_count = 0; // we found work so reset empty counter
    621         #endif
    622        
    623         // potentially reclaim some of the current queue's vector space if it is unused
    624         reclaim( *current_queue );
     319
     320            if ( should_delete ) delete( &req );
     321        } // while
    625322    } // for
    626323}
     
    631328
    632329static inline void send( actor & this, request & req ) {
    633     verifyf( this.ticket != (unsigned long int)MAX, "Attempted to send message to deleted/dead actor\n" );
    634330    send( *__actor_executor_, req, this.ticket );
    635331}
    636332
    637 static inline void __reset_stats() {
    638     #ifdef ACTOR_STATS
    639     __total_tries = 0;
    640     __total_stolen = 0;
    641     __all_gulps = 0;
    642     __total_failed_swaps = 0;
    643     __all_processed = 0;
    644     __num_actors_stats = 0;
    645     __all_msgs_stolen = 0;
    646     #endif
    647 }
    648 
    649333static inline void start_actor_system( size_t num_thds ) {
    650     __reset_stats();
    651334    __actor_executor_thd = active_thread();
    652335    __actor_executor_ = alloc();
     
    654337}
    655338
    656 // TODO: potentially revisit getting number of processors
    657 //  ( currently the value stored in active_cluster()->procs.total is often stale
    658 //  and doesn't reflect how many procs are allocated )
    659 // static inline void start_actor_system() { start_actor_system( active_cluster()->procs.total ); }
    660 static inline void start_actor_system() { start_actor_system( 1 ); }
     339static inline void start_actor_system() { start_actor_system( active_cluster()->procs.total ); }
    661340
    662341static inline void start_actor_system( executor & this ) {
    663     __reset_stats();
    664342    __actor_executor_thd = active_thread();
    665343    __actor_executor_ = &this;
     
    676354    __actor_executor_passed = false;
    677355}
    678 
    679 // Default messages to send to any actor to change status
    680 // assigned at creation to __base_msg_finished to avoid unused message warning
    681 message __base_msg_finished @= { .allocation_ : Finished };
    682 struct __DeleteMsg { inline message; } DeleteMsg = __base_msg_finished;
    683 struct __DestroyMsg { inline message; } DestroyMsg = __base_msg_finished;
    684 struct __FinishedMsg { inline message; } FinishedMsg = __base_msg_finished;
    685 
    686 Allocation receive( actor & this, __DeleteMsg & msg ) { return Delete; }
    687 Allocation receive( actor & this, __DestroyMsg & msg ) { return Destroy; }
    688 Allocation receive( actor & this, __FinishedMsg & msg ) { return Finished; }
    689 
  • libcfa/src/concurrency/channel.hfa

    rb110bcc r2ed94a9  
    1 #pragma once
     1#include <locks.hfa>
    22
    3 #include <locks.hfa>
    4 #include <list.hfa>
    5 #include <mutex_stmt.hfa>
     3struct no_reacq_lock {
     4    inline exp_backoff_then_block_lock;
     5};
    66
    7 // link field used for threads waiting on channel
    8 struct wait_link {
    9     // used to put wait_link on a dl queue
    10     inline dlink(wait_link);
    11 
    12     // waiting thread
    13     struct thread$ * t;
    14 
    15     // shadow field
    16     void * elem;
    17 };
    18 P9_EMBEDDED( wait_link, dlink(wait_link) )
    19 
    20 static inline void ?{}( wait_link & this, thread$ * t, void * elem ) {
    21     this.t = t;
    22     this.elem = elem;
    23 }
    24 
    25 // wake one thread from the list
    26 static inline void wake_one( dlist( wait_link ) & queue ) {
    27     wait_link & popped = try_pop_front( queue );
    28     unpark( popped.t );
    29 }
    30 
    31 // returns true if woken due to shutdown
    32 // blocks thread on list and releases passed lock
    33 static inline bool block( dlist( wait_link ) & queue, void * elem_ptr, go_mutex & lock ) {
    34     wait_link w{ active_thread(), elem_ptr };
    35     insert_last( queue, w );
    36     unlock( lock );
    37     park();
    38     return w.elem == 0p;
    39 }
    40 
    41 // void * used for some fields since exceptions don't work with parametric polymorphism currently
    42 exception channel_closed {
    43     // on failed insert elem is a ptr to the element attempting to be inserted
    44     // on failed remove elem ptr is 0p
    45     // on resumption of a failed insert this elem will be inserted
    46     // so a user may modify it in the resumption handler
    47     void * elem;
    48 
    49     // pointer to chan that is closed
    50     void * closed_chan;
    51 };
    52 vtable(channel_closed) channel_closed_vt;
    53 
    54 // #define CHAN_STATS // define this to get channel stats printed in dtor
     7// have to override these by hand to get around plan 9 inheritance bug where resolver can't find the appropriate routine to call
     8static inline void   ?{}( no_reacq_lock & this ) { ((exp_backoff_then_block_lock &)this){}; }
     9static inline bool   try_lock(no_reacq_lock & this) { return try_lock(((exp_backoff_then_block_lock &)this)); }
     10static inline void   lock(no_reacq_lock & this) { lock(((exp_backoff_then_block_lock &)this)); }
     11static inline void   unlock(no_reacq_lock & this) { unlock(((exp_backoff_then_block_lock &)this)); }
     12static inline void   on_notify(no_reacq_lock & this, struct thread$ * t ) { on_notify(((exp_backoff_then_block_lock &)this), t); }
     13static inline size_t on_wait(no_reacq_lock & this) { return on_wait(((exp_backoff_then_block_lock &)this)); }
     14// override wakeup so that we don't reacquire the lock if using a condvar
     15static inline void   on_wakeup( no_reacq_lock & this, size_t recursion ) {}
    5516
    5617forall( T ) {
    57 
    58 struct __attribute__((aligned(128))) channel {
    59     size_t size, front, back, count;
     18struct channel {
     19    size_t size;
     20    size_t front, back, count;
    6021    T * buffer;
    61     dlist( wait_link ) prods, cons; // lists of blocked threads
    62     go_mutex mutex_lock;            // MX lock
    63     bool closed;                    // indicates channel close/open
    64     #ifdef CHAN_STATS
    65     size_t blocks, operations;      // counts total ops and ops resulting in a blocked thd
    66     #endif
     22    fast_cond_var( no_reacq_lock ) prods, cons;
     23    no_reacq_lock mutex_lock;
    6724};
    6825
     
    7027    size = _size;
    7128    front = back = count = 0;
    72     buffer = aalloc( size );
     29    buffer = anew( size );
    7330    prods{};
    7431    cons{};
    7532    mutex_lock{};
    76     closed = false;
    77     #ifdef CHAN_STATS
    78     blocks = 0;
    79     operations = 0;
    80     #endif
    8133}
    8234
    8335static inline void ?{}( channel(T) &c ){ ((channel(T) &)c){ 0 }; }
    84 static inline void ^?{}( channel(T) &c ) with(c) {
    85     #ifdef CHAN_STATS
    86     printf("Channel %p Blocks: %lu, Operations: %lu, %.2f%% of ops blocked\n", &c, blocks, operations, ((double)blocks)/operations * 100);
    87     #endif
    88     verifyf( cons`isEmpty && prods`isEmpty, "Attempted to delete channel with waiting threads (Deadlock).\n" );
    89     delete( buffer );
    90 }
     36static inline void ^?{}( channel(T) &c ) with(c) { delete( buffer ); }
    9137static inline size_t get_count( channel(T) & chan ) with(chan) { return count; }
    9238static inline size_t get_size( channel(T) & chan ) with(chan) { return size; }
    93 static inline bool has_waiters( channel(T) & chan ) with(chan) { return !cons`isEmpty || !prods`isEmpty; }
    94 static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !cons`isEmpty; }
    95 static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !prods`isEmpty; }
     39static inline bool has_waiters( channel(T) & chan ) with(chan) { return !empty( cons ) || !empty( prods ); }
     40static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !empty( cons ); }
     41static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !empty( prods ); }
    9642
    97 // closes the channel and notifies all blocked threads
    98 static inline void close( channel(T) & chan ) with(chan) {
    99     lock( mutex_lock );
    100     closed = true;
    101 
    102     // flush waiting consumers and producers
    103     while ( has_waiting_consumers( chan ) ) {
    104         cons`first.elem = 0p;
    105         wake_one( cons );
    106     }
    107     while ( has_waiting_producers( chan ) ) {
    108         prods`first.elem = 0p;
    109         wake_one( prods );
    110     }
    111     unlock(mutex_lock);
    112 }
    113 
    114 static inline void is_closed( channel(T) & chan ) with(chan) { return closed; }
    115 
    116 static inline void flush( channel(T) & chan, T elem ) with(chan) {
    117     lock( mutex_lock );
    118     while ( count == 0 && !cons`isEmpty ) {
    119         memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work
    120         wake_one( cons );
    121     }
    122     unlock( mutex_lock );
    123 }
    124 
    125 // handles buffer insert
    126 static inline void __buf_insert( channel(T) & chan, T & elem ) with(chan) {
     43static inline void insert_( channel(T) & chan, T elem ) with(chan) {
    12744    memcpy((void *)&buffer[back], (void *)&elem, sizeof(T));
    12845    count += 1;
     
    13148}
    13249
    133 // does the buffer insert or hands elem directly to consumer if one is waiting
    134 static inline void __do_insert( channel(T) & chan, T & elem ) with(chan) {
    135     if ( count == 0 && !cons`isEmpty ) {
    136         memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work
    137         wake_one( cons );
    138     } else __buf_insert( chan, elem );
    139 }
    140 
    141 // needed to avoid an extra copy in closed case
    142 static inline bool __internal_try_insert( channel(T) & chan, T & elem ) with(chan) {
    143     lock( mutex_lock );
    144     #ifdef CHAN_STATS
    145     operations++;
    146     #endif
    147     if ( count == size ) { unlock( mutex_lock ); return false; }
    148     __do_insert( chan, elem );
    149     unlock( mutex_lock );
    150     return true;
    151 }
    152 
    153 // attempts a nonblocking insert
    154 // returns true if insert was successful, false otherwise
    155 static inline bool try_insert( channel(T) & chan, T elem ) { return __internal_try_insert( chan, elem ); }
    156 
    157 // handles closed case of insert routine
    158 static inline void __closed_insert( channel(T) & chan, T & elem ) with(chan) {
    159     channel_closed except{&channel_closed_vt, &elem, &chan };
    160     throwResume except; // throw closed resumption
    161     if ( !__internal_try_insert( chan, elem ) ) throw except; // if try to insert fails (would block), throw termination
    162 }
    16350
    16451static inline void insert( channel(T) & chan, T elem ) with(chan) {
    165     // check for close before acquire mx
    166     if ( unlikely(closed) ) {
    167         __closed_insert( chan, elem );
    168         return;
    169     }
    170 
    17152    lock( mutex_lock );
    17253
    173     #ifdef CHAN_STATS
    174     if ( !closed ) operations++;
    175     #endif
    176 
    177     // if closed handle
    178     if ( unlikely(closed) ) {
     54    // have to check for the zero size channel case
     55    if ( size == 0 && !empty( cons ) ) {
     56        memcpy((void *)front( cons ), (void *)&elem, sizeof(T));
     57        notify_one( cons );
    17958        unlock( mutex_lock );
    180         __closed_insert( chan, elem );
    18159        return;
    18260    }
    18361
    184     // have to check for the zero size channel case
    185     if ( size == 0 && !cons`isEmpty ) {
    186         memcpy(cons`first.elem, (void *)&elem, sizeof(T));
    187         wake_one( cons );
    188         unlock( mutex_lock );
    189         return true;
    190     }
    191 
    19262    // wait if buffer is full, work will be completed by someone else
    193     if ( count == size ) {
    194         #ifdef CHAN_STATS
    195         blocks++;
    196         #endif
    197 
    198         // check for if woken due to close
    199         if ( unlikely( block( prods, &elem, mutex_lock ) ) )
    200             __closed_insert( chan, elem );
     63    if ( count == size ) {
     64        wait( prods, mutex_lock, (uintptr_t)&elem );
    20165        return;
    20266    } // if
    20367
    204     if ( count == 0 && !cons`isEmpty ) {
    205         memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work
    206         wake_one( cons );
    207     } else __buf_insert( chan, elem );
     68    if ( count == 0 && !empty( cons ) )
     69        // do waiting consumer work
     70        memcpy((void *)front( cons ), (void *)&elem, sizeof(T));
     71    else insert_( chan, elem );
    20872   
     73    notify_one( cons );
    20974    unlock( mutex_lock );
    210     return;
    211 }
    212 
    213 // handles buffer remove
    214 static inline void __buf_remove( channel(T) & chan, T & retval ) with(chan) {
    215     memcpy((void *)&retval, (void *)&buffer[front], sizeof(T));
    216     count -= 1;
    217     front = (front + 1) % size;
    218 }
    219 
    220 // does the buffer remove and potentially does waiting producer work
    221 static inline void __do_remove( channel(T) & chan, T & retval ) with(chan) {
    222     __buf_remove( chan, retval );
    223     if (count == size - 1 && !prods`isEmpty ) {
    224         __buf_insert( chan, *(T *)prods`first.elem );  // do waiting producer work
    225         wake_one( prods );
    226     }
    227 }
    228 
    229 // needed to avoid an extra copy in closed case and single return val case
    230 static inline bool __internal_try_remove( channel(T) & chan, T & retval ) with(chan) {
    231     lock( mutex_lock );
    232     #ifdef CHAN_STATS
    233     operations++;
    234     #endif
    235     if ( count == 0 ) { unlock( mutex_lock ); return false; }
    236     __do_remove( chan, retval );
    237     unlock( mutex_lock );
    238     return true;
    239 }
    240 
    241 // attempts a nonblocking remove
    242 // returns [T, true] if insert was successful
    243 // returns [T, false] if insert was successful (T uninit)
    244 static inline [T, bool] try_remove( channel(T) & chan ) {
    245     T retval;
    246     return [ retval, __internal_try_remove( chan, retval ) ];
    247 }
    248 
    249 static inline T try_remove( channel(T) & chan, T elem ) {
    250     T retval;
    251     __internal_try_remove( chan, retval );
    252     return retval;
    253 }
    254 
    255 // handles closed case of insert routine
    256 static inline void __closed_remove( channel(T) & chan, T & retval ) with(chan) {
    257     channel_closed except{&channel_closed_vt, 0p, &chan };
    258     throwResume except; // throw resumption
    259     if ( !__internal_try_remove( chan, retval ) ) throw except; // if try to remove fails (would block), throw termination
    26075}
    26176
    26277static inline T remove( channel(T) & chan ) with(chan) {
     78    lock( mutex_lock );
    26379    T retval;
    264     if ( unlikely(closed) ) {
    265         __closed_remove( chan, retval );
    266         return retval;
    267     }
    268     lock( mutex_lock );
    269 
    270     #ifdef CHAN_STATS
    271     if ( !closed ) operations++;
    272     #endif
    273 
    274     if ( unlikely(closed) ) {
    275         unlock( mutex_lock );
    276         __closed_remove( chan, retval );
    277         return retval;
    278     }
    27980
    28081    // have to check for the zero size channel case
    281     if ( size == 0 && !prods`isEmpty ) {
    282         memcpy((void *)&retval, (void *)prods`first.elem, sizeof(T));
    283         wake_one( prods );
     82    if ( size == 0 && !empty( prods ) ) {
     83        memcpy((void *)&retval, (void *)front( prods ), sizeof(T));
     84        notify_one( prods );
    28485        unlock( mutex_lock );
    28586        return retval;
     
    28788
    28889    // wait if buffer is empty, work will be completed by someone else
    289     if (count == 0) {
    290         #ifdef CHAN_STATS
    291         blocks++;
    292         #endif
    293         // check for if woken due to close
    294         if ( unlikely( block( cons, &retval, mutex_lock ) ) )
    295             __closed_remove( chan, retval );
     90    if (count == 0) {
     91        wait( cons, mutex_lock, (uintptr_t)&retval );
    29692        return retval;
    29793    }
    29894
    29995    // Remove from buffer
    300     __do_remove( chan, retval );
     96    memcpy((void *)&retval, (void *)&buffer[front], sizeof(T));
     97    count -= 1;
     98    front = (front + 1) % size;
    30199
     100    if (count == size - 1 && !empty( prods ) )
     101        insert_( chan, *((T *)front( prods )) );  // do waiting producer work
     102
     103    notify_one( prods );
    302104    unlock( mutex_lock );
    303105    return retval;
    304106}
     107
    305108} // forall( T )
  • libcfa/src/concurrency/clib/cfathread.cfa

    rb110bcc r2ed94a9  
    1616// #define EPOLL_FOR_SOCKETS
    1717
    18 #include <string.h>
    19 
    2018#include "fstream.hfa"
    2119#include "locks.hfa"
     
    2523#include "time.hfa"
    2624#include "stdlib.hfa"
    27 #include "iofwd.hfa"
     25
    2826#include "cfathread.h"
     27
     28extern "C" {
     29                #include <string.h>
     30                #include <errno.h>
     31}
    2932
    3033extern void ?{}(processor &, const char[], cluster &, thread$ *);
    3134extern "C" {
    32         extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
     35      extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
     36        extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
    3337}
    3438
     
    468472}
    469473
     474#include <iofwd.hfa>
     475
    470476extern "C" {
     477        #include <unistd.h>
     478        #include <sys/types.h>
     479        #include <sys/socket.h>
     480
    471481        //--------------------
    472482        // IO operations
     
    478488                , protocol);
    479489        }
    480         int cfathread_bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) {
     490        int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {
    481491                return bind(socket, address, address_len);
    482492        }
     
    486496        }
    487497
    488         int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len) {
     498        int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
    489499                #if defined(EPOLL_FOR_SOCKETS)
    490500                        int ret;
     
    503513        }
    504514
    505         int cfathread_connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) {
     515        int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {
    506516                #if defined(EPOLL_FOR_SOCKETS)
    507517                        int ret;
  • libcfa/src/concurrency/clib/cfathread.h

    rb110bcc r2ed94a9  
    99// Author           : Thierry Delisle
    1010// Created On       : Tue Sep 22 15:31:20 2020
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 13 23:48:40 2023
    13 // Update Count     : 7
     11// Last Modified By :
     12// Last Modified On :
     13// Update Count     :
    1414//
    1515
    16 #pragma once
    17 
    1816#if defined(__cforall) || defined(__cplusplus)
    19 #include <unistd.h>
    20 #include <errno.h>
    21 #include <sys/socket.h>
    22 
    2317extern "C" {
    2418#endif
     19        #include <asm/types.h>
     20        #include <errno.h>
     21        #include <unistd.h>
     22
     23
    2524        //--------------------
    2625        // Basic types
     
    7473        } cfathread_mutexattr_t;
    7574        typedef struct cfathread_mutex * cfathread_mutex_t;
    76         int cfathread_mutex_init(cfathread_mutex_t * restrict mut, const cfathread_mutexattr_t * restrict attr) __attribute__((nonnull (1)));
     75        int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict attr) __attribute__((nonnull (1)));
    7776        int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
    7877        int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
     
    9291        //--------------------
    9392        // IO operations
     93        struct sockaddr;
     94        struct msghdr;
    9495        int cfathread_socket(int domain, int type, int protocol);
    95         int cfathread_bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len);
     96        int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len);
    9697        int cfathread_listen(int socket, int backlog);
    97         int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t * restrict address_len);
    98         int cfathread_connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len);
     98        int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
     99        int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len);
    99100        int cfathread_dup(int fildes);
    100101        int cfathread_close(int fildes);
  • libcfa/src/concurrency/coroutine.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 16 15:34:46 2023
    13 // Update Count     : 24
     12// Last Modified On : Tue Dec 15 12:06:04 2020
     13// Update Count     : 23
    1414//
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819#include "coroutine.hfa"
  • libcfa/src/concurrency/future.hfa

    rb110bcc r2ed94a9  
    1414//
    1515
    16 #pragma once
     16// #pragma once
    1717
    1818#include "bits/locks.hfa"
  • libcfa/src/concurrency/invoke.h

    rb110bcc r2ed94a9  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 14 13:39:31 2023
    13 // Update Count     : 59
    14 //
    15 
    16 // No not use #pragma once was this file is included twice in some places. It has its own guard system.
     12// Last Modified On : Tue Nov 29 20:42:21 2022
     13// Update Count     : 56
     14//
    1715
    1816#include "bits/containers.hfa"
  • libcfa/src/concurrency/io.cfa

    rb110bcc r2ed94a9  
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819#if defined(__CFA_DEBUG__)
     
    295296                                // make sure the target hasn't stopped existing since last time
    296297                                HELP: if(target < ctxs_count) {
    297                                         // calculate it's age and how young it could be before we give up on helping
     298                                        // calculate it's age and how young it could be before we give ip on helping
    298299                                        const __readyQ_avg_t cutoff = calc_cutoff(ctsc, ctx->cq.id, ctxs_count, io.data, io.tscs, __shard_factor.io, false);
    299300                                        const __readyQ_avg_t age = moving_average(ctsc, io.tscs[target].t.tv, io.tscs[target].t.ma, false);
  • libcfa/src/concurrency/io/call.cfa.in

    rb110bcc r2ed94a9  
    3131Prelude = """#define __cforall_thread__
    3232
    33 #include <unistd.h>
    34 #include <errno.h>
    35 #include <sys/socket.h>
    36 #include <time.hfa>
    37 
    3833#include "bits/defs.hfa"
    3934#include "kernel.hfa"
     
    4843        #include <assert.h>
    4944        #include <stdint.h>
     45        #include <errno.h>
    5046        #include <linux/io_uring.h>
     47
    5148        #include "kernel/fwd.hfa"
    5249
     
    8582// I/O Forwards
    8683//=============================================================================================
     84#include <time.hfa>
     85
     86// Some forward declarations
     87#include <errno.h>
     88#include <unistd.h>
    8789
    8890extern "C" {
     91        #include <asm/types.h>
     92        #include <sys/socket.h>
     93        #include <sys/syscall.h>
     94
    8995#if defined(CFA_HAVE_PREADV2)
    9096        struct iovec;
    91         extern ssize_t preadv2 (int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags);
     97        extern ssize_t preadv2 (int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
    9298#endif
    9399#if defined(CFA_HAVE_PWRITEV2)
    94100        struct iovec;
    95         extern ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags);
     101        extern ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
    96102#endif
    97103
     
    108114        struct msghdr;
    109115        struct sockaddr;
    110         extern ssize_t sendmsg(int sockfd, const struct msghdr * msg, int flags);
    111         extern ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags);
    112         extern ssize_t send(int sockfd, const void * buf, size_t len, int flags);
    113         extern ssize_t recv(int sockfd, void * buf, size_t len, int flags);
     116        extern ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
     117        extern ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
     118        extern ssize_t send(int sockfd, const void *buf, size_t len, int flags);
     119        extern ssize_t recv(int sockfd, void *buf, size_t len, int flags);
     120        extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
     121        extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    114122
    115123        extern int fallocate(int fd, int mode, off_t offset, off_t len);
    116124        extern int posix_fadvise(int fd, off_t offset, off_t len, int advice);
    117         extern int madvise(void * addr, size_t length, int advice);
    118 
    119         extern int openat(int dirfd, const char * pathname, int flags, mode_t mode);
     125        extern int madvise(void *addr, size_t length, int advice);
     126
     127        extern int openat(int dirfd, const char *pathname, int flags, mode_t mode);
    120128        extern int close(int fd);
    121129
    122         extern ssize_t read (int fd, void * buf, size_t count);
     130        extern ssize_t read (int fd, void *buf, size_t count);
    123131
    124132        struct epoll_event;
    125         extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event);
    126 
    127         extern ssize_t splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags);
     133        extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
     134
     135        extern ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags);
    128136        extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
    129137}
     
    224232calls = [
    225233        # CFA_HAVE_IORING_OP_READV
    226         Call('READV', 'ssize_t preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', {
     234        Call('READV', 'ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)', {
    227235                'fd'  : 'fd',
    228                 'addr': '(typeof(sqe->addr))iov',
     236                'off' : 'offset',
     237                'addr': '(uintptr_t)iov',
    229238                'len' : 'iovcnt',
    230                 'off' : 'offset',
    231                 'rw_flags' : 'flags'
    232239        }, define = 'CFA_HAVE_PREADV2'),
    233240        # CFA_HAVE_IORING_OP_WRITEV
    234         Call('WRITEV', 'ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', {
     241        Call('WRITEV', 'ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)', {
    235242                'fd'  : 'fd',
    236                 'addr': '(typeof(sqe->addr))iov',
    237                 'len' : 'iovcnt',
    238243                'off' : 'offset',
    239                 'rw_flags' : 'flags'
     244                'addr': '(uintptr_t)iov',
     245                'len' : 'iovcnt'
    240246        }, define = 'CFA_HAVE_PWRITEV2'),
    241247        # CFA_HAVE_IORING_OP_FSYNC
     
    244250        }),
    245251        # CFA_HAVE_IORING_OP_EPOLL_CTL
    246         Call('EPOLL_CTL', 'int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event)', {
     252        Call('EPOLL_CTL', 'int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)', {
    247253                'fd': 'epfd',
     254                'addr': 'fd',
    248255                'len': 'op',
    249                 'addr': 'fd',
    250                 'off': '(typeof(sqe->off))event'
     256                'off': '(uintptr_t)event'
    251257        }),
    252258        # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
     
    258264        }),
    259265        # CFA_HAVE_IORING_OP_SENDMSG
    260         Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr * msg, int flags)', {
    261                 'fd': 'sockfd',
    262                 'addr': '(typeof(sqe->addr))(struct msghdr *)msg',
     266        Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', {
     267                'fd': 'sockfd',
     268                'addr': '(uintptr_t)(struct msghdr *)msg',
    263269                'len': '1',
    264270                'msg_flags': 'flags'
    265271        }),
    266272        # CFA_HAVE_IORING_OP_RECVMSG
    267         Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags)', {
    268                 'fd': 'sockfd',
    269                 'addr': '(typeof(sqe->addr))(struct msghdr *)msg',
     273        Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', {
     274                'fd': 'sockfd',
     275                'addr': '(uintptr_t)(struct msghdr *)msg',
    270276                'len': '1',
    271277                'msg_flags': 'flags'
    272278        }),
    273279        # CFA_HAVE_IORING_OP_SEND
    274         Call('SEND', 'ssize_t send(int sockfd, const void * buf, size_t len, int flags)', {
    275                 'fd': 'sockfd',
    276                 'addr': '(typeof(sqe->addr))buf',
     280        Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', {
     281                'fd': 'sockfd',
     282                'addr': '(uintptr_t)buf',
    277283                'len': 'len',
    278284                'msg_flags': 'flags'
    279285        }),
    280286        # CFA_HAVE_IORING_OP_RECV
    281         Call('RECV', 'ssize_t recv(int sockfd, void * buf, size_t len, int flags)', {
    282                 'fd': 'sockfd',
    283                 'addr': '(typeof(sqe->addr))buf',
     287        Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', {
     288                'fd': 'sockfd',
     289                'addr': '(uintptr_t)buf',
    284290                'len': 'len',
    285291                'msg_flags': 'flags'
    286292        }),
    287293        # CFA_HAVE_IORING_OP_ACCEPT
    288         Call('ACCEPT', 'int accept4(int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags)', {
    289                 'fd': 'sockfd',
    290                 'addr': '(typeof(sqe->addr))&addr',
    291                 'addr2': '(typeof(sqe->addr2))addrlen',
     294        Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', {
     295                'fd': 'sockfd',
     296                'addr': '(uintptr_t)addr',
     297                'addr2': '(uintptr_t)addrlen',
    292298                'accept_flags': 'flags'
    293299        }),
    294300        # CFA_HAVE_IORING_OP_CONNECT
    295         Call('CONNECT', 'int connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen)', {
    296                 'fd': 'sockfd',
    297                 'addr': '(typeof(sqe->addr))&addr',
     301        Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {
     302                'fd': 'sockfd',
     303                'addr': '(uintptr_t)addr',
    298304                'off': 'addrlen'
    299305        }),
     
    301307        Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
    302308                'fd': 'fd',
     309                'addr': '(uintptr_t)len',
    303310                'len': 'mode',
    304                 'off': 'offset',
    305                 'addr': 'len'
     311                'off': 'offset'
    306312        }),
    307313        # CFA_HAVE_IORING_OP_FADVISE
     
    313319        }),
    314320        # CFA_HAVE_IORING_OP_MADVISE
    315         Call('MADVISE', 'int madvise(void * addr, size_t length, int advice)', {
    316                 'addr': '(typeof(sqe->addr))addr',
     321        Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', {
     322                'addr': '(uintptr_t)addr',
    317323                'len': 'length',
    318324                'fadvise_advice': 'advice'
    319325        }),
    320326        # CFA_HAVE_IORING_OP_OPENAT
    321         Call('OPENAT', 'int openat(int dirfd, const char * pathname, int flags, mode_t mode)', {
     327        Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', {
    322328                'fd': 'dirfd',
    323                 'addr': '(typeof(sqe->addr))pathname',
    324                 'open_flags': 'flags;',
    325                 'len': 'mode'
     329                'addr': '(uintptr_t)pathname',
     330                'len': 'mode',
     331                'open_flags': 'flags;'
    326332        }),
    327333        # CFA_HAVE_IORING_OP_OPENAT2
    328         Call('OPENAT2', 'int openat2(int dirfd, const char * pathname, struct open_how * how, size_t size)', {
     334        Call('OPENAT2', 'int openat2(int dirfd, const char *pathname, struct open_how * how, size_t size)', {
    329335                'fd': 'dirfd',
    330                 'addr': '(typeof(sqe->addr))pathname',
    331                 'off': '(typeof(sqe->off))how',
    332                 'len': 'sizeof(*how)'
     336                'addr': 'pathname',
     337                'len': 'sizeof(*how)',
     338                'off': '(uintptr_t)how',
    333339        }, define = 'CFA_HAVE_OPENAT2'),
    334340        # CFA_HAVE_IORING_OP_CLOSE
     
    337343        }),
    338344        # CFA_HAVE_IORING_OP_STATX
    339         Call('STATX', 'int statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf)', {
     345        Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', {
    340346                'fd': 'dirfd',
    341                 'addr': '(typeof(sqe->addr))pathname',
    342                 'statx_flags': 'flags',
     347                'off': '(uintptr_t)statxbuf',
     348                'addr': 'pathname',
    343349                'len': 'mask',
    344                 'off': '(typeof(sqe->off))statxbuf'
     350                'statx_flags': 'flags'
    345351        }, define = 'CFA_HAVE_STATX'),
    346352        # CFA_HAVE_IORING_OP_READ
    347353        Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
    348354                'fd': 'fd',
    349                 'addr': '(typeof(sqe->addr))buf',
     355                'addr': '(uintptr_t)buf',
    350356                'len': 'count'
    351357        }),
     
    353359        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
    354360                'fd': 'fd',
    355                 'addr': '(typeof(sqe->addr))buf',
     361                'addr': '(uintptr_t)buf',
    356362                'len': 'count'
    357363        }),
    358364        # CFA_HAVE_IORING_OP_SPLICE
    359         Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags)', {
     365        Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags)', {
    360366                'splice_fd_in': 'fd_in',
    361                 'splice_off_in': 'off_in ? (typeof(sqe->splice_off_in))*off_in : (typeof(sqe->splice_off_in))-1',
     367                'splice_off_in': 'off_in ? (__u64)*off_in : (__u64)-1',
    362368                'fd': 'fd_out',
    363                 'off': 'off_out ? (typeof(sqe->off))*off_out : (typeof(sqe->off))-1',
     369                'off': 'off_out ? (__u64)*off_out : (__u64)-1',
    364370                'len': 'len',
    365371                'splice_flags': 'flags'
  • libcfa/src/concurrency/io/setup.cfa

    rb110bcc r2ed94a9  
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819#if defined(__CFA_DEBUG__)
  • libcfa/src/concurrency/iofwd.hfa

    rb110bcc r2ed94a9  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu Apr 23 17:31:00 2020
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 13 23:54:57 2023
    13 // Update Count     : 1
     11// Last Modified By :
     12// Last Modified On :
     13// Update Count     :
    1414//
    1515
     
    1717
    1818#include <unistd.h>
    19 #include <sys/socket.h>
    20 
    2119extern "C" {
    2220        #include <asm/types.h>
     
    5048typedef __off64_t off64_t;
    5149
     50struct cluster;
     51struct io_context$;
     52
     53struct iovec;
     54struct msghdr;
     55struct sockaddr;
     56struct statx;
    5257struct epoll_event;
     58
     59struct io_uring_sqe;
    5360
    5461//-----------------------------------------------------------------------
     
    8188// synchronous calls
    8289#if defined(CFA_HAVE_PREADV2)
    83         extern ssize_t cfa_preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     90        extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    8491#endif
    8592#if defined(CFA_HAVE_PWRITEV2)
    86         extern ssize_t cfa_pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     93        extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    8794#endif
    8895extern int cfa_fsync(int fd, __u64 submit_flags);
    89 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);
     96extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
    9097extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
    91 extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);
    92 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);
    93 extern ssize_t cfa_send(int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);
    94 extern ssize_t cfa_recv(int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);
    95 extern int cfa_accept4(int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags);
    96 extern int cfa_connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags);
     98extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
     99extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
     100extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
     101extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
     102extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
     103extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
    97104extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    98105extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
    99 extern int cfa_madvise(void * addr, size_t length, int advice, __u64 submit_flags);
    100 extern int cfa_openat(int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);
     106extern int cfa_madvise(void *addr, size_t length, int advice, __u64 submit_flags);
     107extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
    101108#if defined(CFA_HAVE_OPENAT2)
    102         extern int cfa_openat2(int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags);
     109        extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
    103110#endif
    104111extern int cfa_close(int fd, __u64 submit_flags);
    105112#if defined(CFA_HAVE_STATX)
    106         extern int cfa_statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf, __u64 submit_flags);
     113        extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);
    107114#endif
    108115extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags);
    109116extern ssize_t cfa_write(int fd, void * buf, size_t count, __u64 submit_flags);
    110 extern ssize_t cfa_splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags, __u64 submit_flags);
     117extern ssize_t cfa_splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);
    111118extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    112119
     
    114121// asynchronous calls
    115122#if defined(CFA_HAVE_PREADV2)
    116         extern void async_preadv2(io_future_t & future, int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     123        extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    117124#endif
    118125#if defined(CFA_HAVE_PWRITEV2)
    119         extern void async_pwritev2(io_future_t & future, int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     126        extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    120127#endif
    121128extern void async_fsync(io_future_t & future, int fd, __u64 submit_flags);
    122 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);
     129extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
    123130extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
    124 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);
    125 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);
    126 extern void async_send(io_future_t & future, int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);
    127 extern void async_recv(io_future_t & future, int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);
    128 extern void async_accept4(io_future_t & future, int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags);
    129 extern void async_connect(io_future_t & future, int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags);
     131extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
     132extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
     133extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
     134extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
     135extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
     136extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
    130137extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    131138extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
    132 extern void async_madvise(io_future_t & future, void * addr, size_t length, int advice, __u64 submit_flags);
    133 extern void async_openat(io_future_t & future, int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);
     139extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, __u64 submit_flags);
     140extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
    134141#if defined(CFA_HAVE_OPENAT2)
    135         extern void async_openat2(io_future_t & future, int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags);
     142        extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
    136143#endif
    137144extern void async_close(io_future_t & future, int fd, __u64 submit_flags);
    138145#if defined(CFA_HAVE_STATX)
    139         extern void async_statx(io_future_t & future, int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf, __u64 submit_flags);
     146        extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);
    140147#endif
    141148void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
    142149extern void async_write(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
    143 extern void async_splice(io_future_t & future, int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags, __u64 submit_flags);
     150extern void async_splice(io_future_t & future, int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);
    144151extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    145152
  • libcfa/src/concurrency/kernel.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan  9 08:42:05 2023
    13 // Update Count     : 77
     12// Last Modified On : Wed Nov 30 18:14:08 2022
     13// Update Count     : 76
    1414//
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
  • libcfa/src/concurrency/kernel/cluster.cfa

    rb110bcc r2ed94a9  
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819#include "bits/defs.hfa"
     
    6869        return max_cores_l;
    6970}
     71
     72#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
     73        // No forward declaration needed
     74        #define __kernel_rseq_register rseq_register_current_thread
     75        #define __kernel_rseq_unregister rseq_unregister_current_thread
     76#elif defined(CFA_HAVE_LINUX_RSEQ_H)
     77        static void __kernel_raw_rseq_register  (void);
     78        static void __kernel_raw_rseq_unregister(void);
     79
     80        #define __kernel_rseq_register __kernel_raw_rseq_register
     81        #define __kernel_rseq_unregister __kernel_raw_rseq_unregister
     82#else
     83        // No forward declaration needed
     84        // No initialization needed
     85        static inline void noop(void) {}
     86
     87        #define __kernel_rseq_register noop
     88        #define __kernel_rseq_unregister noop
     89#endif
    7090
    7191//=======================================================================
     
    91111// Lock-Free registering/unregistering of threads
    92112unsigned register_proc_id( void ) with(__scheduler_lock.lock) {
     113        __kernel_rseq_register();
     114
    93115        bool * handle = (bool *)&kernelTLS().sched_lock;
    94116
     
    140162
    141163        __atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
     164
     165        __kernel_rseq_unregister();
    142166}
    143167
     
    481505        /* paranoid */ verify( mock_head(this)    == this.l.prev );
    482506}
     507
     508#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
     509        // No definition needed
     510#elif defined(CFA_HAVE_LINUX_RSEQ_H)
     511
     512        #if defined( __x86_64 ) || defined( __i386 )
     513                #define RSEQ_SIG        0x53053053
     514        #elif defined( __ARM_ARCH )
     515                #ifdef __ARMEB__
     516                #define RSEQ_SIG    0xf3def5e7      /* udf    #24035    ; 0x5de3 (ARMv6+) */
     517                #else
     518                #define RSEQ_SIG    0xe7f5def3      /* udf    #24035    ; 0x5de3 */
     519                #endif
     520        #endif
     521
     522        extern void __disable_interrupts_hard();
     523        extern void __enable_interrupts_hard();
     524
     525        static void __kernel_raw_rseq_register  (void) {
     526                /* paranoid */ verify( __cfaabi_rseq.cpu_id == RSEQ_CPU_ID_UNINITIALIZED );
     527
     528                // int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, (sigset_t *)0p, _NSIG / 8);
     529                int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, RSEQ_SIG);
     530                if(ret != 0) {
     531                        int e = errno;
     532                        switch(e) {
     533                        case EINVAL: abort("KERNEL ERROR: rseq register invalid argument");
     534                        case ENOSYS: abort("KERNEL ERROR: rseq register no supported");
     535                        case EFAULT: abort("KERNEL ERROR: rseq register with invalid argument");
     536                        case EBUSY : abort("KERNEL ERROR: rseq register already registered");
     537                        case EPERM : abort("KERNEL ERROR: rseq register sig  argument  on unregistration does not match the signature received on registration");
     538                        default: abort("KERNEL ERROR: rseq register unexpected return %d", e);
     539                        }
     540                }
     541        }
     542
     543        static void __kernel_raw_rseq_unregister(void) {
     544                /* paranoid */ verify( __cfaabi_rseq.cpu_id >= 0 );
     545
     546                // int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, (sigset_t *)0p, _NSIG / 8);
     547                int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
     548                if(ret != 0) {
     549                        int e = errno;
     550                        switch(e) {
     551                        case EINVAL: abort("KERNEL ERROR: rseq unregister invalid argument");
     552                        case ENOSYS: abort("KERNEL ERROR: rseq unregister no supported");
     553                        case EFAULT: abort("KERNEL ERROR: rseq unregister with invalid argument");
     554                        case EBUSY : abort("KERNEL ERROR: rseq unregister already registered");
     555                        case EPERM : abort("KERNEL ERROR: rseq unregister sig  argument  on unregistration does not match the signature received on registration");
     556                        default: abort("KERNEL ERROR: rseq unregisteunexpected return %d", e);
     557                        }
     558                }
     559        }
     560#else
     561        // No definition needed
     562#endif
  • libcfa/src/concurrency/kernel/cluster.hfa

    rb110bcc r2ed94a9  
    146146}
    147147
    148 const static struct {
    149         unsigned readyq;
    150         unsigned io;
     148static struct {
     149        const unsigned readyq;
     150        const unsigned io;
    151151} __shard_factor = { 2, 1 };
    152152
  • libcfa/src/concurrency/kernel/private.hfa

    rb110bcc r2ed94a9  
    1010// Created On       : Mon Feb 13 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar  2 16:04:46 2023
    13 // Update Count     : 11
     12// Last Modified On : Wed Aug 12 08:21:33 2020
     13// Update Count     : 9
    1414//
    1515
     
    2929
    3030extern "C" {
     31#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
     32        #include <rseq/rseq.h>
     33#elif defined(CFA_HAVE_LINUX_RSEQ_H)
     34        #include <linux/rseq.h>
     35#else
     36        #ifndef _GNU_SOURCE
     37        #error kernel/private requires gnu_source
     38        #endif
    3139        #include <sched.h>
     40#endif
    3241}
    3342
     
    101110// Hardware
    102111
     112#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
     113        // No data needed
     114#elif defined(CFA_HAVE_LINUX_RSEQ_H)
     115        extern "Cforall" {
     116                extern __attribute__((aligned(64))) __thread volatile struct rseq __cfaabi_rseq;
     117        }
     118#else
     119        // No data needed
     120#endif
     121
    103122static inline int __kernel_getcpu() {
    104123        /* paranoid */ verify( ! __preemption_enabled() );
     124#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
     125        return rseq_current_cpu();
     126#elif defined(CFA_HAVE_LINUX_RSEQ_H)
     127        int r = __cfaabi_rseq.cpu_id;
     128        /* paranoid */ verify( r >= 0 );
     129        return r;
     130#else
    105131        return sched_getcpu();
     132#endif
    106133}
    107134
  • libcfa/src/concurrency/kernel/startup.cfa

    rb110bcc r2ed94a9  
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    1920
    2021// C Includes
    21 #include <errno.h>                                                                              // errno
     22#include <errno.h>                                      // errno
    2223#include <signal.h>
    23 #include <string.h>                                                                             // strerror
    24 #include <unistd.h>
    25 #include <limits.h>                                                                             // PTHREAD_STACK_MIN
     24#include <string.h>                                     // strerror
     25#include <unistd.h>                                     // sysconf
     26
    2627extern "C" {
    27         #include <sys/eventfd.h>                                                        // eventfd
    28         #include <sys/mman.h>                                                           // mprotect
    29         #include <sys/resource.h>                                                       // getrlimit
     28        #include <limits.h>                             // PTHREAD_STACK_MIN
     29        #include <unistd.h>                             // syscall
     30        #include <sys/eventfd.h>                        // eventfd
     31        #include <sys/mman.h>                           // mprotect
     32        #include <sys/resource.h>                       // getrlimit
    3033}
    3134
     
    3336#include "kernel/private.hfa"
    3437#include "iofwd.hfa"
    35 #include "startup.hfa"                                                                  // STARTUP_PRIORITY_XXX
     38#include "startup.hfa"                                  // STARTUP_PRIORITY_XXX
    3639#include "limits.hfa"
    3740#include "math.hfa"
     
    147150__scheduler_RWLock_t __scheduler_lock @= { 0 };
    148151
     152#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
     153        // No data needed
     154#elif defined(CFA_HAVE_LINUX_RSEQ_H)
     155        extern "Cforall" {
     156                __attribute__((aligned(64))) __thread volatile struct rseq __cfaabi_rseq @= {
     157                        .cpu_id : RSEQ_CPU_ID_UNINITIALIZED,
     158                };
     159        }
     160#else
     161        // No data needed
     162#endif
     163
    149164//-----------------------------------------------------------------------------
    150165// Struct to steal stack
  • libcfa/src/concurrency/locks.cfa

    rb110bcc r2ed94a9  
    1616
    1717#define __cforall_thread__
     18#define _GNU_SOURCE
    1819
    1920#include "locks.hfa"
  • libcfa/src/concurrency/locks.hfa

    rb110bcc r2ed94a9  
    3232#include <fstream.hfa>
    3333
     34
    3435// futex headers
    3536#include <linux/futex.h>      /* Definition of FUTEX_* constants */
     
    154155// futex_mutex
    155156
     157// - No cond var support
    156158// - Kernel thd blocking alternative to the spinlock
    157159// - No ownership (will deadlock on reacq)
     
    183185        int state;
    184186
    185         for( int spin = 4; spin < 1024; spin += spin) {
    186                 state = 0;
    187                 // if unlocked, lock and return
    188                 if (internal_try_lock(this, state)) return;
    189                 if (2 == state) break;
    190                 for (int i = 0; i < spin; i++) Pause();
    191         }
    192 
    193         // // no contention try to acquire
    194         // if (internal_try_lock(this, state)) return;
     187       
     188        // // linear backoff omitted for now
     189        // for( int spin = 4; spin < 1024; spin += spin) {
     190        //      state = 0;
     191        //      // if unlocked, lock and return
     192        //      if (internal_try_lock(this, state)) return;
     193        //      if (2 == state) break;
     194        //      for (int i = 0; i < spin; i++) Pause();
     195        // }
     196
     197        // no contention try to acquire
     198        if (internal_try_lock(this, state)) return;
    195199       
    196200        // if not in contended state, set to be in contended state
     
    205209
    206210static inline void unlock(futex_mutex & this) with(this) {
    207         // if uncontended do atomic unlock and then return
    208     if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
     211        // if uncontended do atomice unlock and then return
     212        if (__atomic_fetch_sub(&val, 1, __ATOMIC_RELEASE) == 1) return; // TODO: try acq/rel
    209213       
    210214        // otherwise threads are blocked so we must wake one
     215        __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);
    211216        futex((int *)&val, FUTEX_WAKE, 1);
    212217}
     
    217222// to set recursion count after getting signalled;
    218223static inline void on_wakeup( futex_mutex & f, size_t recursion ) {}
    219 
    220 //-----------------------------------------------------------------------------
    221 // go_mutex
    222 
    223 // - Kernel thd blocking alternative to the spinlock
    224 // - No ownership (will deadlock on reacq)
    225 // - Golang's flavour of mutex
    226 // - Impl taken from Golang: src/runtime/lock_futex.go
    227 struct go_mutex {
    228         // lock state any state other than UNLOCKED is locked
    229         // enum LockState { UNLOCKED = 0, LOCKED = 1, SLEEPING = 2 };
    230        
    231         // stores a lock state
    232         int val;
    233 };
    234 
    235 static inline void  ?{}( go_mutex & this ) with(this) { val = 0; }
    236 
    237 static inline bool internal_try_lock(go_mutex & this, int & compare_val, int new_val ) with(this) {
    238         return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, new_val, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
    239 }
    240 
    241 static inline int internal_exchange(go_mutex & this, int swap ) with(this) {
    242         return __atomic_exchange_n((int*)&val, swap, __ATOMIC_ACQUIRE);
    243 }
    244 
    245 // if this is called recursively IT WILL DEADLOCK!!!!!
    246 static inline void lock(go_mutex & this) with(this) {
    247         int state, init_state;
    248 
    249     // speculative grab
    250     state = internal_exchange(this, 1);
    251     if ( !state ) return; // state == 0
    252     init_state = state;
    253     for (;;) {
    254         for( int i = 0; i < 4; i++ ) {
    255             while( !val ) { // lock unlocked
    256                 state = 0;
    257                 if (internal_try_lock(this, state, init_state)) return;
    258             }
    259             for (int i = 0; i < 30; i++) Pause();
    260         }
    261 
    262         while( !val ) { // lock unlocked
    263             state = 0;
    264             if (internal_try_lock(this, state, init_state)) return;
    265         }
    266         sched_yield();
    267        
    268         // if not in contended state, set to be in contended state
    269         state = internal_exchange(this, 2);
    270         if ( !state ) return; // state == 0
    271         init_state = 2;
    272         futex((int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK
    273     }
    274 }
    275 
    276 static inline void unlock( go_mutex & this ) with(this) {
    277         // if uncontended do atomic unlock and then return
    278     if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
    279        
    280         // otherwise threads are blocked so we must wake one
    281         futex((int *)&val, FUTEX_WAKE, 1);
    282 }
    283 
    284 static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); }
    285 static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;}
    286 static inline void on_wakeup( go_mutex & f, size_t recursion ) {}
    287224
    288225//-----------------------------------------------------------------------------
     
    316253static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); }
    317254
     255
    318256//-----------------------------------------------------------------------------
    319257// Exponential backoff then block lock
     
    334272        this.lock_value = 0;
    335273}
    336 
    337 static inline void  ^?{}( exp_backoff_then_block_lock & this ){}
     274static inline void ^?{}( exp_backoff_then_block_lock & this ) {}
     275// static inline void ?{}( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void;
     276// static inline void ?=?( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void;
    338277
    339278static inline bool internal_try_lock(exp_backoff_then_block_lock & this, size_t & compare_val) with(this) {
    340         return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
     279        if (__atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
     280                return true;
     281        }
     282        return false;
    341283}
    342284
     
    344286
    345287static inline bool try_lock_contention(exp_backoff_then_block_lock & this) with(this) {
    346         return !__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE);
     288        if (__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE) == 0) {
     289                return true;
     290        }
     291        return false;
    347292}
    348293
    349294static inline bool block(exp_backoff_then_block_lock & this) with(this) {
    350     lock( spinlock __cfaabi_dbg_ctx2 );
    351     if (__atomic_load_n( &lock_value, __ATOMIC_SEQ_CST) != 2) {
    352         unlock( spinlock );
    353         return true;
    354     }
    355     insert_last( blocked_threads, *active_thread() );
    356     unlock( spinlock );
     295        lock( spinlock __cfaabi_dbg_ctx2 ); // TODO change to lockfree queue (MPSC)
     296        if (lock_value != 2) {
     297                unlock( spinlock );
     298                return true;
     299        }
     300        insert_last( blocked_threads, *active_thread() );
     301        unlock( spinlock );
    357302        park( );
    358303        return true;
     
    362307        size_t compare_val = 0;
    363308        int spin = 4;
    364 
    365309        // linear backoff
    366310        for( ;; ) {
     
    380324static inline void unlock(exp_backoff_then_block_lock & this) with(this) {
    381325    if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return;
    382     lock( spinlock __cfaabi_dbg_ctx2 );
    383     thread$ * t = &try_pop_front( blocked_threads );
    384     unlock( spinlock );
    385     unpark( t );
     326        lock( spinlock __cfaabi_dbg_ctx2 );
     327        thread$ * t = &try_pop_front( blocked_threads );
     328        unlock( spinlock );
     329        unpark( t );
    386330}
    387331
  • libcfa/src/concurrency/monitor.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 19 17:00:59 2023
    13 // Update Count     : 12
     12// Last Modified On : Wed Dec  4 07:55:14 2019
     13// Update Count     : 10
    1414//
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819#include "monitor.hfa"
  • libcfa/src/concurrency/mutex.cfa

    rb110bcc r2ed94a9  
    1212// Created On       : Fri May 25 01:37:11 2018
    1313// Last Modified By : Peter A. Buhr
    14 // Last Modified On : Sun Feb 19 17:01:36 2023
    15 // Update Count     : 3
     14// Last Modified On : Wed Dec  4 09:16:39 2019
     15// Update Count     : 1
    1616//
    1717
    1818#define __cforall_thread__
     19#define _GNU_SOURCE
    1920
    2021#include "mutex.hfa"
  • libcfa/src/concurrency/mutex_stmt.hfa

    rb110bcc r2ed94a9  
    1 #pragma once
    2 
    31#include "bits/algorithm.hfa"
    42#include "bits/defs.hfa"
     
    64//-----------------------------------------------------------------------------
    75// is_lock
    8 forall(L & | sized(L))
    9 trait is_lock {
     6trait is_lock(L & | sized(L)) {
    107        // For acquiring a lock
    118        void lock( L & );
     
    2724    // Sort locks based on address
    2825    __libcfa_small_sort(this.lockarr, count);
     26
     27    // acquire locks in order
     28    // for ( size_t i = 0; i < count; i++ ) {
     29    //     lock(*this.lockarr[i]);
     30    // }
     31}
     32
     33static inline void ^?{}( __mutex_stmt_lock_guard & this ) with(this) {
     34    // for ( size_t i = count; i > 0; i-- ) {
     35    //     unlock(*lockarr[i - 1]);
     36    // }
    2937}
    3038
  • libcfa/src/concurrency/preemption.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Mon Jun 5 14:20:42 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan  9 08:42:59 2023
    13 // Update Count     : 60
     12// Last Modified On : Thu Feb 17 11:18:57 2022
     13// Update Count     : 59
    1414//
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819// #define __CFA_DEBUG_PRINT_PREEMPTION__
  • libcfa/src/concurrency/pthread.cfa

    rb110bcc r2ed94a9  
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819#include <signal.h>
     
    3435struct pthread_values{
    3536        inline Seqable;
    36         void * value;
     37        void* value;
    3738        bool in_use;
    3839};
     
    5051struct pthread_keys {
    5152        bool in_use;
    52         void (* destructor)( void * );
     53        void (*destructor)( void * );
    5354        Sequence(pthread_values) threads;
    5455};
    5556
    56 static void ?{}(pthread_keys& k) {
     57static void ?{}(pthread_keys& k){
    5758        k.threads{};
    5859}
     
    6162static pthread_keys cfa_pthread_keys_storage[PTHREAD_KEYS_MAX] __attribute__((aligned (16)));
    6263
    63 static void init_pthread_storage() {
    64         for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
     64static void init_pthread_storage(){
     65        for (int i = 0; i < PTHREAD_KEYS_MAX; i++){
    6566                cfa_pthread_keys_storage[i]{};
    6667        }
     
    9596
    9697/* condvar helper routines */
    97 static void init(pthread_cond_t * pcond) {
     98static void init(pthread_cond_t* pcond){
    9899        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
    99         cfa2pthr_cond_var_t * _cond = (cfa2pthr_cond_var_t *)pcond;
     100        cfa2pthr_cond_var_t* _cond = (cfa2pthr_cond_var_t*)pcond;
    100101        ?{}(*_cond);
    101102}
    102103
    103 static cfa2pthr_cond_var_t * get(pthread_cond_t * pcond) {
     104static cfa2pthr_cond_var_t* get(pthread_cond_t* pcond){
    104105        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
    105         return (cfa2pthr_cond_var_t *)pcond;
    106 }
    107 
    108 static void destroy(pthread_cond_t * cond) {
     106        return (cfa2pthr_cond_var_t*)pcond;
     107}
     108
     109static void destroy(pthread_cond_t* cond){
    109110        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
    110111        ^?{}(*get(cond));
     
    115116
    116117/* mutex helper routines */
    117 static void mutex_check(pthread_mutex_t * t) {
     118static void mutex_check(pthread_mutex_t* t){
    118119        // Use double check to improve performance.
    119120        // Check is safe on x86; volatile prevents compiler reordering
    120         volatile pthread_mutex_t * const mutex_ = t;
     121        volatile pthread_mutex_t *const mutex_ = t;
    121122
    122123        // SKULLDUGGERY: not a portable way to access the kind field, /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h
     
    135136
    136137
    137 static void init(pthread_mutex_t * plock) {
     138static void init(pthread_mutex_t* plock){
    138139        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
    139         simple_owner_lock * _lock = (simple_owner_lock *)plock;
     140        simple_owner_lock* _lock = (simple_owner_lock*)plock;
    140141        ?{}(*_lock);
    141142}
    142143
    143 static simple_owner_lock * get(pthread_mutex_t * plock) {
     144static simple_owner_lock* get(pthread_mutex_t* plock){
    144145        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
    145         return (simple_owner_lock *)plock;
    146 }
    147 
    148 static void destroy(pthread_mutex_t * plock) {
     146        return (simple_owner_lock*)plock;
     147}
     148
     149static void destroy(pthread_mutex_t* plock){
    149150        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
    150151        ^?{}(*get(plock));
     
    152153
    153154//######################### Attr helpers #########################
    154 typedef struct cfaPthread_attr_t {                                              // thread attributes
     155struct cfaPthread_attr_t {                                                              // thread attributes
    155156                int contentionscope;
    156157                int detachstate;
    157158                size_t stacksize;
    158                 void * stackaddr;
     159                void *stackaddr;
    159160                int policy;
    160161                int inheritsched;
    161162                struct sched_param param;
    162 } cfaPthread_attr_t;
    163 
    164 static const cfaPthread_attr_t default_attrs {
     163} typedef cfaPthread_attr_t;
     164
     165static const cfaPthread_attr_t default_attrs{
    165166        0,
    166167        0,
    167         65_000,
    168         NULL,
     168        (size_t)65000,
     169        (void *)NULL,
    169170        0,
    170171        0,
     
    172173};
    173174
    174 static cfaPthread_attr_t * get(const pthread_attr_t * attr) {
    175         static_assert(sizeof(pthread_attr_t) >= sizeof(cfaPthread_attr_t), "sizeof(pthread_attr_t) < sizeof(cfaPthread_attr_t)");
    176         return (cfaPthread_attr_t *)attr;
     175static cfaPthread_attr_t* get(const pthread_attr_t* attr){
     176        static_assert(sizeof(pthread_attr_t) >= sizeof(cfaPthread_attr_t),"sizeof(pthread_attr_t) < sizeof(cfaPthread_attr_t)");
     177        return (cfaPthread_attr_t*)attr;
    177178}
    178179
     
    189190
    190191        // pthreads return value
    191         void * joinval;
     192        void *joinval;
    192193
    193194        // pthread attributes
    194195        pthread_attr_t pthread_attr;
    195196
    196         void *(* start_routine)(void *);
    197         void * start_arg;
     197        void *(*start_routine)(void *);
     198        void *start_arg;
    198199
    199200        // thread local data
    200         pthread_values * pthreadData;
     201        pthread_values* pthreadData;
    201202
    202203        // flag used for tryjoin
     
    206207/* thread part routines */
    207208//  cfaPthread entry point
    208 void main(cfaPthread & _thread) with(_thread) {
    209         joinval = start_routine(start_arg);
     209void main(cfaPthread& _thread) with(_thread){
     210        joinval =  start_routine(start_arg);
    210211        isTerminated = true;
    211212}
    212213
    213 static cfaPthread * lookup( pthread_t p ) {
    214         static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *),"sizeof(pthread_t) < sizeof(cfaPthread *)");
    215         return (cfaPthread *)p;
    216 }
    217 
    218 static void pthread_deletespecific_( pthread_values * values )  { // see uMachContext::invokeTask
    219         pthread_values * value;
    220         pthread_keys * key;
     214static cfaPthread *lookup( pthread_t p ){
     215        static_assert(sizeof(pthread_t) >= sizeof(cfaPthread*),"sizeof(pthread_t) < sizeof(cfaPthread*)");
     216        return (cfaPthread*)p;
     217}
     218
     219static void pthread_deletespecific_( pthread_values* values )  { // see uMachContext::invokeTask
     220        pthread_values* value;
     221        pthread_keys* key;
    221222        bool destcalled = true;
    222         if (values != NULL) {
     223        if (values != NULL){
    223224                for ( int attempts = 0; attempts < PTHREAD_DESTRUCTOR_ITERATIONS && destcalled ; attempts += 1 ) {
    224225                        destcalled = false;
    225226                        lock(key_lock);
    226                         for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
     227                        for (int i = 0; i < PTHREAD_KEYS_MAX; i++){
    227228                                // for each valid key
    228                                 if ( values[i].in_use) {
     229                                if ( values[i].in_use){
    229230                                        value = &values[i];
    230231                                        key = &cfa_pthread_keys[i];
     
    233234                                        // if  a  key  value  has  a  non-NULL  destructor pointer,  and  the  thread  has  a  non-NULL  value associated with that key,
    234235                                        // the value of the key is set to NULL, and then the function pointed to is called with the previously associated value as its sole argument.
    235                                         if (value->value != NULL && key->destructor != NULL) {
     236                                        if (value->value != NULL && key->destructor != NULL){
    236237                                                unlock(key_lock);
    237238                                                key->destructor(value->value); // run destructor
     
    248249}
    249250
    250 static void ^?{}(cfaPthread & mutex t) {
     251static void ^?{}(cfaPthread & mutex t){
    251252        // delete pthread local storage
    252253        pthread_values * values = t.pthreadData;
     
    254255}
    255256
    256 static void ?{}(cfaPthread & t, pthread_t * _thread, const pthread_attr_t * _attr,void *(* start_routine)(void *), void * arg) {
    257         static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *), "pthread_t too small to hold a pointer: sizeof(pthread_t) < sizeof(cfaPthread *)");
     257static void ?{}(cfaPthread &t, pthread_t* _thread, const pthread_attr_t * _attr,void *(*start_routine)(void *), void * arg) {
     258        static_assert(sizeof(pthread_t) >= sizeof(cfaPthread*), "pthread_t too small to hold a pointer: sizeof(pthread_t) < sizeof(cfaPthread*)");
    258259
    259260        // set up user thread stackSize
     
    277278        //######################### Pthread Attrs #########################
    278279
    279         int pthread_attr_init(pthread_attr_t * attr) libcfa_public __THROW {
    280                 cfaPthread_attr_t * _attr = get(attr);
     280        int pthread_attr_init(pthread_attr_t *attr) libcfa_public __THROW {
     281                cfaPthread_attr_t* _attr = get(attr);
    281282                ?{}(*_attr, default_attrs);
    282283                return 0;
    283284        }
    284         int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW {
     285        int pthread_attr_destroy(pthread_attr_t *attr) libcfa_public __THROW {
    285286                ^?{}(*get(attr));
    286287                return 0;
    287288        }
    288289
    289         int pthread_attr_setscope( pthread_attr_t * attr, int contentionscope ) libcfa_public __THROW {
     290        int pthread_attr_setscope( pthread_attr_t *attr, int contentionscope ) libcfa_public __THROW {
    290291                get( attr )->contentionscope = contentionscope;
    291292                return 0;
    292293        } // pthread_attr_setscope
    293294
    294         int pthread_attr_getscope( const pthread_attr_t * attr, int * contentionscope ) libcfa_public __THROW {
     295        int pthread_attr_getscope( const pthread_attr_t *attr, int *contentionscope ) libcfa_public __THROW {
    295296                *contentionscope = get( attr )->contentionscope;
    296297                return 0;
    297298        } // pthread_attr_getscope
    298299
    299         int pthread_attr_setdetachstate( pthread_attr_t * attr, int detachstate ) libcfa_public __THROW {
     300        int pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate ) libcfa_public __THROW {
    300301                get( attr )->detachstate = detachstate;
    301302                return 0;
    302303        } // pthread_attr_setdetachstate
    303304
    304         int pthread_attr_getdetachstate( const pthread_attr_t * attr, int * detachstate ) libcfa_public __THROW {
     305        int pthread_attr_getdetachstate( const pthread_attr_t *attr, int *detachstate ) libcfa_public __THROW {
    305306                *detachstate = get( attr )->detachstate;
    306307                return 0;
    307308        } // pthread_attr_getdetachstate
    308309
    309         int pthread_attr_setstacksize( pthread_attr_t * attr, size_t stacksize ) libcfa_public __THROW {
     310        int pthread_attr_setstacksize( pthread_attr_t *attr, size_t stacksize ) libcfa_public __THROW {
    310311                get( attr )->stacksize = stacksize;
    311312                return 0;
    312313        } // pthread_attr_setstacksize
    313314
    314         int pthread_attr_getstacksize( const pthread_attr_t * attr, size_t * stacksize ) libcfa_public __THROW {
     315        int pthread_attr_getstacksize( const pthread_attr_t *attr, size_t *stacksize ) libcfa_public __THROW {
    315316                *stacksize = get( attr )->stacksize;
    316317                return 0;
     
    325326        } // pthread_attr_setguardsize
    326327
    327         int pthread_attr_setstackaddr( pthread_attr_t * attr, void * stackaddr ) libcfa_public __THROW {
     328        int pthread_attr_setstackaddr( pthread_attr_t *attr, void *stackaddr ) libcfa_public __THROW {
    328329                get( attr )->stackaddr = stackaddr;
    329330                return 0;
    330331        } // pthread_attr_setstackaddr
    331332
    332         int pthread_attr_getstackaddr( const pthread_attr_t * attr, void ** stackaddr ) libcfa_public __THROW {
     333        int pthread_attr_getstackaddr( const pthread_attr_t *attr, void **stackaddr ) libcfa_public __THROW {
    333334                *stackaddr = get( attr )->stackaddr;
    334335                return 0;
    335336        } // pthread_attr_getstackaddr
    336337
    337         int pthread_attr_setstack( pthread_attr_t * attr, void * stackaddr, size_t stacksize ) libcfa_public __THROW {
     338        int pthread_attr_setstack( pthread_attr_t *attr, void *stackaddr, size_t stacksize ) libcfa_public __THROW {
    338339                get( attr )->stackaddr = stackaddr;
    339340                get( attr )->stacksize = stacksize;
     
    341342        } // pthread_attr_setstack
    342343
    343         int pthread_attr_getstack( const pthread_attr_t * attr, void ** stackaddr, size_t * stacksize ) libcfa_public __THROW {
     344        int pthread_attr_getstack( const pthread_attr_t *attr, void **stackaddr, size_t *stacksize ) libcfa_public __THROW {
    344345                *stackaddr = get( attr )->stackaddr;
    345346                *stacksize = get( attr )->stacksize;
     
    350351        // already running thread threadID. It shall be called on unitialized attr
    351352        // and destroyed with pthread_attr_destroy when no longer needed.
    352         int pthread_getattr_np( pthread_t threadID, pthread_attr_t * attr ) libcfa_public __THROW { // GNU extension
     353        int pthread_getattr_np( pthread_t threadID, pthread_attr_t *attr ) libcfa_public __THROW { // GNU extension
    353354                check_nonnull(attr);
    354355
     
    362363        //######################### Threads #########################
    363364
    364         int pthread_create(pthread_t * _thread, const pthread_attr_t * attr, void *(* start_routine)(void *), void * arg) libcfa_public __THROW {
    365                 cfaPthread * t = alloc();
     365        int pthread_create(pthread_t * _thread, const pthread_attr_t * attr, void *(*start_routine)(void *), void * arg) libcfa_public __THROW {
     366                cfaPthread *t = alloc();
    366367                (*t){_thread, attr, start_routine, arg};
    367368                return 0;
    368369        }
    369370
    370         int pthread_join(pthread_t _thread, void ** value_ptr) libcfa_public __THROW {
     371
     372        int pthread_join(pthread_t _thread, void **value_ptr) libcfa_public __THROW {
    371373                // if thread is invalid
    372374                if (_thread == NULL) return EINVAL;
     
    374376
    375377                // get user thr pointer
    376                 cfaPthread * p = lookup(_thread);
     378                cfaPthread* p = lookup(_thread);
    377379                try {
    378380                        join(*p);
     
    387389        }
    388390
    389         int pthread_tryjoin_np(pthread_t _thread, void ** value_ptr) libcfa_public __THROW {
     391        int pthread_tryjoin_np(pthread_t _thread, void **value_ptr) libcfa_public __THROW {
    390392                // if thread is invalid
    391393                if (_thread == NULL) return EINVAL;
    392394                if (_thread == pthread_self()) return EDEADLK;
    393395
    394                 cfaPthread * p = lookup(_thread);
     396                cfaPthread* p = lookup(_thread);
    395397
    396398                // thread not finished ?
     
    410412        void pthread_exit(void * status) libcfa_public __THROW {
    411413                pthread_t pid = pthread_self();
    412                 cfaPthread * _thread = (cfaPthread *)pid;
     414                cfaPthread* _thread = (cfaPthread*)pid;
    413415                _thread->joinval = status;  // set return value
    414416                _thread->isTerminated = 1;  // set terminated flag
     
    424426        //######################### Mutex #########################
    425427
    426         int pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t * attr) libcfa_public __THROW {
     428        int pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t *attr) libcfa_public __THROW {
    427429                check_nonnull(_mutex);
    428430                init(_mutex);
     
    433435        int pthread_mutex_destroy(pthread_mutex_t *_mutex) libcfa_public __THROW {
    434436                check_nonnull(_mutex);
    435                 simple_owner_lock * _lock = get(_mutex);
    436                 if (_lock->owner != NULL) {
     437                simple_owner_lock* _lock = get(_mutex);
     438                if (_lock->owner != NULL){
    437439                        return EBUSY;
    438440                }
     
    444446                check_nonnull(_mutex);
    445447                mutex_check(_mutex);
    446                 simple_owner_lock * _lock = get(_mutex);
     448                simple_owner_lock* _lock = get(_mutex);
    447449                lock(*_lock);
    448450                return 0;
     
    451453        int pthread_mutex_unlock(pthread_mutex_t *_mutex) libcfa_public __THROW {
    452454                check_nonnull(_mutex);
    453                 simple_owner_lock * _lock = get(_mutex);
    454                 if (_lock->owner != active_thread()) {
     455                simple_owner_lock* _lock = get(_mutex);
     456                if (_lock->owner != active_thread()){
    455457                        return EPERM;
    456458                } // current thread does not hold the mutex
     
    461463        int pthread_mutex_trylock(pthread_mutex_t *_mutex) libcfa_public __THROW {
    462464                check_nonnull(_mutex);
    463                 simple_owner_lock * _lock = get(_mutex);
    464                 if (_lock->owner != active_thread() && _lock->owner != NULL) {
     465                simple_owner_lock* _lock = get(_mutex);
     466                if (_lock->owner != active_thread() && _lock->owner != NULL){
    465467                        return EBUSY;
    466468                }   // if mutex is owned
     
    472474
    473475        /* conditional variable routines */
    474         int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) libcfa_public __THROW {
     476        int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) libcfa_public __THROW {
    475477                check_nonnull(cond);
    476478                init(cond);
     
    478480        }  //pthread_cond_init
    479481
    480         int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t *_mutex) libcfa_public __THROW {
     482        int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *_mutex) libcfa_public __THROW {
    481483                check_nonnull(_mutex);
    482484                check_nonnull(cond);
     
    492494        } // pthread_cond_timedwait
    493495
    494         int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW {
     496        int pthread_cond_signal(pthread_cond_t *cond) libcfa_public __THROW {
    495497                check_nonnull(cond);
    496498                return notify_one(*get(cond));
    497499        } // pthread_cond_signal
    498500
    499         int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW {
     501        int pthread_cond_broadcast(pthread_cond_t *cond) libcfa_public __THROW {
    500502                check_nonnull(cond);
    501503                return notify_all(*get(cond));
    502504        } // pthread_cond_broadcast
    503505
    504         int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW {
     506        int pthread_cond_destroy(pthread_cond_t *cond) libcfa_public __THROW {
    505507                check_nonnull(cond);
    506508                destroy(cond);
     
    512514        //######################### Local storage #########################
    513515
    514         int pthread_once(pthread_once_t * once_control, void (* init_routine)(void)) libcfa_public __THROW {
     516        int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) libcfa_public __THROW {
    515517                static_assert(sizeof(pthread_once_t) >= sizeof(int),"sizeof(pthread_once_t) < sizeof(int)");
    516518                check_nonnull(once_control);
     
    525527        } // pthread_once
    526528
    527         int pthread_key_create( pthread_key_t * key, void (* destructor)( void * ) ) libcfa_public __THROW {
     529        int pthread_key_create( pthread_key_t *key, void (*destructor)( void * ) ) libcfa_public __THROW {
    528530                lock(key_lock);
    529531                for ( int i = 0; i < PTHREAD_KEYS_MAX; i += 1 ) {
     
    560562        }   // pthread_key_delete
    561563
    562         int pthread_setspecific( pthread_key_t key, const void * value ) libcfa_public __THROW {
     564        int pthread_setspecific( pthread_key_t key, const void *value ) libcfa_public __THROW {
    563565                // get current thread
    564                 cfaPthread * t = lookup(pthread_self());
     566                cfaPthread* t = lookup(pthread_self());
    565567                // if current thread's pthreadData is NULL; initialize it
    566                 pthread_values * values;
    567                 if (t->pthreadData == NULL) {
     568                pthread_values* values;
     569                if (t->pthreadData == NULL){
    568570                        values = anew( PTHREAD_KEYS_MAX);
    569571                        t->pthreadData = values;
    570                         for ( int i = 0;i < PTHREAD_KEYS_MAX; i++ ) {
     572                        for (int i = 0;i < PTHREAD_KEYS_MAX; i++){
    571573                                t->pthreadData[i].in_use = false;
    572574                        }   // for
     
    591593        } //pthread_setspecific
    592594
    593         void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW {
     595        void* pthread_getspecific(pthread_key_t key) libcfa_public __THROW {
    594596                if (key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use) return NULL;
    595597
    596598                // get current thread
    597                 cfaPthread * t = lookup(pthread_self());
     599                cfaPthread* t = lookup(pthread_self());
    598600                if (t->pthreadData == NULL) return NULL;
    599601                lock(key_lock);
    600                 pthread_values & entry = ((pthread_values *)t->pthreadData)[key];
     602                pthread_values &entry = ((pthread_values *)t->pthreadData)[key];
    601603                if ( ! entry.in_use ) {
    602604                        unlock( key_lock );
    603605                        return NULL;
    604606                } // if
    605                 void * value = entry.value;
     607                void *value = entry.value;
    606608                unlock(key_lock);
    607609
     
    873875        //######################### Parallelism #########################
    874876
    875         // int pthread_setaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
    876         //      abort( "pthread_setaffinity_np" );
    877         // } // pthread_setaffinity_np
    878 
    879         // int pthread_getaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
    880         //      abort( "pthread_getaffinity_np" );
    881         // } // pthread_getaffinity_np
    882 
    883         // int pthread_attr_setaffinity_np( pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
    884         //      abort( "pthread_attr_setaffinity_np" );
    885         // } // pthread_attr_setaffinity_np
    886 
    887         // int pthread_attr_getaffinity_np( __const pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
    888         //      abort( "pthread_attr_getaffinity_np" );
    889         // } // pthread_attr_getaffinity_np
     877        int pthread_setaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
     878                abort( "pthread_setaffinity_np" );
     879        } // pthread_setaffinity_np
     880
     881        int pthread_getaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
     882                abort( "pthread_getaffinity_np" );
     883        } // pthread_getaffinity_np
     884
     885        int pthread_attr_setaffinity_np( pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
     886                abort( "pthread_attr_setaffinity_np" );
     887        } // pthread_attr_setaffinity_np
     888
     889        int pthread_attr_getaffinity_np( __const pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
     890                abort( "pthread_attr_getaffinity_np" );
     891        } // pthread_attr_getaffinity_np
    890892
    891893        //######################### Cancellation #########################
     
    904906        } // pthread_cancel
    905907
    906         int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW {
     908        int pthread_setcancelstate( int state, int *oldstate ) libcfa_public __THROW {
    907909                abort("pthread_setcancelstate not implemented");
    908910                return 0;
    909911        } // pthread_setcancelstate
    910912
    911         int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW {
     913        int pthread_setcanceltype( int type, int *oldtype ) libcfa_public __THROW {
    912914                abort("pthread_setcanceltype not implemented");
    913915                return 0;
     
    916918
    917919#pragma GCC diagnostic pop
     920
  • libcfa/src/concurrency/ready_queue.cfa

    rb110bcc r2ed94a9  
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819// #define __CFA_DEBUG_PRINT_READY_QUEUE__
  • libcfa/src/concurrency/select.hfa

    rb110bcc r2ed94a9  
    1 #pragma once
    2 
    31#include "containers/list.hfa"
    42#include <stdint.h>
  • libcfa/src/concurrency/thread.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan  9 08:42:33 2023
    13 // Update Count     : 103
     12// Last Modified On : Sun Dec 11 20:56:54 2022
     13// Update Count     : 102
    1414//
    1515
    1616#define __cforall_thread__
     17#define _GNU_SOURCE
    1718
    1819#include "thread.hfa"
  • libcfa/src/containers/array.hfa

    rb110bcc r2ed94a9  
    99
    1010
    11 //
    12 // The `array` macro is the public interface.
    13 // It computes the type of a dense (trivially strided) array.
    14 // All user-declared objects are dense arrays.
    15 //
    16 // The `arpk` (ARray with PacKing info explicit) type is, generally, a slice with _any_ striding.
    17 // This type is meant for internal use.
    18 // CFA programmers should not instantiate it directly, nor access its field.
    19 // CFA programmers should call ?[?] on it.
    20 // Yet user-given `array(stuff)` expands to `arpk(stuff')`.
    21 // The comments here explain the resulting internals.
    22 //
    23 // Just as a plain-C "multidimesional" array is really array-of-array-of-...,
    24 // so does arpk generally show up as arpk-of-arpk-of...
    25 //
    26 // In the example of `array(float, 3, 4, 5) a;`,
    27 // `typeof(a)` is an `arpk` instantiation.
    28 // These comments explain _its_ arguments, i.e. those of the topmost `arpk` level.
    29 //
    30 // [N]    : the number of elements in `a`; 3 in the example
    31 // S      : carries the stride size (distance in bytes between &myA[0] and &myA[1]), in sizeof(S);
    32 //          same as Timmed when striding is trivial, same as Timmed in the example
    33 // Timmed : (T-immediate) the inner type; conceptually, `typeof(a)` is "arpk of Timmed";
    34 //          array(float, 4, 5) in the example
    35 // Tbase  : (T-base) the deepest element type that is not arpk; float in the example
    36 //
     11//
     12// Single-dim array sruct (with explicit packing and atom)
     13//
     14
    3715forall( [N], S & | sized(S), Timmed &, Tbase & ) {
    38 
    39     //
    40     // Single-dim array sruct (with explicit packing and atom)
    41     //
    4216    struct arpk {
    4317        S strides[N];
  • libcfa/src/containers/list.hfa

    rb110bcc r2ed94a9  
    3232static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; }
    3333
    34 
    35 //
    36 // P9_EMBEDDED: Use on every case of plan-9 inheritance, to make "implements embedded" be a closure of plan-9 inheritance.
    37 //
    38 // struct foo {
    39 //    int a, b, c;
    40 //    inline (bar);
    41 // };
    42 // P9_EMBEDDED( foo, bar )
    43 //
    44 
    45 // usual version, for structs that are top-level declarations
    46 #define P9_EMBEDDED(        derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, static ) P9_EMBEDDED_BDY_( immedBase )
    47 
    48 // special version, for structs that are declared in functions
    49 #define P9_EMBEDDED_INFUNC( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase,        ) P9_EMBEDDED_BDY_( immedBase )
    50 
    51 // forward declarations of both the above; generally not needed
    52 // may help you control where the P9_EMBEEDED cruft goes, in case "right after the stuct" isn't where you want it
    53 #define P9_EMBEDDED_FWD(        derived, immedBase )      P9_EMBEDDED_DECL_( derived, immedBase, static ) ;
    54 #define P9_EMBEDDED_FWD_INFUNC( derived, immedBase ) auto P9_EMBEDDED_DECL_( derived, immedBase,        ) ;
    55 
    56 // private helpers
    57 #define P9_EMBEDDED_DECL_( derived, immedBase, STORAGE ) \
    58     forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \
    59     STORAGE inline tytagref(immedBase, Tbase) ?`inner( derived & this )
    60    
    61 #define P9_EMBEDDED_BDY_( immedBase ) { \
     34// use this on every case of plan-9 inheritance, to make embedded a closure of plan-9 inheritance
     35#define P9_EMBEDDED( derived, immedBase ) \
     36forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \
     37    static inline tytagref(immedBase, Tbase) ?`inner( derived & this ) { \
    6238        immedBase & ib = this; \
    6339        Tbase & b = ib`inner; \
  • libcfa/src/containers/vector2.hfa

    rb110bcc r2ed94a9  
    99// Author           : Michael Brooks
    1010// Created On       : Thu Jun 23 22:00:00 2021
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 14 08:40:53 2023
    13 // Update Count     : 2
    14 //
    15 
    16 #pragma once
     11// Last Modified By : Michael Brooks
     12// Last Modified On : Thu Jun 23 22:00:00 2021
     13// Update Count     : 1
     14//
    1715
    1816#include <stdlib.hfa>
  • libcfa/src/interpose.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Wed Mar 29 16:10:31 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 27 21:09:03 2023
    13 // Update Count     : 196
    14 //
    15 
     12// Last Modified On : Thu Jan  5 22:23:57 2023
     13// Update Count     : 180
     14//
     15
     16#include <stdarg.h>                                                                             // va_start, va_end
    1617#include <stdio.h>
     18#include <string.h>                                                                             // strlen
    1719#include <unistd.h>                                                                             // _exit, getpid
     20#include <signal.h>
    1821extern "C" {
    1922#include <dlfcn.h>                                                                              // dlopen, dlsym
     
    2124}
    2225
     26#include "bits/debug.hfa"
    2327#include "bits/defs.hfa"
    2428#include "bits/signal.hfa"                                                              // sigHandler_?
     
    3640
    3741typedef void (* generic_fptr_t)(void);
    38 
    3942static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) {
     43        const char * error;
     44
    4045        union { generic_fptr_t fptr; void * ptr; } originalFunc;
    4146
    4247        #if defined( _GNU_SOURCE )
    43         if ( version ) {
    44                 originalFunc.ptr = dlvsym( library, symbol, version );
    45         } else {
     48                if ( version ) {
     49                        originalFunc.ptr = dlvsym( library, symbol, version );
     50                } else {
     51                        originalFunc.ptr = dlsym( library, symbol );
     52                }
     53        #else
    4654                originalFunc.ptr = dlsym( library, symbol );
     55        #endif // _GNU_SOURCE
     56
     57        error = dlerror();
     58        if ( error ) abort( "interpose_symbol : internal error, %s\n", error );
     59
     60        return originalFunc.fptr;
     61}
     62
     63static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
     64        const char * error;
     65
     66        static void * library;
     67        static void * pthread_library;
     68        if ( ! library ) {
     69                #if defined( RTLD_NEXT )
     70                        library = RTLD_NEXT;
     71                #else
     72                        // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
     73                        library = dlopen( "libc.so.6", RTLD_LAZY );
     74                        error = dlerror();
     75                        if ( error ) {
     76                                abort( "interpose_symbol : failed to open libc, %s\n", error );
     77                        }
     78                #endif
    4779        } // if
    48         #else
    49         originalFunc.ptr = dlsym( library, symbol );
    50         #endif // _GNU_SOURCE
    51 
    52         if ( ! originalFunc.ptr ) {                                                     // == nullptr
    53                 abort( "interpose_symbol : internal error, %s\n", dlerror() );
     80        if ( ! pthread_library ) {
     81                #if defined( RTLD_NEXT )
     82                        pthread_library = RTLD_NEXT;
     83                #else
     84                        // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
     85                        pthread_library = dlopen( "libpthread.so", RTLD_LAZY );
     86                        error = dlerror();
     87                        if ( error ) {
     88                                abort( "interpose_symbol : failed to open libpthread, %s\n", error );
     89                        }
     90                #endif
    5491        } // if
    55         return originalFunc.fptr;
    56 }
    57 
    58 static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
    59         void * library;
    60 
    61         #if defined( RTLD_NEXT )
    62         library = RTLD_NEXT;
    63         #else
    64         // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
    65         library = dlopen( "libc.so.6", RTLD_LAZY );
    66         if ( ! library ) {                                                                      // == nullptr
    67                 abort( "interpose_symbol : failed to open libc, %s\n", dlerror() );
    68         } // if
    69         #endif // RTLD_NEXT
    70 
    71         return do_interpose_symbol( library, symbol, version );
     92
     93        return do_interpose_symbol(library, symbol, version);
    7294}
    7395
     
    99121                preload_libgcc();
    100122
    101                 #pragma GCC diagnostic push
    102                 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
     123#pragma GCC diagnostic push
     124#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
    103125                INTERPOSE_LIBC( abort, version );
    104126                INTERPOSE_LIBC( exit , version );
    105                 #pragma GCC diagnostic pop
     127#pragma GCC diagnostic pop
    106128
    107129                if(__cfathreadabi_interpose_startup) __cfathreadabi_interpose_startup( do_interpose_symbol );
    108 
    109                 // SKULLDUGGERY: In Ubuntu 22.04, someone augmented signal.h to allow SIGSTKSZ to be "sysconf(_SC_SIGSTKSZ)" in
    110                 // sigstksz.h, as well as 8192 in sigstack.h. HOWEVER, they forgot to provide a mechanism to tell signal.h to
    111                 // use sigstack.h rather than sigstksz.h. (I'm not happy.) By undefining _GNU_SOURCE before signal.h and
    112                 // redefining it afterwards, you can get 8192, but then nothing works correctly inside of signal.h without
    113                 // _GNU_SOURCE defined.  So what is needed is a way to get signal.h to use sigstack.h WITH _GNU_SOURCE defined.
    114                 // Basically something is wrong with features.h and its use in signal.h.
    115 
    116                 #undef SIGSTKSZ
    117                 #define SIGSTKSZ 8192
    118130
    119131                // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
     
    281293        va_start( args, fmt );
    282294        __abort( false, fmt, args );
    283         // CONTROL NEVER REACHES HERE!
     295    // CONTROL NEVER REACHES HERE!
    284296        va_end( args );
    285297}
    286298
    287299void abort( bool signalAbort, const char fmt[], ... ) {
    288         va_list args;
    289         va_start( args, fmt );
    290         __abort( signalAbort, fmt, args );
    291         // CONTROL NEVER REACHES HERE!
    292         va_end( args );
     300    va_list args;
     301    va_start( args, fmt );
     302    __abort( signalAbort, fmt, args );
     303    // CONTROL NEVER REACHES HERE!
     304    va_end( args );
    293305}
    294306
  • libcfa/src/interpose_thread.cfa

    rb110bcc r2ed94a9  
    1414//
    1515
    16 // BUG in 32-bit gcc with interpose: fixed in >= gcc-9.5, gcc-10.4, gcc-12.2
    17 #ifdef __i386__                                                                                 // 32-bit architecture
    18 #undef _GNU_SOURCE
    19 #endif // __i386__
    20 
     16#include <stdarg.h>                                                                             // va_start, va_end
     17#include <stdio.h>
     18#include <string.h>                                                                             // strlen
    2119#include <signal.h>
    2220#include <pthread.h>
    23 #include <signal.h>
    2421extern "C" {
    2522#include <dlfcn.h>                                                                              // dlopen, dlsym
     23#include <execinfo.h>                                                                   // backtrace, messages
    2624}
    2725
     26#include "bits/debug.hfa"
    2827#include "bits/defs.hfa"
     28#include <assert.h>
    2929
    3030//=============================================================================================
     
    3434typedef void (* generic_fptr_t)(void);
    3535
    36 generic_fptr_t libcfa_public interpose_symbol(
     36generic_fptr_t interpose_symbol(
    3737        generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ),
    3838        const char symbol[],
    3939        const char version[]
    40 ) {
    41         void * library;
     40) libcfa_public {
     41        const char * error;
    4242
    43         #if defined( RTLD_NEXT )
    44         library = RTLD_NEXT;
    45         #else
    46         // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
    47         library = dlopen( "libpthread.so", RTLD_LAZY );
    48         if ( ! library ) {                                                                      // == nullptr
    49                 abort( "interpose_symbol : failed to open libpthread, %s\n", dlerror() );
     43        static void * library;
     44        if ( ! library ) {
     45                #if defined( RTLD_NEXT )
     46                        library = RTLD_NEXT;
     47                #else
     48                        // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
     49                        library = dlopen( "libpthread.so", RTLD_LAZY );
     50                        error = dlerror();
     51                        if ( error ) {
     52                                abort( "interpose_symbol : failed to open libpthread, %s\n", error );
     53                        }
     54                #endif
    5055        } // if
    51         #endif // RTLD_NEXT
    5256
    53         return do_interpose_symbol( library, symbol, version );
     57        return do_interpose_symbol(library, symbol, version);
    5458}
    5559
     
    7983#pragma GCC diagnostic push
    8084#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
    81                 INTERPOSE( pthread_create, version );
    82                 INTERPOSE( pthread_join, version );
    83                 INTERPOSE( pthread_self, version );
    84                 INTERPOSE( pthread_attr_init, version );
    85                 INTERPOSE( pthread_attr_destroy, version );
    86                 INTERPOSE( pthread_attr_setstack, version );
    87                 INTERPOSE( pthread_attr_getstacksize, version );
    88                 INTERPOSE( pthread_sigmask, version );
    89                 INTERPOSE( pthread_sigqueue, version );
    90                 INTERPOSE( pthread_once, version );
     85                INTERPOSE( pthread_create , version );
     86                INTERPOSE( pthread_join , version );
     87                INTERPOSE( pthread_self , version );
     88                INTERPOSE( pthread_attr_init , version );
     89                INTERPOSE( pthread_attr_destroy , version );
     90                INTERPOSE( pthread_attr_setstack , version );
     91                INTERPOSE( pthread_attr_getstacksize , version );
     92                INTERPOSE( pthread_sigmask , version );
     93                INTERPOSE( pthread_sigqueue , version );
     94                INTERPOSE( pthread_once , version );
    9195#pragma GCC diagnostic pop
    9296        }
  • libcfa/src/iostream.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan  9 09:27:58 2023
    13 // Update Count     : 1361
     12// Last Modified On : Sat Aug 27 15:04:15 2022
     13// Update Count     : 1358
    1414//
    1515
     
    667667                        } /* if */ \
    668668                        if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \
    669                                 len2 = snprintf( &buf[len], size - len, "e%d", (int)exp10 /* ambiguity with function exp10 */ ); \
     669                                len2 = snprintf( &buf[len], size - len, "e%d", exp10 ); \
    670670                        } else { \
    671671                                len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
  • libcfa/src/limits.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Wed Apr  6 18:06:52 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb 17 12:25:39 2023
    13 // Update Count     : 87
     12// Last Modified On : Thu Jan  5 22:27:40 2023
     13// Update Count     : 84
    1414//
    1515
     16#define _GNU_SOURCE                                                                             // access long double M_*l in math.h
    1617#include <limits.h>
    1718#include <float.h>
  • libcfa/src/stdlib.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Thu Jan 28 17:10:29 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 16 16:31:34 2023
    13 // Update Count     : 633
     12// Last Modified On : Fri Dec  9 15:11:30 2022
     13// Update Count     : 631
    1414//
    1515
     
    2020//---------------------------------------
    2121
     22#define _XOPEN_SOURCE 600                                                               // posix_memalign, *rand48
    2223#include <string.h>                                                                             // memcpy, memset
    2324//#include <math.h>                                                                             // fabsf, fabs, fabsl
  • libcfa/src/vec/vec.hfa

    rb110bcc r2ed94a9  
    1818#include <math.hfa>
    1919
    20 forall(T)
    21 trait fromint {
     20trait fromint(T) {
    2221    void ?{}(T&, int);
    2322};
    24 forall(T)
    25 trait zeroinit {
     23trait zeroinit(T) {
    2624    void ?{}(T&, zero_t);
    2725};
    28 forall(T)
    29 trait zero_assign {
     26trait zero_assign(T) {
    3027    T ?=?(T&, zero_t);
    3128};
    32 forall(T)
    33 trait subtract {
     29trait subtract(T) {
    3430    T ?-?(T, T);
    3531};
    36 forall(T)
    37 trait negate {
     32trait negate(T) {
    3833    T -?(T);
    3934};
    40 forall(T)
    41 trait add {
     35trait add(T) {
    4236    T ?+?(T, T);
    4337};
    44 forall(T)
    45 trait multiply {
     38trait multiply(T) {
    4639    T ?*?(T, T);
    4740};
    48 forall(T)
    49 trait divide {
     41trait divide(T) {
    5042    T ?/?(T, T);
    5143};
    52 forall(T)
    53 trait lessthan {
     44trait lessthan(T) {
    5445    int ?<?(T, T);
    5546};
    56 forall(T)
    57 trait equality {
     47trait equality(T) {
    5848    int ?==?(T, T);
    5949};
    60 forall(T)
    61 trait sqrt {
     50trait sqrt(T) {
    6251    T sqrt(T);
    6352};
  • src/AST/Attribute.hpp

    rb110bcc r2ed94a9  
    2727class Expr;
    2828
    29 /// An entry in an attribute list: `__attribute__(( ... ))`
    3029class Attribute final : public Node {
    3130public:
  • src/AST/Convert.cpp

    rb110bcc r2ed94a9  
    559559                auto stmt = new SuspendStmt();
    560560                stmt->then   = get<CompoundStmt>().accept1( node->then   );
    561                 switch (node->kind) {
     561                switch(node->type) {
    562562                        case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
    563563                        case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
     
    16831683                        GET_ACCEPT_V(attributes, Attribute),
    16841684                        { old->get_funcSpec().val },
    1685                         (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs
     1685                        old->type->isVarArgs
    16861686                };
    16871687
     
    19891989                        GET_ACCEPT_1(else_, Stmt),
    19901990                        GET_ACCEPT_V(initialization, Stmt),
    1991                         (old->isDoWhile) ? ast::DoWhile : ast::While,
     1991                        old->isDoWhile,
    19921992                        GET_LABELS_V(old->labels)
    19931993                );
     
    21312131        virtual void visit( const SuspendStmt * old ) override final {
    21322132                if ( inCache( old ) ) return;
    2133                 ast::SuspendStmt::Kind type;
     2133                ast::SuspendStmt::Type type;
    21342134                switch (old->type) {
    21352135                        case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
  • src/AST/Create.cpp

    rb110bcc r2ed94a9  
    2020#include "AST/Decl.hpp"
    2121#include "AST/Type.hpp"
    22 #include "Common/Iterate.hpp"
    2322
    2423namespace ast {
  • src/AST/Decl.cpp

    rb110bcc r2ed94a9  
    2020#include <unordered_map>
    2121
    22 #include "Common/Eval.h"       // for eval
     22#include "Common/utility.h"
    2323
    2424#include "Fwd.hpp"             // for UniqueId
     
    5757        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    5858        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    59         std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
     59        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
    6060: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ),
    6161        type_params(std::move(forall)), assertions(),
    6262        params(std::move(params)), returns(std::move(returns)), stmts( stmts ) {
    63         FunctionType * ftype = new FunctionType( isVarArgs );
     63        FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
    6464        for (auto & param : this->params) {
    6565                ftype->params.emplace_back(param->get_type());
     
    8181        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    8282        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    83         std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
     83        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
    8484: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
    8585                type_params( std::move( forall) ), assertions( std::move( assertions ) ),
    8686                params( std::move(params) ), returns( std::move(returns) ),
    8787                type( nullptr ), stmts( stmts ) {
    88         FunctionType * type = new FunctionType( isVarArgs );
     88        FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
    8989        for ( auto & param : this->params ) {
    9090                type->params.emplace_back( param->get_type() );
  • src/AST/Decl.hpp

    rb110bcc r2ed94a9  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr  5 10:42:00 2023
    13 // Update Count     : 35
     12// Last Modified On : Thu Nov 24  9:44:00 2022
     13// Update Count     : 34
    1414//
    1515
     
    122122};
    123123
    124 /// Function variable arguments flag
    125 enum ArgumentFlag { FixedArgs, VariableArgs };
    126 
    127124/// Object declaration `int foo()`
    128125class FunctionDecl : public DeclWithType {
     
    147144                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    148145                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    149                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
     146                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    150147
    151148        FunctionDecl( const CodeLocation & location, const std::string & name,
     
    153150                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    154151                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    155                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
     152                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    156153
    157154        const Type * get_type() const override;
     
    316313public:
    317314        bool isTyped; // isTyped indicated if the enum has a declaration like:
    318         // enum (type_optional) Name {...}
     315        // enum (type_optional) Name {...} 
    319316        ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    320317        enum class EnumHiding { Visible, Hide } hide;
     
    374371};
    375372
    376 /// Assembly declaration: `asm ... ( "..." : ... )`
    377373class AsmDecl : public Decl {
    378374public:
  • src/AST/Expr.hpp

    rb110bcc r2ed94a9  
    254254};
    255255
    256 /// A name qualified by a namespace or type.
    257256class QualifiedNameExpr final : public Expr {
    258257public:
     
    260259        std::string name;
    261260
    262         QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
     261        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 
    263262        : Expr( loc ), type_decl( d ), name( n ) {}
    264263
     
    622621};
    623622
    624 /// A name that refers to a generic dimension parameter.
    625623class DimensionExpr final : public Expr {
    626624public:
     
    912910};
    913911
     912
    914913}
    915914
  • src/AST/Fwd.hpp

    rb110bcc r2ed94a9  
    1515
    1616#pragma once
    17 
    18 template<typename> struct bitfield;
    1917
    2018#include "AST/Node.hpp"
     
    149147class TranslationGlobal;
    150148
    151 // For the following types, only use the using type.
    152 namespace CV {
    153         struct qualifier_flags;
    154         using Qualifiers = bitfield<qualifier_flags>;
    155149}
    156 namespace Function {
    157         struct spec_flags;
    158         using Specs = bitfield<spec_flags>;
    159 }
    160 namespace Storage {
    161         struct class_flags;
    162         using Classes = bitfield<class_flags>;
    163 }
    164 namespace Linkage {
    165         struct spec_flags;
    166         using Spec = bitfield<spec_flags>;
    167 }
    168 
    169 }
  • src/AST/Init.hpp

    rb110bcc r2ed94a9  
    117117        ptr<Init> init;
    118118
    119         ConstructorInit(
     119        ConstructorInit( 
    120120                const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
    121121        : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
  • src/AST/Inspect.cpp

    rb110bcc r2ed94a9  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Apr 14 15:09:00 2023
    13 // Update Count     : 4
     12// Last Modified On : Mon Oct  3 11:04:00 2022
     13// Update Count     : 3
    1414//
    1515
     
    168168}
    169169
    170 bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
    171         return obj && obj->name.empty() && obj->bitfieldWidth;
    172 }
    173 
    174170} // namespace ast
  • src/AST/Inspect.hpp

    rb110bcc r2ed94a9  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Apr 14 15:09:00 2023
    13 // Update Count     : 3
     12// Last Modified On : Thr Sep 22 13:44:00 2022
     13// Update Count     : 2
    1414//
    1515
     
    3838const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr );
    3939
    40 /// Returns true if obj's name is the empty string and it has a bitfield width.
    41 bool isUnnamedBitfield( const ObjectDecl * obj );
    42 
    4340}
  • src/AST/ParseNode.hpp

    rb110bcc r2ed94a9  
    4040        template<typename node_t>
    4141        friend node_t * mutate(const node_t * node);
    42         template<typename node_t>
    43         friend node_t * shallowCopy(const node_t * node);
    4442};
    4543
  • src/AST/Pass.impl.hpp

    rb110bcc r2ed94a9  
    2222#include "AST/TranslationUnit.hpp"
    2323#include "AST/TypeSubstitution.hpp"
    24 #include "Common/Iterate.hpp"
    2524
    2625#define VISIT_START( node ) \
     
    20422041        if ( __visit_children() ) {
    20432042                maybe_accept( node, &TupleType::types );
     2043                maybe_accept( node, &TupleType::members );
    20442044        }
    20452045
  • src/AST/Pass.proto.hpp

    rb110bcc r2ed94a9  
    1818
    1919#include "Common/Stats/Heap.h"
     20
    2021namespace ast {
    21         template<typename core_t> class Pass;
    22         class TranslationUnit;
    23         struct PureVisitor;
    24         template<typename node_t> node_t * deepCopy( const node_t * );
    25 }
    26 
    27 namespace ast::__pass {
    28 
    29 typedef std::function<void( void * )> cleanup_func_t;
    30 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
    31 
    32 // boolean reference that may be null
    33 // either refers to a boolean value or is null and returns true
    34 class bool_ref {
    35 public:
    36         bool_ref() = default;
    37         ~bool_ref() = default;
    38 
    39         operator bool() { return m_ref ? *m_ref : true; }
    40         bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
    41 
    42 private:
    43 
    44         friend class visit_children_guard;
    45 
    46         bool * set( bool * val ) {
    47                 bool * prev = m_ref;
    48                 m_ref = val;
    49                 return prev;
    50         }
    51 
    52         bool * m_ref = nullptr;
    53 };
    54 
    55 // Implementation of the guard value
    56 // Created inside the visit scope
    57 class guard_value {
    58 public:
    59         /// Push onto the cleanup
    60         guard_value( at_cleanup_t * at_cleanup ) {
    61                 if( at_cleanup ) {
    62                         *at_cleanup = [this]( cleanup_func_t && func, void* val ) {
    63                                 push( std::move( func ), val );
    64                         };
    65                 }
    66         }
    67 
    68         ~guard_value() {
    69                 while( !cleanups.empty() ) {
    70                         auto& cleanup = cleanups.top();
    71                         cleanup.func( cleanup.val );
    72                         cleanups.pop();
    73                 }
    74         }
    75 
    76         void push( cleanup_func_t && func, void* val ) {
    77                 cleanups.emplace( std::move(func), val );
    78         }
    79 
    80 private:
    81         struct cleanup_t {
    82                 cleanup_func_t func;
    83                 void * val;
    84 
    85                 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
    86         };
    87 
    88         std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
    89 };
    90 
    91 // Guard structure implementation for whether or not children should be visited
    92 class visit_children_guard {
    93 public:
    94 
    95         visit_children_guard( bool_ref * ref )
    96                 : m_val ( true )
    97                 , m_prev( ref ? ref->set( &m_val ) : nullptr )
    98                 , m_ref ( ref )
    99         {}
    100 
    101         ~visit_children_guard() {
    102                 if( m_ref ) {
    103                         m_ref->set( m_prev );
    104                 }
    105         }
    106 
    107         operator bool() { return m_val; }
    108 
    109 private:
    110         bool       m_val;
    111         bool     * m_prev;
    112         bool_ref * m_ref;
    113 };
    114 
    115 /// "Short hand" to check if this is a valid previsit function
    116 /// Mostly used to make the static_assert look (and print) prettier
    117 template<typename core_t, typename node_t>
    118 struct is_valid_previsit {
    119         using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) );
    120 
    121         static constexpr bool value = std::is_void< ret_t >::value ||
    122                 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value;
    123 };
    124 
    125 /// The result is a single node.
    126 template< typename node_t >
    127 struct result1 {
    128         bool differs = false;
    129         const node_t * value = nullptr;
    130 
    131         template< typename object_t, typename super_t, typename field_t >
    132         void apply( object_t *, field_t super_t::* field );
    133 };
    134 
    135 /// The result is a container of statements.
    136 template< template<class...> class container_t >
    137 struct resultNstmt {
    138         /// The delta/change on a single node.
    139         struct delta {
    140                 ptr<Stmt> new_val;
    141                 ssize_t old_idx;
    142                 bool is_old;
    143 
    144                 delta(const Stmt * s, ssize_t i, bool old) :
    145                         new_val(s), old_idx(i), is_old(old) {}
    146         };
    147 
    148         bool differs = false;
    149         container_t< delta > values;
    150 
    151         template< typename object_t, typename super_t, typename field_t >
    152         void apply( object_t *, field_t super_t::* field );
    153 
    154         template< template<class...> class incontainer_t >
    155         void take_all( incontainer_t<ptr<Stmt>> * stmts );
    156 
    157         template< template<class...> class incontainer_t >
    158         void take_all( incontainer_t<ptr<Decl>> * decls );
    159 };
    160 
    161 /// The result is a container of nodes.
    162 template< template<class...> class container_t, typename node_t >
    163 struct resultN {
    164         bool differs = false;
    165         container_t<ptr<node_t>> values;
    166 
    167         template< typename object_t, typename super_t, typename field_t >
    168         void apply( object_t *, field_t super_t::* field );
    169 };
    170 
    171 /// Used by previsit implementation
    172 /// We need to reassign the result to 'node', unless the function
    173 /// returns void, then we just leave 'node' unchanged
    174 template<bool is_void>
    175 struct __assign;
    176 
    177 template<>
    178 struct __assign<true> {
     22template<typename core_t>
     23class Pass;
     24
     25class TranslationUnit;
     26
     27struct PureVisitor;
     28
     29template<typename node_t>
     30node_t * deepCopy( const node_t * localRoot );
     31
     32namespace __pass {
     33        typedef std::function<void( void * )> cleanup_func_t;
     34        typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
     35
     36
     37        // boolean reference that may be null
     38        // either refers to a boolean value or is null and returns true
     39        class bool_ref {
     40        public:
     41                bool_ref() = default;
     42                ~bool_ref() = default;
     43
     44                operator bool() { return m_ref ? *m_ref : true; }
     45                bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
     46
     47        private:
     48
     49                friend class visit_children_guard;
     50
     51                bool * set( bool * val ) {
     52                        bool * prev = m_ref;
     53                        m_ref = val;
     54                        return prev;
     55                }
     56
     57                bool * m_ref = nullptr;
     58        };
     59
     60        // Implementation of the guard value
     61        // Created inside the visit scope
     62        class guard_value {
     63        public:
     64                /// Push onto the cleanup
     65                guard_value( at_cleanup_t * at_cleanup ) {
     66                        if( at_cleanup ) {
     67                                *at_cleanup = [this]( cleanup_func_t && func, void* val ) {
     68                                        push( std::move( func ), val );
     69                                };
     70                        }
     71                }
     72
     73                ~guard_value() {
     74                        while( !cleanups.empty() ) {
     75                                auto& cleanup = cleanups.top();
     76                                cleanup.func( cleanup.val );
     77                                cleanups.pop();
     78                        }
     79                }
     80
     81                void push( cleanup_func_t && func, void* val ) {
     82                        cleanups.emplace( std::move(func), val );
     83                }
     84
     85        private:
     86                struct cleanup_t {
     87                        cleanup_func_t func;
     88                        void * val;
     89
     90                        cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
     91                };
     92
     93                std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
     94        };
     95
     96        // Guard structure implementation for whether or not children should be visited
     97        class visit_children_guard {
     98        public:
     99
     100                visit_children_guard( bool_ref * ref )
     101                        : m_val ( true )
     102                        , m_prev( ref ? ref->set( &m_val ) : nullptr )
     103                        , m_ref ( ref )
     104                {}
     105
     106                ~visit_children_guard() {
     107                        if( m_ref ) {
     108                                m_ref->set( m_prev );
     109                        }
     110                }
     111
     112                operator bool() { return m_val; }
     113
     114        private:
     115                bool       m_val;
     116                bool     * m_prev;
     117                bool_ref * m_ref;
     118        };
     119
     120        /// "Short hand" to check if this is a valid previsit function
     121        /// Mostly used to make the static_assert look (and print) prettier
    179122        template<typename core_t, typename node_t>
    180         static inline void result( core_t & core, const node_t * & node ) {
    181                 core.previsit( node );
    182         }
    183 };
    184 
    185 template<>
    186 struct __assign<false> {
     123        struct is_valid_previsit {
     124                using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) );
     125
     126                static constexpr bool value = std::is_void< ret_t >::value ||
     127                        std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value;
     128        };
     129
     130        /// The result is a single node.
     131        template< typename node_t >
     132        struct result1 {
     133                bool differs = false;
     134                const node_t * value = nullptr;
     135
     136                template< typename object_t, typename super_t, typename field_t >
     137                void apply( object_t *, field_t super_t::* field );
     138        };
     139
     140        /// The result is a container of statements.
     141        template< template<class...> class container_t >
     142        struct resultNstmt {
     143                /// The delta/change on a single node.
     144                struct delta {
     145                        ptr<Stmt> new_val;
     146                        ssize_t old_idx;
     147                        bool is_old;
     148
     149                        delta(const Stmt * s, ssize_t i, bool old) :
     150                                new_val(s), old_idx(i), is_old(old) {}
     151                };
     152
     153                bool differs = false;
     154                container_t< delta > values;
     155
     156                template< typename object_t, typename super_t, typename field_t >
     157                void apply( object_t *, field_t super_t::* field );
     158
     159                template< template<class...> class incontainer_t >
     160                void take_all( incontainer_t<ptr<Stmt>> * stmts );
     161
     162                template< template<class...> class incontainer_t >
     163                void take_all( incontainer_t<ptr<Decl>> * decls );
     164        };
     165
     166        /// The result is a container of nodes.
     167        template< template<class...> class container_t, typename node_t >
     168        struct resultN {
     169                bool differs = false;
     170                container_t<ptr<node_t>> values;
     171
     172                template< typename object_t, typename super_t, typename field_t >
     173                void apply( object_t *, field_t super_t::* field );
     174        };
     175
     176        /// Used by previsit implementation
     177        /// We need to reassign the result to 'node', unless the function
     178        /// returns void, then we just leave 'node' unchanged
     179        template<bool is_void>
     180        struct __assign;
     181
     182        template<>
     183        struct __assign<true> {
     184                template<typename core_t, typename node_t>
     185                static inline void result( core_t & core, const node_t * & node ) {
     186                        core.previsit( node );
     187                }
     188        };
     189
     190        template<>
     191        struct __assign<false> {
     192                template<typename core_t, typename node_t>
     193                static inline void result( core_t & core, const node_t * & node ) {
     194                        node = core.previsit( node );
     195                        assertf(node, "Previsit must not return NULL");
     196                }
     197        };
     198
     199        /// Used by postvisit implementation
     200        /// We need to return the result unless the function
     201        /// returns void, then we just return the original node
     202        template<bool is_void>
     203        struct __return;
     204
     205        template<>
     206        struct __return<true> {
     207                template<typename core_t, typename node_t>
     208                static inline const node_t * result( core_t & core, const node_t * & node ) {
     209                        core.postvisit( node );
     210                        return node;
     211                }
     212        };
     213
     214        template<>
     215        struct __return<false> {
     216                template<typename core_t, typename node_t>
     217                static inline auto result( core_t & core, const node_t * & node ) {
     218                        return core.postvisit( node );
     219                }
     220        };
     221
     222        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     223        // Deep magic (a.k.a template meta programming) to make the templated visitor work
     224        // Basically the goal is to make 2 previsit
     225        // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
     226        //     'pass.previsit( node )' that compiles will be used for that node for that type
     227        //     This requires that this option only compile for passes that actually define an appropriate visit.
     228        //     SFINAE will make sure the compilation errors in this function don't halt the build.
     229        //     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
     230        // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
     231        //     This is needed only to eliminate the need for passes to specify any kind of handlers.
     232        //     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
     233        //     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
     234        //     the first implementation takes priority in regards to overloading.
     235        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     236        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    187237        template<typename core_t, typename node_t>
    188         static inline void result( core_t & core, const node_t * & node ) {
    189                 node = core.previsit( node );
    190                 assertf(node, "Previsit must not return NULL");
    191         }
    192 };
    193 
    194 /// Used by postvisit implementation
    195 /// We need to return the result unless the function
    196 /// returns void, then we just return the original node
    197 template<bool is_void>
    198 struct __return;
    199 
    200 template<>
    201 struct __return<true> {
     238        static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
     239                static_assert(
     240                        is_valid_previsit<core_t, node_t>::value,
     241                        "Previsit may not change the type of the node. It must return its paremeter or void."
     242                );
     243
     244                __assign<
     245                        std::is_void<
     246                                decltype( core.previsit( node ) )
     247                        >::value
     248                >::result( core, node );
     249        }
     250
    202251        template<typename core_t, typename node_t>
    203         static inline const node_t * result( core_t & core, const node_t * & node ) {
    204                 core.postvisit( node );
    205                 return node;
    206         }
    207 };
    208 
    209 template<>
    210 struct __return<false> {
     252        static inline auto previsit( core_t &, const node_t *, long ) {}
     253
     254        // PostVisit : never mutates the passed pointer but may return a different node
    211255        template<typename core_t, typename node_t>
    212         static inline auto result( core_t & core, const node_t * & node ) {
    213                 return core.postvisit( node );
    214         }
    215 };
    216 
    217 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    218 // Deep magic (a.k.a template meta programming) to make the templated visitor work
    219 // Basically the goal is to make 2 previsit
    220 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
    221 //     'pass.previsit( node )' that compiles will be used for that node for that type
    222 //     This requires that this option only compile for passes that actually define an appropriate visit.
    223 //     SFINAE will make sure the compilation errors in this function don't halt the build.
    224 //     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
    225 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
    226 //     This is needed only to eliminate the need for passes to specify any kind of handlers.
    227 //     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
    228 //     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
    229 //     the first implementation takes priority in regards to overloading.
    230 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    231 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    232 template<typename core_t, typename node_t>
    233 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
    234         static_assert(
    235                 is_valid_previsit<core_t, node_t>::value,
    236                 "Previsit may not change the type of the node. It must return its paremeter or void."
    237         );
    238 
    239         __assign<
    240                 std::is_void<
    241                         decltype( core.previsit( node ) )
    242                 >::value
    243         >::result( core, node );
    244 }
    245 
    246 template<typename core_t, typename node_t>
    247 static inline auto previsit( core_t &, const node_t *, long ) {}
    248 
    249 // PostVisit : never mutates the passed pointer but may return a different node
    250 template<typename core_t, typename node_t>
    251 static inline auto postvisit( core_t & core, const node_t * node, int ) ->
    252         decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    253 {
    254         return __return<
    255                 std::is_void<
    256                         decltype( core.postvisit( node ) )
    257                 >::value
    258         >::result( core, node );
    259 }
    260 
    261 template<typename core_t, typename node_t>
    262 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
    263 
    264 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    265 // Deep magic (a.k.a template meta programming) continued
    266 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
    267 // from in order to get extra functionallity for example
    268 // class ErrorChecker : WithShortCircuiting { ... };
    269 // Pass<ErrorChecker> checker;
    270 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
    271 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
    272 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    273 // For several accessories, the feature is enabled by detecting that a specific field is present
    274 // Use a macro the encapsulate the logic of detecting a particular field
    275 // The type is not strictly enforced but does match the accessory
    276 #define FIELD_PTR( name, default_type ) \
    277 template< typename core_t > \
    278 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
    279 \
    280 template< typename core_t > \
    281 static inline default_type * name( core_t &, long ) { return nullptr; }
    282 
    283 // List of fields and their expected types
    284 FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
    285 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
    286 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
    287 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
    288 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
    289 FIELD_PTR( visit_children, __pass::bool_ref )
    290 FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    291 FIELD_PTR( visitor, ast::Pass<core_t> * const )
    292 
    293 // Remove the macro to make sure we don't clash
    294 #undef FIELD_PTR
    295 
    296 template< typename core_t >
    297 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    298         // Stats::Heap::stacktrace_push(core_t::traceId);
    299 }
    300 
    301 template< typename core_t >
    302 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    303         // Stats::Heap::stacktrace_pop();
    304 }
    305 
    306 template< typename core_t >
    307 static void beginTrace(core_t &, long) {}
    308 
    309 template< typename core_t >
    310 static void endTrace(core_t &, long) {}
    311 
    312 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error.
    313 // If on_error() returns false, the error will be ignored. By default, it returns true.
    314 
    315 template< typename core_t >
    316 static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
    317 
    318 template< typename core_t >
    319 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
    320         return core.on_error(decl);
    321 }
    322 
    323 template< typename core_t, typename node_t >
    324 static auto make_location_guard( core_t & core, node_t * node, int )
    325                 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) {
    326         ValueGuardPtr<const CodeLocation *> guard( &core.location );
    327         core.location = &node->location;
    328         return guard;
    329 }
    330 
    331 template< typename core_t, typename node_t >
    332 static auto make_location_guard( core_t &, node_t *, long ) -> int {
    333         return 0;
    334 }
    335 
    336 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
    337 // All passes which have such functions are assumed desire this behaviour
    338 // detect it using the same strategy
    339 namespace scope {
    340         template<typename core_t>
    341         static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
    342                 core.beginScope();
    343         }
    344 
    345         template<typename core_t>
    346         static inline void enter( core_t &, long ) {}
    347 
    348         template<typename core_t>
    349         static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
    350                 core.endScope();
    351         }
    352 
    353         template<typename core_t>
    354         static inline void leave( core_t &, long ) {}
    355 } // namespace scope
    356 
    357 // Certain passes desire an up to date symbol table automatically
    358 // detect the presence of a member name `symtab` and call all the members appropriately
    359 namespace symtab {
    360         // Some simple scoping rules
    361         template<typename core_t>
    362         static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
    363                 core.symtab.enterScope();
    364         }
    365 
    366         template<typename core_t>
    367         static inline auto enter( core_t &, long ) {}
    368 
    369         template<typename core_t>
    370         static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
    371                 core.symtab.leaveScope();
    372         }
    373 
    374         template<typename core_t>
    375         static inline auto leave( core_t &, long ) {}
    376 
    377         // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    378         // Create macro to condense these common patterns
    379         #define SYMTAB_FUNC1( func, type ) \
    380         template<typename core_t> \
    381         static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
    382                 core.symtab.func( arg ); \
    383         } \
     256        static inline auto postvisit( core_t & core, const node_t * node, int ) ->
     257                decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
     258        {
     259                return __return<
     260                        std::is_void<
     261                                decltype( core.postvisit( node ) )
     262                        >::value
     263                >::result( core, node );
     264        }
     265
     266        template<typename core_t, typename node_t>
     267        static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
     268
     269        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     270        // Deep magic (a.k.a template meta programming) continued
     271        // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
     272        // from in order to get extra functionallity for example
     273        // class ErrorChecker : WithShortCircuiting { ... };
     274        // Pass<ErrorChecker> checker;
     275        // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
     276        // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
     277        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     278        // For several accessories, the feature is enabled by detecting that a specific field is present
     279        // Use a macro the encapsulate the logic of detecting a particular field
     280        // The type is not strictly enforced but does match the accessory
     281        #define FIELD_PTR( name, default_type ) \
     282        template< typename core_t > \
     283        static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
    384284        \
    385         template<typename core_t> \
    386         static inline void func( core_t &, long, type ) {}
    387 
    388         #define SYMTAB_FUNC2( func, type1, type2 ) \
    389         template<typename core_t> \
    390         static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
    391                 core.symtab.func( arg1, arg2 ); \
    392         } \
    393         \
    394         template<typename core_t> \
    395         static inline void func( core_t &, long, type1, type2 ) {}
    396 
    397         SYMTAB_FUNC1( addId     , const DeclWithType *  );
    398         SYMTAB_FUNC1( addType   , const NamedTypeDecl * );
    399         SYMTAB_FUNC1( addStruct , const StructDecl *    );
    400         SYMTAB_FUNC1( addEnum   , const EnumDecl *      );
    401         SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    402         SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    403         SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
    404 
    405         // A few extra functions have more complicated behaviour, they are hand written
    406         template<typename core_t>
    407         static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
    408                 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    409                 for ( const auto & param : decl->params ) {
    410                         fwd->params.push_back( deepCopy( param.get() ) );
    411                 }
    412                 core.symtab.addStruct( fwd );
    413         }
    414 
    415         template<typename core_t>
    416         static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
    417 
    418         template<typename core_t>
    419         static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
    420                 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name );
    421                 for ( const auto & param : decl->params ) {
    422                         fwd->params.push_back( deepCopy( param.get() ) );
    423                 }
    424                 core.symtab.addUnion( fwd );
    425         }
    426 
    427         template<typename core_t>
    428         static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
    429 
    430         template<typename core_t>
    431         static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
    432                 if ( ! core.symtab.lookupStruct( str ) ) {
    433                         core.symtab.addStruct( str );
    434                 }
    435         }
    436 
    437         template<typename core_t>
    438         static inline void addStruct( core_t &, long, const std::string & ) {}
    439 
    440         template<typename core_t>
    441         static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
    442                 if ( ! core.symtab.lookupUnion( str ) ) {
    443                         core.symtab.addUnion( str );
    444                 }
    445         }
    446 
    447         template<typename core_t>
    448         static inline void addUnion( core_t &, long, const std::string & ) {}
    449 
    450         #undef SYMTAB_FUNC1
    451         #undef SYMTAB_FUNC2
    452 } // namespace symtab
    453 
    454 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
    455 // Detect the presence of a member name `subs` and call all members appropriately
    456 namespace forall {
    457         // Some simple scoping rules
    458         template<typename core_t>
    459         static inline auto enter( core_t & core, int, const ast::FunctionType * type )
    460                         -> decltype( core.subs, void() ) {
    461                 if ( ! type->forall.empty() ) core.subs.beginScope();
    462         }
    463 
    464         template<typename core_t>
    465         static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
    466 
    467         template<typename core_t>
    468         static inline auto leave( core_t & core, int, const ast::FunctionType * type )
    469                         -> decltype( core.subs, void() ) {
    470                 if ( ! type->forall.empty() ) { core.subs.endScope(); }
    471         }
    472 
    473         template<typename core_t>
    474         static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
    475 
    476         // Replaces a TypeInstType's base TypeDecl according to the table
    477         template<typename core_t>
    478         static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
    479                         -> decltype( core.subs, void() ) {
    480                 inst = ast::mutate_field(
    481                         inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
    482         }
    483 
    484         template<typename core_t>
    485         static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
    486 } // namespace forall
    487 
    488 // For passes that need access to the global context. Searches `translationUnit`
    489 namespace translation_unit {
    490         template<typename core_t>
    491         static inline auto get_cptr( core_t & core, int )
    492                         -> decltype( &core.translationUnit ) {
    493                 return &core.translationUnit;
    494         }
    495 
    496         template<typename core_t>
    497         static inline const TranslationUnit ** get_cptr( core_t &, long ) {
    498                 return nullptr;
    499         }
    500 }
    501 
    502 // For passes, usually utility passes, that have a result.
    503 namespace result {
    504         template<typename core_t>
    505         static inline auto get( core_t & core, char ) -> decltype( core.result() ) {
    506                 return core.result();
    507         }
    508 
    509         template<typename core_t>
    510         static inline auto get( core_t & core, int ) -> decltype( core.result ) {
    511                 return core.result;
    512         }
    513 
    514         template<typename core_t>
    515         static inline void get( core_t &, long ) {}
    516 }
    517 
    518 } // namespace ast::__pass
     285        template< typename core_t > \
     286        static inline default_type * name( core_t &, long ) { return nullptr; }
     287
     288        // List of fields and their expected types
     289        FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
     290        FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
     291        FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     292        FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
     293        FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
     294        FIELD_PTR( visit_children, __pass::bool_ref )
     295        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
     296        FIELD_PTR( visitor, ast::Pass<core_t> * const )
     297
     298        // Remove the macro to make sure we don't clash
     299        #undef FIELD_PTR
     300
     301        template< typename core_t >
     302        static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     303                // Stats::Heap::stacktrace_push(core_t::traceId);
     304        }
     305
     306        template< typename core_t >
     307        static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     308                // Stats::Heap::stacktrace_pop();
     309        }
     310
     311        template< typename core_t >
     312        static void beginTrace(core_t &, long) {}
     313
     314        template< typename core_t >
     315        static void endTrace(core_t &, long) {}
     316
     317        // Allows visitor to handle an error on top-level declarations, and possibly suppress the error.
     318        // If onError() returns false, the error will be ignored. By default, it returns true.
     319
     320        template< typename core_t >
     321        static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
     322
     323        template< typename core_t >
     324        static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
     325                return core.on_error(decl);
     326        }
     327
     328        template< typename core_t, typename node_t >
     329        static auto make_location_guard( core_t & core, node_t * node, int )
     330                        -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) {
     331                ValueGuardPtr<const CodeLocation *> guard( &core.location );
     332                core.location = &node->location;
     333                return guard;
     334        }
     335
     336        template< typename core_t, typename node_t >
     337        static auto make_location_guard( core_t &, node_t *, long ) -> int {
     338                return 0;
     339        }
     340
     341        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     342        // All passes which have such functions are assumed desire this behaviour
     343        // detect it using the same strategy
     344        namespace scope {
     345                template<typename core_t>
     346                static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
     347                        core.beginScope();
     348                }
     349
     350                template<typename core_t>
     351                static inline void enter( core_t &, long ) {}
     352
     353                template<typename core_t>
     354                static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
     355                        core.endScope();
     356                }
     357
     358                template<typename core_t>
     359                static inline void leave( core_t &, long ) {}
     360        } // namespace scope
     361
     362        // Certain passes desire an up to date symbol table automatically
     363        // detect the presence of a member name `symtab` and call all the members appropriately
     364        namespace symtab {
     365                // Some simple scoping rules
     366                template<typename core_t>
     367                static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
     368                        core.symtab.enterScope();
     369                }
     370
     371                template<typename core_t>
     372                static inline auto enter( core_t &, long ) {}
     373
     374                template<typename core_t>
     375                static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
     376                        core.symtab.leaveScope();
     377                }
     378
     379                template<typename core_t>
     380                static inline auto leave( core_t &, long ) {}
     381
     382                // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
     383                // Create macro to condense these common patterns
     384                #define SYMTAB_FUNC1( func, type ) \
     385                template<typename core_t> \
     386                static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
     387                        core.symtab.func( arg ); \
     388                } \
     389                \
     390                template<typename core_t> \
     391                static inline void func( core_t &, long, type ) {}
     392
     393                #define SYMTAB_FUNC2( func, type1, type2 ) \
     394                template<typename core_t> \
     395                static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
     396                        core.symtab.func( arg1, arg2 ); \
     397                } \
     398                        \
     399                template<typename core_t> \
     400                static inline void func( core_t &, long, type1, type2 ) {}
     401
     402                SYMTAB_FUNC1( addId     , const DeclWithType *  );
     403                SYMTAB_FUNC1( addType   , const NamedTypeDecl * );
     404                SYMTAB_FUNC1( addStruct , const StructDecl *    );
     405                SYMTAB_FUNC1( addEnum   , const EnumDecl *      );
     406                SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
     407                SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
     408                SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
     409
     410                // A few extra functions have more complicated behaviour, they are hand written
     411                template<typename core_t>
     412                static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
     413                        ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
     414                        for ( const auto & param : decl->params ) {
     415                                fwd->params.push_back( deepCopy( param.get() ) );
     416                        }
     417                        core.symtab.addStruct( fwd );
     418                }
     419
     420                template<typename core_t>
     421                static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
     422
     423                template<typename core_t>
     424                static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
     425                        ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name );
     426                        for ( const auto & param : decl->params ) {
     427                                fwd->params.push_back( deepCopy( param.get() ) );
     428                        }
     429                        core.symtab.addUnion( fwd );
     430                }
     431
     432                template<typename core_t>
     433                static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
     434
     435                template<typename core_t>
     436                static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
     437                        if ( ! core.symtab.lookupStruct( str ) ) {
     438                                core.symtab.addStruct( str );
     439                        }
     440                }
     441
     442                template<typename core_t>
     443                static inline void addStruct( core_t &, long, const std::string & ) {}
     444
     445                template<typename core_t>
     446                static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
     447                        if ( ! core.symtab.lookupUnion( str ) ) {
     448                                core.symtab.addUnion( str );
     449                        }
     450                }
     451
     452                template<typename core_t>
     453                static inline void addUnion( core_t &, long, const std::string & ) {}
     454
     455                #undef SYMTAB_FUNC1
     456                #undef SYMTAB_FUNC2
     457        } // namespace symtab
     458
     459        // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
     460        // Detect the presence of a member name `subs` and call all members appropriately
     461        namespace forall {
     462                // Some simple scoping rules
     463                template<typename core_t>
     464                static inline auto enter( core_t & core, int, const ast::FunctionType * type )
     465                -> decltype( core.subs, void() ) {
     466                        if ( ! type->forall.empty() ) core.subs.beginScope();
     467                }
     468
     469                template<typename core_t>
     470                static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
     471
     472                template<typename core_t>
     473                static inline auto leave( core_t & core, int, const ast::FunctionType * type )
     474                -> decltype( core.subs, void() ) {
     475                        if ( ! type->forall.empty() ) { core.subs.endScope(); }
     476                }
     477
     478                template<typename core_t>
     479                static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
     480
     481                // Replaces a TypeInstType's base TypeDecl according to the table
     482                template<typename core_t>
     483                static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
     484                -> decltype( core.subs, void() ) {
     485                        inst = ast::mutate_field(
     486                                inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
     487                }
     488
     489                template<typename core_t>
     490                static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
     491        } // namespace forall
     492
     493        // For passes that need access to the global context. Sreaches `translationUnit`
     494        namespace translation_unit {
     495                template<typename core_t>
     496                static inline auto get_cptr( core_t & core, int )
     497                                -> decltype( &core.translationUnit ) {
     498                        return &core.translationUnit;
     499                }
     500
     501                template<typename core_t>
     502                static inline const TranslationUnit ** get_cptr( core_t &, long ) {
     503                        return nullptr;
     504                }
     505        }
     506
     507        // For passes, usually utility passes, that have a result.
     508        namespace result {
     509                template<typename core_t>
     510                static inline auto get( core_t & core, char ) -> decltype( core.result() ) {
     511                        return core.result();
     512                }
     513
     514                template<typename core_t>
     515                static inline auto get( core_t & core, int ) -> decltype( core.result ) {
     516                        return core.result;
     517                }
     518
     519                template<typename core_t>
     520                static inline void get( core_t &, long ) {}
     521        }
     522} // namespace __pass
     523} // namespace ast
  • src/AST/Print.cpp

    rb110bcc r2ed94a9  
    2929namespace ast {
    3030
    31 namespace {
    32 
    33 template<typename C, typename... T>
    34 constexpr array<C, sizeof...(T)> make_array( T&&... values ) {
    35         return array<C, sizeof...(T)>{ std::forward<T>( values )... };
    36 }
    37 
    38 namespace Names {
    39         static constexpr auto FuncSpecifiers = make_array<const char*>(
    40                 "inline", "_Noreturn", "fortran"
    41         );
    42 
    43         static constexpr auto StorageClasses = make_array<const char*>(
    44                 "extern", "static", "auto", "register", "__thread", "_Thread_local"
    45         );
    46 
    47         static constexpr auto Qualifiers = make_array<const char*>(
    48                 "const", "restrict", "volatile", "mutex", "_Atomic"
    49         );
    50 }
    51 
    52 template<typename bits_t, size_t N>
    53 void print( ostream & os, const bits_t & bits,
    54                 const array<const char *, N> & names ) {
    55         if ( !bits.any() ) return;
    56         for ( size_t i = 0 ; i < N ; i += 1 ) {
    57                 if ( bits[i] ) {
    58                         os << names[i] << ' ';
    59                 }
    60         }
     31template <typename C, typename... T>
     32constexpr array<C,sizeof...(T)> make_array(T&&... values)
     33{
     34        return array<C,sizeof...(T)>{
     35                std::forward<T>(values)...
     36        };
    6137}
    6238
     
    10480        static const char* Names[];
    10581
     82        struct Names {
     83                static constexpr auto FuncSpecifiers = make_array<const char*>(
     84                        "inline", "_Noreturn", "fortran"
     85                );
     86
     87                static constexpr auto StorageClasses = make_array<const char*>(
     88                        "extern", "static", "auto", "register", "__thread", "_Thread_local"
     89                );
     90
     91                static constexpr auto Qualifiers = make_array<const char*>(
     92                        "const", "restrict", "volatile", "mutex", "_Atomic"
     93                );
     94        };
     95
     96        template<typename storage_t, size_t N>
     97        void print(const storage_t & storage, const array<const char *, N> & Names ) {
     98                if ( storage.any() ) {
     99                        for ( size_t i = 0; i < Names.size(); i += 1 ) {
     100                                if ( storage[i] ) {
     101                                        os << Names[i] << ' ';
     102                                }
     103                        }
     104                }
     105        }
     106
     107        void print( const ast::Function::Specs & specs ) {
     108                print(specs, Names::FuncSpecifiers);
     109        }
     110
     111        void print( const ast::Storage::Classes & storage ) {
     112                print(storage, Names::StorageClasses);
     113        }
     114
     115        void print( const ast::CV::Qualifiers & qualifiers ) {
     116                print(qualifiers, Names::Qualifiers);
     117        }
     118
    106119        void print( const std::vector<ast::Label> & labels ) {
    107120                if ( labels.empty() ) return;
     
    217230                }
    218231
    219                 ast::print( os, node->storage );
     232                print( node->storage );
    220233                os << node->typeString();
    221234
     
    259272
    260273        void preprint( const ast::Type * node ) {
    261                 ast::print( os, node->qualifiers );
     274                print( node->qualifiers );
    262275        }
    263276
     
    265278                print( node->forall );
    266279                print( node->assertions );
    267                 ast::print( os, node->qualifiers );
     280                print( node->qualifiers );
    268281        }
    269282
    270283        void preprint( const ast::BaseInstType * node ) {
    271284                print( node->attributes );
    272                 ast::print( os, node->qualifiers );
     285                print( node->qualifiers );
    273286        }
    274287
     
    281294                }
    282295
    283                 ast::print( os, node->storage );
     296                print( node->storage );
    284297
    285298                if ( node->type ) {
     
    325338                if ( ! short_mode ) printAll( node->attributes );
    326339
    327                 ast::print( os, node->storage );
    328                 ast::print( os, node->funcSpec );
     340                print( node->storage );
     341                print( node->funcSpec );
     342
     343
    329344
    330345                if ( node->type && node->isTypeFixed ) {
     
    369384                                --indent;
    370385                        }
    371                 }
    372 
    373                 if ( ! node->withExprs.empty() ) {
    374                         // Not with a clause, but the 'with clause'.
    375                         ++indent;
    376                         os << " with clause" << endl << indent;
    377                         printAll( node->withExprs );
    378                         --indent;
    379386                }
    380387
     
    739746        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    740747                os << "Suspend Statement";
    741                 switch (node->kind) {
    742                 case ast::SuspendStmt::None     : os << " with implicit target"; break;
    743                 case ast::SuspendStmt::Generator: os << " for generator"; break;
    744                 case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
     748                switch (node->type) {
     749                        case ast::SuspendStmt::None     : os << " with implicit target"; break;
     750                        case ast::SuspendStmt::Generator: os << " for generator"; break;
     751                        case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
    745752                }
    746753                os << endl;
     
    16201627};
    16211628
    1622 } // namespace
    1623 
    16241629void print( ostream & os, const ast::Node * node, Indenter indent ) {
    16251630        Printer printer { os, indent, false };
     
    16321637}
    16331638
    1634 void print( ostream & os, Function::Specs specs ) {
    1635         print( os, specs, Names::FuncSpecifiers );
     1639// Annoyingly these needed to be defined out of line to avoid undefined references.
     1640// The size here needs to be explicit but at least the compiler will produce an error
     1641// if the wrong size is specified
     1642constexpr array<const char*, 3> Printer::Names::FuncSpecifiers;
     1643constexpr array<const char*, 6> Printer::Names::StorageClasses;
     1644constexpr array<const char*, 5> Printer::Names::Qualifiers;
    16361645}
    1637 
    1638 void print( ostream & os, Storage::Classes storage ) {
    1639         print( os, storage, Names::StorageClasses );
    1640 }
    1641 
    1642 void print( ostream & os, CV::Qualifiers qualifiers ) {
    1643         print( os, qualifiers, Names::Qualifiers );
    1644 }
    1645 
    1646 } // namespace ast
  • src/AST/Print.hpp

    rb110bcc r2ed94a9  
    1616#pragma once
    1717
    18 #include <iosfwd>
     18#include <iostream>
     19#include <utility>   // for forward
    1920
    20 #include "AST/Fwd.hpp"
     21#include "AST/Node.hpp"
    2122#include "Common/Indenter.h"
    2223
    2324namespace ast {
     25
     26class Decl;
    2427
    2528/// Print a node with the given indenter
     
    4144}
    4245
    43 /// Print each cv-qualifier used in the set, followed by a space.
    44 void print( std::ostream & os, CV::Qualifiers );
    45 /// Print each function specifier used in the set, followed by a space.
    46 void print( std::ostream & os, Function::Specs );
    47 /// Print each storage class used in the set, followed by a space.
    48 void print( std::ostream & os, Storage::Classes );
    49 
    5046}
  • src/AST/Stmt.hpp

    rb110bcc r2ed94a9  
    1010// Created On       : Wed May  8 13:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr  5 10:34:00 2023
    13 // Update Count     : 37
     12// Last Modified On : Wed Apr 20 14:34:00 2022
     13// Update Count     : 36
    1414//
    1515
     
    205205};
    206206
    207 // A while loop or a do-while loop:
    208 enum WhileDoKind { While, DoWhile };
    209 
    210207// While loop: while (...) ... else ... or do ... while (...) else ...;
    211208class WhileDoStmt final : public Stmt {
     
    215212        ptr<Stmt> else_;
    216213        std::vector<ptr<Stmt>> inits;
    217         WhileDoKind isDoWhile;
     214        bool isDoWhile;
    218215
    219216        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
    220                                  const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
     217                                 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
    221218                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    222219
    223220        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_,
    224                                  const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
     221                                 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
    225222                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    226223
     
    367364  public:
    368365        ptr<CompoundStmt> then;
    369         enum Kind { None, Coroutine, Generator } kind = None;
    370 
    371         SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Kind kind, const std::vector<Label> && labels = {} )
    372                 : Stmt(loc, std::move(labels)), then(then), kind(kind) {}
     366        enum Type { None, Coroutine, Generator } type = None;
     367
     368        SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, const std::vector<Label> && labels = {} )
     369                : Stmt(loc, std::move(labels)), then(then), type(type) {}
    373370
    374371        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    397394};
    398395
    399 // Clause in a waitfor statement: waitfor (..., ...) ...
    400396class WaitForClause final : public StmtClause {
    401397  public:
     
    458454        MUTATE_FRIEND
    459455};
    460 
    461456} // namespace ast
    462457
  • src/AST/SymbolTable.cpp

    rb110bcc r2ed94a9  
    7070        if ( baseExpr ) {
    7171                if (baseExpr->env) {
    72                         Expr * base = deepCopy(baseExpr);
     72                        Expr * base = shallowCopy(baseExpr);
    7373                        const TypeSubstitution * subs = baseExpr->env;
    7474                        base->env = nullptr;
     
    260260void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) {
    261261        // default handling of conflicts is to raise an error
    262         addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     262        addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    263263}
    264264
    265265void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) {
    266266        // default handling of conflicts is to raise an error
    267         addIdCommon( decl, OnConflict::error(), nullptr, deleter );
     267        addId( decl, OnConflict::error(), nullptr, deleter );
    268268}
    269269
     
    677677}
    678678
    679 void SymbolTable::addIdCommon(
    680                 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
    681                 const Expr * baseExpr, const Decl * deleter ) {
     679void SymbolTable::addId(
     680                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
     681                const Decl * deleter ) {
    682682        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    683683        if (kind == NUMBER_OF_KINDS) { // not a special decl
    684                 addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
     684                addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
    685685        }
    686686        else {
     
    695695                        assertf(false, "special decl with non-function type");
    696696                }
    697                 addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
    698         }
    699 }
    700 
    701 void SymbolTable::addIdToTable(
    702                 const DeclWithType * decl, const std::string & lookupKey,
    703                 IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
    704                 const Expr * baseExpr, const Decl * deleter ) {
     697                addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
     698        }
     699}
     700
     701void SymbolTable::addId(
     702                const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
     703                const Decl * deleter ) {
    705704        ++*stats().add_calls;
    706705        const std::string &name = decl->name;
     
    779778void SymbolTable::addMembers(
    780779                const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) {
    781         for ( const ptr<Decl> & decl : aggr->members ) {
    782                 auto dwt = decl.as<DeclWithType>();
    783                 if ( nullptr == dwt ) continue;
    784                 addIdCommon( dwt, handleConflicts, expr );
    785                 // Inline through unnamed struct/union members.
    786                 if ( "" != dwt->name ) continue;
    787                 const Type * t = dwt->get_type()->stripReferences();
    788                 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
    789                         if ( ! dynamic_cast<const StructInstType *>(rty)
    790                                 && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
    791                         ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
    792                         ast::ptr<ast::TypeSubstitution> tmp = expr->env;
    793                         expr = mutate_field(expr, &Expr::env, nullptr);
    794                         const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
    795                         base = mutate_field(base, &Expr::env, tmp);
    796 
    797                         addMembers(
    798                                 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
     780        for ( const Decl * decl : aggr->members ) {
     781                if ( auto dwt = dynamic_cast< const DeclWithType * >( decl ) ) {
     782                        addId( dwt, handleConflicts, expr );
     783                        if ( dwt->name == "" ) {
     784                                const Type * t = dwt->get_type()->stripReferences();
     785                                if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
     786                                        if ( ! dynamic_cast<const StructInstType *>(rty)
     787                                                && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
     788                                        ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
     789                                        ast::ptr<ast::TypeSubstitution> tmp = expr->env;
     790                                        expr = mutate_field(expr, &Expr::env, nullptr);
     791                                        const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
     792                                        base = mutate_field(base, &Expr::env, tmp);
     793
     794                                        addMembers(
     795                                                rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
     796                                }
     797                        }
    799798                }
    800799        }
  • src/AST/SymbolTable.hpp

    rb110bcc r2ed94a9  
    192192
    193193        /// common code for addId, addDeletedId, etc.
    194         void addIdCommon(
    195                 const DeclWithType * decl, OnConflict handleConflicts,
    196                 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr );
     194        void addId(
     195                const DeclWithType * decl, OnConflict handleConflicts, const Expr * baseExpr = nullptr,
     196                const Decl * deleter = nullptr );
    197197
    198198        /// common code for addId when special decls are placed into separate tables
    199         void addIdToTable(
    200                 const DeclWithType * decl, const std::string & lookupKey,
    201                 IdTable::Ptr & idTable, OnConflict handleConflicts,
     199        void addId(
     200                const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts,
    202201                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr);
    203 
     202       
    204203        /// adds all of the members of the Aggregate (addWith helper)
    205204        void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts );
  • src/AST/TranslationUnit.hpp

    rb110bcc r2ed94a9  
    1010// Created On       : Tue Jun 11 15:30:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Mar  9 16:41:00 2023
    13 // Update Count     : 2
     12// Last Modified On : Tue Mar 11 11:19:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    1717
    1818#include <map>
    19 #include <list>
     19#include <vector>
    2020
    2121#include "Fwd.hpp"
     
    2828
    2929        ptr<Type> sizeType;
    30         const FunctionDecl * dereference = nullptr;
    31         const StructDecl * dtorStruct = nullptr;
    32         const FunctionDecl * dtorDestroy = nullptr;
     30        const FunctionDecl * dereference;
     31        const StructDecl * dtorStruct;
     32        const FunctionDecl * dtorDestroy;
    3333};
    3434
  • src/AST/Type.cpp

    rb110bcc r2ed94a9  
    1010// Created On       : Mon May 13 15:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Apr  6 15:59:00 2023
    13 // Update Count     : 7
     12// Last Modified On : Thu Nov 24  9:49:00 2022
     13// Update Count     : 6
    1414//
    1515
     
    199199
    200200TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    201 : Type( q ), types( std::move(ts) ) {}
     201: Type( q ), types( std::move(ts) ), members() {
     202        // This constructor is awkward. `TupleType` needs to contain objects so that members can be
     203        // named, but members without initializer nodes end up getting constructors, which breaks
     204        // things. This happens because the object decls have to be visited so that their types are
     205        // kept in sync with the types listed here. Ultimately, the types listed here should perhaps
     206        // be eliminated and replaced with a list-view over members. The temporary solution is to
     207        // make a `ListInit` with `maybeConstructed = false`, so when the object is visited it is not
     208        // constructed. Potential better solutions include:
     209        //   a) Separate `TupleType` from its declarations, into `TupleDecl` and `Tuple{Inst?}Type`,
     210        //      similar to the aggregate types.
     211        //   b) Separate initializer nodes better, e.g. add a `MaybeConstructed` node that is replaced
     212        //      by `genInit`, rather than the current boolean flag.
     213        members.reserve( types.size() );
     214        for ( const Type * ty : types ) {
     215                members.emplace_back( new ObjectDecl{
     216                        CodeLocation(), "", ty, new ListInit( CodeLocation(), {}, {}, NoConstruct ),
     217                        Storage::Classes{}, Linkage::Cforall } );
     218        }
     219}
    202220
    203221bool isUnboundType(const Type * type) {
  • src/AST/Type.hpp

    rb110bcc r2ed94a9  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Apr  6 15:58:00 2023
    13 // Update Count     : 9
     12// Last Modified On : Thu Nov 24  9:47:00 2022
     13// Update Count     : 8
    1414//
    1515
     
    265265};
    266266
     267/// Function variable arguments flag
     268enum ArgumentFlag { FixedArgs, VariableArgs };
     269
    267270/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    268271class FunctionType final : public Type {
     
    457460public:
    458461        std::vector<ptr<Type>> types;
     462        std::vector<ptr<Decl>> members;
    459463
    460464        TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} );
  • src/AST/porting.md

    rb110bcc r2ed94a9  
    213213* `get_statement()` exclusively used for code location, replaced with `CodeLocation` field
    214214
    215 `CaseStmt` => `CaseClause`
     215`CaseStmt`
    216216* `_isDefault` has been removed
    217217  * `isDefault` calculates value from `cond`
     
    227227* `block` -> `body` and `finallyBlock` -> `finally`
    228228
    229 `ThrowStmt` and `CatchStmt` => `CatchClause`
     229`ThrowStmt` `CatchStmt`
    230230* moved `Kind` enums to shared `ast::ExceptionKind` enum
    231231
    232 `FinallyStmt` => `FinallyClause`
     232`FinallyStmt`
    233233* `block` -> `body`
    234234
     
    280280* Template class, with specializations and using to implement some other types:
    281281  * `StructInstType`, `UnionInstType` & `EnumInstType`
    282   * `baseStruct`, `baseUnion` & `baseEnum` => `base`
    283282
    284283`TypeInstType`
  • src/CodeGen/CodeGenerator.cc

    rb110bcc r2ed94a9  
    1717#include <cassert>                   // for assert, assertf
    1818#include <list>                      // for _List_iterator, list, list<>::it...
    19 #include <sstream>                   // for stringstream
    2019
    2120#include "AST/Decl.hpp"              // for DeclWithType
    2221#include "Common/UniqueName.h"       // for UniqueName
     22#include "Common/utility.h"          // for CodeLocation, toString
    2323#include "GenType.h"                 // for genType
    2424#include "InitTweak/InitTweak.h"     // for getPointerBase
  • src/Common/CodeLocationTools.cpp

    rb110bcc r2ed94a9  
    208208
    209209struct LeafKindVisitor : public ast::Visitor {
    210         LeafKind result;
     210        LeafKind kind;
    211211
    212212#define VISIT(node_type, return_type) \
    213213        const ast::return_type * visit( const ast::node_type * ) final { \
    214                 result = LeafKind::node_type; \
     214                kind = LeafKind::node_type; \
    215215                return nullptr; \
    216216        }
     
    222222
    223223LeafKind get_leaf_kind( ast::Node const * node ) {
    224         return ast::Pass<LeafKindVisitor>::read( node );
     224        LeafKindVisitor visitor;
     225        node->accept( visitor );
     226        return visitor.kind;
    225227}
    226228
  • src/Common/DeclStats.cpp

    rb110bcc r2ed94a9  
    2323#include <iostream>
    2424#include <map>
    25 #include <sstream>
    2625#include <unordered_map>
    2726#include <unordered_set>
  • src/Common/Eval.cc

    rb110bcc r2ed94a9  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Eval.cc -- Evaluate parts of the ast at compile time.
     7// utility.h --
    88//
    99// Author           : Richard C. Bilson
     
    1313// Update Count     : 119
    1414//
    15 
    16 #include "Eval.h"
    1715
    1816#include <utility> // for pair
  • src/Common/ResolvProtoDump.cpp

    rb110bcc r2ed94a9  
    1919#include <iostream>
    2020#include <set>
    21 #include <sstream>
    2221#include <unordered_set>
    2322
     
    2726#include "AST/Type.hpp"
    2827#include "CodeGen/OperatorTable.h"
     28#include "Common/utility.h"
    2929
    3030namespace {
  • src/Common/SemanticError.h

    rb110bcc r2ed94a9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 25 12:01:31 2023
    13 // Update Count     : 37
     12// Last Modified On : Thu Feb  2 10:59:10 2023
     13// Update Count     : 36
    1414//
    1515
     
    5656        {"self-assign"              , Severity::Warn    , "self assignment of expression: %s"                          },
    5757        {"reference-conversion"     , Severity::Warn    , "rvalue to reference conversion of rvalue: %s"               },
    58         {"qualifiers-zero_t-one_t"  , Severity::Warn    , "questionable use of type qualifier(s) with %s"              },
     58        {"qualifiers-zero_t-one_t"  , Severity::Warn    , "questionable use of type qualifier %s with %s"              },
    5959        {"aggregate-forward-decl"   , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
    6060        {"superfluous-decl"         , Severity::Warn    , "declaration does not allocate storage: %s"                  },
  • src/Common/module.mk

    rb110bcc r2ed94a9  
    2020        Common/CodeLocationTools.hpp \
    2121        Common/CodeLocationTools.cpp \
     22        Common/CompilerError.h \
     23        Common/Debug.h \
    2224        Common/DeclStats.hpp \
    2325        Common/DeclStats.cpp \
    2426        Common/ErrorObjects.h \
    2527        Common/Eval.cc \
    26         Common/Eval.h \
    2728        Common/Examine.cc \
    2829        Common/Examine.h \
     
    3031        Common/Indenter.h \
    3132        Common/Indenter.cc \
    32         Common/Iterate.hpp \
    3333        Common/PassVisitor.cc \
    3434        Common/PassVisitor.h \
     
    5252        Common/Stats/Time.cc \
    5353        Common/Stats/Time.h \
    54         Common/ToString.hpp \
     54        Common/UnimplementedError.h \
    5555        Common/UniqueName.cc \
    5656        Common/UniqueName.h \
  • src/Common/utility.h

    rb110bcc r2ed94a9  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // utility.h -- General utilities used across the compiler.
     7// utility.h --
    88//
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Feb 17 15:25:00 2023
    13 // Update Count     : 53
     12// Last Modified On : Mon Apr 25 14:26:00 2022
     13// Update Count     : 51
    1414//
    1515
     
    1919#include <cctype>
    2020#include <algorithm>
     21#include <functional>
    2122#include <iostream>
     23#include <iterator>
    2224#include <list>
    2325#include <memory>
     26#include <sstream>
    2427#include <string>
    2528#include <type_traits>
     29#include <utility>
    2630#include <vector>
    2731#include <cstring>                                                                              // memcmp
     
    4549                return 0;
    4650        } // if
     51}
     52
     53template< typename T, typename U >
     54struct maybeBuild_t {
     55        static T * doit( const U *orig ) {
     56                if ( orig ) {
     57                        return orig->build();
     58                } else {
     59                        return 0;
     60                } // if
     61        }
     62};
     63
     64template< typename T, typename U >
     65static inline T * maybeBuild( const U *orig ) {
     66        return maybeBuild_t<T,U>::doit(orig);
     67}
     68
     69template< typename T, typename U >
     70static inline T * maybeMoveBuild( const U *orig ) {
     71        T* ret = maybeBuild<T>(orig);
     72        delete orig;
     73        return ret;
    4774}
    4875
     
    141168        splice( src, dst );
    142169        dst.swap( src );
     170}
     171
     172template < typename T >
     173void toString_single( std::ostream & os, const T & value ) {
     174        os << value;
     175}
     176
     177template < typename T, typename... Params >
     178void toString_single( std::ostream & os, const T & value, const Params & ... params ) {
     179        os << value;
     180        toString_single( os, params ... );
     181}
     182
     183template < typename ... Params >
     184std::string toString( const Params & ... params ) {
     185        std::ostringstream os;
     186        toString_single( os, params... );
     187        return os.str();
     188}
     189
     190#define toCString( ... ) toString( __VA_ARGS__ ).c_str()
     191
     192// replace element of list with all elements of another list
     193template< typename T >
     194void replace( std::list< T > &org, typename std::list< T >::iterator pos, std::list< T > &with ) {
     195        typename std::list< T >::iterator next = pos; advance( next, 1 );
     196
     197        //if ( next != org.end() ) {
     198        org.erase( pos );
     199        org.splice( next, with );
     200        //}
     201
     202        return;
     203}
     204
     205// replace range of a list with a single element
     206template< typename T >
     207void replace( std::list< T > &org, typename std::list< T >::iterator begin, typename std::list< T >::iterator end, const T & with ) {
     208        org.insert( begin, with );
     209        org.erase( begin, end );
    143210}
    144211
     
    169236}
    170237
     238template< typename... Args >
     239auto zip(Args&&... args) -> decltype(zipWith(std::forward<Args>(args)..., std::make_pair)) {
     240  return zipWith(std::forward<Args>(args)..., std::make_pair);
     241}
     242
     243template< class InputIterator1, class InputIterator2, class OutputIterator, class BinFunction >
     244void zipWith( InputIterator1 b1, InputIterator1 e1, InputIterator2 b2, InputIterator2 e2, OutputIterator out, BinFunction func ) {
     245        while ( b1 != e1 && b2 != e2 )
     246                *out++ = func(*b1++, *b2++);
     247}
     248
     249// it's nice to actually be able to increment iterators by an arbitrary amount
     250template< class InputIt, class Distance >
     251InputIt operator+( InputIt it, Distance n ) {
     252        advance(it, n);
     253        return it;
     254}
     255
     256template< typename T >
     257void warn_single( const T & arg ) {
     258        std::cerr << arg << std::endl;
     259}
     260
     261template< typename T, typename... Params >
     262void warn_single(const T & arg, const Params & ... params ) {
     263        std::cerr << arg;
     264        warn_single( params... );
     265}
     266
     267template< typename... Params >
     268void warn( const Params & ... params ) {
     269        std::cerr << "Warning: ";
     270        warn_single( params... );
     271}
     272
    171273// determines if pref is a prefix of str
    172274static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
    173275        if ( pref.size() > str.size() ) return false;
    174         return pref == str.substr(start, pref.size());
    175 }
     276    return 0 == memcmp( str.c_str() + start, pref.c_str(), pref.size() );
     277        // return prefix == full.substr(0, prefix.size()); // for future, requires c++17
     278}
     279
     280// -----------------------------------------------------------------------------
     281// Ref Counted Singleton class
     282// Objects that inherit from this class will have at most one reference to it
     283// but if all references die, the object will be deleted.
     284
     285template< typename ThisType >
     286class RefCountSingleton {
     287  public:
     288        static std::shared_ptr<ThisType> get() {
     289                if( global_instance.expired() ) {
     290                        std::shared_ptr<ThisType> new_instance = std::make_shared<ThisType>();
     291                        global_instance = new_instance;
     292                        return std::move(new_instance);
     293                }
     294                return global_instance.lock();
     295        }
     296  private:
     297        static std::weak_ptr<ThisType> global_instance;
     298};
     299
     300template< typename ThisType >
     301std::weak_ptr<ThisType> RefCountSingleton<ThisType>::global_instance;
    176302
    177303// -----------------------------------------------------------------------------
     
    230356        ~ValueGuardPtr() { if( ref ) { swap( *ref, old ); } }
    231357};
     358
     359// -----------------------------------------------------------------------------
     360// Helper struct and function to support
     361// for ( val : reverseIterate( container ) ) {}
     362// syntax to have a for each that iterates backwards
     363
     364template< typename T >
     365struct reverse_iterate_t {
     366        T& ref;
     367
     368        reverse_iterate_t( T & ref ) : ref(ref) {}
     369
     370        // this does NOT work on const T!!!
     371        // typedef typename T::reverse_iterator iterator;
     372        auto begin() { return ref.rbegin(); }
     373        auto end() { return ref.rend(); }
     374};
     375
     376template< typename T >
     377reverse_iterate_t< T > reverseIterate( T & ref ) {
     378        return reverse_iterate_t< T >( ref );
     379}
     380
     381template< typename T >
     382struct enumerate_t {
     383        template<typename val_t>
     384        struct value_t {
     385                val_t & val;
     386                size_t idx;
     387        };
     388
     389        template< typename iter_t, typename val_t >
     390        struct iterator_t {
     391                iter_t it;
     392                size_t idx;
     393
     394                iterator_t( iter_t _it, size_t _idx ) : it(_it), idx(_idx) {}
     395
     396                value_t<val_t> operator*() const { return value_t<val_t>{ *it, idx }; }
     397
     398                bool operator==(const iterator_t & o) const { return o.it == it; }
     399                bool operator!=(const iterator_t & o) const { return o.it != it; }
     400
     401                iterator_t & operator++() {
     402                        it++;
     403                        idx++;
     404                        return *this;
     405                }
     406
     407                using difference_type   = typename std::iterator_traits< iter_t >::difference_type;
     408                using value_type        = value_t<val_t>;
     409                using pointer           = value_t<val_t> *;
     410                using reference         = value_t<val_t> &;
     411                using iterator_category = std::forward_iterator_tag;
     412        };
     413
     414        T & ref;
     415
     416        using iterator = iterator_t< typename T::iterator, typename T::value_type >;
     417        using const_iterator = iterator_t< typename T::const_iterator, const typename T::value_type >;
     418
     419        iterator begin() { return iterator( ref.begin(), 0 ); }
     420        iterator end()   { return iterator( ref.end(), ref.size() ); }
     421
     422        const_iterator begin() const { return const_iterator( ref.cbegin(), 0 ); }
     423        const_iterator end()   const { return const_iterator( ref.cend(), ref.size() ); }
     424
     425        const_iterator cbegin() const { return const_iterator( ref.cbegin(), 0 ); }
     426        const_iterator cend()   const { return const_iterator( ref.cend(), ref.size() ); }
     427};
     428
     429template< typename T >
     430enumerate_t<T> enumerate( T & ref ) {
     431        return enumerate_t< T >{ ref };
     432}
     433
     434template< typename T >
     435const enumerate_t< const T > enumerate( const T & ref ) {
     436        return enumerate_t< const T >{ ref };
     437}
     438
     439template< typename OutType, typename Range, typename Functor >
     440OutType map_range( const Range& range, Functor&& functor ) {
     441        OutType out;
     442
     443        std::transform(
     444                begin( range ),
     445                end( range ),
     446                std::back_inserter( out ),
     447                std::forward< Functor >( functor )
     448        );
     449
     450        return out;
     451}
     452
     453// -----------------------------------------------------------------------------
     454// Helper struct and function to support:
     455// for ( auto val : group_iterate( container1, container2, ... ) ) { ... }
     456// This iteraters through multiple containers of the same size.
     457
     458template<typename... Args>
     459class group_iterate_t {
     460        using Iterables = std::tuple<Args...>;
     461        Iterables iterables;
     462
     463        // Getting the iterator and value types this way preserves const.
     464        template<size_t I> using Iter = decltype(std::get<I>(iterables).begin());
     465        template<size_t I> using Data = decltype(*std::get<I>(iterables).begin());
     466        template<typename> struct base_iterator;
     467
     468        // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1`
     469        // into a pack. These are the indexes into the tuples, so unpacking can
     470        // go over each element of the tuple.
     471        // The std::integer_sequence is just used to build that sequence.
     472        // A library reference will probably explain it better than I can.
     473        template<std::size_t... Indices>
     474        struct base_iterator<std::integer_sequence<std::size_t, Indices...>> {
     475                using value_type = std::tuple< Data<Indices>... >;
     476                std::tuple<Iter<Indices>...> iterators;
     477
     478                base_iterator( Iter<Indices>... is ) : iterators( is... ) {}
     479                base_iterator operator++() {
     480                        return base_iterator( ++std::get<Indices>( iterators )... );
     481                }
     482                bool operator!=( const base_iterator& other ) const {
     483                        return iterators != other.iterators;
     484                }
     485                value_type operator*() const {
     486                        return std::tie( *std::get<Indices>( iterators )... );
     487                }
     488
     489                static base_iterator make_begin( Iterables & data ) {
     490                        return base_iterator( std::get<Indices>( data ).begin()... );
     491                }
     492                static base_iterator make_end( Iterables & data ) {
     493                        return base_iterator( std::get<Indices>( data ).end()... );
     494                }
     495        };
     496
     497public:
     498        group_iterate_t( const Args &... args ) : iterables( args... ) {}
     499
     500        using iterator = base_iterator<decltype(
     501                std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
     502
     503        iterator begin() { return iterator::make_begin( iterables ); }
     504        iterator end() { return iterator::make_end( iterables ); }
     505};
     506
     507// Helpers for the bounds checks (the non-varatic part of group_iterate):
     508static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
     509        assertf( size0 == size1,
     510                "group iteration requires containers of the same size: <%zd, %zd>.",
     511                size0, size1 );
     512}
     513
     514static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
     515        assertf( size0 == size1 && size1 == size2,
     516                "group iteration requires containers of the same size: <%zd, %zd, %zd>.",
     517                size0, size1, size2 );
     518}
     519
     520/// Performs bounds check to ensure that all arguments are of the same length.
     521template< typename... Args >
     522group_iterate_t<Args...> group_iterate( Args &&... args ) {
     523        runGroupBoundsCheck( args.size()... );
     524        return group_iterate_t<Args...>( std::forward<Args>( args )... );
     525}
     526
     527/// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
     528template< typename... Args >
     529group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
     530        return group_iterate_t<Args...>( std::forward<Args>( args )... );
     531}
     532
     533// -----------------------------------------------------------------------------
     534// Helper struct and function to support
     535// for ( val : lazy_map( container1, f ) ) {}
     536// syntax to have a for each that iterates a container, mapping each element by applying f
     537template< typename T, typename Func >
     538struct lambda_iterate_t {
     539        const T & ref;
     540        std::function<Func> f;
     541
     542        struct iterator {
     543                typedef decltype(begin(ref)) Iter;
     544                Iter it;
     545                std::function<Func> f;
     546                iterator( Iter it, std::function<Func> f ) : it(it), f(f) {}
     547                iterator & operator++() {
     548                        ++it; return *this;
     549                }
     550                bool operator!=( const iterator &other ) const { return it != other.it; }
     551                auto operator*() const -> decltype(f(*it)) { return f(*it); }
     552        };
     553
     554        lambda_iterate_t( const T & ref, std::function<Func> f ) : ref(ref), f(f) {}
     555
     556        auto begin() const -> decltype(iterator(std::begin(ref), f)) { return iterator(std::begin(ref), f); }
     557        auto end() const   -> decltype(iterator(std::end(ref), f)) { return iterator(std::end(ref), f); }
     558};
     559
     560template< typename... Args >
     561lambda_iterate_t<Args...> lazy_map( const Args &... args ) {
     562        return lambda_iterate_t<Args...>( args...);
     563}
    232564
    233565// -----------------------------------------------------------------------------
     
    251583} // ilog2
    252584
     585// -----------------------------------------------------------------------------
     586/// evaluates expr as a long long int. If second is false, expr could not be evaluated
     587std::pair<long long int, bool> eval(const Expression * expr);
     588
     589namespace ast {
     590        class Expr;
     591}
     592
     593std::pair<long long int, bool> eval(const ast::Expr * expr);
     594
     595// -----------------------------------------------------------------------------
     596/// Reorders the input range in-place so that the minimal-value elements according to the
     597/// comparator are in front;
     598/// returns the iterator after the last minimal-value element.
     599template<typename Iter, typename Compare>
     600Iter sort_mins( Iter begin, Iter end, Compare& lt ) {
     601        if ( begin == end ) return end;
     602
     603        Iter min_pos = begin;
     604        for ( Iter i = begin + 1; i != end; ++i ) {
     605                if ( lt( *i, *min_pos ) ) {
     606                        // new minimum cost; swap into first position
     607                        min_pos = begin;
     608                        std::iter_swap( min_pos, i );
     609                } else if ( ! lt( *min_pos, *i ) ) {
     610                        // duplicate minimum cost; swap into next minimum position
     611                        ++min_pos;
     612                        std::iter_swap( min_pos, i );
     613                }
     614        }
     615        return ++min_pos;
     616}
     617
     618template<typename Iter, typename Compare>
     619inline Iter sort_mins( Iter begin, Iter end, Compare&& lt ) {
     620        return sort_mins( begin, end, lt );
     621}
     622
     623/// sort_mins defaulted to use std::less
     624template<typename Iter>
     625inline Iter sort_mins( Iter begin, Iter end ) {
     626        return sort_mins( begin, end, std::less<typename std::iterator_traits<Iter>::value_type>{} );
     627}
     628
    253629// Local Variables: //
    254630// tab-width: 4 //
  • src/CompilationState.cc

    rb110bcc r2ed94a9  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 19:12:50 2023
    13 // Update Count     : 6
     11// Last Modified By : Henry Xue
     12// Last Modified On : Tue Jul 20 04:27:35 2021
     13// Update Count     : 5
    1414//
    1515
     
    2727        expraltp = false,
    2828        genericsp = false,
    29         invariant = false,
    3029        libcfap = false,
    3130        nopreludep = false,
  • src/CompilationState.h

    rb110bcc r2ed94a9  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 19:12:53 2023
    13 // Update Count     : 6
     11// Last Modified By : Henry Xue
     12// Last Modified On : Tue Jul 20 04:27:35 2021
     13// Update Count     : 5
    1414//
    1515
     
    2626        expraltp,
    2727        genericsp,
    28         invariant,
    2928        libcfap,
    3029        nopreludep,
  • src/Concurrency/Actors.cpp

    rb110bcc r2ed94a9  
    4545    // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
    4646    void previsit( const StructDecl * decl ) {
    47         if ( !decl->body ) return;
    48         if ( decl->name == "actor" ) {
    49             actorStructDecls.insert( decl ); // skip inserting fwd decl
    50             *actorDecl = decl;
    51         } else if( decl->name == "message" ) {
    52             messageStructDecls.insert( decl ); // skip inserting fwd decl
    53             *msgDecl = decl;
    54         } else if( decl->name == "request" ) *requestDecl = decl;
    55         else {
    56             GuardValue(insideStruct);
    57             insideStruct = true;
    58             parentDecl = mutate( decl );
    59         }
     47        GuardValue(insideStruct);
     48        insideStruct = true;
     49        parentDecl = mutate( decl );
     50        if( decl->name == "actor" ) *actorDecl = decl;
     51        if( decl->name == "message" ) *msgDecl = decl;
     52        if( decl->name == "request" ) *requestDecl = decl;
    6053        }
    6154
     
    7164    }
    7265
    73     // this collects the derived actor and message struct decl ptrs
     66    // this collects the valid actor and message struct decl pts
    7467    void postvisit( const StructInstType * node ) {
    7568        if ( ! *actorDecl || ! *msgDecl ) return;
    7669        if ( insideStruct && !namedDecl ) {
    77             auto actorIter = actorStructDecls.find( node->aggr() );   
    78             if ( actorIter != actorStructDecls.end() ) {
     70            if ( node->aggr() == *actorDecl ) {
    7971                actorStructDecls.insert( parentDecl );
    80                 return;
    81             }
    82             auto messageIter = messageStructDecls.find( node->aggr() );
    83             if ( messageIter != messageStructDecls.end() ) {
     72            } else if ( node->aggr() == *msgDecl ) {
    8473                messageStructDecls.insert( parentDecl );
    8574            }
     
    191180};
    192181
    193 // generates the definitions of send operators for actors
    194 // collects data needed for next pass that does the circular defn resolution
    195 //     for message send operators (via table above)
    196 struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
     182#define __ALLOC 0 // C_TODO: complete swap to no-alloc version
     183
     184struct GenReceiveDecls : public ast::WithDeclsToAdd<> {
    197185    unordered_set<const StructDecl *> & actorStructDecls;
    198186    unordered_set<const StructDecl *>  & messageStructDecls;
     
    203191    FwdDeclTable & forwardDecls;
    204192
    205     // generates the operator for actor message sends
    206193        void postvisit( const FunctionDecl * decl ) {
    207194        // return if not of the form receive( param1, param2 ) or if it is a forward decl
     
    222209        auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
    223210        if ( actorIter != actorStructDecls.end() && messageIter != messageStructDecls.end() ) {
     211
     212            // check that we have found all the decls we need from <actor.hfa>
     213            if ( !*allocationDecl || !*requestDecl )
     214                SemanticError( decl->location, "using actors requires a header, add #include <actor.hfa>\n" );
     215
    224216            //////////////////////////////////////////////////////////////////////
    225217            // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
    226218            /*
    227219                static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
    228                     request new_req;
     220                    request * new_req = alloc();
    229221                    Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
    230222                    __receive_fn fn = (__receive_fn)my_work_fn;
    231                     new_req{ &receiver, &msg, fn };
    232                     send( receiver, new_req );
     223                    (*new_req){ &receiver, &msg, fn };
     224                    send( receiver, *new_req );
    233225                    return receiver;
    234226                }
    235             */
     227            */ // C_TODO: update this with new no alloc version
    236228            CompoundStmt * sendBody = new CompoundStmt( decl->location );
    237229
     230            #if __ALLOC
     231            // Generates: request * new_req = alloc();
     232            sendBody->push_back( new DeclStmt(
     233                decl->location,
     234                new ObjectDecl(
     235                    decl->location,
     236                    "new_req",
     237                    new PointerType( new StructInstType( *requestDecl ) ),
     238                    new SingleInit( decl->location, new UntypedExpr( decl->location, new NameExpr( decl->location, "alloc" ), {} ) )
     239                )
     240            ));
     241            #else
    238242            // Generates: request new_req;
    239243            sendBody->push_back( new DeclStmt(
     
    245249                )
    246250            ));
     251            #endif
    247252           
    248253            // Function type is: Allocation (*)( derived_actor &, derived_msg & )
     
    263268            ));
    264269
    265             // Function type is: Allocation (*)( actor &, message & )
     270            // Function type is: Allocation (*)( actor &, messsage & )
    266271            FunctionType * genericReceive = new FunctionType();
    267272            genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
     
    269274            genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    270275
    271             // Generates: Allocation (*fn)( actor &, message & ) = (Allocation (*)( actor &, message & ))my_work_fn;
     276            // Generates: Allocation (*fn)( actor &, messsage & ) = (Allocation (*)( actor &, messsage & ))my_work_fn;
    272277            // More readable synonymous code:
    273278            //     typedef Allocation (*__receive_fn)(actor &, message &);
     
    285290            ));
    286291
     292            #if __ALLOC
     293            // Generates: (*new_req){ &receiver, &msg, fn };
     294            sendBody->push_back( new ExprStmt(
     295                decl->location,
     296                                new UntypedExpr (
     297                    decl->location,
     298                                        new NameExpr( decl->location, "?{}" ),
     299                                        {
     300                                                new UntypedExpr( decl->location, new NameExpr( decl->location, "*?" ), {  new NameExpr( decl->location, "new_req" ) } ),
     301                        new AddressExpr( new NameExpr( decl->location, "receiver" ) ),
     302                        new AddressExpr( new NameExpr( decl->location, "msg" ) ),
     303                        new NameExpr( decl->location, "fn" )
     304                                        }
     305                                )
     306                        ));
     307
     308            // Generates: send( receiver, *new_req );
     309            sendBody->push_back( new ExprStmt(
     310                decl->location,
     311                                new UntypedExpr (
     312                    decl->location,
     313                                        new NameExpr( decl->location, "send" ),
     314                                        {
     315                                                {
     316                            new NameExpr( decl->location, "receiver" ),
     317                            new UntypedExpr( decl->location, new NameExpr( decl->location, "*?" ), {  new NameExpr( decl->location, "new_req" ) } )
     318                        }
     319                                        }
     320                                )
     321                        ));
     322            #else
    287323            // Generates: new_req{ &receiver, &msg, fn };
    288324            sendBody->push_back( new ExprStmt(
     
    314350                                )
    315351                        ));
     352            #endif
    316353           
    317354            // Generates: return receiver;
     
    321358            FunctionDecl * sendOperatorFunction = new FunctionDecl(
    322359                decl->location,
    323                 "?<<?",
     360                "?|?",
    324361                {},                     // forall
    325362                {
     
    351388            // forward decls to resolve use before decl problem for '|' routines
    352389            forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
     390            // forwardDecls.push_back( ast::deepCopy( sendOperatorFunction ) );
    353391
    354392            sendOperatorFunction->stmts = sendBody;
     
    358396
    359397  public:
    360     GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     398    GenReceiveDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    361399        const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
    362400        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
     
    364402};
    365403
    366 
    367 // separate pass is needed since this pass resolves circular defn issues
    368 // generates the forward declarations of the send operator for actor routines
    369 struct FwdDeclOperator : public ast::WithDeclsToAdd<> {
     404struct GenFwdDecls : public ast::WithDeclsToAdd<> {
    370405    unordered_set<const StructDecl *> & actorStructDecls;
    371406    unordered_set<const StructDecl *>  & messageStructDecls;
    372407    FwdDeclTable & forwardDecls;
    373408
    374     // handles forward declaring the message operator
    375409    void postvisit( const StructDecl * decl ) {
    376410        list<FunctionDecl *> toAddAfter;
     
    399433
    400434  public:
    401     FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    402         FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
     435    GenFwdDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     436        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
     437        forwardDecls(forwardDecls) {}
    403438};
    404439
     
    426461    Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    427462        allocationDecl, actorDecl, msgDecl );
    428 
    429     // check that we have found all the decls we need from <actor.hfa>, if not no need to run the rest of this pass
    430     if ( !allocationDeclPtr || !requestDeclPtr || !actorDeclPtr || !msgDeclPtr )
    431         return;
    432 
     463       
    433464    // second pass locates all receive() routines that overload the generic receive fn
    434465    // it then generates the appropriate operator '|' send routines for the receive routines
    435     Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
     466    Pass<GenReceiveDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    436467        allocationDecl, actorDecl, msgDecl, forwardDecls );
    437468
    438469    // The third pass forward declares operator '|' send routines
    439     Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
     470    Pass<GenFwdDecls>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
    440471}
    441472
  • src/Concurrency/Actors.hpp

    rb110bcc r2ed94a9  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Actors.hpp -- Implement concurrency constructs from their keywords.
     7// Keywords.h -- Implement concurrency constructs from their keywords.
    88//
    99// Author           : Colby Parsons
  • src/Concurrency/KeywordsNew.cpp

    rb110bcc r2ed94a9  
    779779
    780780const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
    781         switch ( stmt->kind ) {
     781        switch ( stmt->type ) {
    782782        case ast::SuspendStmt::None:
    783783                // Use the context to determain the implicit target.
  • src/ControlStruct/ExceptDeclNew.cpp

    rb110bcc r2ed94a9  
    1515
    1616#include "ExceptDecl.h"
    17 
    18 #include <sstream>
    1917
    2018#include "AST/Decl.hpp"
  • src/ControlStruct/ExceptTranslateNew.cpp

    rb110bcc r2ed94a9  
    314314                nullptr,
    315315                ast::Storage::Classes{},
    316                 ast::Linkage::Cforall,
    317                 {},
    318                 { ast::Function::Inline }
     316                ast::Linkage::Cforall
    319317        );
    320318}
  • src/ControlStruct/MLEMutator.cc

    rb110bcc r2ed94a9  
    2525#include <memory>                          // for allocator_traits<>::value_...
    2626
    27 #include "Common/ToString.hpp"             // for toString
     27#include "Common/utility.h"                // for toString, operator+
    2828#include "ControlStruct/LabelGenerator.h"  // for LabelGenerator
    2929#include "MLEMutator.h"
  • src/GenPoly/Box.cc

    rb110bcc r2ed94a9  
    3131#include "Common/SemanticError.h"        // for SemanticError
    3232#include "Common/UniqueName.h"           // for UniqueName
    33 #include "Common/ToString.hpp"           // for toCString
     33#include "Common/utility.h"              // for toString
    3434#include "FindFunction.h"                // for findFunction, findAndReplace...
    3535#include "GenPoly/ErasableScopedMap.h"   // for ErasableScopedMap<>::const_i...
     
    8080                        CallAdapter();
    8181
    82                         void premutate( Declaration * declaration );
    8382                        void premutate( FunctionDecl * functionDecl );
    8483                        void premutate( TypeDecl * typeDecl );
     
    455454
    456455                CallAdapter::CallAdapter() : tempNamer( "_temp" ) {}
    457 
    458                 void CallAdapter::premutate( Declaration * ) {
    459                         // Prevent type declaration information from leaking out.
    460                         GuardScope( scopeTyVars );
    461                 }
    462456
    463457                void CallAdapter::premutate( FunctionDecl *functionDecl ) {
  • src/GenPoly/FindFunction.cc

    rb110bcc r2ed94a9  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct  7 17:05:20 2022
    13 // Update Count     : 7
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Fri Feb 05 12:22:20 2016
     13// Update Count     : 6
    1414//
    1515
     
    1818#include <utility>                      // for pair
    1919
    20 #include "AST/Pass.hpp"                 // for Pass
    21 #include "AST/Type.hpp"
    2220#include "Common/PassVisitor.h"         // for PassVisitor
    2321#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::iterator
     
    9189                handleForall( pointerType->get_forall() );
    9290        }
    93 
    94 namespace {
    95 
    96 struct FindFunctionCore :
    97                 public ast::WithGuards,
    98                 public ast::WithShortCircuiting,
    99                 public ast::WithVisitorRef<FindFunctionCore> {
    100         FindFunctionCore(
    101                 std::vector<ast::ptr<ast::FunctionType>> & functions,
    102                 const TypeVarMap & typeVars, FindFunctionPred predicate,
    103                 bool replaceMode );
    104 
    105         void previsit( ast::FunctionType const * type );
    106         ast::Type const * postvisit( ast::FunctionType const * type );
    107         void previsit( ast::PointerType const * type );
    108 private:
    109         void handleForall( const ast::FunctionType::ForallList & forall );
    110 
    111         std::vector<ast::ptr<ast::FunctionType>> &functions;
    112         TypeVarMap typeVars;
    113         FindFunctionPred predicate;
    114         bool replaceMode;
    115 };
    116 
    117 FindFunctionCore::FindFunctionCore(
    118                 std::vector<ast::ptr<ast::FunctionType>> & functions,
    119                 const TypeVarMap &typeVars, FindFunctionPred predicate,
    120                 bool replaceMode ) :
    121         functions( functions ), typeVars( typeVars ),
    122         predicate( predicate ), replaceMode( replaceMode ) {}
    123 
    124 void FindFunctionCore::handleForall( const ast::FunctionType::ForallList & forall ) {
    125         for ( const ast::ptr<ast::TypeInstType> & td : forall ) {
    126                 TypeVarMap::iterator var = typeVars.find( *td );
    127                 if ( var != typeVars.end() ) {
    128                         typeVars.erase( var->first );
    129                 } // if
    130         } // for
    131 }
    132 
    133 void FindFunctionCore::previsit( ast::FunctionType const * type ) {
    134         visit_children = false;
    135         GuardScope( typeVars );
    136         handleForall( type->forall );
    137         //ast::accept_all( type->returns, *visitor );
    138         // This might have to become ast::mutate_each with return.
    139         ast::accept_each( type->returns, *visitor );
    140 }
    141 
    142 ast::Type const * FindFunctionCore::postvisit( ast::FunctionType const * type ) {
    143         ast::Type const * ret = type;
    144         if ( predicate( type, typeVars ) ) {
    145                 functions.push_back( type );
    146                 if ( replaceMode ) {
    147                         // replace type parameters in function type with void*
    148                         ret = scrubTypeVars( ast::deepCopy( type ), typeVars );
    149                 } // if
    150         } // if
    151         return ret;
    152 }
    153 
    154 void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) {
    155         GuardScope( typeVars );
    156         //handleForall( type->forall );
    157 }
    158 
    159 } // namespace
    160 
    161 void findFunction( const ast::Type * type,
    162                 std::vector<ast::ptr<ast::FunctionType>> & functions,
    163                 const TypeVarMap & typeVars, FindFunctionPred predicate ) {
    164         ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false );
    165         type->accept( pass );
    166         //(void)type;
    167         //(void)functions;
    168         //(void)typeVars;
    169         //(void)predicate;
    170 }
    171 
    172 const ast::Type * findAndReplaceFunction( const ast::Type * type,
    173                 std::vector<ast::ptr<ast::FunctionType>> & functions,
    174                 const TypeVarMap & typeVars, FindFunctionPred predicate ) {
    175         ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true );
    176         return type->accept( pass );
    177         //(void)functions;
    178         //(void)typeVars;
    179         //(void)predicate;
    180         //return type;
    181 }
    182 
    18391} // namespace GenPoly
    18492
  • src/GenPoly/FindFunction.h

    rb110bcc r2ed94a9  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct  7 10:30:00 2022
    13 // Update Count     : 3
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jul 22 09:23:36 2017
     13// Update Count     : 2
    1414//
    1515
     
    3030        /// like `findFunction`, but also replaces the function type with void ()(void)
    3131        void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    32 
    33 typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & );
    34 
    35 /// Recursively walks `type`, placing all functions that match `predicate`
    36 /// under `typeVars` into `functions`.
    37 void findFunction( const ast::Type * type,
    38                 std::vector<ast::ptr<ast::FunctionType>> & functions,
    39                 const TypeVarMap & typeVars, FindFunctionPred predicate );
    40 /// Like findFunction, but also replaces the function type with `void ()(void)`.
    41 const ast::Type * findAndReplaceFunction( const ast::Type * type,
    42                 std::vector<ast::ptr<ast::FunctionType>> & functions,
    43                 const TypeVarMap & typeVars, FindFunctionPred predicate );
    44 
    4532} // namespace GenPoly
    4633
  • src/GenPoly/GenPoly.cc

    rb110bcc r2ed94a9  
    275275        }
    276276
    277 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) {
    278         if ( func->returns.empty() ) return nullptr;
    279 
    280         TypeVarMap forallTypes = { ast::TypeData() };
    281         makeTypeVarMap( func, forallTypes );
    282         return isDynType( func->returns.front(), forallTypes );
    283 }
    284 
    285277        bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {
    286278//              if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {
     
    327319                return 0;
    328320        }
    329 
    330 const ast::Type * isPolyPtr(
    331                 const ast::Type * type, const TypeVarMap & typeVars,
    332                 const ast::TypeSubstitution * typeSubs ) {
    333         type = replaceTypeInst( type, typeSubs );
    334 
    335         if ( auto * ptr = dynamic_cast<ast::PointerType const *>( type ) ) {
    336                 return isPolyType( ptr->base, typeVars, typeSubs );
    337         }
    338         return nullptr;
    339 }
    340321
    341322        Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {
     
    815796        }
    816797
    817 void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) {
    818         typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) );
    819 }
    820 
    821798void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
    822         typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) );
     799        typeVars.insert( *type, ast::TypeData( type->base ) );
    823800}
    824801
     
    845822}
    846823
    847 void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ) {
    848         for ( auto & typeDecl : decl->type_params ) {
    849                 addToTypeVarMap( typeDecl, typeVars );
    850         }
    851 }
    852 
    853824        void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
    854825                for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {
  • src/GenPoly/GenPoly.h

    rb110bcc r2ed94a9  
    111111        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );
    112112        void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars );
    113         void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars );
    114113
    115114        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    116115        void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
    117116        void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
    118         void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars );
    119117
    120118        /// Prints type variable map
  • src/GenPoly/Lvalue.cc

    rb110bcc r2ed94a9  
    1717#include <string>                        // for string
    1818
    19 #include "Common/ToString.hpp"           // for toCString
    2019#include "Common/UniqueName.h"
    2120#include "Common/PassVisitor.h"
  • src/GenPoly/LvalueNew.cpp

    rb110bcc r2ed94a9  
    2525#include "AST/Pass.hpp"
    2626#include "Common/SemanticError.h"      // for SemanticWarning
    27 #include "Common/ToString.hpp"         // for toCString
    2827#include "Common/UniqueName.h"         // for UniqueName
    2928#include "GenPoly/GenPoly.h"           // for genFunctionType
  • src/InitTweak/FixInit.cc

    rb110bcc r2ed94a9  
    3232#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    3333#include "Common/SemanticError.h"      // for SemanticError
    34 #include "Common/ToString.hpp"         // for toCString
    3534#include "Common/UniqueName.h"         // for UniqueName
     35#include "Common/utility.h"            // for CodeLocation, ValueGuard, toSt...
    3636#include "FixGlobalInit.h"             // for fixGlobalInit
    3737#include "GenInit.h"                   // for genCtorDtor
     
    12331233                }
    12341234
     1235                template< typename Visitor, typename... Params >
     1236                void error( Visitor & v, CodeLocation loc, const Params &... params ) {
     1237                        SemanticErrorException err( loc, toString( params... ) );
     1238                        v.errors.append( err );
     1239                }
     1240
    12351241                template< typename... Params >
    12361242                void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
    1237                         SemanticErrorException err( loc, toString( params... ) );
    1238                         errors.append( err );
     1243                        // toggle warnings vs. errors here.
     1244                        // warn( params... );
     1245                        error( *this, loc, params... );
    12391246                }
    12401247
  • src/InitTweak/FixInitNew.cpp

    rb110bcc r2ed94a9  
    1414#include <utility>                     // for pair
    1515
    16 #include "AST/DeclReplacer.hpp"
    17 #include "AST/Expr.hpp"
    1816#include "AST/Inspect.hpp"             // for getFunction, getPointerBase, g...
    19 #include "AST/Node.hpp"
    20 #include "AST/Pass.hpp"
    21 #include "AST/Print.hpp"
    22 #include "AST/SymbolTable.hpp"
    23 #include "AST/Type.hpp"
    2417#include "CodeGen/GenType.h"           // for genPrettyType
    2518#include "CodeGen/OperatorTable.h"
     19#include "Common/CodeLocationTools.hpp"
    2620#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    2721#include "Common/SemanticError.h"      // for SemanticError
    28 #include "Common/ToString.hpp"         // for toCString
    2922#include "Common/UniqueName.h"         // for UniqueName
     23#include "Common/utility.h"            // for CodeLocation, ValueGuard, toSt...
    3024#include "FixGlobalInit.h"             // for fixGlobalInit
    3125#include "GenInit.h"                   // for genCtorDtor
     
    3428#include "ResolvExpr/Unify.h"          // for typesCompatible
    3529#include "SymTab/Autogen.h"            // for genImplicitCall
    36 #include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3730#include "SymTab/Indexer.h"            // for Indexer
    3831#include "SymTab/Mangler.h"            // for Mangler
     
    5245#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    5346
     47#include "AST/Expr.hpp"
     48#include "AST/Node.hpp"
     49#include "AST/Pass.hpp"
     50#include "AST/Print.hpp"
     51#include "AST/SymbolTable.hpp"
     52#include "AST/Type.hpp"
     53#include "AST/DeclReplacer.hpp"
     54
    5455extern bool ctordtorp; // print all debug
    5556extern bool ctorp; // print ctor debug
     
    6263namespace InitTweak {
    6364namespace {
    64 
    65         // Shallow copy the pointer list for return.
    66         std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) {
    67                 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
    68                         return inst->base->params;
    69                 }
    70                 if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
    71                         return inst->base->params;
    72                 }
    73                 return {};
    74         }
    75 
    76         /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
    77         ast::FunctionDecl * genDefaultFunc(
    78                         const CodeLocation loc,
    79                         const std::string fname,
    80                         const ast::Type * paramType,
    81                         bool maybePolymorphic = true) {
    82                 std::vector<ast::ptr<ast::TypeDecl>> typeParams;
    83                 if ( maybePolymorphic ) typeParams = getGenericParams( paramType );
    84                 auto dstParam = new ast::ObjectDecl( loc,
    85                         "_dst",
    86                         new ast::ReferenceType( paramType ),
    87                         nullptr,
    88                         {},
    89                         ast::Linkage::Cforall
    90                 );
    91                 return new ast::FunctionDecl( loc,
    92                         fname,
    93                         std::move(typeParams),
    94                         {dstParam},
    95                         {},
    96                         new ast::CompoundStmt(loc),
    97                         {},
    98                         ast::Linkage::Cforall
    99                 );
    100         }
    101 
    10265        struct SelfAssignChecker {
    10366                void previsit( const ast::ApplicationExpr * appExpr );
     
    144107        private:
    145108                /// hack to implement WithTypeSubstitution while conforming to mutation safety.
    146                 ast::TypeSubstitution * env         = nullptr;
    147                 bool                    envModified = false;
     109                ast::TypeSubstitution * env;
     110                bool                    envModified;
    148111        };
    149112
     
    158121                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    159122
    160         protected:
     123          protected:
    161124                ObjectSet curVars;
    162125        };
     
    239202
    240203                SemanticErrorException errors;
    241         private:
     204          private:
    242205                template< typename... Params >
    243206                void emit( CodeLocation, const Params &... params );
     
    325288                static UniqueName dtorNamer( "__cleanup_dtor" );
    326289                std::string name = dtorNamer.newName();
    327                 ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
     290                ast::FunctionDecl * dtorFunc = SymTab::genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
    328291                stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
    329292
     
    559522        {
    560523                static UniqueName tempNamer("_tmp_cp");
     524                assert( env );
    561525                const CodeLocation loc = impCpCtorExpr->location;
    562526                // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )
     
    570534
    571535                // xxx - this originally mutates arg->result in place. is it correct?
    572                 assert( env );
    573536                result = env->applyFree( result.get() ).node;
    574537                auto mutResult = result.get_and_mutate();
     
    11171080        void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
    11181081                switch( stmt->kind ) {
    1119                 case ast::BranchStmt::Continue:
    1120                 case ast::BranchStmt::Break:
     1082                  case ast::BranchStmt::Continue:
     1083                  case ast::BranchStmt::Break:
    11211084                        // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
    11221085                        // always be empty), but it serves as a small sanity check.
    1123                 case ast::BranchStmt::Goto:
     1086                  case ast::BranchStmt::Goto:
    11241087                        handleGoto( stmt );
    11251088                        break;
    1126                 default:
     1089                  default:
    11271090                        assert( false );
    11281091                } // switch
     
    13401303        }
    13411304
     1305        template< typename Visitor, typename... Params >
     1306        void error( Visitor & v, CodeLocation loc, const Params &... params ) {
     1307                SemanticErrorException err( loc, toString( params... ) );
     1308                v.errors.append( err );
     1309        }
     1310
    13421311        template< typename... Params >
    13431312        void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
    1344                 SemanticErrorException err( loc, toString( params... ) );
    1345                 errors.append( err );
     1313                // toggle warnings vs. errors here.
     1314                // warn( params... );
     1315                error( *this, loc, params... );
    13461316        }
    13471317
     
    13491319                // xxx - functions returning ast::ptr seems wrong...
    13501320                auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
    1351                 return res.release();
     1321                // Fix CodeLocation (at least until resolver is fixed).
     1322                auto fix = localFillCodeLocations( untypedExpr->location, res.release() );
     1323                return strict_dynamic_cast<const ast::Expr *>( fix );
    13521324        }
    13531325
  • src/InitTweak/GenInit.cc

    rb110bcc r2ed94a9  
    3131#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
    3232#include "Common/SemanticError.h"      // for SemanticError
    33 #include "Common/ToString.hpp"         // for toCString
    3433#include "Common/UniqueName.h"         // for UniqueName
    3534#include "Common/utility.h"            // for ValueGuard, maybeClone
     
    3938#include "ResolvExpr/Resolver.h"
    4039#include "SymTab/Autogen.h"            // for genImplicitCall
    41 #include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4240#include "SymTab/Mangler.h"            // for Mangler
    4341#include "SynTree/LinkageSpec.h"       // for isOverridable, C
  • src/Parser/DeclarationNode.cc

    rb110bcc r2ed94a9  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 12:34:05 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr 20 11:46:00 2023
    13 // Update Count     : 1393
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Aug  8 17:07:00 2022
     13// Update Count     : 1185
    1414//
    15 
    16 #include "DeclarationNode.h"
    1715
    1816#include <cassert>                 // for assert, assertf, strict_dynamic_cast
     
    2321#include <string>                  // for string, operator+, allocator, char...
    2422
    25 #include "AST/Attribute.hpp"       // for Attribute
    26 #include "AST/Copy.hpp"            // for shallowCopy
    27 #include "AST/Decl.hpp"            // for Decl
    28 #include "AST/Expr.hpp"            // for Expr
    29 #include "AST/Print.hpp"           // for print
    30 #include "AST/Stmt.hpp"            // for AsmStmt, DirectiveStmt
    31 #include "AST/StorageClasses.hpp"  // for Storage::Class
    32 #include "AST/Type.hpp"            // for Type
    33 #include "Common/CodeLocation.h"   // for CodeLocation
    34 #include "Common/Iterate.hpp"      // for reverseIterate
    3523#include "Common/SemanticError.h"  // for SemanticError
    3624#include "Common/UniqueName.h"     // for UniqueName
    37 #include "Common/utility.h"        // for maybeClone
    38 #include "Parser/ExpressionNode.h" // for ExpressionNode
    39 #include "Parser/InitializerNode.h"// for InitializerNode
    40 #include "Parser/StatementNode.h"  // for StatementNode
     25#include "Common/utility.h"        // for maybeClone, maybeBuild, CodeLocation
     26#include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
     27#include "SynTree/LinkageSpec.h"   // for Spec, linkageName, Cforall
     28#include "SynTree/Attribute.h"     // for Attribute
     29#include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, InlineMemberDecl, Declaration
     30#include "SynTree/Expression.h"    // for Expression, ConstantExpr
     31#include "SynTree/Statement.h"     // for AsmStmt
     32#include "SynTree/Type.h"          // for Type, Type::StorageClasses, Type::...
    4133#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
    4234#include "TypedefTable.h"          // for TypedefTable
     
    4941
    5042// These must harmonize with the corresponding DeclarationNode enumerations.
    51 const char * DeclarationNode::basicTypeNames[] = {
    52         "void", "_Bool", "char", "int", "int128",
    53         "float", "double", "long double", "float80", "float128",
    54         "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames"
    55 };
    56 const char * DeclarationNode::complexTypeNames[] = {
    57         "_Complex", "NoComplexTypeNames", "_Imaginary"
    58 }; // Imaginary unsupported => parse, but make invisible and print error message
    59 const char * DeclarationNode::signednessNames[] = {
    60         "signed", "unsigned", "NoSignednessNames"
    61 };
    62 const char * DeclarationNode::lengthNames[] = {
    63         "short", "long", "long long", "NoLengthNames"
    64 };
    65 const char * DeclarationNode::builtinTypeNames[] = {
    66         "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames"
    67 };
     43const char * DeclarationNode::basicTypeNames[] = { "void", "_Bool", "char", "int", "int128",
     44                                                                                                   "float", "double", "long double", "float80", "float128",
     45                                                                                                   "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames" };
     46const char * DeclarationNode::complexTypeNames[] = { "_Complex", "NoComplexTypeNames", "_Imaginary" }; // Imaginary unsupported => parse, but make invisible and print error message
     47const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" };
     48const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" };
     49const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" };
    6850
    6951UniqueName DeclarationNode::anonymous( "__anonymous" );
    7052
    71 extern ast::Linkage::Spec linkage;                                              // defined in parser.yy
     53extern LinkageSpec::Spec linkage;                                               // defined in parser.yy
    7254
    7355DeclarationNode::DeclarationNode() :
     
    7557
    7658//      variable.name = nullptr;
    77         variable.tyClass = ast::TypeDecl::NUMBER_OF_KINDS;
     59        variable.tyClass = TypeDecl::NUMBER_OF_KINDS;
    7860        variable.assertions = nullptr;
    7961        variable.initializer = nullptr;
    8062
     63//      attr.name = nullptr;
     64        attr.expr = nullptr;
     65        attr.type = nullptr;
     66
    8167        assert.condition = nullptr;
    8268        assert.message = nullptr;
     
    8470
    8571DeclarationNode::~DeclarationNode() {
     72//      delete attr.name;
     73        delete attr.expr;
     74        delete attr.type;
     75
    8676//      delete variable.name;
    8777        delete variable.assertions;
    8878        delete variable.initializer;
    8979
    90 //      delete type;
     80//      delete type;
    9181        delete bitfieldWidth;
    9282
     
    113103        newnode->hasEllipsis = hasEllipsis;
    114104        newnode->linkage = linkage;
    115         newnode->asmName = maybeCopy( asmName );
    116         newnode->attributes = attributes;
     105        newnode->asmName = maybeClone( asmName );
     106        cloneAll( attributes, newnode->attributes );
    117107        newnode->initializer = maybeClone( initializer );
    118108        newnode->extension = extension;
     
    125115        newnode->variable.initializer = maybeClone( variable.initializer );
    126116
     117//      newnode->attr.name = attr.name ? new string( *attr.name ) : nullptr;
     118        newnode->attr.expr = maybeClone( attr.expr );
     119        newnode->attr.type = maybeClone( attr.type );
     120
    127121        newnode->assert.condition = maybeClone( assert.condition );
    128         newnode->assert.message = maybeCopy( assert.message );
     122        newnode->assert.message = maybeClone( assert.message );
    129123        return newnode;
    130124} // DeclarationNode::clone
     
    136130        } // if
    137131
    138         if ( linkage != ast::Linkage::Cforall ) {
    139                 os << ast::Linkage::name( linkage ) << " ";
    140         } // if
    141 
    142         ast::print( os, storageClasses );
    143         ast::print( os, funcSpecs );
     132        if ( linkage != LinkageSpec::Cforall ) {
     133                os << LinkageSpec::name( linkage ) << " ";
     134        } // if
     135
     136        storageClasses.print( os );
     137        funcSpecs.print( os );
    144138
    145139        if ( type ) {
     
    160154        } // if
    161155
    162         if ( ! attributes.empty() ) {
    163                 os << string( indent + 2, ' ' ) << "with attributes " << endl;
    164                 for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( attributes ) ) {
    165                         os << string( indent + 4, ' ' ) << attr->name.c_str() << endl;
    166                 } // for
    167         } // if
     156        for ( Attribute * attr: reverseIterate( attributes ) ) {
     157                os << string( indent + 2, ' ' ) << "attr " << attr->name.c_str();
     158        } // for
    168159
    169160        os << endl;
     
    177168}
    178169
    179 DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) {
     170DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) {
    180171        DeclarationNode * newnode = new DeclarationNode;
    181172        newnode->storageClasses = sc;
     
    183174} // DeclarationNode::newStorageClass
    184175
    185 DeclarationNode * DeclarationNode::newFuncSpecifier( ast::Function::Specs fs ) {
     176DeclarationNode * DeclarationNode::newFuncSpecifier( Type::FuncSpecifiers fs ) {
    186177        DeclarationNode * newnode = new DeclarationNode;
    187178        newnode->funcSpecs = fs;
     
    189180} // DeclarationNode::newFuncSpecifier
    190181
    191 DeclarationNode * DeclarationNode::newTypeQualifier( ast::CV::Qualifiers tq ) {
     182DeclarationNode * DeclarationNode::newTypeQualifier( Type::Qualifiers tq ) {
    192183        DeclarationNode * newnode = new DeclarationNode;
    193184        newnode->type = new TypeData();
     
    249240}
    250241
    251 DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
     242DeclarationNode * DeclarationNode::newAggregate( AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
    252243        DeclarationNode * newnode = new DeclarationNode;
    253244        newnode->type = new TypeData( TypeData::Aggregate );
    254245        newnode->type->aggregate.kind = kind;
    255         newnode->type->aggregate.anon = name == nullptr;
    256         newnode->type->aggregate.name = newnode->type->aggregate.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
     246        newnode->type->aggregate.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
    257247        newnode->type->aggregate.actuals = actuals;
    258248        newnode->type->aggregate.fields = fields;
     
    260250        newnode->type->aggregate.tagged = false;
    261251        newnode->type->aggregate.parent = nullptr;
     252        newnode->type->aggregate.anon = name == nullptr;
    262253        return newnode;
    263254} // DeclarationNode::newAggregate
     
    266257        DeclarationNode * newnode = new DeclarationNode;
    267258        newnode->type = new TypeData( TypeData::Enum );
    268         newnode->type->enumeration.anon = name == nullptr;
    269         newnode->type->enumeration.name = newnode->type->enumeration.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
     259        newnode->type->enumeration.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
    270260        newnode->type->enumeration.constants = constants;
    271261        newnode->type->enumeration.body = body;
     262        newnode->type->enumeration.anon = name == nullptr;
    272263        newnode->type->enumeration.typed = typed;
    273264        newnode->type->enumeration.hiding = hiding;
    274         if ( base && base->type )  {
     265        if ( base && base->type)  {
    275266                newnode->type->base = base->type;
    276267        } // if
     
    278269        return newnode;
    279270} // DeclarationNode::newEnum
     271
     272
    280273
    281274DeclarationNode * DeclarationNode::newName( const string * name ) {
     
    330323} // DeclarationNode::newFromTypeGen
    331324
    332 DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) {
     325DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {
    333326        DeclarationNode * newnode = newName( name );
    334327        newnode->type = nullptr;
     
    342335        newnode->type = new TypeData( TypeData::Aggregate );
    343336        newnode->type->aggregate.name = name;
    344         newnode->type->aggregate.kind = ast::AggregateDecl::Trait;
     337        newnode->type->aggregate.kind = AggregateDecl::Trait;
    345338        newnode->type->aggregate.params = params;
    346339        newnode->type->aggregate.fields = asserts;
     
    352345        newnode->type = new TypeData( TypeData::AggregateInst );
    353346        newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
    354         newnode->type->aggInst.aggregate->aggregate.kind = ast::AggregateDecl::Trait;
     347        newnode->type->aggInst.aggregate->aggregate.kind = AggregateDecl::Trait;
    355348        newnode->type->aggInst.aggregate->aggregate.name = name;
    356349        newnode->type->aggInst.params = params;
     
    387380        newnode->type->array.dimension = size;
    388381        newnode->type->array.isStatic = isStatic;
    389         if ( newnode->type->array.dimension == nullptr || newnode->type->array.dimension->isExpressionType<ast::ConstantExpr *>() ) {
     382        if ( newnode->type->array.dimension == nullptr || newnode->type->array.dimension->isExpressionType<ConstantExpr * >() ) {
    390383                newnode->type->array.isVarLen = false;
    391384        } else {
     
    457450        DeclarationNode * newnode = new DeclarationNode;
    458451        newnode->type = nullptr;
    459         std::vector<ast::ptr<ast::Expr>> exprs;
     452        std::list< Expression * > exprs;
    460453        buildList( expr, exprs );
    461         newnode->attributes.push_back(
    462                 new ast::Attribute( *name, std::move( exprs ) ) );
     454        newnode->attributes.push_back( new Attribute( *name, exprs ) );
    463455        delete name;
    464456        return newnode;
     
    477469}
    478470
    479 DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, ast::Expr * message ) {
     471DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, Expression * message ) {
    480472        DeclarationNode * newnode = new DeclarationNode;
    481473        newnode->assert.condition = condition;
     
    484476}
    485477
    486 static void appendError( string & dst, const string & src ) {
     478
     479void appendError( string & dst, const string & src ) {
    487480        if ( src.empty() ) return;
    488481        if ( dst.empty() ) { dst = src; return; }
     
    491484
    492485void DeclarationNode::checkQualifiers( const TypeData * src, const TypeData * dst ) {
    493         const ast::CV::Qualifiers qsrc = src->qualifiers, qdst = dst->qualifiers; // optimization
    494         const ast::CV::Qualifiers duplicates = qsrc & qdst;
    495 
    496         if ( duplicates.any() ) {
    497                 std::stringstream str;
    498                 str << "duplicate ";
    499                 ast::print( str, duplicates );
    500                 str << "qualifier(s)";
    501                 appendError( error, str.str() );
     486        const Type::Qualifiers qsrc = src->qualifiers, qdst = dst->qualifiers; // optimization
     487
     488        if ( (qsrc & qdst).any() ) {                                            // duplicates ?
     489                for ( unsigned int i = 0; i < Type::NumTypeQualifier; i += 1 ) { // find duplicates
     490                        if ( qsrc[i] && qdst[i] ) {
     491                                appendError( error, string( "duplicate " ) + Type::QualifiersNames[i] );
     492                        } // if
     493                } // for
    502494        } // for
    503495} // DeclarationNode::checkQualifiers
    504496
    505497void DeclarationNode::checkSpecifiers( DeclarationNode * src ) {
    506         ast::Function::Specs fsDups = funcSpecs & src->funcSpecs;
    507         if ( fsDups.any() ) {
    508                 std::stringstream str;
    509                 str << "duplicate ";
    510                 ast::print( str, fsDups );
    511                 str << "function specifier(s)";
    512                 appendError( error, str.str() );
    513         } // if
    514 
    515         // Skip if everything is unset.
    516         if ( storageClasses.any() && src->storageClasses.any() ) {
    517                 ast::Storage::Classes dups = storageClasses & src->storageClasses;
    518                 // Check for duplicates.
    519                 if ( dups.any() ) {
    520                         std::stringstream str;
    521                         str << "duplicate ";
    522                         ast::print( str, dups );
    523                         str << "storage class(es)";
    524                         appendError( error, str.str() );
    525                 // Check for conflicts.
    526                 } else if ( !src->storageClasses.is_threadlocal_any() ) {
    527                         std::stringstream str;
    528                         str << "conflicting ";
    529                         ast::print( str, ast::Storage::Classes( 1 << storageClasses.ffs() ) );
    530                         str << "& ";
    531                         ast::print( str, ast::Storage::Classes( 1 << src->storageClasses.ffs() ) );
    532                         str << "storage classes";
    533                         appendError( error, str.str() );
    534                         // FIX to preserve invariant of one basic storage specifier
    535                         src->storageClasses.reset();
    536                 }
     498        if ( (funcSpecs & src->funcSpecs).any() ) {                     // duplicates ?
     499                for ( unsigned int i = 0; i < Type::NumFuncSpecifier; i += 1 ) { // find duplicates
     500                        if ( funcSpecs[i] && src->funcSpecs[i] ) {
     501                                appendError( error, string( "duplicate " ) + Type::FuncSpecifiersNames[i] );
     502                        } // if
     503                } // for
     504        } // if
     505
     506        if ( storageClasses.any() && src->storageClasses.any() ) { // any reason to check ?
     507                if ( (storageClasses & src->storageClasses ).any() ) { // duplicates ?
     508                        for ( unsigned int i = 0; i < Type::NumStorageClass; i += 1 ) { // find duplicates
     509                                if ( storageClasses[i] && src->storageClasses[i] ) {
     510                                        appendError( error, string( "duplicate " ) + Type::StorageClassesNames[i] );
     511                                } // if
     512                        } // for
     513                        // src is the new item being added and has a single bit
     514                } else if ( ! src->storageClasses.is_threadlocal_any() ) { // conflict ?
     515                        appendError( error, string( "conflicting " ) + Type::StorageClassesNames[storageClasses.ffs()] +
     516                                                 " & " + Type::StorageClassesNames[src->storageClasses.ffs()] );
     517                        src->storageClasses.reset();                            // FIX to preserve invariant of one basic storage specifier
     518                } // if
    537519        } // if
    538520
     
    544526        storageClasses |= q->storageClasses;
    545527
    546         std::vector<ast::ptr<ast::Attribute>> tmp;
    547         tmp.reserve( q->attributes.size() );
    548         for ( auto const & attr : q->attributes ) {
    549                 tmp.emplace_back( ast::shallowCopy( attr.get() ) );
    550         }
    551         spliceBegin( attributes, tmp );
    552 
     528        for ( Attribute * attr: reverseIterate( q->attributes ) ) {
     529                attributes.push_front( attr->clone() );
     530        } // for
    553531        return this;
    554532} // DeclarationNode::copySpecifiers
     
    598576
    599577        checkQualifiers( type, q->type );
    600         if ( (builtin == Zero || builtin == One) && q->type->qualifiers.any() && error.length() == 0 ) {
    601                 SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, builtinTypeNames[builtin] );
     578        if ( (builtin == Zero || builtin == One) && q->type->qualifiers.val != 0 && error.length() == 0 ) {
     579                SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, Type::QualifiersNames[ilog2( q->type->qualifiers.val )], builtinTypeNames[builtin] );
    602580        } // if
    603581        addQualifiersToType( q->type, type );
     
    620598        } else {
    621599                switch ( dst->kind ) {
    622                 case TypeData::Unknown:
     600                  case TypeData::Unknown:
    623601                        src->qualifiers |= dst->qualifiers;
    624602                        dst = src;
    625603                        src = nullptr;
    626604                        break;
    627                 case TypeData::Basic:
     605                  case TypeData::Basic:
    628606                        dst->qualifiers |= src->qualifiers;
    629607                        if ( src->kind != TypeData::Unknown ) {
     
    653631                        } // if
    654632                        break;
    655                 default:
     633                  default:
    656634                        switch ( src->kind ) {
    657                         case TypeData::Aggregate:
    658                         case TypeData::Enum:
     635                          case TypeData::Aggregate:
     636                          case TypeData::Enum:
    659637                                dst->base = new TypeData( TypeData::AggregateInst );
    660638                                dst->base->aggInst.aggregate = src;
     
    665643                                src = nullptr;
    666644                                break;
    667                         default:
     645                          default:
    668646                                if ( dst->forall ) {
    669647                                        dst->forall->appendList( src->forall );
     
    736714
    737715DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) {
    738         if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
    739                 if ( variable.assertions ) {
    740                         variable.assertions->appendList( assertions );
    741                 } else {
    742                         variable.assertions = assertions;
    743                 } // if
    744                 return this;
     716        if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
     717                if ( variable.assertions ) {
     718                        variable.assertions->appendList( assertions );
     719                } else {
     720                        variable.assertions = assertions;
     721                } // if
     722                return this;
    745723        } // if
    746724
    747725        assert( type );
    748726        switch ( type->kind ) {
    749         case TypeData::Symbolic:
     727          case TypeData::Symbolic:
    750728                if ( type->symbolic.assertions ) {
    751729                        type->symbolic.assertions->appendList( assertions );
     
    754732                } // if
    755733                break;
    756         default:
     734          default:
    757735                assert( false );
    758736        } // switch
     
    818796DeclarationNode * DeclarationNode::copyAttribute( DeclarationNode * a ) {
    819797        if ( a ) {
    820                 spliceBegin( attributes, a->attributes );
     798                for ( Attribute *attr: reverseIterate( a->attributes ) ) {
     799                        attributes.push_front( attr );
     800                } // for
    821801                a->attributes.clear();
    822802        } // if
     
    851831                if ( type ) {
    852832                        switch ( type->kind ) {
    853                         case TypeData::Aggregate:
    854                         case TypeData::Enum:
     833                          case TypeData::Aggregate:
     834                          case TypeData::Enum:
    855835                                p->type->base = new TypeData( TypeData::AggregateInst );
    856836                                p->type->base->aggInst.aggregate = type;
     
    861841                                break;
    862842
    863                         default:
     843                          default:
    864844                                p->type->base = type;
    865845                        } // switch
     
    883863
    884864DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
    885         if ( ! a ) return this;
     865  if ( ! a ) return this;
    886866        assert( a->type->kind == TypeData::Array );
    887867        TypeData * lastArray = findLast( a->type );
    888868        if ( type ) {
    889869                switch ( type->kind ) {
    890                 case TypeData::Aggregate:
    891                 case TypeData::Enum:
     870                  case TypeData::Aggregate:
     871                  case TypeData::Enum:
    892872                        lastArray->base = new TypeData( TypeData::AggregateInst );
    893873                        lastArray->base->aggInst.aggregate = type;
     
    897877                        lastArray->base->qualifiers |= type->qualifiers;
    898878                        break;
    899                 default:
     879                  default:
    900880                        lastArray->base = type;
    901881                } // switch
     
    939919
    940920DeclarationNode * DeclarationNode::addTypeInitializer( DeclarationNode * init ) {
    941         assertf( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
     921        assertf( variable.tyClass != TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
    942922        variable.initializer = init;
    943923        return this;
     
    1003983}
    1004984
    1005 // If a typedef wraps an anonymous declaration, name the inner declaration
    1006 // so it has a consistent name across translation units.
    1007 static void nameTypedefedDecl(
    1008                 DeclarationNode * innerDecl,
    1009                 const DeclarationNode * outerDecl ) {
    1010         TypeData * outer = outerDecl->type;
    1011         assert( outer );
    1012         // First make sure this is a typedef:
    1013         if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) {
    1014                 return;
    1015         }
    1016         TypeData * inner = innerDecl->type;
    1017         assert( inner );
    1018         // Always clear any CVs associated with the aggregate:
    1019         inner->qualifiers.reset();
    1020         // Handle anonymous aggregates: typedef struct { int i; } foo
    1021         if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) {
    1022                 delete inner->aggregate.name;
    1023                 inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
    1024                 inner->aggregate.anon = false;
    1025                 assert( outer->base );
    1026                 delete outer->base->aggInst.aggregate->aggregate.name;
    1027                 outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
    1028                 outer->base->aggInst.aggregate->aggregate.anon = false;
    1029                 outer->base->aggInst.aggregate->qualifiers.reset();
    1030         // Handle anonymous enumeration: typedef enum { A, B, C } foo
    1031         } else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) {
    1032                 delete inner->enumeration.name;
    1033                 inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
    1034                 inner->enumeration.anon = false;
    1035                 assert( outer->base );
    1036                 delete outer->base->aggInst.aggregate->enumeration.name;
    1037                 outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
    1038                 outer->base->aggInst.aggregate->enumeration.anon = false;
    1039                 // No qualifiers.reset() here.
    1040         }
    1041 }
    1042 
    1043 // This code handles a special issue with the attribute transparent_union.
    1044 //
    1045 //    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
    1046 //
    1047 // Here the attribute aligned goes with the typedef_name, so variables declared of this type are
    1048 // aligned.  However, the attribute transparent_union must be moved from the typedef_name to
    1049 // alias union U.  Currently, this is the only know attribute that must be moved from typedef to
    1050 // alias.
    1051 static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) {
    1052         if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
    1053                 // Is the typedef alias a union aggregate?
    1054                 if ( nullptr == unionDecl ) return;
    1055 
    1056                 // If typedef is an alias for a union, then its alias type was hoisted above and remembered.
    1057                 if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
    1058                         auto instType = ast::mutate( unionInstType );
    1059                         // Remove all transparent_union attributes from typedef and move to alias union.
    1060                         for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) {
    1061                                 assert( *attr );
    1062                                 if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
    1063                                         unionDecl->attributes.emplace_back( attr->release() );
    1064                                         attr = instType->attributes.erase( attr );
    1065                                 } else {
    1066                                         attr++;
    1067                                 }
    1068                         }
    1069                         typedefDecl->base = instType;
    1070                 }
    1071         }
    1072 }
    1073 
    1074 // Get the non-anonymous name of the instance type of the declaration,
    1075 // if one exists.
    1076 static const std::string * getInstTypeOfName( ast::Decl * decl ) {
    1077         if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    1078                 if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
    1079                         if ( aggr->name.find("anonymous") == std::string::npos ) {
    1080                                 return &aggr->name;
    1081                         }
    1082                 }
    1083         }
    1084         return nullptr;
    1085 }
    1086 
    1087 void buildList( DeclarationNode * firstNode,
    1088                 std::vector<ast::ptr<ast::Decl>> & outputList ) {
     985void buildList( const DeclarationNode * firstNode, std::list< Declaration * > & outputList ) {
    1089986        SemanticErrorException errors;
    1090         std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
    1091 
    1092         for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
     987        std::back_insert_iterator< std::list< Declaration * > > out( outputList );
     988
     989        for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
    1093990                try {
    1094                         bool extracted_named = false;
    1095                         ast::UnionDecl * unionDecl = nullptr;
    1096 
     991                        bool extracted = false;
     992                        bool anon = false;
    1097993                        if ( DeclarationNode * extr = cur->extractAggregate() ) {
    1098                                 assert( cur->type );
    1099                                 nameTypedefedDecl( extr, cur );
    1100 
    1101                                 if ( ast::Decl * decl = extr->build() ) {
    1102                                         // Remember the declaration if it is a union aggregate ?
    1103                                         unionDecl = dynamic_cast<ast::UnionDecl *>( decl );
    1104 
    1105                                         *out++ = decl;
     994                                // handle the case where a structure declaration is contained within an object or type declaration
     995                                Declaration * decl = extr->build();
     996                                if ( decl ) {
     997                                        // hoist the structure declaration
     998                                        decl->location = cur->location;
     999                                        * out++ = decl;
    11061000
    11071001                                        // need to remember the cases where a declaration contains an anonymous aggregate definition
     1002                                        extracted = true;
    11081003                                        assert( extr->type );
    11091004                                        if ( extr->type->kind == TypeData::Aggregate ) {
    1110                                                 // typedef struct { int A } B is the only case?
    1111                                                 extracted_named = !extr->type->aggregate.anon;
     1005                                                anon = extr->type->aggregate.anon;
    11121006                                        } else if ( extr->type->kind == TypeData::Enum ) {
    1113                                                 // typedef enum { A } B is the only case?
    1114                                                 extracted_named = !extr->type->enumeration.anon;
    1115                                         } else {
    1116                                                 extracted_named = true;
     1007                                                // xxx - is it useful to have an implicit anonymous enum member?
     1008                                                anon = extr->type->enumeration.anon;
    11171009                                        }
    11181010                                } // if
     
    11201012                        } // if
    11211013
    1122                         if ( ast::Decl * decl = cur->build() ) {
    1123                                 moveUnionAttribute( decl, unionDecl );
    1124 
    1125                                 if ( "" == decl->name && !cur->get_inLine() ) {
    1126                                         // Don't include anonymous declaration for named aggregates,
    1127                                         // but do include them for anonymous aggregates, e.g.:
    1128                                         // struct S {
    1129                                         //   struct T { int x; }; // no anonymous member
    1130                                         //   struct { int y; };   // anonymous member
    1131                                         //   struct T;            // anonymous member
    1132                                         // };
    1133                                         if ( extracted_named ) {
    1134                                                 continue;
    1135                                         }
    1136 
    1137                                         if ( auto name = getInstTypeOfName( decl ) ) {
    1138                                                 // Temporary: warn about anonymous member declarations of named types, since
    1139                                                 // this conflicts with the syntax for the forward declaration of an anonymous type.
    1140                                                 SemanticWarning( cur->location, Warning::AggrForwardDecl, name->c_str() );
    1141                                         }
     1014                        Declaration * decl = cur->build();
     1015                        if ( decl ) {
     1016                                // don't include anonymous declaration for named aggregates, but do include them for anonymous aggregates, e.g.:
     1017                                // struct S {
     1018                                //   struct T { int x; }; // no anonymous member
     1019                                //   struct { int y; };   // anonymous member
     1020                                //   struct T;            // anonymous member
     1021                                // };
     1022                                if ( ! (extracted && decl->name == "" && ! anon && ! cur->get_inLine()) ) {
     1023                                        if ( decl->name == "" ) {
     1024                                                if ( DeclarationWithType * dwt = dynamic_cast<DeclarationWithType *>( decl ) ) {
     1025                                                        if ( ReferenceToType * aggr = dynamic_cast<ReferenceToType *>( dwt->get_type() ) ) {
     1026                                                                if ( aggr->name.find("anonymous") == std::string::npos ) {
     1027                                                                        if ( ! cur->get_inLine() ) {
     1028                                                                                // temporary: warn about anonymous member declarations of named types, since
     1029                                                                                // this conflicts with the syntax for the forward declaration of an anonymous type
     1030                                                                                SemanticWarning( cur->location, Warning::AggrForwardDecl, aggr->name.c_str() );
     1031                                                                        } // if
     1032                                                                } // if
     1033                                                        } // if
     1034                                                } // if
     1035                                        } // if
     1036                                        decl->location = cur->location;
     1037                                        *out++ = decl;
    11421038                                } // if
    1143                                 *out++ = decl;
    11441039                        } // if
    1145                 } catch ( SemanticErrorException & e ) {
     1040                } catch( SemanticErrorException & e ) {
    11461041                        errors.append( e );
    11471042                } // try
     
    11541049
    11551050// currently only builds assertions, function parameters, and return values
    1156 void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
     1051void buildList( const DeclarationNode * firstNode, std::list< DeclarationWithType * > & outputList ) {
    11571052        SemanticErrorException errors;
    1158         std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
    1159 
    1160         for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
     1053        std::back_insert_iterator< std::list< DeclarationWithType * > > out( outputList );
     1054
     1055        for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
    11611056                try {
    1162                         ast::Decl * decl = cur->build();
    1163                         assertf( decl, "buildList: build for ast::DeclWithType." );
    1164                         if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
     1057                        Declaration * decl = cur->build();
     1058                        assert( decl );
     1059                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
    11651060                                dwt->location = cur->location;
    11661061                                *out++ = dwt;
    1167                         } else if ( ast::StructDecl * agg = dynamic_cast<ast::StructDecl *>( decl ) ) {
     1062                        } else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) {
    11681063                                // e.g., int foo(struct S) {}
    1169                                 auto inst = new ast::StructInstType( agg->name );
    1170                                 auto obj = new ast::ObjectDecl( cur->location, "", inst );
    1171                                 obj->linkage = linkage;
     1064                                StructInstType * inst = new StructInstType( Type::Qualifiers(), agg->name );
     1065                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
     1066                                obj->location = cur->location;
    11721067                                *out++ = obj;
    11731068                                delete agg;
    1174                         } else if ( ast::UnionDecl * agg = dynamic_cast<ast::UnionDecl *>( decl ) ) {
     1069                        } else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) {
    11751070                                // e.g., int foo(union U) {}
    1176                                 auto inst = new ast::UnionInstType( agg->name );
    1177                                 auto obj = new ast::ObjectDecl( cur->location,
    1178                                         "", inst, nullptr, ast::Storage::Classes(),
    1179                                         linkage );
     1071                                UnionInstType * inst = new UnionInstType( Type::Qualifiers(), agg->name );
     1072                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
     1073                                obj->location = cur->location;
    11801074                                *out++ = obj;
    1181                         } else if ( ast::EnumDecl * agg = dynamic_cast<ast::EnumDecl *>( decl ) ) {
     1075                        } else if ( EnumDecl * agg = dynamic_cast< EnumDecl * >( decl ) ) {
    11821076                                // e.g., int foo(enum E) {}
    1183                                 auto inst = new ast::EnumInstType( agg->name );
    1184                                 auto obj = new ast::ObjectDecl( cur->location,
    1185                                         "",
    1186                                         inst,
    1187                                         nullptr,
    1188                                         ast::Storage::Classes(),
    1189                                         linkage
    1190                                 );
     1077                                EnumInstType * inst = new EnumInstType( Type::Qualifiers(), agg->name );
     1078                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
     1079                                obj->location = cur->location;
    11911080                                *out++ = obj;
    1192                         } else {
    1193                                 assertf( false, "buildList: Could not convert to ast::DeclWithType." );
    11941081                        } // if
    1195                 } catch ( SemanticErrorException & e ) {
     1082                } catch( SemanticErrorException & e ) {
    11961083                        errors.append( e );
    11971084                } // try
     
    12031090} // buildList
    12041091
    1205 void buildTypeList( const DeclarationNode * firstNode,
    1206                 std::vector<ast::ptr<ast::Type>> & outputList ) {
     1092void buildTypeList( const DeclarationNode * firstNode, std::list< Type * > & outputList ) {
    12071093        SemanticErrorException errors;
    1208         std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
    1209 
    1210         for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
     1094        std::back_insert_iterator< std::list< Type * > > out( outputList );
     1095        const DeclarationNode * cur = firstNode;
     1096
     1097        while ( cur ) {
    12111098                try {
    12121099                        * out++ = cur->buildType();
    1213                 } catch ( SemanticErrorException & e ) {
     1100                } catch( SemanticErrorException & e ) {
    12141101                        errors.append( e );
    12151102                } // try
    1216         } // for
     1103                cur = dynamic_cast< DeclarationNode * >( cur->get_next() );
     1104        } // while
    12171105
    12181106        if ( ! errors.isEmpty() ) {
     
    12211109} // buildTypeList
    12221110
    1223 ast::Decl * DeclarationNode::build() const {
     1111Declaration * DeclarationNode::build() const {
    12241112        if ( ! error.empty() ) SemanticError( this, error + " in declaration of " );
    12251113
    12261114        if ( asmStmt ) {
    1227                 auto stmt = strict_dynamic_cast<ast::AsmStmt *>( asmStmt->build() );
    1228                 return new ast::AsmDecl( stmt->location, stmt );
     1115                return new AsmDecl( strict_dynamic_cast<AsmStmt *>( asmStmt->build() ) );
    12291116        } // if
    12301117        if ( directiveStmt ) {
    1231                 auto stmt = strict_dynamic_cast<ast::DirectiveStmt *>( directiveStmt->build() );
    1232                 return new ast::DirectiveDecl( stmt->location, stmt );
    1233         } // if
    1234 
    1235         if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
     1118                return new DirectiveDecl( strict_dynamic_cast<DirectiveStmt *>( directiveStmt->build() ) );
     1119        } // if
     1120
     1121        if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
    12361122                // otype is internally converted to dtype + otype parameters
    1237                 static const ast::TypeDecl::Kind kindMap[] = { ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Ftype, ast::TypeDecl::Ttype, ast::TypeDecl::Dimension };
    1238                 static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == ast::TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
     1123                static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::Dtype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::Dimension };
     1124                static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
    12391125                assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
    1240                 ast::TypeDecl * ret = new ast::TypeDecl( location,
    1241                         *name,
    1242                         ast::Storage::Classes(),
    1243                         (ast::Type *)nullptr,
    1244                         kindMap[ variable.tyClass ],
    1245                         variable.tyClass == ast::TypeDecl::Otype || variable.tyClass == ast::TypeDecl::DStype,
    1246                         variable.initializer ? variable.initializer->buildType() : nullptr
    1247                 );
    1248                 buildList( variable.assertions, ret->assertions );
     1126                TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype || variable.tyClass == TypeDecl::DStype, variable.initializer ? variable.initializer->buildType() : nullptr );
     1127                buildList( variable.assertions, ret->get_assertions() );
    12491128                return ret;
    12501129        } // if
     
    12681147                } // if
    12691148                bool isDelete = initializer && initializer->get_isDelete();
    1270                 ast::Decl * decl = buildDecl(
    1271                         type,
    1272                         name ? *name : string( "" ),
    1273                         storageClasses,
    1274                         maybeBuild( bitfieldWidth ),
    1275                         funcSpecs,
    1276                         linkage,
    1277                         asmName,
    1278                         isDelete ? nullptr : maybeBuild( initializer ),
    1279                         copy( attributes )
    1280                 )->set_extension( extension );
     1149                Declaration * decl = buildDecl( type, name ? *name : string( "" ), storageClasses, maybeBuild< Expression >( bitfieldWidth ), funcSpecs, linkage, asmName, isDelete ? nullptr : maybeBuild< Initializer >(initializer), attributes )->set_extension( extension );
    12811150                if ( isDelete ) {
    1282                         auto dwt = strict_dynamic_cast<ast::DeclWithType *>( decl );
     1151                        DeclarationWithType * dwt = strict_dynamic_cast<DeclarationWithType *>( decl );
    12831152                        dwt->isDeleted = true;
    12841153                }
     
    12871156
    12881157        if ( assert.condition ) {
    1289                 auto cond = maybeBuild( assert.condition );
    1290                 auto msg = strict_dynamic_cast<ast::ConstantExpr *>( maybeCopy( assert.message ) );
    1291                 return new ast::StaticAssertDecl( location, cond, msg );
     1158                return new StaticAssertDecl( maybeBuild< Expression >( assert.condition ), strict_dynamic_cast< ConstantExpr * >( maybeClone( assert.message ) ) );
    12921159        }
    12931160
     
    13001167        } // if
    13011168        if ( enumInLine ) {
    1302                 return new ast::InlineMemberDecl( location,
    1303                         *name, (ast::Type*)nullptr, storageClasses, linkage );
     1169                return new InlineMemberDecl( *name, storageClasses, linkage, nullptr );
    13041170        } // if
    13051171        assertf( name, "ObjectDecl must a have name\n" );
    1306         auto ret = new ast::ObjectDecl( location,
    1307                 *name,
    1308                 (ast::Type*)nullptr,
    1309                 maybeBuild( initializer ),
    1310                 storageClasses,
    1311                 linkage,
    1312                 maybeBuild( bitfieldWidth )
    1313         );
    1314         ret->asmName = asmName;
    1315         ret->extension = extension;
    1316         return ret;
    1317 }
    1318 
    1319 ast::Type * DeclarationNode::buildType() const {
     1172        return (new ObjectDecl( *name, storageClasses, linkage, maybeBuild< Expression >( bitfieldWidth ), nullptr, maybeBuild< Initializer >( initializer ) ))->set_asmName( asmName )->set_extension( extension );
     1173}
     1174
     1175Type * DeclarationNode::buildType() const {
    13201176        assert( type );
    13211177
     1178        if ( attr.expr ) {
     1179                return new AttrType( buildQualifiers( type ), *name, attr.expr->build(), attributes );
     1180        } else if ( attr.type ) {
     1181                return new AttrType( buildQualifiers( type ), *name, attr.type->buildType(), attributes );
     1182        } // if
     1183
    13221184        switch ( type->kind ) {
    1323         case TypeData::Enum:
    1324         case TypeData::Aggregate: {
    1325                 ast::BaseInstType * ret =
    1326                         buildComAggInst( type, copy( attributes ), linkage );
    1327                 buildList( type->aggregate.actuals, ret->params );
    1328                 return ret;
    1329         }
    1330         case TypeData::Symbolic: {
    1331                 ast::TypeInstType * ret = new ast::TypeInstType(
    1332                         *type->symbolic.name,
    1333                         // This is just a default, the true value is not known yet.
    1334                         ast::TypeDecl::Dtype,
    1335                         buildQualifiers( type ),
    1336                         copy( attributes ) );
    1337                 buildList( type->symbolic.actuals, ret->params );
    1338                 return ret;
    1339         }
    1340         default:
    1341                 ast::Type * simpletypes = typebuild( type );
    1342                 // copy because member is const
    1343                 simpletypes->attributes = attributes;
     1185          case TypeData::Enum:
     1186          case TypeData::Aggregate: {
     1187                  ReferenceToType * ret = buildComAggInst( type, attributes, linkage );
     1188                  buildList( type->aggregate.actuals, ret->get_parameters() );
     1189                  return ret;
     1190          }
     1191          case TypeData::Symbolic: {
     1192                  TypeInstType * ret = new TypeInstType( buildQualifiers( type ), *type->symbolic.name, false, attributes );
     1193                  buildList( type->symbolic.actuals, ret->get_parameters() );
     1194                  return ret;
     1195          }
     1196          default:
     1197                Type * simpletypes = typebuild( type );
     1198                simpletypes->get_attributes() = attributes;             // copy because member is const
    13441199                return simpletypes;
    13451200        } // switch
  • src/Parser/ExpressionNode.cc

    rb110bcc r2ed94a9  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 13:17:07 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 11:07:00 2023
    13 // Update Count     : 1083
    14 //
    15 
    16 #include "ExpressionNode.h"
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Aug  7 09:18:56 2021
     13// Update Count     : 1077
     14//
    1715
    1816#include <cassert>                 // for assert
     
    2321#include <string>                  // for string, operator+, operator==
    2422
    25 #include "AST/Expr.hpp"            // for NameExpr
    26 #include "AST/Type.hpp"            // for BaseType, SueInstType
    2723#include "Common/SemanticError.h"  // for SemanticError
    2824#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild, CodeLo...
    29 #include "DeclarationNode.h"       // for DeclarationNode
    30 #include "InitializerNode.h"       // for InitializerNode
     25#include "ParseNode.h"             // for ExpressionNode, maybeMoveBuildType
     26#include "SynTree/Constant.h"      // for Constant
     27#include "SynTree/Declaration.h"   // for EnumDecl, StructDecl, UnionDecl
     28#include "SynTree/Expression.h"    // for Expression, ConstantExpr, NameExpr
     29#include "SynTree/Statement.h"     // for CompoundStmt, Statement
     30#include "SynTree/Type.h"          // for BasicType, Type, Type::Qualifiers
    3131#include "parserutility.h"         // for notZeroExpr
     32
     33class Initializer;
    3234
    3335using namespace std;
     
    4648// because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their
    4749// type.
     50
     51extern const Type::Qualifiers noQualifiers;                             // no qualifiers on constants
    4852
    4953// static inline bool checkH( char c ) { return c == 'h' || c == 'H'; }
     
    6771        size_t end = str.length() - 1;
    6872        if ( posn == end ) { type = 3; return; }                        // no length after 'l' => long
    69 
     73       
    7074        string::size_type next = posn + 1;                                      // advance to length
    7175        if ( str[next] == '3' ) {                                                       // 32
     
    118122                if ( str[i] == '1' ) v |= 1;
    119123                i += 1;
    120                 if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
     124          if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
    121125                v <<= 1;
    122126        } // for
    123127} // scanbin
    124128
    125 ast::Expr * build_constantInteger(
    126                 const CodeLocation & location, string & str ) {
    127         static const ast::BasicType::Kind kind[2][6] = {
     129Expression * build_constantInteger( string & str ) {
     130        static const BasicType::Kind kind[2][6] = {
    128131                // short (h) must be before char (hh) because shorter type has the longer suffix
    129                 { ast::BasicType::ShortSignedInt, ast::BasicType::SignedChar, ast::BasicType::SignedInt, ast::BasicType::LongSignedInt, ast::BasicType::LongLongSignedInt, /* BasicType::SignedInt128 */ ast::BasicType::LongLongSignedInt, },
    130                 { ast::BasicType::ShortUnsignedInt, ast::BasicType::UnsignedChar, ast::BasicType::UnsignedInt, ast::BasicType::LongUnsignedInt, ast::BasicType::LongLongUnsignedInt, /* BasicType::UnsignedInt128 */ ast::BasicType::LongLongUnsignedInt, },
     132                { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, /* BasicType::SignedInt128 */ BasicType::LongLongSignedInt, },
     133                { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, /* BasicType::UnsignedInt128 */ BasicType::LongLongUnsignedInt, },
    131134        };
    132135
     
    138141        string str2( "0x0" );
    139142        unsigned long long int v, v2 = 0;                                       // converted integral value
    140         ast::Expr * ret, * ret2;
     143        Expression * ret, * ret2;
    141144
    142145        int type = -1;                                                                          // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
     
    146149        // special constants
    147150        if ( str == "0" ) {
    148                 ret = new ast::ConstantExpr( location, new ast::ZeroType(), str, 0 );
     151                ret = new ConstantExpr( Constant( (Type *)new ZeroType( noQualifiers ), str, (unsigned long long int)0 ) );
    149152                goto CLEANUP;
    150153        } // if
    151154        if ( str == "1" ) {
    152                 ret = new ast::ConstantExpr( location, new ast::OneType(), str, 1 );
     155                ret = new ConstantExpr( Constant( (Type *)new OneType( noQualifiers ), str, (unsigned long long int)1 ) );
    153156                goto CLEANUP;
    154157        } // if
     158
     159        string::size_type posn;
    155160
    156161        // 'u' can appear before or after length suffix
     
    161166        } else {
    162167                // At least one digit in integer constant, so safe to backup while looking for suffix.
    163                 // This declaration and the comma expressions in the conditions mimic
    164                 // the declare and check pattern allowed in later compiler versions.
    165                 // (Only some early compilers/C++ standards do not support it.)
    166                 string::size_type posn;
    167                 // pointer value
    168                 if ( posn = str.find_last_of( "pP" ), posn != string::npos ) {
    169                         ltype = 5; str.erase( posn, 1 );
    170                 // size_t
    171                 } else if ( posn = str.find_last_of( "zZ" ), posn != string::npos ) {
    172                         Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 );
    173                 // signed char
    174                 } else if ( posn = str.rfind( "hh" ), posn != string::npos ) {
    175                         type = 1; str.erase( posn, 2 );
    176                 // signed char
    177                 } else if ( posn = str.rfind( "HH" ), posn != string::npos ) {
    178                         type = 1; str.erase( posn, 2 );
    179                 // short
    180                 } else if ( posn = str.find_last_of( "hH" ), posn != string::npos ) {
    181                         type = 0; str.erase( posn, 1 );
    182                 // int (natural number)
    183                 } else if ( posn = str.find_last_of( "nN" ), posn != string::npos ) {
    184                         type = 2; str.erase( posn, 1 );
    185                 } else if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) {
    186                         type = 4;
    187                 } else {
    188                         lnthSuffix( str, type, ltype );
    189                 } // if
     168
     169                posn = str.find_last_of( "pP" );                                // pointer value
     170                if ( posn != string::npos ) { ltype = 5; str.erase( posn, 1 ); goto FINI; }
     171
     172                posn = str.find_last_of( "zZ" );                                // size_t
     173                if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; }
     174
     175                posn = str.rfind( "hh" );                                               // char
     176                if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
     177
     178                posn = str.rfind( "HH" );                                               // char
     179                if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
     180
     181                posn = str.find_last_of( "hH" );                                // short
     182                if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; }
     183
     184                posn = str.find_last_of( "nN" );                                // int (natural number)
     185                if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; }
     186
     187                if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; }
     188
     189                lnthSuffix( str, type, ltype );                                 // must be after check for "ll"
     190          FINI: ;
    190191        } // if
    191192
     
    195196        if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target " + str );
    196197#endif // ! __SIZEOF_INT128__
    197 
     198       
    198199        if ( str[0] == '0' ) {                                                          // radix character ?
    199200                dec = false;
     
    205206                                unsigned int len = str.length();
    206207                                if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large " + str );
    207                                 // hex digits < 2^64
    208                                 if ( len > (2 + 16) ) {
    209                                         str2 = "0x" + str.substr( len - 16 );
    210                                         sscanf( (char *)str2.c_str(), "%llx", &v2 );
    211                                         str = str.substr( 0, len - 16 );
    212                                 } // if
     208                          if ( len <= (2 + 16) ) goto FHEX1;            // hex digits < 2^64
     209                                str2 = "0x" + str.substr( len - 16 );
     210                                sscanf( (char *)str2.c_str(), "%llx", &v2 );
     211                                str = str.substr( 0, len - 16 );
     212                          FHEX1: ;
    213213                                sscanf( (char *)str.c_str(), "%llx", &v );
    214214#endif // __SIZEOF_INT128__
     
    301301
    302302        // Constant type is correct for overload resolving.
    303         ret = new ast::ConstantExpr( location,
    304                 new ast::BasicType( kind[Unsigned][type] ), str, v );
     303        ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][type] ), str, v ) );
    305304        if ( Unsigned && type < 2 ) {                                           // hh or h, less than int ?
    306305                // int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values.
    307                 ret = new ast::CastExpr( location,
    308                         ret,
    309                         new ast::BasicType( kind[Unsigned][type] ),
    310                         ast::ExplicitCast );
     306                ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
    311307        } else if ( ltype != -1 ) {                                                     // explicit length ?
    312308                if ( ltype == 6 ) {                                                             // int128, (int128)constant
    313                         ret2 = new ast::ConstantExpr( location,
    314                                 new ast::BasicType( ast::BasicType::LongLongSignedInt ),
    315                                 str2,
    316                                 v2 );
    317                         ret = build_compoundLiteral( location,
    318                                 DeclarationNode::newBasicType(
    319                                         DeclarationNode::Int128
    320                                 )->addType(
    321                                         DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ),
    322                                 new InitializerNode(
    323                                         (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true )
    324                         );
     309//                      ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
     310                        ret2 = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::LongLongSignedInt ), str2, v2 ) );
     311                        ret = build_compoundLiteral( DeclarationNode::newBasicType( DeclarationNode::Int128 )->addType( DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ),
     312                                                                                 new InitializerNode( (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true ) );
    325313                } else {                                                                                // explicit length, (length_type)constant
    326                         ret = new ast::CastExpr( location,
    327                                 ret,
    328                                 new ast::TypeInstType( lnthsInt[Unsigned][ltype], ast::TypeDecl::Dtype ),
    329                                 ast::ExplicitCast );
     314                        ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false );
    330315                        if ( ltype == 5 ) {                                                     // pointer, intptr( (uintptr_t)constant )
    331                                 ret = build_func( location,
    332                                         new ExpressionNode(
    333                                                 build_varref( location, new string( "intptr" ) ) ),
    334                                         new ExpressionNode( ret ) );
     316                                ret = build_func( new ExpressionNode( build_varref( new string( "intptr" ) ) ), new ExpressionNode( ret ) );
    335317                        } // if
    336318                } // if
     
    376358
    377359
    378 ast::Expr * build_constantFloat(
    379                 const CodeLocation & location, string & str ) {
    380         static const ast::BasicType::Kind kind[2][12] = {
    381                 { ast::BasicType::Float, ast::BasicType::Double, ast::BasicType::LongDouble, ast::BasicType::uuFloat80, ast::BasicType::uuFloat128, ast::BasicType::uFloat16, ast::BasicType::uFloat32, ast::BasicType::uFloat32x, ast::BasicType::uFloat64, ast::BasicType::uFloat64x, ast::BasicType::uFloat128, ast::BasicType::uFloat128x },
    382                 { ast::BasicType::FloatComplex, ast::BasicType::DoubleComplex, ast::BasicType::LongDoubleComplex, ast::BasicType::NUMBER_OF_BASIC_TYPES, ast::BasicType::NUMBER_OF_BASIC_TYPES, ast::BasicType::uFloat16Complex, ast::BasicType::uFloat32Complex, ast::BasicType::uFloat32xComplex, ast::BasicType::uFloat64Complex, ast::BasicType::uFloat64xComplex, ast::BasicType::uFloat128Complex, ast::BasicType::uFloat128xComplex },
     360Expression * build_constantFloat( string & str ) {
     361        static const BasicType::Kind kind[2][12] = {
     362                { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x },
     363                { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::NUMBER_OF_BASIC_TYPES, BasicType::NUMBER_OF_BASIC_TYPES, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex },
    383364        };
    384365
     
    417398
    418399        assert( 0 <= type && type < 12 );
    419         ast::Expr * ret = new ast::ConstantExpr( location,
    420                 new ast::BasicType( kind[complx][type] ),
    421                 str,
    422                 v );
    423         // explicit length ?
    424         if ( explnth ) {
    425                 ret = new ast::CastExpr( location,
    426                         ret,
    427                         new ast::BasicType( kind[complx][type] ),
    428                         ast::ExplicitCast );
     400        Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[complx][type] ), str, v ) );
     401        if ( explnth ) {                                                                        // explicit length ?
     402                ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[complx][type] ), false );
    429403        } // if
    430404
     
    441415} // sepString
    442416
    443 ast::Expr * build_constantChar( const CodeLocation & location, string & str ) {
     417Expression * build_constantChar( string & str ) {
    444418        string units;                                                                           // units
    445419        sepString( str, units, '\'' );                                          // separate constant from units
    446420
    447         ast::Expr * ret = new ast::ConstantExpr( location,
    448                 new ast::BasicType( ast::BasicType::Char ),
    449                 str,
    450                 (unsigned long long int)(unsigned char)str[1] );
     421        Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::Char ), str, (unsigned long long int)(unsigned char)str[1] ) );
    451422        if ( units.length() != 0 ) {
    452                 ret = new ast::UntypedExpr( location,
    453                         new ast::NameExpr( location, units ),
    454                         { ret } );
     423                ret = new UntypedExpr( new NameExpr( units ), { ret } );
    455424        } // if
    456425
     
    459428} // build_constantChar
    460429
    461 ast::Expr * build_constantStr(
    462                 const CodeLocation & location,
    463                 string & str ) {
     430Expression * build_constantStr( string & str ) {
    464431        assert( str.length() > 0 );
    465432        string units;                                                                           // units
    466433        sepString( str, units, '"' );                                           // separate constant from units
    467434
    468         ast::Type * strtype;
     435        Type * strtype;
    469436        switch ( str[0] ) {                                                                     // str has >= 2 characters, i.e, null string "" => safe to look at subscripts 0/1
    470         case 'u':
     437          case 'u':
    471438                if ( str[1] == '8' ) goto Default;                              // utf-8 characters => array of char
    472439                // lookup type of associated typedef
    473                 strtype = new ast::TypeInstType( "char16_t", ast::TypeDecl::Dtype );
     440                strtype = new TypeInstType( Type::Qualifiers( ), "char16_t", false );
    474441                break;
    475         case 'U':
    476                 strtype = new ast::TypeInstType( "char32_t", ast::TypeDecl::Dtype );
     442          case 'U':
     443                strtype = new TypeInstType( Type::Qualifiers( ), "char32_t", false );
    477444                break;
    478         case 'L':
    479                 strtype = new ast::TypeInstType( "wchar_t", ast::TypeDecl::Dtype );
     445          case 'L':
     446                strtype = new TypeInstType( Type::Qualifiers( ), "wchar_t", false );
    480447                break;
    481         Default:                                                                                        // char default string type
    482         default:
    483                 strtype = new ast::BasicType( ast::BasicType::Char );
     448          Default:                                                                                      // char default string type
     449          default:
     450                strtype = new BasicType( Type::Qualifiers( ), BasicType::Char );
    484451        } // switch
    485         ast::ArrayType * at = new ast::ArrayType(
    486                 strtype,
    487                 // Length is adjusted: +1 for '\0' and -2 for '"'
    488                 ast::ConstantExpr::from_ulong( location, str.size() + 1 - 2 ),
    489                 ast::FixedLen,
    490                 ast::DynamicDim );
    491         ast::Expr * ret = new ast::ConstantExpr( location, at, str, std::nullopt );
     452        ArrayType * at = new ArrayType( noQualifiers, strtype,
     453                                                                        new ConstantExpr( Constant::from_ulong( str.size() + 1 - 2 ) ), // +1 for '\0' and -2 for '"'
     454                                                                        false, false );
     455        Expression * ret = new ConstantExpr( Constant( at, str, std::nullopt ) );
    492456        if ( units.length() != 0 ) {
    493                 ret = new ast::UntypedExpr( location,
    494                         new ast::NameExpr( location, units ),
    495                         { ret } );
     457                ret = new UntypedExpr( new NameExpr( units ), { ret } );
    496458        } // if
    497459
     
    500462} // build_constantStr
    501463
    502 ast::Expr * build_field_name_FLOATING_FRACTIONconstant(
    503                 const CodeLocation & location, const string & str ) {
     464Expression * build_field_name_FLOATING_FRACTIONconstant( const string & str ) {
    504465        if ( str.find_first_not_of( "0123456789", 1 ) != string::npos ) SemanticError( yylloc, "invalid tuple index " + str );
    505         ast::Expr * ret = build_constantInteger( location,
    506                 *new string( str.substr(1) ) );
     466        Expression * ret = build_constantInteger( *new string( str.substr(1) ) );
    507467        delete &str;
    508468        return ret;
    509469} // build_field_name_FLOATING_FRACTIONconstant
    510470
    511 ast::Expr * build_field_name_FLOATING_DECIMALconstant(
    512                 const CodeLocation & location, const string & str ) {
     471Expression * build_field_name_FLOATING_DECIMALconstant( const string & str ) {
    513472        if ( str[str.size() - 1] != '.' ) SemanticError( yylloc, "invalid tuple index " + str );
    514         ast::Expr * ret = build_constantInteger(
    515                 location, *new string( str.substr( 0, str.size()-1 ) ) );
     473        Expression * ret = build_constantInteger( *new string( str.substr( 0, str.size()-1 ) ) );
    516474        delete &str;
    517475        return ret;
    518476} // build_field_name_FLOATING_DECIMALconstant
    519477
    520 ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation & location,
    521                 const string & str ) {
     478Expression * build_field_name_FLOATINGconstant( const string & str ) {
    522479        // str is of the form A.B -> separate at the . and return member expression
    523480        int a, b;
     
    525482        stringstream ss( str );
    526483        ss >> a >> dot >> b;
    527         auto ret = new ast::UntypedMemberExpr( location,
    528                 ast::ConstantExpr::from_int( location, b ),
    529                 ast::ConstantExpr::from_int( location, a )
    530         );
     484        UntypedMemberExpr * ret = new UntypedMemberExpr( new ConstantExpr( Constant::from_int( b ) ), new ConstantExpr( Constant::from_int( a ) ) );
    531485        delete &str;
    532486        return ret;
    533487} // build_field_name_FLOATINGconstant
    534488
    535 ast::Expr * make_field_name_fraction_constants( const CodeLocation & location,
    536                 ast::Expr * fieldName,
    537                 ast::Expr * fracts ) {
    538         if ( nullptr == fracts ) {
    539                 return fieldName;
    540         } else if ( auto memberExpr = dynamic_cast<ast::UntypedMemberExpr *>( fracts ) ) {
    541                 memberExpr->member = make_field_name_fraction_constants( location,
    542                         fieldName,
    543                         ast::mutate( memberExpr->aggregate.get() ) );
    544                 return memberExpr;
    545         } else {
    546                 return new ast::UntypedMemberExpr( location, fracts, fieldName );
    547         } // if
     489Expression * make_field_name_fraction_constants( Expression * fieldName, Expression * fracts ) {
     490        if ( fracts ) {
     491                if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( fracts ) ) {
     492                        memberExpr->set_member( make_field_name_fraction_constants( fieldName, memberExpr->get_aggregate() ) );
     493                        return memberExpr;
     494                } else {
     495                        return new UntypedMemberExpr( fracts, fieldName );
     496                } // if
     497        } // if
     498        return fieldName;
    548499} // make_field_name_fraction_constants
    549500
    550 ast::Expr * build_field_name_fraction_constants( const CodeLocation & location,
    551                 ast::Expr * fieldName,
    552                 ExpressionNode * fracts ) {
    553         return make_field_name_fraction_constants( location, fieldName, maybeMoveBuild( fracts ) );
     501Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ) {
     502        return make_field_name_fraction_constants( fieldName, maybeMoveBuild< Expression >( fracts ) );
    554503} // build_field_name_fraction_constants
    555504
    556 ast::NameExpr * build_varref( const CodeLocation & location,
    557                 const string * name ) {
    558         ast::NameExpr * expr = new ast::NameExpr( location, *name );
     505NameExpr * build_varref( const string * name ) {
     506        NameExpr * expr = new NameExpr( *name );
    559507        delete name;
    560508        return expr;
    561509} // build_varref
    562510
    563 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
    564                 const DeclarationNode * decl_node,
    565                 const ast::NameExpr * name ) {
    566         ast::Decl * newDecl = maybeBuild( decl_node );
    567         if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
    568                 if ( const ast::Type * t = newDeclWithType->get_type() ) {
    569                         if ( auto typeInst = dynamic_cast<const ast::TypeInstType *>( t ) ) {
    570                                 newDecl = new ast::EnumDecl( location, typeInst->name );
     511QualifiedNameExpr * build_qualified_expr( const DeclarationNode * decl_node, const NameExpr * name ) {
     512        Declaration * newDecl = maybeBuild< Declaration >(decl_node);
     513        if ( DeclarationWithType * newDeclWithType = dynamic_cast< DeclarationWithType * >( newDecl ) ) {
     514                const Type * t = newDeclWithType->get_type();
     515                if ( t ) {
     516                        if ( const TypeInstType * typeInst = dynamic_cast<const TypeInstType *>( t ) ) {
     517                                newDecl= new EnumDecl( typeInst->name );
    571518                        }
    572519                }
    573520        }
    574         return new ast::QualifiedNameExpr( location, newDecl, name->name );
     521        return new QualifiedNameExpr( newDecl, name->name );
    575522}
    576523
    577 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
    578                 const ast::EnumDecl * decl,
    579                 const ast::NameExpr * name ) {
    580         return new ast::QualifiedNameExpr( location, decl, name->name );
     524QualifiedNameExpr * build_qualified_expr( const EnumDecl * decl_node, const NameExpr * name ) {
     525        EnumDecl * newDecl = const_cast< EnumDecl * >( decl_node );
     526        return new QualifiedNameExpr( newDecl, name->name );
    581527}
    582528
    583 ast::DimensionExpr * build_dimensionref( const CodeLocation & location,
    584                 const string * name ) {
    585         ast::DimensionExpr * expr = new ast::DimensionExpr( location, *name );
     529DimensionExpr * build_dimensionref( const string * name ) {
     530        DimensionExpr * expr = new DimensionExpr( *name );
    586531        delete name;
    587532        return expr;
     
    599544}; // OperName
    600545
    601 ast::Expr * build_cast( const CodeLocation & location,
    602                 DeclarationNode * decl_node,
    603                 ExpressionNode * expr_node ) {
    604         ast::Type * targetType = maybeMoveBuildType( decl_node );
    605         if ( dynamic_cast<ast::VoidType *>( targetType ) ) {
     546Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) {
     547        Type * targetType = maybeMoveBuildType( decl_node );
     548        if ( dynamic_cast< VoidType * >( targetType ) ) {
    606549                delete targetType;
    607                 return new ast::CastExpr( location,
    608                         maybeMoveBuild( expr_node ),
    609                         ast::ExplicitCast );
     550                return new CastExpr( maybeMoveBuild< Expression >(expr_node), false );
    610551        } else {
    611                 return new ast::CastExpr( location,
    612                         maybeMoveBuild( expr_node ),
    613                         targetType,
    614                         ast::ExplicitCast );
     552                return new CastExpr( maybeMoveBuild< Expression >(expr_node), targetType, false );
    615553        } // if
    616554} // build_cast
    617555
    618 ast::Expr * build_keyword_cast( const CodeLocation & location,
    619                 ast::AggregateDecl::Aggregate target,
    620                 ExpressionNode * expr_node ) {
    621         return new ast::KeywordCastExpr( location,
    622                 maybeMoveBuild( expr_node ),
    623                 target
    624         );
     556Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node ) {
     557        return new KeywordCastExpr( maybeMoveBuild< Expression >(expr_node), target );
    625558}
    626559
    627 ast::Expr * build_virtual_cast( const CodeLocation & location,
    628                 DeclarationNode * decl_node,
    629                 ExpressionNode * expr_node ) {
    630         return new ast::VirtualCastExpr( location,
    631                 maybeMoveBuild( expr_node ),
    632                 maybeMoveBuildType( decl_node )
    633         );
     560Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) {
     561        return new VirtualCastExpr( maybeMoveBuild< Expression >( expr_node ), maybeMoveBuildType( decl_node ) );
    634562} // build_virtual_cast
    635563
    636 ast::Expr * build_fieldSel( const CodeLocation & location,
    637                 ExpressionNode * expr_node,
    638                 ast::Expr * member ) {
    639         return new ast::UntypedMemberExpr( location,
    640                 member,
    641                 maybeMoveBuild( expr_node )
    642         );
     564Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member ) {
     565        return new UntypedMemberExpr( member, maybeMoveBuild< Expression >(expr_node) );
    643566} // build_fieldSel
    644567
    645 ast::Expr * build_pfieldSel( const CodeLocation & location,
    646                 ExpressionNode * expr_node,
    647                 ast::Expr * member ) {
    648         auto deref = new ast::UntypedExpr( location,
    649                 new ast::NameExpr( location, "*?" )
    650         );
     568Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member ) {
     569        UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) );
    651570        deref->location = expr_node->location;
    652         deref->args.push_back( maybeMoveBuild( expr_node ) );
    653         auto ret = new ast::UntypedMemberExpr( location, member, deref );
     571        deref->get_args().push_back( maybeMoveBuild< Expression >(expr_node) );
     572        UntypedMemberExpr * ret = new UntypedMemberExpr( member, deref );
    654573        return ret;
    655574} // build_pfieldSel
    656575
    657 ast::Expr * build_offsetOf( const CodeLocation & location,
    658                 DeclarationNode * decl_node,
    659                 ast::NameExpr * member ) {
    660         ast::Expr * ret = new ast::UntypedOffsetofExpr( location,
    661                 maybeMoveBuildType( decl_node ),
    662                 member->name
    663         );
    664         ret->result = new ast::BasicType( ast::BasicType::LongUnsignedInt );
     576Expression * build_offsetOf( DeclarationNode * decl_node, NameExpr * member ) {
     577        Expression * ret = new UntypedOffsetofExpr( maybeMoveBuildType( decl_node ), member->get_name() );
    665578        delete member;
    666579        return ret;
    667580} // build_offsetOf
    668581
    669 ast::Expr * build_and_or( const CodeLocation & location,
    670                 ExpressionNode * expr_node1,
    671                 ExpressionNode * expr_node2,
    672                 ast::LogicalFlag flag ) {
    673         return new ast::LogicalExpr( location,
    674                 notZeroExpr( maybeMoveBuild( expr_node1 ) ),
    675                 notZeroExpr( maybeMoveBuild( expr_node2 ) ),
    676                 flag
    677         );
     582Expression * build_and_or( ExpressionNode * expr_node1, ExpressionNode * expr_node2, bool kind ) {
     583        return new LogicalExpr( notZeroExpr( maybeMoveBuild< Expression >(expr_node1) ), notZeroExpr( maybeMoveBuild< Expression >(expr_node2) ), kind );
    678584} // build_and_or
    679585
    680 ast::Expr * build_unary_val( const CodeLocation & location,
    681                 OperKinds op,
    682                 ExpressionNode * expr_node ) {
    683         std::vector<ast::ptr<ast::Expr>> args;
    684         args.push_back( maybeMoveBuild( expr_node ) );
    685         return new ast::UntypedExpr( location,
    686                 new ast::NameExpr( location, OperName[ (int)op ] ),
    687                 std::move( args )
    688         );
     586Expression * build_unary_val( OperKinds op, ExpressionNode * expr_node ) {
     587        list< Expression * > args;
     588        args.push_back( maybeMoveBuild< Expression >(expr_node) );
     589        return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
    689590} // build_unary_val
    690591
    691 ast::Expr * build_binary_val( const CodeLocation & location,
    692                 OperKinds op,
    693                 ExpressionNode * expr_node1,
    694                 ExpressionNode * expr_node2 ) {
    695         std::vector<ast::ptr<ast::Expr>> args;
    696         args.push_back( maybeMoveBuild( expr_node1 ) );
    697         args.push_back( maybeMoveBuild( expr_node2 ) );
    698         return new ast::UntypedExpr( location,
    699                 new ast::NameExpr( location, OperName[ (int)op ] ),
    700                 std::move( args )
    701         );
     592Expression * build_unary_ptr( OperKinds op, ExpressionNode * expr_node ) {
     593        list< Expression * > args;
     594        args.push_back(  maybeMoveBuild< Expression >(expr_node) ); // xxx -- this is exactly the same as the val case now, refactor this code.
     595        return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
     596} // build_unary_ptr
     597
     598Expression * build_binary_val( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 ) {
     599        list< Expression * > args;
     600        args.push_back( maybeMoveBuild< Expression >(expr_node1) );
     601        args.push_back( maybeMoveBuild< Expression >(expr_node2) );
     602        return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
    702603} // build_binary_val
    703604
    704 ast::Expr * build_cond( const CodeLocation & location,
    705                 ExpressionNode * expr_node1,
    706                 ExpressionNode * expr_node2,
    707                 ExpressionNode * expr_node3 ) {
    708         return new ast::ConditionalExpr( location,
    709                 notZeroExpr( maybeMoveBuild( expr_node1 ) ),
    710                 maybeMoveBuild( expr_node2 ),
    711                 maybeMoveBuild( expr_node3 )
    712         );
     605Expression * build_binary_ptr( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 ) {
     606        list< Expression * > args;
     607        args.push_back( maybeMoveBuild< Expression >(expr_node1) );
     608        args.push_back( maybeMoveBuild< Expression >(expr_node2) );
     609        return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
     610} // build_binary_ptr
     611
     612Expression * build_cond( ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 ) {
     613        return new ConditionalExpr( notZeroExpr( maybeMoveBuild< Expression >(expr_node1) ), maybeMoveBuild< Expression >(expr_node2), maybeMoveBuild< Expression >(expr_node3) );
    713614} // build_cond
    714615
    715 ast::Expr * build_tuple( const CodeLocation & location,
    716                 ExpressionNode * expr_node ) {
    717         std::vector<ast::ptr<ast::Expr>> exprs;
     616Expression * build_tuple( ExpressionNode * expr_node ) {
     617        list< Expression * > exprs;
    718618        buildMoveList( expr_node, exprs );
    719         return new ast::UntypedTupleExpr( location, std::move( exprs ) );
     619        return new UntypedTupleExpr( exprs );;
    720620} // build_tuple
    721621
    722 ast::Expr * build_func( const CodeLocation & location,
    723                 ExpressionNode * function,
    724                 ExpressionNode * expr_node ) {
    725         std::vector<ast::ptr<ast::Expr>> args;
     622Expression * build_func( ExpressionNode * function, ExpressionNode * expr_node ) {
     623        list< Expression * > args;
    726624        buildMoveList( expr_node, args );
    727         return new ast::UntypedExpr( location,
    728                 maybeMoveBuild( function ),
    729                 std::move( args )
    730         );
     625        return new UntypedExpr( maybeMoveBuild< Expression >(function), args );
    731626} // build_func
    732627
    733 ast::Expr * build_compoundLiteral( const CodeLocation & location,
    734                 DeclarationNode * decl_node,
    735                 InitializerNode * kids ) {
    736         // compound literal type
    737         ast::Decl * newDecl = maybeBuild( decl_node );
    738         // non-sue compound-literal type
    739         if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
    740                 return new ast::CompoundLiteralExpr( location,
    741                         newDeclWithType->get_type(),
    742                         maybeMoveBuild( kids ) );
     628Expression * build_compoundLiteral( DeclarationNode * decl_node, InitializerNode * kids ) {
     629        Declaration * newDecl = maybeBuild< Declaration >(decl_node); // compound literal type
     630        if ( DeclarationWithType * newDeclWithType = dynamic_cast< DeclarationWithType * >( newDecl ) ) { // non-sue compound-literal type
     631                return new CompoundLiteralExpr( newDeclWithType->get_type(), maybeMoveBuild< Initializer >(kids) );
    743632        // these types do not have associated type information
    744         } else if ( auto newDeclStructDecl = dynamic_cast<ast::StructDecl *>( newDecl ) ) {
    745                 if ( newDeclStructDecl->body ) {
    746                         return new ast::CompoundLiteralExpr( location,
    747                                 new ast::StructInstType( newDeclStructDecl ),
    748                                 maybeMoveBuild( kids ) );
     633        } else if ( StructDecl * newDeclStructDecl = dynamic_cast< StructDecl * >( newDecl )  ) {
     634                if ( newDeclStructDecl->has_body() ) {
     635                        return new CompoundLiteralExpr( new StructInstType( Type::Qualifiers(), newDeclStructDecl ), maybeMoveBuild< Initializer >(kids) );
    749636                } else {
    750                         return new ast::CompoundLiteralExpr( location,
    751                                 new ast::StructInstType( newDeclStructDecl->name ),
    752                                 maybeMoveBuild( kids ) );
    753                 } // if
    754         } else if ( auto newDeclUnionDecl = dynamic_cast<ast::UnionDecl *>( newDecl )  ) {
    755                 if ( newDeclUnionDecl->body ) {
    756                         return new ast::CompoundLiteralExpr( location,
    757                                 new ast::UnionInstType( newDeclUnionDecl ),
    758                                 maybeMoveBuild( kids ) );
     637                        return new CompoundLiteralExpr( new StructInstType( Type::Qualifiers(), newDeclStructDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
     638                } // if
     639        } else if ( UnionDecl * newDeclUnionDecl = dynamic_cast< UnionDecl * >( newDecl )  ) {
     640                if ( newDeclUnionDecl->has_body() ) {
     641                        return new CompoundLiteralExpr( new UnionInstType( Type::Qualifiers(), newDeclUnionDecl ), maybeMoveBuild< Initializer >(kids) );
    759642                } else {
    760                         return new ast::CompoundLiteralExpr( location,
    761                                 new ast::UnionInstType( newDeclUnionDecl->name ),
    762                                 maybeMoveBuild( kids ) );
    763                 } // if
    764         } else if ( auto newDeclEnumDecl = dynamic_cast<ast::EnumDecl *>( newDecl )  ) {
    765                 if ( newDeclEnumDecl->body ) {
    766                         return new ast::CompoundLiteralExpr( location,
    767                                 new ast::EnumInstType( newDeclEnumDecl ),
    768                                 maybeMoveBuild( kids ) );
     643                        return new CompoundLiteralExpr( new UnionInstType( Type::Qualifiers(), newDeclUnionDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
     644                } // if
     645        } else if ( EnumDecl * newDeclEnumDecl = dynamic_cast< EnumDecl * >( newDecl )  ) {
     646                if ( newDeclEnumDecl->has_body() ) {
     647                        return new CompoundLiteralExpr( new EnumInstType( Type::Qualifiers(), newDeclEnumDecl ), maybeMoveBuild< Initializer >(kids) );
    769648                } else {
    770                         return new ast::CompoundLiteralExpr( location,
    771                                 new ast::EnumInstType( newDeclEnumDecl->name ),
    772                                 maybeMoveBuild( kids ) );
     649                        return new CompoundLiteralExpr( new EnumInstType( Type::Qualifiers(), newDeclEnumDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
    773650                } // if
    774651        } else {
     
    779656// Local Variables: //
    780657// tab-width: 4 //
     658// mode: c++ //
     659// compile-command: "make install" //
    781660// End: //
  • src/Parser/InitializerNode.cc

    rb110bcc r2ed94a9  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:20:24 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 11:18:00 2023
    13 // Update Count     : 27
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Jul 28 23:27:20 2017
     13// Update Count     : 26
    1414//
    15 
    16 #include "InitializerNode.h"
    1715
    1816#include <iostream>                // for operator<<, ostream, basic_ostream
     
    2018#include <string>                  // for operator<<, string
    2119
    22 #include "AST/Expr.hpp"            // for Expr
    23 #include "AST/Init.hpp"            // for Designator, Init, ListInit, Sing...
     20using namespace std;
     21
    2422#include "Common/SemanticError.h"  // for SemanticError
    2523#include "Common/utility.h"        // for maybeBuild
    26 #include "ExpressionNode.h"        // for ExpressionNode
    27 #include "DeclarationNode.h"       // for buildList
    28 
    29 using namespace std;
    30 
    31 static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
    32         return maybeConstructed ? ast::MaybeConstruct : ast::NoConstruct;
    33 }
     24#include "ParseNode.h"             // for InitializerNode, ExpressionNode
     25#include "SynTree/Expression.h"    // for Expression
     26#include "SynTree/Initializer.h"   // for Initializer, ListInit, SingleInit
    3427
    3528InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des )
     
    4033        if ( kids )
    4134                set_last( nullptr );
    42 } // InitializerNode::InitializerNode
     35} // InitializerNode::InitializerNode
    4336
    4437InitializerNode::InitializerNode( InitializerNode * init, bool aggrp, ExpressionNode * des )
     
    9285} // InitializerNode::printOneLine
    9386
    94 ast::Init * InitializerNode::build() const {
     87Initializer * InitializerNode::build() const {
    9588        assertf( ! isDelete, "Should not build delete stmt InitializerNode" );
    9689        if ( aggregate ) {
    9790                // steal designators from children
    98                 std::vector<ast::ptr<ast::Designation>> designlist;
     91                std::list< Designation * > designlist;
    9992                InitializerNode * child = next_init();
    100                 for ( ; child != nullptr ; child = dynamic_cast< InitializerNode * >( child->get_next() ) ) {
    101                         std::deque<ast::ptr<ast::Expr>> desList;
    102                         buildList( child->designator, desList );
    103                         designlist.push_back(
    104                                 new ast::Designation( location, std::move( desList ) ) );
     93                for ( ; child != nullptr; child = dynamic_cast< InitializerNode * >( child->get_next() ) ) {
     94                        std::list< Expression * > desList;
     95                        buildList< Expression, ExpressionNode >( child->designator, desList );
     96                        designlist.push_back( new Designation( desList ) );
    10597                } // for
    106                 std::vector<ast::ptr<ast::Init>> initlist;
    107                 buildList( next_init(), initlist );
    108                 return new ast::ListInit( location,
    109                         std::move( initlist ),
    110                         std::move( designlist ),
    111                         toConstructFlag( maybeConstructed )
    112                 );
    113         } else if ( get_expression() ) {
    114                 assertf( get_expression()->expr, "The expression of initializer must have value" );
    115                 return new ast::SingleInit( location,
    116                         maybeBuild( get_expression() ),
    117                         toConstructFlag( maybeConstructed )
    118                 );
     98                std::list< Initializer * > initlist;
     99                buildList< Initializer, InitializerNode >( next_init(), initlist );
     100                return new ListInit( initlist, designlist, maybeConstructed );
     101        } else {
     102                if ( get_expression() ) {
     103                        assertf( get_expression()->expr, "The expression of initializer must have value" );
     104                        return new SingleInit( maybeBuild< Expression >( get_expression() ), maybeConstructed );
     105                } // if
    119106        } // if
    120107        return nullptr;
  • src/Parser/ParseNode.h

    rb110bcc r2ed94a9  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:28:16 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Apr  3 17:55:00 2023
    13 // Update Count     : 942
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Nov  2 21:27:07 2022
     13// Update Count     : 939
    1414//
    1515
     
    2424#include <string>                  // for string
    2525
    26 #include "AST/Expr.hpp"            // for Expr, NameExpr LogicalFlag
    27 #include "AST/Fwd.hpp"             // for ptr, Decl, DeclWithType,
    28 #include "AST/Stmt.hpp"            // for Stmt
    2926#include "Common/CodeLocation.h"   // for CodeLocation
    3027#include "Common/SemanticError.h"  // for SemanticError
    3128#include "Common/UniqueName.h"     // for UniqueName
    32 #include "Common/utility.h"        // for maybeClone
    33 #include "Parser/parserutility.h"  // for maybeBuild, maybeCopy
     29#include "Common/utility.h"        // for maybeClone, maybeBuild
     30#include "SynTree/LinkageSpec.h"   // for Spec
     31#include "SynTree/Declaration.h"   // for Aggregate
     32#include "SynTree/Expression.h"    // for Expression, ConstantExpr (ptr only)
     33#include "SynTree/Label.h"         // for Label
     34#include "SynTree/Statement.h"     // for Statement, BranchStmt, BranchStmt:...
     35#include "SynTree/Type.h"          // for Type, Type::FuncSpecifiers, Type::...
    3436
    3537class Attribute;
     
    3840class DeclarationWithType;
    3941class Initializer;
    40 class InitializerNode;
    4142class ExpressionNode;
    4243struct StatementNode;
     
    8081        CodeLocation location = yylloc;
    8182}; // ParseNode
     83
     84//##############################################################################
     85
     86class InitializerNode : public ParseNode {
     87  public:
     88        InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
     89        InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
     90        InitializerNode( bool isDelete );
     91        ~InitializerNode();
     92        virtual InitializerNode * clone() const { assert( false ); return nullptr; }
     93
     94        ExpressionNode * get_expression() const { return expr; }
     95
     96        InitializerNode * set_designators( ExpressionNode * des ) { designator = des; return this; }
     97        ExpressionNode * get_designators() const { return designator; }
     98
     99        InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }
     100        bool get_maybeConstructed() const { return maybeConstructed; }
     101
     102        bool get_isDelete() const { return isDelete; }
     103
     104        InitializerNode * next_init() const { return kids; }
     105
     106        void print( std::ostream & os, int indent = 0 ) const;
     107        void printOneLine( std::ostream & ) const;
     108
     109        virtual Initializer * build() const;
     110  private:
     111        ExpressionNode * expr;
     112        bool aggregate;
     113        ExpressionNode * designator;                                            // may be list
     114        InitializerNode * kids;
     115        bool maybeConstructed;
     116        bool isDelete;
     117}; // InitializerNode
     118
     119//##############################################################################
     120
     121class ExpressionNode final : public ParseNode {
     122  public:
     123        ExpressionNode( Expression * expr = nullptr ) : expr( expr ) {}
     124        virtual ~ExpressionNode() {}
     125        virtual ExpressionNode * clone() const override { return expr ? static_cast<ExpressionNode*>((new ExpressionNode( expr->clone() ))->set_next( maybeClone( get_next() ) )) : nullptr; }
     126
     127        bool get_extension() const { return extension; }
     128        ExpressionNode * set_extension( bool exten ) { extension = exten; return this; }
     129
     130        virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
     131                os << expr.get();
     132        }
     133        void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
     134
     135        template<typename T>
     136        bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }
     137
     138        Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); }
     139
     140        std::unique_ptr<Expression> expr;                                       // public because of lifetime implications
     141  private:
     142        bool extension = false;
     143}; // ExpressionNode
     144
     145template< typename T >
     146struct maybeBuild_t< Expression, T > {
     147        static inline Expression * doit( const T * orig ) {
     148                if ( orig ) {
     149                        Expression * p = orig->build();
     150                        p->set_extension( orig->get_extension() );
     151                        p->location = orig->location;
     152                        return p;
     153                } else {
     154                        return nullptr;
     155                } // if
     156        }
     157};
    82158
    83159// Must harmonize with OperName.
     
    96172
    97173struct LabelNode {
    98         std::vector<ast::Label> labels;
     174        std::list< Label > labels;
    99175};
    100176
     177Expression * build_constantInteger( std::string & str ); // these 4 routines modify the string
     178Expression * build_constantFloat( std::string & str );
     179Expression * build_constantChar( std::string & str );
     180Expression * build_constantStr( std::string & str );
     181Expression * build_field_name_FLOATING_FRACTIONconstant( const std::string & str );
     182Expression * build_field_name_FLOATING_DECIMALconstant( const std::string & str );
     183Expression * build_field_name_FLOATINGconstant( const std::string & str );
     184Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts );
     185
     186NameExpr * build_varref( const std::string * name );
     187QualifiedNameExpr * build_qualified_expr( const DeclarationNode * decl_node, const NameExpr * name );
     188QualifiedNameExpr * build_qualified_expr( const EnumDecl * decl, const NameExpr * name );
     189DimensionExpr * build_dimensionref( const std::string * name );
     190
     191Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
     192Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node );
     193Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
     194Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member );
     195Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member );
     196Expression * build_offsetOf( DeclarationNode * decl_node, NameExpr * member );
     197Expression * build_and( ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
     198Expression * build_and_or( ExpressionNode * expr_node1, ExpressionNode * expr_node2, bool kind );
     199Expression * build_unary_val( OperKinds op, ExpressionNode * expr_node );
     200Expression * build_unary_ptr( OperKinds op, ExpressionNode * expr_node );
     201Expression * build_binary_val( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
     202Expression * build_binary_ptr( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
     203Expression * build_cond( ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );
     204Expression * build_tuple( ExpressionNode * expr_node = nullptr );
     205Expression * build_func( ExpressionNode * function, ExpressionNode * expr_node );
     206Expression * build_compoundLiteral( DeclarationNode * decl_node, InitializerNode * kids );
     207
     208//##############################################################################
     209
     210struct TypeData;
     211
     212struct DeclarationNode : public ParseNode {
     213        // These enumerations must harmonize with their names in DeclarationNode.cc.
     214        enum BasicType { Void, Bool, Char, Int, Int128,
     215                                         Float, Double, LongDouble, uuFloat80, uuFloat128,
     216                                         uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x, NoBasicType };
     217        static const char * basicTypeNames[];
     218        enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message
     219        static const char * complexTypeNames[];
     220        enum Signedness { Signed, Unsigned, NoSignedness };
     221        static const char * signednessNames[];
     222        enum Length { Short, Long, LongLong, NoLength };
     223        static const char * lengthNames[];
     224        enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };
     225        static const char * builtinTypeNames[];
     226
     227        static DeclarationNode * newStorageClass( Type::StorageClasses );
     228        static DeclarationNode * newFuncSpecifier( Type::FuncSpecifiers );
     229        static DeclarationNode * newTypeQualifier( Type::Qualifiers );
     230        static DeclarationNode * newBasicType( BasicType );
     231        static DeclarationNode * newComplexType( ComplexType );
     232        static DeclarationNode * newSignedNess( Signedness );
     233        static DeclarationNode * newLength( Length );
     234        static DeclarationNode * newBuiltinType( BuiltinType );
     235        static DeclarationNode * newForall( DeclarationNode * );
     236        static DeclarationNode * newFromTypedef( const std::string * );
     237        static DeclarationNode * newFromGlobalScope();
     238        static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
     239        static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
     240        static DeclarationNode * newAggregate( AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
     241        static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base = nullptr, EnumHiding hiding = EnumHiding::Visible );
     242        static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
     243        static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init );
     244        static DeclarationNode * newEnumInLine( const std::string name );
     245        static DeclarationNode * newName( const std::string * );
     246        static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );
     247        static DeclarationNode * newTypeParam( TypeDecl::Kind, const std::string * );
     248        static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
     249        static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );
     250        static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams );
     251        static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind );
     252        static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic );
     253        static DeclarationNode * newVarArray( DeclarationNode * qualifiers );
     254        static DeclarationNode * newBitfield( ExpressionNode * size );
     255        static DeclarationNode * newTuple( DeclarationNode * members );
     256        static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
     257        static DeclarationNode * newVtableType( DeclarationNode * expr );
     258        static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
     259        static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
     260        static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement
     261        static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message );
     262
     263        DeclarationNode();
     264        ~DeclarationNode();
     265        DeclarationNode * clone() const override;
     266
     267        DeclarationNode * addQualifiers( DeclarationNode * );
     268        void checkQualifiers( const TypeData *, const TypeData * );
     269        void checkSpecifiers( DeclarationNode * );
     270        DeclarationNode * copySpecifiers( DeclarationNode * );
     271        DeclarationNode * addType( DeclarationNode * );
     272        DeclarationNode * addTypedef();
     273        DeclarationNode * addEnumBase( DeclarationNode * );
     274        DeclarationNode * addAssertions( DeclarationNode * );
     275        DeclarationNode * addName( std::string * );
     276        DeclarationNode * addAsmName( DeclarationNode * );
     277        DeclarationNode * addBitfield( ExpressionNode * size );
     278        DeclarationNode * addVarArgs();
     279        DeclarationNode * addFunctionBody( StatementNode * body, ExpressionNode * with = nullptr );
     280        DeclarationNode * addOldDeclList( DeclarationNode * list );
     281        DeclarationNode * setBase( TypeData * newType );
     282        DeclarationNode * copyAttribute( DeclarationNode * attr );
     283        DeclarationNode * addPointer( DeclarationNode * qualifiers );
     284        DeclarationNode * addArray( DeclarationNode * array );
     285        DeclarationNode * addNewPointer( DeclarationNode * pointer );
     286        DeclarationNode * addNewArray( DeclarationNode * array );
     287        DeclarationNode * addParamList( DeclarationNode * list );
     288        DeclarationNode * addIdList( DeclarationNode * list ); // old-style functions
     289        DeclarationNode * addInitializer( InitializerNode * init );
     290        DeclarationNode * addTypeInitializer( DeclarationNode * init );
     291
     292        DeclarationNode * cloneType( std::string * newName );
     293        DeclarationNode * cloneBaseType( DeclarationNode * newdecl );
     294
     295        DeclarationNode * appendList( DeclarationNode * node ) {
     296                return (DeclarationNode *)set_last( node );
     297        }
     298
     299        virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
     300        virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
     301
     302        Declaration * build() const;
     303        Type * buildType() const;
     304
     305        LinkageSpec::Spec get_linkage() const { return linkage; }
     306        DeclarationNode * extractAggregate() const;
     307        bool has_enumeratorValue() const { return (bool)enumeratorValue; }
     308        ExpressionNode * consume_enumeratorValue() const { return const_cast<DeclarationNode *>(this)->enumeratorValue.release(); }
     309
     310        bool get_extension() const { return extension; }
     311        DeclarationNode * set_extension( bool exten ) { extension = exten; return this; }
     312
     313        bool get_inLine() const { return inLine; }
     314        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
     315
     316        DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
     317
     318        struct Variable_t {
     319//              const std::string * name;
     320                TypeDecl::Kind tyClass;
     321                DeclarationNode * assertions;
     322                DeclarationNode * initializer;
     323        };
     324        Variable_t variable;
     325
     326        struct Attr_t {
     327//              const std::string * name;
     328                ExpressionNode * expr;
     329                DeclarationNode * type;
     330        };
     331        Attr_t attr;
     332
     333        struct StaticAssert_t {
     334                ExpressionNode * condition;
     335                Expression * message;
     336        };
     337        StaticAssert_t assert;
     338
     339        BuiltinType builtin = NoBuiltinType;
     340
     341        TypeData * type = nullptr;
     342
     343        bool inLine = false;
     344        bool enumInLine = false;
     345        Type::FuncSpecifiers funcSpecs;
     346        Type::StorageClasses storageClasses;
     347
     348        ExpressionNode * bitfieldWidth = nullptr;
     349        std::unique_ptr<ExpressionNode> enumeratorValue;
     350        bool hasEllipsis = false;
     351        LinkageSpec::Spec linkage;
     352        Expression * asmName = nullptr;
     353        std::list< Attribute * > attributes;
     354        InitializerNode * initializer = nullptr;
     355        bool extension = false;
     356        std::string error;
     357        StatementNode * asmStmt = nullptr;
     358        StatementNode * directiveStmt = nullptr;
     359
     360        static UniqueName anonymous;
     361}; // DeclarationNode
     362
     363Type * buildType( TypeData * type );
     364
     365static inline Type * maybeMoveBuildType( const DeclarationNode * orig ) {
     366        Type * ret = orig ? orig->buildType() : nullptr;
     367        delete orig;
     368        return ret;
     369}
     370
     371//##############################################################################
     372
     373struct StatementNode final : public ParseNode {
     374        StatementNode() { stmt = nullptr; }
     375        StatementNode( Statement * stmt ) : stmt( stmt ) {}
     376        StatementNode( DeclarationNode * decl );
     377        virtual ~StatementNode() {}
     378
     379        virtual StatementNode * clone() const final { assert( false ); return nullptr; }
     380        Statement * build() const { return const_cast<StatementNode *>(this)->stmt.release(); }
     381
     382        virtual StatementNode * add_label( const std::string * name, DeclarationNode * attr = nullptr ) {
     383                stmt->get_labels().emplace_back( * name, nullptr, attr ? std::move( attr->attributes ) : std::list< Attribute * > {} );
     384                delete attr;
     385                delete name;
     386                return this;
     387        }
     388
     389        virtual StatementNode * append_last_case( StatementNode * );
     390
     391        virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
     392                os << stmt.get() << std::endl;
     393        }
     394
     395        std::unique_ptr<Statement> stmt;
     396}; // StatementNode
     397
     398Statement * build_expr( ExpressionNode * ctl );
     399
     400struct CondCtl {
     401        CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :
     402                init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {}
     403
     404        StatementNode * init;
     405        ExpressionNode * condition;
     406};
     407
     408struct ForCtrl {
     409        ForCtrl( ExpressionNode * expr, ExpressionNode * condition, ExpressionNode * change ) :
     410                init( new StatementNode( build_expr( expr ) ) ), condition( condition ), change( change ) {}
     411        ForCtrl( DeclarationNode * decl, ExpressionNode * condition, ExpressionNode * change ) :
     412                init( new StatementNode( decl ) ), condition( condition ), change( change ) {}
     413
     414        StatementNode * init;
     415        ExpressionNode * condition;
     416        ExpressionNode * change;
     417};
     418
     419Expression * build_if_control( CondCtl * ctl, std::list< Statement * > & init );
     420Statement * build_if( CondCtl * ctl, StatementNode * then, StatementNode * else_ );
     421Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt );
     422Statement * build_case( ExpressionNode * ctl );
     423Statement * build_default();
     424Statement * build_while( CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
     425Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
     426Statement * build_for( ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
     427Statement * build_branch( BranchStmt::Type kind );
     428Statement * build_branch( std::string * identifier, BranchStmt::Type kind );
     429Statement * build_computedgoto( ExpressionNode * ctl );
     430Statement * build_return( ExpressionNode * ctl );
     431Statement * build_throw( ExpressionNode * ctl );
     432Statement * build_resume( ExpressionNode * ctl );
     433Statement * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
     434Statement * build_try( StatementNode * try_, StatementNode * catch_, StatementNode * finally_ );
     435Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
     436Statement * build_finally( StatementNode * stmt );
     437Statement * build_compound( StatementNode * first );
     438StatementNode * maybe_build_compound( StatementNode * first );
     439Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
     440Statement * build_directive( std::string * directive );
     441SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
     442WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
     443WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
     444WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when );
     445WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when, StatementNode * else_stmt, ExpressionNode * else_when );
     446Statement * build_with( ExpressionNode * exprs, StatementNode * stmt );
     447Statement * build_mutex( ExpressionNode * exprs, StatementNode * stmt );
     448
     449//##############################################################################
     450
     451template< typename SynTreeType, typename NodeType, template< typename, typename...> class Container, typename... Args >
     452void buildList( const NodeType * firstNode, Container< SynTreeType *, Args... > & outputList ) {
     453        SemanticErrorException errors;
     454        std::back_insert_iterator< Container< SynTreeType *, Args... > > out( outputList );
     455        const NodeType * cur = firstNode;
     456
     457        while ( cur ) {
     458                try {
     459                        SynTreeType * result = dynamic_cast< SynTreeType * >( maybeBuild< typename std::pointer_traits< decltype(cur->build())>::element_type >( cur ) );
     460                        if ( result ) {
     461                                result->location = cur->location;
     462                                * out++ = result;
     463                        } else {
     464                                SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
     465                        } // if
     466                } catch( SemanticErrorException & e ) {
     467                        errors.append( e );
     468                } // try
     469                const ParseNode * temp = (cur->get_next());
     470                cur = dynamic_cast< const NodeType * >( temp ); // should not return nullptr
     471                if ( ! cur && temp ) {                                                  // non-homogeneous nodes ?
     472                        SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );
     473                } // if
     474        } // while
     475        if ( ! errors.isEmpty() ) {
     476                throw errors;
     477        } // if
     478}
     479
     480// in DeclarationNode.cc
     481void buildList( const DeclarationNode * firstNode, std::list< Declaration * > & outputList );
     482void buildList( const DeclarationNode * firstNode, std::list< DeclarationWithType * > & outputList );
     483void buildTypeList( const DeclarationNode * firstNode, std::list< Type * > & outputList );
     484
     485template< typename SynTreeType, typename NodeType >
     486void buildMoveList( const NodeType * firstNode, std::list< SynTreeType * > & outputList ) {
     487        buildList( firstNode, outputList );
     488        delete firstNode;
     489}
     490
     491// in ParseNode.cc
    101492std::ostream & operator<<( std::ostream & out, const ParseNode * node );
    102493
  • src/Parser/ParserTypes.h

    rb110bcc r2ed94a9  
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 //
    7 // parser.hh --
    8 //
     6// 
     7// parser.hh -- 
     8// 
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Sep 22 08:58:10 2001
  • src/Parser/RunParser.cpp

    rb110bcc r2ed94a9  
    1010// Created On       : Mon Dec 19 11:00:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Mar  6  9:42:00 2023
    13 // Update Count     : 3
     12// Last Modified On : Thr Dec 22 10:18:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    2020#include "CodeTools/TrackLoc.h"             // for fillLocations
    2121#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    22 #include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
     22#include "Parser/ParseNode.h"               // for DeclarationNode, buildList
    2323#include "Parser/TypedefTable.h"            // for TypedefTable
    2424
    2525// Variables global to the parsing code.
    26 ast::Linkage::Spec linkage = ast::Linkage::Cforall;
     26LinkageSpec::Spec linkage = LinkageSpec::Cforall;
    2727TypedefTable typedefTable;
    2828DeclarationNode * parseTree = nullptr;
    2929
    30 void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit ) {
     30void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit ) {
    3131        extern int yyparse( void );
    3232        extern FILE * yyin;
     
    4646
    4747ast::TranslationUnit buildUnit(void) {
    48         std::vector<ast::ptr<ast::Decl>> decls;
    49         buildList( parseTree, decls );
     48        std::list<Declaration *> translationUnit;
     49        buildList( parseTree, translationUnit );
     50
    5051        delete parseTree;
    5152        parseTree = nullptr;
    5253
    53         ast::TranslationUnit transUnit;
    54         for ( auto decl : decls ) {
    55                 transUnit.decls.emplace_back( std::move( decl ) );
    56         }
     54        // When the parse/buildList code is translated to the new ast, these
     55        // fill passes (and the one after 'Hoist Type Decls') should be redundent
     56        // because the code locations should already be filled.
     57        CodeTools::fillLocations( translationUnit );
     58        ast::TranslationUnit transUnit = convert( std::move( translationUnit ) );
     59        forceFillCodeLocations( transUnit );
    5760        return transUnit;
    5861}
  • src/Parser/RunParser.hpp

    rb110bcc r2ed94a9  
    1010// Created On       : Mon Dec 19 10:42:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Feb 16 10:08:00 2023
    13 // Update Count     : 2
     12// Last Modified On : Thr Dec 22 10:23:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    1818#include <iosfwd>                           // for ostream
    1919
    20 #include "AST/LinkageSpec.hpp"              // for Spec
     20#include "SynTree/LinkageSpec.h"            // for Spec
    2121namespace ast {
    2222        class TranslationUnit;
     
    2929/// The input file is closed when complete. Exits instead of returning on
    3030/// error or if alwaysExit is true.
    31 void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit = false );
     31void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit = false );
    3232
    3333/// Drain the internal accumulator of parsed code and build a translation
  • src/Parser/StatementNode.cc

    rb110bcc r2ed94a9  
    1010// Author           : Rodolfo G. Esteves
    1111// Created On       : Sat May 16 14:59:41 2015
    12 // Last Modified By : Andrew Beach
    13 // Last Modified On : Tue Apr 11 10:16:00 2023
    14 // Update Count     : 428
    15 //
    16 
    17 #include "StatementNode.h"
     12// Last Modified By : Peter A. Buhr
     13// Last Modified On : Wed Feb  2 20:29:30 2022
     14// Update Count     : 425
     15//
    1816
    1917#include <cassert>                 // for assert, strict_dynamic_cast, assertf
     18#include <list>                    // for list
    2019#include <memory>                  // for unique_ptr
    2120#include <string>                  // for string
    2221
    23 #include "AST/Label.hpp"           // for Label
    24 #include "AST/Stmt.hpp"            // for Stmt, AsmStmt, BranchStmt, CaseCla...
    2522#include "Common/SemanticError.h"  // for SemanticError
    2623#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
    27 #include "DeclarationNode.h"       // for DeclarationNode
    28 #include "ExpressionNode.h"        // for ExpressionNode
     24#include "ParseNode.h"             // for StatementNode, ExpressionNode, bui...
     25#include "SynTree/Expression.h"    // for Expression, ConstantExpr
     26#include "SynTree/Label.h"         // for Label, noLabels
     27#include "SynTree/Declaration.h"
     28#include "SynTree/Statement.h"     // for Statement, BranchStmt, CaseStmt
    2929#include "parserutility.h"         // for notZeroExpr
    3030
     
    3333using namespace std;
    3434
    35 // Some helpers for cases that really want a single node but check for lists.
    36 static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
    37         std::vector<ast::ptr<ast::Stmt>> list;
    38         buildMoveList( node, list );
    39         assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
    40         return list.front().release();
    41 }
    42 
    43 static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
    44         std::vector<ast::ptr<ast::Stmt>> list;
    45         buildMoveList( node, list );
    46         assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
    47         return list.empty() ? nullptr : list.front().release();
    48 }
    4935
    5036StatementNode::StatementNode( DeclarationNode * decl ) {
     
    5238        DeclarationNode * agg = decl->extractAggregate();
    5339        if ( agg ) {
    54                 StatementNode * nextStmt = new StatementNode(
    55                         new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
     40                StatementNode * nextStmt = new StatementNode( new DeclStmt( maybeBuild< Declaration >( decl ) ) );
    5641                set_next( nextStmt );
    5742                if ( decl->get_next() ) {
     
    6651                agg = decl;
    6752        } // if
    68         // Local copy to avoid accessing the pointer after it is moved from.
    69         CodeLocation declLocation = agg->location;
    70         stmt.reset( new ast::DeclStmt( declLocation, maybeMoveBuild( agg ) ) );
     53        stmt.reset( new DeclStmt( maybeMoveBuild< Declaration >(agg) ) );
    7154} // StatementNode::StatementNode
    7255
    73 StatementNode * StatementNode::add_label(
    74                 const CodeLocation & location,
    75                 const std::string * name,
    76                 DeclarationNode * attr ) {
    77         stmt->labels.emplace_back( location,
    78                 *name,
    79                 attr ? std::move( attr->attributes )
    80                         : std::vector<ast::ptr<ast::Attribute>>{} );
    81         delete attr;
    82         delete name;
    83         return this;
    84 }
    85 
    86 ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
    87         ClauseNode * prev = this;
     56StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
     57        StatementNode * prev = this;
    8858        // find end of list and maintain previous pointer
    89         for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
    90                 ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
    91                 assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
     59        for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) {
     60                StatementNode * node = strict_dynamic_cast< StatementNode * >(curr);
     61                assert( dynamic_cast< CaseStmt * >(node->stmt.get()) );
    9262                prev = curr;
    9363        } // for
    94         ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
    9564        // convert from StatementNode list to Statement list
    96         std::vector<ast::ptr<ast::Stmt>> stmts;
     65        StatementNode * node = dynamic_cast< StatementNode * >(prev);
     66        list< Statement * > stmts;
    9767        buildMoveList( stmt, stmts );
    9868        // splice any new Statements to end of current Statements
    99         auto caseStmt = strict_dynamic_cast<ast::CaseClause *>( node->clause.get() );
    100         for ( auto const & newStmt : stmts ) {
    101                 caseStmt->stmts.emplace_back( newStmt );
    102         }
    103         stmts.clear();
     69        CaseStmt * caseStmt = dynamic_cast< CaseStmt * >(node->stmt.get());
     70        caseStmt->get_statements().splice( caseStmt->get_statements().end(), stmts );
    10471        return this;
    105 } // ClauseNode::append_last_case
    106 
    107 ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
    108         if ( ast::Expr * e = maybeMoveBuild( ctl ) ) {
    109                 return new ast::ExprStmt( location, e );
    110         } else {
    111                 return new ast::NullStmt( location );
    112         }
     72} // StatementNode::append_last_case
     73
     74Statement * build_expr( ExpressionNode * ctl ) {
     75        Expression * e = maybeMoveBuild< Expression >( ctl );
     76
     77        if ( e ) return new ExprStmt( e );
     78        else return new NullStmt();
    11379} // build_expr
    11480
    115 static ast::Expr * build_if_control( CondCtl * ctl,
    116                 std::vector<ast::ptr<ast::Stmt>> & inits ) {
    117         assert( inits.empty() );
    118         if ( nullptr != ctl->init ) {
    119                 buildMoveList( ctl->init, inits );
    120         } // if
    121 
    122         ast::Expr * cond = nullptr;
     81Expression * build_if_control( CondCtl * ctl, list< Statement * > & init ) {
     82        if ( ctl->init != 0 ) {
     83                buildMoveList( ctl->init, init );
     84        } // if
     85
     86        Expression * cond = nullptr;
    12387        if ( ctl->condition ) {
    12488                // compare the provided condition against 0
    125                 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
     89                cond = notZeroExpr( maybeMoveBuild< Expression >(ctl->condition) );
    12690        } else {
    127                 for ( ast::ptr<ast::Stmt> & stmt : inits ) {
     91                for ( Statement * stmt : init ) {
    12892                        // build the && of all of the declared variables compared against 0
    129                         auto declStmt = stmt.strict_as<ast::DeclStmt>();
    130                         auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
    131                         ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
    132                         cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
     93                        DeclStmt * declStmt = strict_dynamic_cast< DeclStmt * >( stmt );
     94                        DeclarationWithType * dwt = strict_dynamic_cast< DeclarationWithType * >( declStmt->decl );
     95                        Expression * nze = notZeroExpr( new VariableExpr( dwt ) );
     96                        cond = cond ? new LogicalExpr( cond, nze, true ) : nze;
    13397                }
    13498        }
     
    137101} // build_if_control
    138102
    139 ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
    140         std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
    141         ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    142 
    143         ast::Stmt const * astthen = buildMoveSingle( then );
    144         ast::Stmt const * astelse = buildMoveOptional( else_ );
    145 
    146         return new ast::IfStmt( location, astcond, astthen, astelse,
    147                 std::move( astinit )
    148         );
     103Statement * build_if( CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
     104        list< Statement * > astinit;                                            // maybe empty
     105        Expression * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
     106
     107        Statement * astthen, * astelse = nullptr;
     108        list< Statement * > aststmt;
     109        buildMoveList< Statement, StatementNode >( then, aststmt );
     110        assert( aststmt.size() == 1 );
     111        astthen = aststmt.front();
     112
     113        if ( else_ ) {
     114                list< Statement * > aststmt;
     115                buildMoveList< Statement, StatementNode >( else_, aststmt );
     116                assert( aststmt.size() == 1 );
     117                astelse = aststmt.front();
     118        } // if
     119
     120        return new IfStmt( astcond, astthen, astelse, astinit );
    149121} // build_if
    150122
    151 ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
    152         std::vector<ast::ptr<ast::CaseClause>> aststmt;
    153         buildMoveList( stmt, aststmt );
    154         // If it is not a switch it is a choose statement.
    155         if ( ! isSwitch ) {
    156                 for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) {
    157                         // Code after "case" is the end of case list.
    158                         if ( !stmt->stmts.empty() ) {
    159                                 auto mutStmt = ast::mutate( stmt.get() );
    160                                 // I believe the stmts are actually always one block.
    161                                 auto stmts = mutStmt->stmts.front().get_and_mutate();
    162                                 auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts );
    163                                 block->kids.push_back( new ast::BranchStmt( block->location,
    164                                         ast::BranchStmt::Break,
    165                                         ast::Label( block->location ) ) );
    166                                 stmt = mutStmt;
     123Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
     124        list< Statement * > aststmt;
     125        buildMoveList< Statement, StatementNode >( stmt, aststmt );
     126        if ( ! isSwitch ) {                                                                     // choose statement
     127                for ( Statement * stmt : aststmt ) {
     128                        CaseStmt * caseStmt = strict_dynamic_cast< CaseStmt * >( stmt );
     129                        if ( ! caseStmt->stmts.empty() ) {                      // code after "case" => end of case list
     130                                CompoundStmt * block = strict_dynamic_cast< CompoundStmt * >( caseStmt->stmts.front() );
     131                                block->kids.push_back( new BranchStmt( "", BranchStmt::Break ) );
    167132                        } // if
    168133                } // for
    169134        } // if
    170135        // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
    171         return new ast::SwitchStmt( location,
    172                 maybeMoveBuild( ctl ), std::move( aststmt ) );
     136        return new SwitchStmt( maybeMoveBuild< Expression >(ctl), aststmt );
    173137} // build_switch
    174138
    175 ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
    176         // stmt starts empty and then added to
    177         auto expr = maybeMoveBuild( ctl );
    178         return new ast::CaseClause( location, expr, {} );
     139Statement * build_case( ExpressionNode * ctl ) {
     140        return new CaseStmt( maybeMoveBuild< Expression >(ctl), {} ); // stmt starts empty and then added to
    179141} // build_case
    180142
    181 ast::CaseClause * build_default( const CodeLocation & location ) {
    182         // stmt starts empty and then added to
    183         return new ast::CaseClause( location, nullptr, {} );
     143Statement * build_default() {
     144        return new CaseStmt( nullptr, {}, true );                       // stmt starts empty and then added to
    184145} // build_default
    185146
    186 ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
    187         std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
    188         ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    189 
    190         return new ast::WhileDoStmt( location,
    191                 astcond,
    192                 buildMoveSingle( stmt ),
    193                 buildMoveOptional( else_ ),
    194                 std::move( astinit ),
    195                 ast::While
    196         );
     147Statement * build_while( CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
     148        list< Statement * > astinit;                                            // maybe empty
     149        Expression * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
     150
     151        list< Statement * > aststmt;                                            // loop body, compound created if empty
     152        buildMoveList< Statement, StatementNode >( stmt, aststmt );
     153        assert( aststmt.size() == 1 );
     154
     155        list< Statement * > astelse;                                            // else clause, maybe empty
     156        buildMoveList< Statement, StatementNode >( else_, astelse );
     157
     158        return new WhileDoStmt( astcond, aststmt.front(), astelse.front(), astinit, false );
    197159} // build_while
    198160
    199 ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
     161Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
     162        list< Statement * > aststmt;                                            // loop body, compound created if empty
     163        buildMoveList< Statement, StatementNode >( stmt, aststmt );
     164        assert( aststmt.size() == 1 );                                          // compound created if empty
     165
     166        list< Statement * > astelse;                                            // else clause, maybe empty
     167        buildMoveList< Statement, StatementNode >( else_, astelse );
     168
    200169        // do-while cannot have declarations in the contitional, so init is always empty
    201         return new ast::WhileDoStmt( location,
    202                 notZeroExpr( maybeMoveBuild( ctl ) ),
    203                 buildMoveSingle( stmt ),
    204                 buildMoveOptional( else_ ),
    205                 {},
    206                 ast::DoWhile
    207         );
     170        return new WhileDoStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), aststmt.front(), astelse.front(), {}, true );
    208171} // build_do_while
    209172
    210 ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
    211         std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
     173Statement * build_for( ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
     174        list< Statement * > astinit;                                            // maybe empty
    212175        buildMoveList( forctl->init, astinit );
    213176
    214         ast::Expr * astcond = nullptr;                                          // maybe empty
    215         astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
    216 
    217         ast::Expr * astincr = nullptr;                                          // maybe empty
    218         astincr = maybeMoveBuild( forctl->change );
     177        Expression * astcond = nullptr;                                         // maybe empty
     178        astcond = notZeroExpr( maybeMoveBuild< Expression >(forctl->condition) );
     179
     180        Expression * astincr = nullptr;                                         // maybe empty
     181        astincr = maybeMoveBuild< Expression >(forctl->change);
    219182        delete forctl;
    220183
    221         return new ast::ForStmt( location,
    222                 std::move( astinit ),
    223                 astcond,
    224                 astincr,
    225                 buildMoveSingle( stmt ),
    226                 buildMoveOptional( else_ )
    227         );
     184        list< Statement * > aststmt;                                            // loop body, compound created if empty
     185        buildMoveList< Statement, StatementNode >( stmt, aststmt );
     186        assert( aststmt.size() == 1 );
     187
     188        list< Statement * > astelse;                                            // else clause, maybe empty
     189        buildMoveList< Statement, StatementNode >( else_, astelse );
     190
     191        return new ForStmt( astinit, astcond, astincr, aststmt.front(), astelse.front() );
    228192} // build_for
    229193
    230 ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
    231         return new ast::BranchStmt( location,
    232                 kind,
    233                 ast::Label( location )
    234         );
     194Statement * build_branch( BranchStmt::Type kind ) {
     195        Statement * ret = new BranchStmt( "", kind );
     196        return ret;
    235197} // build_branch
    236198
    237 ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) {
    238         ast::Stmt * ret = new ast::BranchStmt( location,
    239                 kind,
    240                 ast::Label( location, *identifier )
    241         );
     199Statement * build_branch( string * identifier, BranchStmt::Type kind ) {
     200        Statement * ret = new BranchStmt( * identifier, kind );
    242201        delete identifier;                                                                      // allocated by lexer
    243202        return ret;
    244203} // build_branch
    245204
    246 ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
    247         ast::Expr * expr = maybeMoveBuild( ctl );
    248         return new ast::BranchStmt( expr->location, expr );
     205Statement * build_computedgoto( ExpressionNode * ctl ) {
     206        return new BranchStmt( maybeMoveBuild< Expression >(ctl), BranchStmt::Goto );
    249207} // build_computedgoto
    250208
    251 ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
    252         std::vector<ast::ptr<ast::Expr>> exps;
     209Statement * build_return( ExpressionNode * ctl ) {
     210        list< Expression * > exps;
    253211        buildMoveList( ctl, exps );
    254         return new ast::ReturnStmt( location,
    255                 exps.size() > 0 ? exps.back().release() : nullptr
    256         );
     212        return new ReturnStmt( exps.size() > 0 ? exps.back() : nullptr );
    257213} // build_return
    258214
    259 static ast::Stmt * build_throw_stmt(
    260                 const CodeLocation & location,
    261                 ExpressionNode * ctl,
    262                 ast::ExceptionKind kind ) {
    263         std::vector<ast::ptr<ast::Expr>> exps;
     215Statement * build_throw( ExpressionNode * ctl ) {
     216        list< Expression * > exps;
    264217        buildMoveList( ctl, exps );
    265218        assertf( exps.size() < 2, "CFA internal error: leaking memory" );
    266         return new ast::ThrowStmt( location,
    267                 kind,
    268                 !exps.empty() ? exps.back().release() : nullptr,
    269                 (ast::Expr *)nullptr
    270         );
    271 }
    272 
    273 ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
    274         return build_throw_stmt( loc, ctl, ast::Terminate );
     219        return new ThrowStmt( ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr );
    275220} // build_throw
    276221
    277 ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
    278         return build_throw_stmt( loc, ctl, ast::Resume );
     222Statement * build_resume( ExpressionNode * ctl ) {
     223        list< Expression * > exps;
     224        buildMoveList( ctl, exps );
     225        assertf( exps.size() < 2, "CFA internal error: leaking memory" );
     226        return new ThrowStmt( ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr );
    279227} // build_resume
    280228
    281 ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
     229Statement * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
    282230        (void)ctl;
    283231        (void)target;
     
    285233} // build_resume_at
    286234
    287 ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
    288         std::vector<ast::ptr<ast::CatchClause>> aststmt;
    289         buildMoveList( catch_, aststmt );
    290         ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
    291         ast::FinallyClause * finallyBlock = nullptr;
    292         if ( finally_ ) {
    293                 finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() );
     235Statement * build_try( StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
     236        list< CatchStmt * > aststmt;
     237        buildMoveList< CatchStmt, StatementNode >( catch_, aststmt );
     238        CompoundStmt * tryBlock = strict_dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(try_));
     239        FinallyStmt * finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_) );
     240        return new TryStmt( tryBlock, aststmt, finallyBlock );
     241} // build_try
     242
     243Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
     244        list< Statement * > aststmt;
     245        buildMoveList< Statement, StatementNode >( body, aststmt );
     246        assert( aststmt.size() == 1 );
     247        return new CatchStmt( kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), aststmt.front() );
     248} // build_catch
     249
     250Statement * build_finally( StatementNode * stmt ) {
     251        list< Statement * > aststmt;
     252        buildMoveList< Statement, StatementNode >( stmt, aststmt );
     253        assert( aststmt.size() == 1 );
     254        return new FinallyStmt( dynamic_cast< CompoundStmt * >( aststmt.front() ) );
     255} // build_finally
     256
     257SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) {
     258        auto node = new SuspendStmt();
     259
     260        node->type = type;
     261
     262        list< Statement * > stmts;
     263        buildMoveList< Statement, StatementNode >( then, stmts );
     264        if(!stmts.empty()) {
     265                assert( stmts.size() == 1 );
     266                node->then = dynamic_cast< CompoundStmt * >( stmts.front() );
    294267        }
    295         return new ast::TryStmt( location,
    296                 tryBlock,
    297                 std::move( aststmt ),
    298                 finallyBlock
    299         );
    300 } // build_try
    301 
    302 ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
    303         return new ast::CatchClause( location,
    304                 kind,
    305                 maybeMoveBuild( decl ),
    306                 maybeMoveBuild( cond ),
    307                 buildMoveSingle( body )
    308         );
    309 } // build_catch
    310 
    311 ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
    312         return new ast::FinallyClause( location,
    313                 strict_dynamic_cast<const ast::CompoundStmt *>(
    314                         buildMoveSingle( stmt )
    315                 )
    316         );
    317 } // build_finally
    318 
    319 ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
    320         return new ast::SuspendStmt( location,
    321                 strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
    322                         buildMoveOptional( then )
    323                 ),
    324                 kind
    325         );
    326 } // build_suspend
    327 
    328 ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
    329         auto clause = new ast::WaitForClause( location );
    330         clause->target_func = maybeBuild( targetExpr );
    331         clause->stmt = maybeMoveBuild( stmt );
    332         clause->cond = notZeroExpr( maybeMoveBuild( when ) );
     268
     269        return node;
     270}
     271
     272WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
     273        auto node = new WaitForStmt();
     274
     275        WaitForStmt::Target target;
     276        target.function = maybeBuild<Expression>( targetExpr );
    333277
    334278        ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
    335279        targetExpr->set_next( nullptr );
    336         buildMoveList( next, clause->target_args );
     280        buildMoveList< Expression >( next, target.arguments );
    337281
    338282        delete targetExpr;
    339283
    340         existing->clauses.insert( existing->clauses.begin(), clause );
    341 
    342         return existing;
     284        node->clauses.push_back( WaitForStmt::Clause{
     285                target,
     286                maybeMoveBuild<Statement >( stmt ),
     287                notZeroExpr( maybeMoveBuild<Expression>( when ) )
     288        });
     289
     290        return node;
    343291} // build_waitfor
    344292
    345 ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
    346         existing->else_stmt = maybeMoveBuild( stmt );
    347         existing->else_cond = notZeroExpr( maybeMoveBuild( when ) );
    348 
    349         (void)location;
    350         return existing;
    351 } // build_waitfor_else
    352 
    353 ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
    354         existing->timeout_time = maybeMoveBuild( timeout );
    355         existing->timeout_stmt = maybeMoveBuild( stmt );
    356         existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) );
    357 
    358         (void)location;
    359         return existing;
     293WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when, WaitForStmt * node ) {
     294        WaitForStmt::Target target;
     295        target.function = maybeBuild<Expression>( targetExpr );
     296
     297        ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
     298        targetExpr->set_next( nullptr );
     299        buildMoveList< Expression >( next, target.arguments );
     300
     301        delete targetExpr;
     302
     303        node->clauses.insert( node->clauses.begin(), WaitForStmt::Clause{
     304                std::move( target ),
     305                maybeMoveBuild<Statement >( stmt ),
     306                notZeroExpr( maybeMoveBuild<Expression>( when ) )
     307        });
     308
     309        return node;
     310} // build_waitfor
     311
     312WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when ) {
     313        auto node = new WaitForStmt();
     314
     315        if( timeout ) {
     316                node->timeout.time      = maybeMoveBuild<Expression>( timeout );
     317                node->timeout.statement = maybeMoveBuild<Statement >( stmt    );
     318                node->timeout.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) );
     319        } else {
     320                node->orelse.statement  = maybeMoveBuild<Statement >( stmt );
     321                node->orelse.condition  = notZeroExpr( maybeMoveBuild<Expression>( when ) );
     322        } // if
     323
     324        return node;
    360325} // build_waitfor_timeout
    361326
    362 ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
    363         std::vector<ast::ptr<ast::Expr>> e;
     327WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when,  StatementNode * else_, ExpressionNode * else_when ) {
     328        auto node = new WaitForStmt();
     329
     330        node->timeout.time      = maybeMoveBuild<Expression>( timeout );
     331        node->timeout.statement = maybeMoveBuild<Statement >( stmt    );
     332        node->timeout.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) );
     333
     334        node->orelse.statement  = maybeMoveBuild<Statement >( else_ );
     335        node->orelse.condition  = notZeroExpr( maybeMoveBuild<Expression>( else_when ) );
     336
     337        return node;
     338} // build_waitfor_timeout
     339
     340Statement * build_with( ExpressionNode * exprs, StatementNode * stmt ) {
     341        list< Expression * > e;
    364342        buildMoveList( exprs, e );
    365         ast::Stmt * s = maybeMoveBuild( stmt );
    366         return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
     343        Statement * s = maybeMoveBuild<Statement>( stmt );
     344        return new DeclStmt( new WithStmt( e, s ) );
    367345} // build_with
    368346
    369 ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
    370         auto cs = new ast::CompoundStmt( location );
    371         buildMoveList( first, cs->kids );
     347Statement * build_compound( StatementNode * first ) {
     348        CompoundStmt * cs = new CompoundStmt();
     349        buildMoveList( first, cs->get_kids() );
    372350        return cs;
    373351} // build_compound
     
    377355// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
    378356// conical form for code generation.
    379 StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
     357StatementNode * maybe_build_compound( StatementNode * first ) {
    380358        // Optimization: if the control-structure statement is a compound statement, do not wrap it.
    381359        // e.g., if (...) {...} do not wrap the existing compound statement.
    382         if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
    383                 return new StatementNode( build_compound( location, first ) );
     360        if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
     361                CompoundStmt * cs = new CompoundStmt();
     362                buildMoveList( first, cs->get_kids() );
     363                return new StatementNode( cs );
    384364        } // if
    385365        return first;
     
    387367
    388368// Question
    389 ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    390         std::vector<ast::ptr<ast::Expr>> out, in;
    391         std::vector<ast::ptr<ast::ConstantExpr>> clob;
     369Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
     370        list< Expression * > out, in;
     371        list< ConstantExpr * > clob;
    392372
    393373        buildMoveList( output, out );
    394374        buildMoveList( input, in );
    395375        buildMoveList( clobber, clob );
    396         return new ast::AsmStmt( location,
    397                 is_volatile,
    398                 maybeMoveBuild( instruction ),
    399                 std::move( out ),
    400                 std::move( in ),
    401                 std::move( clob ),
    402                 gotolabels ? gotolabels->labels : std::vector<ast::Label>()
    403         );
     376        return new AsmStmt( voltile, instruction, out, in, clob, gotolabels ? gotolabels->labels : noLabels );
    404377} // build_asm
    405378
    406 ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
    407         auto stmt = new ast::DirectiveStmt( location, *directive );
    408         delete directive;
    409         return stmt;
     379Statement * build_directive( string * directive ) {
     380        return new DirectiveStmt( *directive );
    410381} // build_directive
    411382
    412 ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
    413         std::vector<ast::ptr<ast::Expr>> expList;
     383Statement * build_mutex( ExpressionNode * exprs, StatementNode * stmt ) {
     384        list< Expression * > expList;
    414385        buildMoveList( exprs, expList );
    415         ast::Stmt * body = maybeMoveBuild( stmt );
    416         return new ast::MutexStmt( location, body, std::move( expList ) );
     386        Statement * body = maybeMoveBuild<Statement>( stmt );
     387        return new MutexStmt( body, expList );
    417388} // build_mutex
    418389
  • src/Parser/TypeData.cc

    rb110bcc r2ed94a9  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 15:12:51 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 13:39:00 2023
    13 // Update Count     : 680
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Tue May 10 22:36:52 2022
     13// Update Count     : 677
    1414//
    15 
    16 #include "TypeData.h"
    1715
    1816#include <cassert>                 // for assert
    1917#include <ostream>                 // for operator<<, ostream, basic_ostream
    2018
    21 #include "AST/Decl.hpp"            // for AggregateDecl, ObjectDecl, TypeDe...
    22 #include "AST/Init.hpp"            // for SingleInit, ListInit
    23 #include "AST/Print.hpp"           // for print
    2419#include "Common/SemanticError.h"  // for SemanticError
    25 #include "Common/utility.h"        // for splice, spliceBegin
    26 #include "Parser/ExpressionNode.h" // for ExpressionNode
    27 #include "Parser/StatementNode.h"  // for StatementNode
     20#include "Common/utility.h"        // for maybeClone, maybeBuild, maybeMoveB...
     21#include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
     22#include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, FunctionDecl
     23#include "SynTree/Expression.h"    // for Expression, ConstantExpr (ptr only)
     24#include "SynTree/Initializer.h"   // for SingleInit, Initializer (ptr only)
     25#include "SynTree/Statement.h"     // for CompoundStmt, Statement
     26#include "SynTree/Type.h"          // for BasicType, Type, Type::ForallList
     27#include "TypeData.h"
    2828
    2929class Attribute;
     
    3333TypeData::TypeData( Kind k ) : location( yylloc ), kind( k ), base( nullptr ), forall( nullptr ) /*, PTR1( (void*)(0xdeadbeefdeadbeef)), PTR2( (void*)(0xdeadbeefdeadbeef) ) */ {
    3434        switch ( kind ) {
    35         case Unknown:
    36         case Pointer:
    37         case Reference:
    38         case EnumConstant:
    39         case GlobalScope:
    40         case Basic:
    41                 // No unique data to initialize.
    42                 break;
    43         case Array:
     35          case Unknown:
     36          case Pointer:
     37          case Reference:
     38          case EnumConstant:
     39          case GlobalScope:
     40                // nothing else to initialize
     41                break;
     42          case Basic:
     43                // basic = new Basic_t;
     44                break;
     45          case Array:
     46                // array = new Array_t;
    4447                array.dimension = nullptr;
    4548                array.isVarLen = false;
    4649                array.isStatic = false;
    4750                break;
    48         case Function:
     51          case Function:
     52                // function = new Function_t;
    4953                function.params = nullptr;
    5054                function.idList = nullptr;
     
    5357                function.withExprs = nullptr;
    5458                break;
    55         case Enum:
     59                // Enum is an Aggregate, so both structures are initialized together.
     60          case Enum:
     61                // enumeration = new Enumeration_t;
    5662                enumeration.name = nullptr;
    5763                enumeration.constants = nullptr;
     
    5965                enumeration.anon = false;
    6066                break;
    61         case Aggregate:
    62                 aggregate.kind = ast::AggregateDecl::NoAggregate;
     67          case Aggregate:
     68                // aggregate = new Aggregate_t;
     69                aggregate.kind = AggregateDecl::NoAggregate;
    6370                aggregate.name = nullptr;
    6471                aggregate.params = nullptr;
     
    7077                aggregate.anon = false;
    7178                break;
    72         case AggregateInst:
     79          case AggregateInst:
     80                // aggInst = new AggInst_t;
    7381                aggInst.aggregate = nullptr;
    7482                aggInst.params = nullptr;
    7583                aggInst.hoistType = false;
    7684                break;
    77         case Symbolic:
    78         case SymbolicInst:
     85          case Symbolic:
     86          case SymbolicInst:
     87                // symbolic = new Symbolic_t;
    7988                symbolic.name = nullptr;
    8089                symbolic.params = nullptr;
     
    8291                symbolic.assertions = nullptr;
    8392                break;
    84         case Tuple:
     93          case Tuple:
     94                // tuple = new Tuple_t;
    8595                tuple = nullptr;
    8696                break;
    87         case Typeof:
    88         case Basetypeof:
     97          case Typeof:
     98          case Basetypeof:
     99                // typeexpr = new Typeof_t;
    89100                typeexpr = nullptr;
    90101                break;
    91         case Vtable:
    92         case Builtin:
    93                 // No unique data to initialize.
    94                 break;
    95         case Qualified:
     102          case Vtable:
     103                break;
     104          case Builtin:
     105                // builtin = new Builtin_t;
     106                case Qualified:
    96107                qualified.parent = nullptr;
    97108                qualified.child = nullptr;
     
    106117
    107118        switch ( kind ) {
    108         case Unknown:
    109         case Pointer:
    110         case Reference:
    111         case EnumConstant:
    112         case GlobalScope:
    113         case Basic:
    114                 // No unique data to deconstruct.
    115                 break;
    116         case Array:
     119          case Unknown:
     120          case Pointer:
     121          case Reference:
     122          case EnumConstant:
     123          case GlobalScope:
     124                // nothing to destroy
     125                break;
     126          case Basic:
     127                // delete basic;
     128                break;
     129          case Array:
    117130                delete array.dimension;
    118                 break;
    119         case Function:
     131                // delete array;
     132                break;
     133          case Function:
    120134                delete function.params;
    121135                delete function.idList;
     
    123137                delete function.body;
    124138                delete function.withExprs;
    125                 break;
    126         case Aggregate:
     139                // delete function;
     140                break;
     141          case Aggregate:
    127142                delete aggregate.name;
    128143                delete aggregate.params;
    129144                delete aggregate.actuals;
    130145                delete aggregate.fields;
    131                 break;
    132         case AggregateInst:
     146                // delete aggregate;
     147                break;
     148          case AggregateInst:
    133149                delete aggInst.aggregate;
    134150                delete aggInst.params;
    135                 break;
    136         case Enum:
     151                // delete aggInst;
     152                break;
     153          case Enum:
    137154                delete enumeration.name;
    138155                delete enumeration.constants;
    139                 break;
    140         case Symbolic:
    141         case SymbolicInst:
     156                // delete enumeration;
     157                break;
     158          case Symbolic:
     159          case SymbolicInst:
    142160                delete symbolic.name;
    143161                delete symbolic.params;
    144162                delete symbolic.actuals;
    145163                delete symbolic.assertions;
    146                 break;
    147         case Tuple:
     164                // delete symbolic;
     165                break;
     166          case Tuple:
     167                // delete tuple->members;
    148168                delete tuple;
    149169                break;
    150         case Typeof:
    151         case Basetypeof:
     170          case Typeof:
     171          case Basetypeof:
     172                // delete typeexpr->expr;
    152173                delete typeexpr;
    153174                break;
    154         case Vtable:
    155         case Builtin:
    156                 // No unique data to deconstruct.
    157                 break;
    158         case Qualified:
     175          case Vtable:
     176                break;
     177          case Builtin:
     178                // delete builtin;
     179                break;
     180          case Qualified:
    159181                delete qualified.parent;
    160182                delete qualified.child;
    161                 break;
    162183        } // switch
    163184} // TypeData::~TypeData
     
    171192
    172193        switch ( kind ) {
    173         case Unknown:
    174         case EnumConstant:
    175         case Pointer:
    176         case Reference:
    177         case GlobalScope:
     194          case Unknown:
     195          case EnumConstant:
     196          case Pointer:
     197          case Reference:
     198          case GlobalScope:
    178199                // nothing else to copy
    179200                break;
    180         case Basic:
     201          case Basic:
    181202                newtype->basictype = basictype;
    182203                newtype->complextype = complextype;
     
    184205                newtype->length = length;
    185206                break;
    186         case Array:
     207          case Array:
    187208                newtype->array.dimension = maybeClone( array.dimension );
    188209                newtype->array.isVarLen = array.isVarLen;
    189210                newtype->array.isStatic = array.isStatic;
    190211                break;
    191         case Function:
     212          case Function:
    192213                newtype->function.params = maybeClone( function.params );
    193214                newtype->function.idList = maybeClone( function.idList );
     
    196217                newtype->function.withExprs = maybeClone( function.withExprs );
    197218                break;
    198         case Aggregate:
     219          case Aggregate:
    199220                newtype->aggregate.kind = aggregate.kind;
    200221                newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
     
    207228                newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
    208229                break;
    209         case AggregateInst:
     230          case AggregateInst:
    210231                newtype->aggInst.aggregate = maybeClone( aggInst.aggregate );
    211232                newtype->aggInst.params = maybeClone( aggInst.params );
    212233                newtype->aggInst.hoistType = aggInst.hoistType;
    213234                break;
    214         case Enum:
     235          case Enum:
    215236                newtype->enumeration.name = enumeration.name ? new string( *enumeration.name ) : nullptr;
    216237                newtype->enumeration.constants = maybeClone( enumeration.constants );
     
    218239                newtype->enumeration.anon = enumeration.anon;
    219240                break;
    220         case Symbolic:
    221         case SymbolicInst:
     241          case Symbolic:
     242          case SymbolicInst:
    222243                newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr;
    223244                newtype->symbolic.params = maybeClone( symbolic.params );
     
    226247                newtype->symbolic.isTypedef = symbolic.isTypedef;
    227248                break;
    228         case Tuple:
     249          case Tuple:
    229250                newtype->tuple = maybeClone( tuple );
    230251                break;
    231         case Typeof:
    232         case Basetypeof:
     252          case Typeof:
     253          case Basetypeof:
    233254                newtype->typeexpr = maybeClone( typeexpr );
    234255                break;
    235         case Vtable:
    236                 break;
    237         case Builtin:
     256          case Vtable:
     257                break;
     258          case Builtin:
    238259                assert( builtintype == DeclarationNode::Zero || builtintype == DeclarationNode::One );
    239260                newtype->builtintype = builtintype;
    240261                break;
    241         case Qualified:
     262                case Qualified:
    242263                newtype->qualified.parent = maybeClone( qualified.parent );
    243264                newtype->qualified.child = maybeClone( qualified.child );
     
    249270
    250271void TypeData::print( ostream &os, int indent ) const {
    251         ast::print( os, qualifiers );
     272        for ( int i = 0; i < Type::NumTypeQualifier; i += 1 ) {
     273                if ( qualifiers[i] ) os << Type::QualifiersNames[ i ] << ' ';
     274        } // for
    252275
    253276        if ( forall ) {
     
    257280
    258281        switch ( kind ) {
    259         case Basic:
     282          case Basic:
    260283                if ( signedness != DeclarationNode::NoSignedness ) os << DeclarationNode::signednessNames[ signedness ] << " ";
    261284                if ( length != DeclarationNode::NoLength ) os << DeclarationNode::lengthNames[ length ] << " ";
     
    263286                if ( basictype != DeclarationNode::NoBasicType ) os << DeclarationNode::basicTypeNames[ basictype ] << " ";
    264287                break;
    265         case Pointer:
     288          case Pointer:
    266289                os << "pointer ";
    267290                if ( base ) {
     
    270293                } // if
    271294                break;
    272         case Reference:
     295          case Reference:
    273296                os << "reference ";
    274297                if ( base ) {
     
    277300                } // if
    278301                break;
    279         case Array:
     302          case Array:
    280303                if ( array.isStatic ) {
    281304                        os << "static ";
     
    293316                } // if
    294317                break;
    295         case Function:
     318          case Function:
    296319                os << "function" << endl;
    297320                if ( function.params ) {
     
    321344                } // if
    322345                break;
    323         case Aggregate:
    324                 os << ast::AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
     346          case Aggregate:
     347                os << AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
    325348                if ( aggregate.params ) {
    326349                        os << string( indent + 2, ' ' ) << "with type parameters" << endl;
     
    339362                } // if
    340363                break;
    341         case AggregateInst:
     364          case AggregateInst:
    342365                if ( aggInst.aggregate ) {
    343366                        os << "instance of " ;
     
    351374                } // if
    352375                break;
    353         case Enum:
    354                 os << "enumeration " << *enumeration.name << endl;;
     376          case Enum:
     377                os << "enumeration ";
    355378                if ( enumeration.constants ) {
    356379                        os << "with constants" << endl;
     
    365388                } // if
    366389                break;
    367         case EnumConstant:
     390          case EnumConstant:
    368391                os << "enumeration constant ";
    369392                break;
    370         case Symbolic:
     393          case Symbolic:
    371394                if ( symbolic.isTypedef ) {
    372395                        os << "typedef definition ";
     
    388411                } // if
    389412                break;
    390         case SymbolicInst:
     413          case SymbolicInst:
    391414                os << *symbolic.name;
    392415                if ( symbolic.actuals ) {
     
    396419                } // if
    397420                break;
    398         case Tuple:
     421          case Tuple:
    399422                os << "tuple ";
    400423                if ( tuple ) {
     
    403426                } // if
    404427                break;
    405         case Basetypeof:
     428          case Basetypeof:
    406429                os << "base-";
    407430                #if defined(__GNUC__) && __GNUC__ >= 7
     
    409432                #endif
    410433                // FALL THROUGH
    411         case Typeof:
     434          case Typeof:
    412435                os << "type-of expression ";
    413436                if ( typeexpr ) {
     
    415438                } // if
    416439                break;
    417         case Vtable:
     440          case Vtable:
    418441                os << "vtable";
    419442                break;
    420         case Builtin:
     443          case Builtin:
    421444                os << DeclarationNode::builtinTypeNames[builtintype];
    422445                break;
    423         case GlobalScope:
    424                 break;
    425         case Qualified:
     446          case GlobalScope:
     447                break;
     448          case Qualified:
    426449                qualified.parent->print( os );
    427450                os << ".";
    428451                qualified.child->print( os );
    429452                break;
    430         case Unknown:
     453          case Unknown:
    431454                os << "entity of unknown type ";
    432455                break;
    433         default:
     456          default:
    434457                os << "internal error: TypeData::print " << kind << endl;
    435458                assert( false );
     
    439462const std::string * TypeData::leafName() const {
    440463        switch ( kind ) {
    441         case Unknown:
    442         case Pointer:
    443         case Reference:
    444         case EnumConstant:
    445         case GlobalScope:
    446         case Array:
    447         case Basic:
    448         case Function:
    449         case AggregateInst:
    450         case Tuple:
    451         case Typeof:
    452         case Basetypeof:
    453         case Builtin:
    454         case Vtable:
     464          case Unknown:
     465          case Pointer:
     466          case Reference:
     467          case EnumConstant:
     468          case GlobalScope:
     469          case Array:
     470          case Basic:
     471          case Function:
     472          case AggregateInst:
     473          case Tuple:
     474          case Typeof:
     475          case Basetypeof:
     476          case Builtin:
     477          case Vtable:
    455478                assertf(false, "Tried to get leaf name from kind without a name: %d", kind);
    456479                break;
    457         case Aggregate:
     480          case Aggregate:
    458481                return aggregate.name;
    459         case Enum:
     482          case Enum:
    460483                return enumeration.name;
    461         case Symbolic:
    462         case SymbolicInst:
     484          case Symbolic:
     485          case SymbolicInst:
    463486                return symbolic.name;
    464         case Qualified:
     487          case Qualified:
    465488                return qualified.child->leafName();
    466489        } // switch
     
    469492
    470493
    471 void buildForall(
    472                 const DeclarationNode * firstNode,
    473                 std::vector<ast::ptr<ast::TypeInstType>> &outputList ) {
    474         {
    475                 std::vector<ast::ptr<ast::Type>> tmpList;
    476                 buildTypeList( firstNode, tmpList );
    477                 for ( auto tmp : tmpList ) {
    478                         outputList.emplace_back(
    479                                 strict_dynamic_cast<const ast::TypeInstType *>(
    480                                         tmp.release() ) );
    481                 }
    482         }
     494template< typename ForallList >
     495void buildForall( const DeclarationNode * firstNode, ForallList &outputList ) {
     496        buildList( firstNode, outputList );
    483497        auto n = firstNode;
    484         for ( auto i = outputList.begin() ;
    485                         i != outputList.end() ;
    486                         ++i, n = (DeclarationNode*)n->get_next() ) {
    487                 // Only the object type class adds additional assertions.
    488                 if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
    489                         continue;
    490                 }
    491 
    492                 ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
    493                 std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
    494                 auto mutTypeDecl = ast::mutate( td );
    495                 const CodeLocation & location = mutTypeDecl->location;
    496                 *i = mutTypeDecl;
    497 
    498                 // add assertion parameters to `type' tyvars in reverse order
    499                 // add assignment operator:  T * ?=?(T *, T)
    500                 newAssertions.push_back( new ast::FunctionDecl(
    501                         location,
    502                         "?=?",
    503                         {}, // forall
    504                         {}, // assertions
    505                         {
    506                                 new ast::ObjectDecl(
    507                                         location,
    508                                         "",
    509                                         new ast::ReferenceType( i->get() ),
    510                                         (ast::Init *)nullptr,
    511                                         ast::Storage::Classes(),
    512                                         ast::Linkage::Cforall,
    513                                         (ast::Expr *)nullptr
    514                                 ),
    515                                 new ast::ObjectDecl(
    516                                         location,
    517                                         "",
    518                                         i->get(),
    519                                         (ast::Init *)nullptr,
    520                                         ast::Storage::Classes(),
    521                                         ast::Linkage::Cforall,
    522                                         (ast::Expr *)nullptr
    523                                 ),
    524                         }, // params
    525                         {
    526                                 new ast::ObjectDecl(
    527                                         location,
    528                                         "",
    529                                         i->get(),
    530                                         (ast::Init *)nullptr,
    531                                         ast::Storage::Classes(),
    532                                         ast::Linkage::Cforall,
    533                                         (ast::Expr *)nullptr
    534                                 ),
    535                         }, // returns
    536                         (ast::CompoundStmt *)nullptr,
    537                         ast::Storage::Classes(),
    538                         ast::Linkage::Cforall
    539                 ) );
    540 
    541                 // add default ctor:  void ?{}(T *)
    542                 newAssertions.push_back( new ast::FunctionDecl(
    543                         location,
    544                         "?{}",
    545                         {}, // forall
    546                         {}, // assertions
    547                         {
    548                                 new ast::ObjectDecl(
    549                                         location,
    550                                         "",
    551                                         new ast::ReferenceType( i->get() ),
    552                                         (ast::Init *)nullptr,
    553                                         ast::Storage::Classes(),
    554                                         ast::Linkage::Cforall,
    555                                         (ast::Expr *)nullptr
    556                                 ),
    557                         }, // params
    558                         {}, // returns
    559                         (ast::CompoundStmt *)nullptr,
    560                         ast::Storage::Classes(),
    561                         ast::Linkage::Cforall
    562                 ) );
    563 
    564                 // add copy ctor:  void ?{}(T *, T)
    565                 newAssertions.push_back( new ast::FunctionDecl(
    566                         location,
    567                         "?{}",
    568                         {}, // forall
    569                         {}, // assertions
    570                         {
    571                                 new ast::ObjectDecl(
    572                                         location,
    573                                         "",
    574                                         new ast::ReferenceType( i->get() ),
    575                                         (ast::Init *)nullptr,
    576                                         ast::Storage::Classes(),
    577                                         ast::Linkage::Cforall,
    578                                         (ast::Expr *)nullptr
    579                                 ),
    580                                 new ast::ObjectDecl(
    581                                         location,
    582                                         "",
    583                                         i->get(),
    584                                         (ast::Init *)nullptr,
    585                                         ast::Storage::Classes(),
    586                                         ast::Linkage::Cforall,
    587                                         (ast::Expr *)nullptr
    588                                 ),
    589                         }, // params
    590                         {}, // returns
    591                         (ast::CompoundStmt *)nullptr,
    592                         ast::Storage::Classes(),
    593                         ast::Linkage::Cforall
    594                 ) );
    595 
    596                 // add dtor:  void ^?{}(T *)
    597                 newAssertions.push_back( new ast::FunctionDecl(
    598                         location,
    599                         "^?{}",
    600                         {}, // forall
    601                         {}, // assertions
    602                         {
    603                                 new ast::ObjectDecl(
    604                                         location,
    605                                         "",
    606                                         new ast::ReferenceType( i->get() ),
    607                                         (ast::Init *)nullptr,
    608                                         ast::Storage::Classes(),
    609                                         ast::Linkage::Cforall,
    610                                         (ast::Expr *)nullptr
    611                                 ),
    612                         }, // params
    613                         {}, // returns
    614                         (ast::CompoundStmt *)nullptr,
    615                         ast::Storage::Classes(),
    616                         ast::Linkage::Cforall
    617                 ) );
    618 
    619                 spliceBegin( mutTypeDecl->assertions, newAssertions );
    620         } // for
    621 }
    622 
    623 
    624 void buildForall(
    625                 const DeclarationNode * firstNode,
    626                 std::vector<ast::ptr<ast::TypeDecl>> &outputForall ) {
    627         buildList( firstNode, outputForall );
    628         auto n = firstNode;
    629         for ( auto i = outputForall.begin() ;
    630                         i != outputForall.end() ;
    631                         ++i, n = (DeclarationNode*)n->get_next() ) {
    632                 // Only the object type class adds additional assertions.
    633                 if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
    634                         continue;
    635                 }
    636 
    637                 ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
    638                 std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
    639                 auto mutTypeDecl = ast::mutate( td );
    640                 const CodeLocation & location = mutTypeDecl->location;
    641                 *i = mutTypeDecl;
    642 
    643                 // add assertion parameters to `type' tyvars in reverse order
    644                 // add assignment operator:  T * ?=?(T *, T)
    645                 newAssertions.push_back( new ast::FunctionDecl(
    646                         location,
    647                         "?=?",
    648                         {}, // forall
    649                         {}, // assertions
    650                         {
    651                                 new ast::ObjectDecl(
    652                                         location,
    653                                         "",
    654                                         new ast::ReferenceType( new ast::TypeInstType( td->name, *i ) ),
    655                                         (ast::Init *)nullptr,
    656                                         ast::Storage::Classes(),
    657                                         ast::Linkage::Cforall,
    658                                         (ast::Expr *)nullptr
    659                                 ),
    660                                 new ast::ObjectDecl(
    661                                         location,
    662                                         "",
    663                                         new ast::TypeInstType( td->name, *i ),
    664                                         (ast::Init *)nullptr,
    665                                         ast::Storage::Classes(),
    666                                         ast::Linkage::Cforall,
    667                                         (ast::Expr *)nullptr
    668                                 ),
    669                         }, // params
    670                         {
    671                                 new ast::ObjectDecl(
    672                                         location,
    673                                         "",
    674                                         new ast::TypeInstType( td->name, *i ),
    675                                         (ast::Init *)nullptr,
    676                                         ast::Storage::Classes(),
    677                                         ast::Linkage::Cforall,
    678                                         (ast::Expr *)nullptr
    679                                 ),
    680                         }, // returns
    681                         (ast::CompoundStmt *)nullptr,
    682                         ast::Storage::Classes(),
    683                         ast::Linkage::Cforall
    684                 ) );
    685 
    686                 // add default ctor:  void ?{}(T *)
    687                 newAssertions.push_back( new ast::FunctionDecl(
    688                         location,
    689                         "?{}",
    690                         {}, // forall
    691                         {}, // assertions
    692                         {
    693                                 new ast::ObjectDecl(
    694                                         location,
    695                                         "",
    696                                         new ast::ReferenceType(
    697                                                 new ast::TypeInstType( td->name, i->get() ) ),
    698                                         (ast::Init *)nullptr,
    699                                         ast::Storage::Classes(),
    700                                         ast::Linkage::Cforall,
    701                                         (ast::Expr *)nullptr
    702                                 ),
    703                         }, // params
    704                         {}, // returns
    705                         (ast::CompoundStmt *)nullptr,
    706                         ast::Storage::Classes(),
    707                         ast::Linkage::Cforall
    708                 ) );
    709 
    710                 // add copy ctor:  void ?{}(T *, T)
    711                 newAssertions.push_back( new ast::FunctionDecl(
    712                         location,
    713                         "?{}",
    714                         {}, // forall
    715                         {}, // assertions
    716                         {
    717                                 new ast::ObjectDecl(
    718                                         location,
    719                                         "",
    720                                         new ast::ReferenceType(
    721                                                 new ast::TypeInstType( td->name, *i ) ),
    722                                         (ast::Init *)nullptr,
    723                                         ast::Storage::Classes(),
    724                                         ast::Linkage::Cforall,
    725                                         (ast::Expr *)nullptr
    726                                 ),
    727                                 new ast::ObjectDecl(
    728                                         location,
    729                                         "",
    730                                         new ast::TypeInstType( td->name, *i ),
    731                                         (ast::Init *)nullptr,
    732                                         ast::Storage::Classes(),
    733                                         ast::Linkage::Cforall,
    734                                         (ast::Expr *)nullptr
    735                                 ),
    736                         }, // params
    737                         {}, // returns
    738                         (ast::CompoundStmt *)nullptr,
    739                         ast::Storage::Classes(),
    740                         ast::Linkage::Cforall
    741                 ) );
    742 
    743                 // add dtor:  void ^?{}(T *)
    744                 newAssertions.push_back( new ast::FunctionDecl(
    745                         location,
    746                         "^?{}",
    747                         {}, // forall
    748                         {}, // assertions
    749                         {
    750                                 new ast::ObjectDecl(
    751                                         location,
    752                                         "",
    753                                         new ast::ReferenceType(
    754                                                 new ast::TypeInstType( i->get() )
    755                                         ),
    756                                         (ast::Init *)nullptr,
    757                                         ast::Storage::Classes(),
    758                                         ast::Linkage::Cforall,
    759                                         (ast::Expr *)nullptr
    760                                 ),
    761                         }, // params
    762                         {}, // returns
    763                         (ast::CompoundStmt *)nullptr,
    764                         ast::Storage::Classes(),
    765                         ast::Linkage::Cforall
    766                 ) );
    767 
    768                 spliceBegin( mutTypeDecl->assertions, newAssertions );
     498        for ( typename ForallList::iterator i = outputList.begin(); i != outputList.end(); ++i, n = (DeclarationNode*)n->get_next() ) {
     499                TypeDecl * td = static_cast<TypeDecl *>(*i);
     500                if ( n->variable.tyClass == TypeDecl::Otype ) {
     501                        // add assertion parameters to `type' tyvars in reverse order
     502                        // add dtor:  void ^?{}(T *)
     503                        FunctionType * dtorType = new FunctionType( Type::Qualifiers(), false );
     504                        dtorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
     505                        td->get_assertions().push_front( new FunctionDecl( "^?{}", Type::StorageClasses(), LinkageSpec::Cforall, dtorType, nullptr ) );
     506
     507                        // add copy ctor:  void ?{}(T *, T)
     508                        FunctionType * copyCtorType = new FunctionType( Type::Qualifiers(), false );
     509                        copyCtorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
     510                        copyCtorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
     511                        td->get_assertions().push_front( new FunctionDecl( "?{}", Type::StorageClasses(), LinkageSpec::Cforall, copyCtorType, nullptr ) );
     512
     513                        // add default ctor:  void ?{}(T *)
     514                        FunctionType * ctorType = new FunctionType( Type::Qualifiers(), false );
     515                        ctorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
     516                        td->get_assertions().push_front( new FunctionDecl( "?{}", Type::StorageClasses(), LinkageSpec::Cforall, ctorType, nullptr ) );
     517
     518                        // add assignment operator:  T * ?=?(T *, T)
     519                        FunctionType * assignType = new FunctionType( Type::Qualifiers(), false );
     520                        assignType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
     521                        assignType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
     522                        assignType->get_returnVals().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
     523                        td->get_assertions().push_front( new FunctionDecl( "?=?", Type::StorageClasses(), LinkageSpec::Cforall, assignType, nullptr ) );
     524                } // if
    769525        } // for
    770526} // buildForall
    771527
    772528
    773 ast::Type * typebuild( const TypeData * td ) {
     529Type * typebuild( const TypeData * td ) {
    774530        assert( td );
    775531        switch ( td->kind ) {
    776         case TypeData::Unknown:
     532          case TypeData::Unknown:
    777533                // fill in implicit int
    778                 return new ast::BasicType(
    779                         ast::BasicType::SignedInt,
    780                         buildQualifiers( td )
    781                 );
    782         case TypeData::Basic:
     534                return new BasicType( buildQualifiers( td ), BasicType::SignedInt );
     535          case TypeData::Basic:
    783536                return buildBasicType( td );
    784         case TypeData::Pointer:
     537          case TypeData::Pointer:
    785538                return buildPointer( td );
    786         case TypeData::Array:
     539          case TypeData::Array:
    787540                return buildArray( td );
    788         case TypeData::Reference:
     541          case TypeData::Reference:
    789542                return buildReference( td );
    790         case TypeData::Function:
    791                 return buildFunctionType( td );
    792         case TypeData::AggregateInst:
     543          case TypeData::Function:
     544                return buildFunction( td );
     545          case TypeData::AggregateInst:
    793546                return buildAggInst( td );
    794         case TypeData::EnumConstant:
    795                 return new ast::EnumInstType( "", buildQualifiers( td ) );
    796         case TypeData::SymbolicInst:
     547          case TypeData::EnumConstant:
     548                return new EnumInstType( buildQualifiers( td ), "" );
     549          case TypeData::SymbolicInst:
    797550                return buildSymbolicInst( td );
    798         case TypeData::Tuple:
     551          case TypeData::Tuple:
    799552                return buildTuple( td );
    800         case TypeData::Typeof:
    801         case TypeData::Basetypeof:
     553          case TypeData::Typeof:
     554          case TypeData::Basetypeof:
    802555                return buildTypeof( td );
    803         case TypeData::Vtable:
     556          case TypeData::Vtable:
    804557                return buildVtable( td );
    805         case TypeData::Builtin:
     558          case TypeData::Builtin:
    806559                switch ( td->builtintype ) {
    807                 case DeclarationNode::Zero:
    808                         return new ast::ZeroType();
    809                 case DeclarationNode::One:
    810                         return new ast::OneType();
    811                 default:
    812                         return new ast::VarArgsType( buildQualifiers( td ) );
     560                  case DeclarationNode::Zero:
     561                        return new ZeroType( noQualifiers );
     562                  case DeclarationNode::One:
     563                        return new OneType( noQualifiers );
     564                  default:
     565                        return new VarArgsType( buildQualifiers( td ) );
    813566                } // switch
    814         case TypeData::GlobalScope:
    815                 return new ast::GlobalScopeType();
    816         case TypeData::Qualified:
    817                 return new ast::QualifiedType(
    818                         typebuild( td->qualified.parent ),
    819                         typebuild( td->qualified.child ),
    820                         buildQualifiers( td )
    821                 );
    822         case TypeData::Symbolic:
    823         case TypeData::Enum:
    824         case TypeData::Aggregate:
     567          case TypeData::GlobalScope:
     568                return new GlobalScopeType();
     569          case TypeData::Qualified:
     570                return new QualifiedType( buildQualifiers( td ), typebuild( td->qualified.parent ), typebuild( td->qualified.child ) );
     571          case TypeData::Symbolic:
     572          case TypeData::Enum:
     573          case TypeData::Aggregate:
    825574                assert( false );
    826575        } // switch
     
    834583
    835584        switch ( td->kind ) {
    836         case TypeData::Aggregate:
     585          case TypeData::Aggregate:
    837586                if ( ! toplevel && td->aggregate.body ) {
    838587                        ret = td->clone();
    839588                } // if
    840589                break;
    841         case TypeData::Enum:
     590          case TypeData::Enum:
    842591                if ( ! toplevel && td->enumeration.body ) {
    843592                        ret = td->clone();
    844593                } // if
    845594                break;
    846         case TypeData::AggregateInst:
     595          case TypeData::AggregateInst:
    847596                if ( td->aggInst.aggregate ) {
    848597                        ret = typeextractAggregate( td->aggInst.aggregate, false );
    849598                } // if
    850599                break;
    851         default:
     600          default:
    852601                if ( td->base ) {
    853602                        ret = typeextractAggregate( td->base, false );
     
    858607
    859608
    860 ast::CV::Qualifiers buildQualifiers( const TypeData * td ) {
     609Type::Qualifiers buildQualifiers( const TypeData * td ) {
    861610        return td->qualifiers;
    862611} // buildQualifiers
     
    867616} // genTSError
    868617
    869 ast::Type * buildBasicType( const TypeData * td ) {
    870         ast::BasicType::Kind ret;
     618Type * buildBasicType( const TypeData * td ) {
     619        BasicType::Kind ret;
    871620
    872621        switch ( td->basictype ) {
    873         case DeclarationNode::Void:
     622          case DeclarationNode::Void:
    874623                if ( td->signedness != DeclarationNode::NoSignedness ) {
    875624                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    878627                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
    879628                } // if
    880                 return new ast::VoidType( buildQualifiers( td ) );
    881                 break;
    882 
    883         case DeclarationNode::Bool:
     629                return new VoidType( buildQualifiers( td ) );
     630                break;
     631
     632          case DeclarationNode::Bool:
    884633                if ( td->signedness != DeclarationNode::NoSignedness ) {
    885634                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    889638                } // if
    890639
    891                 ret = ast::BasicType::Bool;
    892                 break;
    893 
    894         case DeclarationNode::Char:
     640                ret = BasicType::Bool;
     641                break;
     642
     643          case DeclarationNode::Char:
    895644                // C11 Standard 6.2.5.15: The three types char, signed char, and unsigned char are collectively called the
    896645                // character types. The implementation shall define char to have the same range, representation, and behavior as
    897646                // either signed char or unsigned char.
    898                 static ast::BasicType::Kind chartype[] = { ast::BasicType::SignedChar, ast::BasicType::UnsignedChar, ast::BasicType::Char };
     647                static BasicType::Kind chartype[] = { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::Char };
    899648
    900649                if ( td->length != DeclarationNode::NoLength ) {
     
    905654                break;
    906655
    907         case DeclarationNode::Int:
    908                 static ast::BasicType::Kind inttype[2][4] = {
    909                         { ast::BasicType::ShortSignedInt, ast::BasicType::LongSignedInt, ast::BasicType::LongLongSignedInt, ast::BasicType::SignedInt },
    910                         { ast::BasicType::ShortUnsignedInt, ast::BasicType::LongUnsignedInt, ast::BasicType::LongLongUnsignedInt, ast::BasicType::UnsignedInt },
     656          case DeclarationNode::Int:
     657                static BasicType::Kind inttype[2][4] = {
     658                        { BasicType::ShortSignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt },
     659                        { BasicType::ShortUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt },
    911660                };
    912661
    913         Integral: ;
     662          Integral: ;
    914663                if ( td->signedness == DeclarationNode::NoSignedness ) {
    915664                        const_cast<TypeData *>(td)->signedness = DeclarationNode::Signed;
     
    918667                break;
    919668
    920         case DeclarationNode::Int128:
    921                 ret = td->signedness == DeclarationNode::Unsigned ? ast::BasicType::UnsignedInt128 : ast::BasicType::SignedInt128;
     669          case DeclarationNode::Int128:
     670                ret = td->signedness == DeclarationNode::Unsigned ? BasicType::UnsignedInt128 : BasicType::SignedInt128;
    922671                if ( td->length != DeclarationNode::NoLength ) {
    923672                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
     
    925674                break;
    926675
    927         case DeclarationNode::Float:
    928         case DeclarationNode::Double:
    929         case DeclarationNode::LongDouble:                                       // not set until below
    930         case DeclarationNode::uuFloat80:
    931         case DeclarationNode::uuFloat128:
    932         case DeclarationNode::uFloat16:
    933         case DeclarationNode::uFloat32:
    934         case DeclarationNode::uFloat32x:
    935         case DeclarationNode::uFloat64:
    936         case DeclarationNode::uFloat64x:
    937         case DeclarationNode::uFloat128:
    938         case DeclarationNode::uFloat128x:
    939                 static ast::BasicType::Kind floattype[2][12] = {
    940                         { ast::BasicType::FloatComplex, ast::BasicType::DoubleComplex, ast::BasicType::LongDoubleComplex, (ast::BasicType::Kind)-1, (ast::BasicType::Kind)-1, ast::BasicType::uFloat16Complex, ast::BasicType::uFloat32Complex, ast::BasicType::uFloat32xComplex, ast::BasicType::uFloat64Complex, ast::BasicType::uFloat64xComplex, ast::BasicType::uFloat128Complex, ast::BasicType::uFloat128xComplex, },
    941                         { ast::BasicType::Float, ast::BasicType::Double, ast::BasicType::LongDouble, ast::BasicType::uuFloat80, ast::BasicType::uuFloat128, ast::BasicType::uFloat16, ast::BasicType::uFloat32, ast::BasicType::uFloat32x, ast::BasicType::uFloat64, ast::BasicType::uFloat64x, ast::BasicType::uFloat128, ast::BasicType::uFloat128x, },
     676          case DeclarationNode::Float:
     677          case DeclarationNode::Double:
     678          case DeclarationNode::LongDouble:                                     // not set until below
     679          case DeclarationNode::uuFloat80:
     680          case DeclarationNode::uuFloat128:
     681          case DeclarationNode::uFloat16:
     682          case DeclarationNode::uFloat32:
     683          case DeclarationNode::uFloat32x:
     684          case DeclarationNode::uFloat64:
     685          case DeclarationNode::uFloat64x:
     686          case DeclarationNode::uFloat128:
     687          case DeclarationNode::uFloat128x:
     688                static BasicType::Kind floattype[2][12] = {
     689                        { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, (BasicType::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex, },
     690                        { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x, },
    942691                };
    943692
    944         FloatingPoint: ;
     693          FloatingPoint: ;
    945694                if ( td->signedness != DeclarationNode::NoSignedness ) {
    946695                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    966715                break;
    967716
    968         case DeclarationNode::NoBasicType:
     717          case DeclarationNode::NoBasicType:
    969718                // No basic type in declaration => default double for Complex/Imaginary and int type for integral types
    970719                if ( td->complextype == DeclarationNode::Complex || td->complextype == DeclarationNode::Imaginary ) {
     
    975724                const_cast<TypeData *>(td)->basictype = DeclarationNode::Int;
    976725                goto Integral;
    977         default:
    978                 assertf( false, "unknown basic type" );
     726          default:
     727                assertf( false, "unknown basic type" );
    979728                return nullptr;
    980729        } // switch
    981730
    982         ast::BasicType * bt = new ast::BasicType( ret, buildQualifiers( td ) );
     731        BasicType * bt = new BasicType( buildQualifiers( td ), ret );
     732        buildForall( td->forall, bt->get_forall() );
    983733        return bt;
    984734} // buildBasicType
    985735
    986736
    987 ast::PointerType * buildPointer( const TypeData * td ) {
    988         ast::PointerType * pt;
     737PointerType * buildPointer( const TypeData * td ) {
     738        PointerType * pt;
    989739        if ( td->base ) {
    990                 pt = new ast::PointerType(
    991                         typebuild( td->base ),
    992                         buildQualifiers( td )
    993                 );
     740                pt = new PointerType( buildQualifiers( td ), typebuild( td->base ) );
    994741        } else {
    995                 pt = new ast::PointerType(
    996                         new ast::BasicType( ast::BasicType::SignedInt ),
    997                         buildQualifiers( td )
    998                 );
     742                pt = new PointerType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    999743        } // if
     744        buildForall( td->forall, pt->get_forall() );
    1000745        return pt;
    1001746} // buildPointer
    1002747
    1003748
    1004 ast::ArrayType * buildArray( const TypeData * td ) {
    1005         ast::ArrayType * at;
     749ArrayType * buildArray( const TypeData * td ) {
     750        ArrayType * at;
    1006751        if ( td->base ) {
    1007                 at = new ast::ArrayType(
    1008                         typebuild( td->base ),
    1009                         maybeBuild( td->array.dimension ),
    1010                         td->array.isVarLen ? ast::VariableLen : ast::FixedLen,
    1011                         td->array.isStatic ? ast::StaticDim : ast::DynamicDim,
    1012                         buildQualifiers( td )
    1013                 );
     752                at = new ArrayType( buildQualifiers( td ), typebuild( td->base ), maybeBuild< Expression >( td->array.dimension ),
     753                                                        td->array.isVarLen, td->array.isStatic );
    1014754        } else {
    1015                 at = new ast::ArrayType(
    1016                         new ast::BasicType( ast::BasicType::SignedInt ),
    1017                         maybeBuild( td->array.dimension ),
    1018                         td->array.isVarLen ? ast::VariableLen : ast::FixedLen,
    1019                         td->array.isStatic ? ast::StaticDim : ast::DynamicDim,
    1020                         buildQualifiers( td )
    1021                 );
     755                at = new ArrayType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ),
     756                                                        maybeBuild< Expression >( td->array.dimension ), td->array.isVarLen, td->array.isStatic );
    1022757        } // if
     758        buildForall( td->forall, at->get_forall() );
    1023759        return at;
    1024760} // buildArray
    1025761
    1026762
    1027 ast::ReferenceType * buildReference( const TypeData * td ) {
    1028         ast::ReferenceType * rt;
     763ReferenceType * buildReference( const TypeData * td ) {
     764        ReferenceType * rt;
    1029765        if ( td->base ) {
    1030                 rt = new ast::ReferenceType(
    1031                         typebuild( td->base ),
    1032                         buildQualifiers( td )
    1033                 );
     766                rt = new ReferenceType( buildQualifiers( td ), typebuild( td->base ) );
    1034767        } else {
    1035                 rt = new ast::ReferenceType(
    1036                         new ast::BasicType( ast::BasicType::SignedInt ),
    1037                         buildQualifiers( td )
    1038                 );
     768                rt = new ReferenceType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    1039769        } // if
     770        buildForall( td->forall, rt->get_forall() );
    1040771        return rt;
    1041772} // buildReference
    1042773
    1043774
    1044 ast::AggregateDecl * buildAggregate( const TypeData * td, std::vector<ast::ptr<ast::Attribute>> attributes, ast::Linkage::Spec linkage ) {
     775AggregateDecl * buildAggregate( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
    1045776        assert( td->kind == TypeData::Aggregate );
    1046         ast::AggregateDecl * at;
     777        AggregateDecl * at;
    1047778        switch ( td->aggregate.kind ) {
    1048         case ast::AggregateDecl::Struct:
    1049         case ast::AggregateDecl::Coroutine:
    1050         case ast::AggregateDecl::Exception:
    1051         case ast::AggregateDecl::Generator:
    1052         case ast::AggregateDecl::Monitor:
    1053         case ast::AggregateDecl::Thread:
    1054                 at = new ast::StructDecl( td->location,
    1055                         *td->aggregate.name,
    1056                         td->aggregate.kind,
    1057                         std::move( attributes ),
    1058                         linkage
    1059                 );
    1060                 buildForall( td->aggregate.params, at->params );
    1061                 break;
    1062         case ast::AggregateDecl::Union:
    1063                 at = new ast::UnionDecl( td->location,
    1064                         *td->aggregate.name,
    1065                         std::move( attributes ),
    1066                         linkage
    1067                 );
    1068                 buildForall( td->aggregate.params, at->params );
    1069                 break;
    1070         case ast::AggregateDecl::Trait:
    1071                 at = new ast::TraitDecl( td->location,
    1072                         *td->aggregate.name,
    1073                         std::move( attributes ),
    1074                         linkage
    1075                 );
    1076                 buildList( td->aggregate.params, at->params );
    1077                 break;
    1078         default:
     779          case AggregateDecl::Struct:
     780          case AggregateDecl::Coroutine:
     781          case AggregateDecl::Exception:
     782          case AggregateDecl::Generator:
     783          case AggregateDecl::Monitor:
     784          case AggregateDecl::Thread:
     785                at = new StructDecl( *td->aggregate.name, td->aggregate.kind, attributes, linkage );
     786                buildForall( td->aggregate.params, at->get_parameters() );
     787                break;
     788          case AggregateDecl::Union:
     789                at = new UnionDecl( *td->aggregate.name, attributes, linkage );
     790                buildForall( td->aggregate.params, at->get_parameters() );
     791                break;
     792          case AggregateDecl::Trait:
     793                at = new TraitDecl( *td->aggregate.name, attributes, linkage );
     794                buildList( td->aggregate.params, at->get_parameters() );
     795                break;
     796          default:
    1079797                assert( false );
    1080798        } // switch
    1081799
    1082         buildList( td->aggregate.fields, at->members );
     800        buildList( td->aggregate.fields, at->get_members() );
    1083801        at->set_body( td->aggregate.body );
    1084802
     
    1087805
    1088806
    1089 ast::BaseInstType * buildComAggInst(
    1090                 const TypeData * type,
    1091                 std::vector<ast::ptr<ast::Attribute>> && attributes,
    1092                 ast::Linkage::Spec linkage ) {
     807ReferenceToType * buildComAggInst( const TypeData * type, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
    1093808        switch ( type->kind ) {
    1094         case TypeData::Enum:
    1095                 if ( type->enumeration.body ) {
    1096                         ast::EnumDecl * typedecl =
    1097                                 buildEnum( type, std::move( attributes ), linkage );
    1098                         return new ast::EnumInstType(
    1099                                 typedecl,
    1100                                 buildQualifiers( type )
    1101                         );
    1102                 } else {
    1103                         return new ast::EnumInstType(
    1104                                 *type->enumeration.name,
    1105                                 buildQualifiers( type )
    1106                         );
    1107                 } // if
    1108                 break;
    1109         case TypeData::Aggregate:
    1110                 if ( type->aggregate.body ) {
    1111                         ast::AggregateDecl * typedecl =
    1112                                 buildAggregate( type, std::move( attributes ), linkage );
    1113                         switch ( type->aggregate.kind ) {
    1114                         case ast::AggregateDecl::Struct:
    1115                         case ast::AggregateDecl::Coroutine:
    1116                         case ast::AggregateDecl::Monitor:
    1117                         case ast::AggregateDecl::Thread:
    1118                                 return new ast::StructInstType(
    1119                                         strict_dynamic_cast<ast::StructDecl *>( typedecl ),
    1120                                         buildQualifiers( type )
    1121                                 );
    1122                         case ast::AggregateDecl::Union:
    1123                                 return new ast::UnionInstType(
    1124                                         strict_dynamic_cast<ast::UnionDecl *>( typedecl ),
    1125                                         buildQualifiers( type )
    1126                                 );
    1127                         case ast::AggregateDecl::Trait:
    1128                                 assert( false );
    1129                                 break;
    1130                         default:
    1131                                 assert( false );
    1132                         } // switch
    1133                 } else {
    1134                         switch ( type->aggregate.kind ) {
    1135                         case ast::AggregateDecl::Struct:
    1136                         case ast::AggregateDecl::Coroutine:
    1137                         case ast::AggregateDecl::Monitor:
    1138                         case ast::AggregateDecl::Thread:
    1139                                 return new ast::StructInstType(
    1140                                         *type->aggregate.name,
    1141                                         buildQualifiers( type )
    1142                                 );
    1143                         case ast::AggregateDecl::Union:
    1144                                 return new ast::UnionInstType(
    1145                                         *type->aggregate.name,
    1146                                         buildQualifiers( type )
    1147                                 );
    1148                         case ast::AggregateDecl::Trait:
    1149                                 return new ast::TraitInstType(
    1150                                         *type->aggregate.name,
    1151                                         buildQualifiers( type )
    1152                                 );
    1153                         default:
    1154                                 assert( false );
    1155                         } // switch
    1156                         break;
    1157                 } // if
    1158                 break;
    1159         default:
     809          case TypeData::Enum: {
     810                  if ( type->enumeration.body ) {
     811                          EnumDecl * typedecl = buildEnum( type, attributes, linkage );
     812                          return new EnumInstType( buildQualifiers( type ), typedecl );
     813                  } else {
     814                          return new EnumInstType( buildQualifiers( type ), *type->enumeration.name );
     815                  } // if
     816          }
     817          case TypeData::Aggregate: {
     818                  ReferenceToType * ret;
     819                  if ( type->aggregate.body ) {
     820                          AggregateDecl * typedecl = buildAggregate( type, attributes, linkage );
     821                          switch ( type->aggregate.kind ) {
     822                                case AggregateDecl::Struct:
     823                                case AggregateDecl::Coroutine:
     824                                case AggregateDecl::Monitor:
     825                                case AggregateDecl::Thread:
     826                                  ret = new StructInstType( buildQualifiers( type ), (StructDecl *)typedecl );
     827                                  break;
     828                                case AggregateDecl::Union:
     829                                  ret = new UnionInstType( buildQualifiers( type ), (UnionDecl *)typedecl );
     830                                  break;
     831                                case AggregateDecl::Trait:
     832                                  assert( false );
     833                                  //ret = new TraitInstType( buildQualifiers( type ), (TraitDecl *)typedecl );
     834                                  break;
     835                                default:
     836                                  assert( false );
     837                          } // switch
     838                  } else {
     839                          switch ( type->aggregate.kind ) {
     840                                case AggregateDecl::Struct:
     841                                case AggregateDecl::Coroutine:
     842                                case AggregateDecl::Monitor:
     843                                case AggregateDecl::Thread:
     844                                  ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
     845                                  break;
     846                                case AggregateDecl::Union:
     847                                  ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
     848                                  break;
     849                                case AggregateDecl::Trait:
     850                                  ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
     851                                  break;
     852                                default:
     853                                  assert( false );
     854                          } // switch
     855                  } // if
     856                  return ret;
     857          }
     858          default:
    1160859                assert( false );
    1161860        } // switch
    1162         assert( false );
    1163861} // buildAggInst
    1164862
    1165863
    1166 ast::BaseInstType * buildAggInst( const TypeData * td ) {
     864ReferenceToType * buildAggInst( const TypeData * td ) {
    1167865        assert( td->kind == TypeData::AggregateInst );
    1168866
    1169         ast::BaseInstType * ret = nullptr;
     867        // ReferenceToType * ret = buildComAggInst( td->aggInst.aggregate, std::list< Attribute * >() );
     868        ReferenceToType * ret = nullptr;
    1170869        TypeData * type = td->aggInst.aggregate;
    1171870        switch ( type->kind ) {
    1172         case TypeData::Enum:
    1173                 return new ast::EnumInstType(
    1174                         *type->enumeration.name,
    1175                         buildQualifiers( type )
    1176                 );
    1177         case TypeData::Aggregate:
    1178                 switch ( type->aggregate.kind ) {
    1179                 case ast::AggregateDecl::Struct:
    1180                 case ast::AggregateDecl::Coroutine:
    1181                 case ast::AggregateDecl::Monitor:
    1182                 case ast::AggregateDecl::Thread:
    1183                         ret = new ast::StructInstType(
    1184                                 *type->aggregate.name,
    1185                                 buildQualifiers( type )
    1186                         );
    1187                         break;
    1188                 case ast::AggregateDecl::Union:
    1189                         ret = new ast::UnionInstType(
    1190                                 *type->aggregate.name,
    1191                                 buildQualifiers( type )
    1192                         );
    1193                         break;
    1194                 case ast::AggregateDecl::Trait:
    1195                         ret = new ast::TraitInstType(
    1196                                 *type->aggregate.name,
    1197                                 buildQualifiers( type )
    1198                         );
    1199                         break;
    1200                 default:
    1201                         assert( false );
    1202                 } // switch
    1203                 break;
    1204         default:
     871          case TypeData::Enum: {
     872                  return new EnumInstType( buildQualifiers( type ), *type->enumeration.name );
     873          }
     874          case TypeData::Aggregate: {
     875                  switch ( type->aggregate.kind ) {
     876                        case AggregateDecl::Struct:
     877                        case AggregateDecl::Coroutine:
     878                        case AggregateDecl::Monitor:
     879                        case AggregateDecl::Thread:
     880                          ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
     881                          break;
     882                        case AggregateDecl::Union:
     883                          ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
     884                          break;
     885                        case AggregateDecl::Trait:
     886                          ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
     887                          break;
     888                        default:
     889                          assert( false );
     890                  } // switch
     891          }
     892          break;
     893          default:
    1205894                assert( false );
    1206895        } // switch
    1207896
    1208         ret->hoistType = td->aggInst.hoistType;
    1209         buildList( td->aggInst.params, ret->params );
     897        ret->set_hoistType( td->aggInst.hoistType );
     898        buildList( td->aggInst.params, ret->get_parameters() );
     899        buildForall( td->forall, ret->get_forall() );
    1210900        return ret;
    1211901} // buildAggInst
    1212902
    1213903
    1214 ast::NamedTypeDecl * buildSymbolic(
    1215                 const TypeData * td,
    1216                 std::vector<ast::ptr<ast::Attribute>> attributes,
    1217                 const std::string & name,
    1218                 ast::Storage::Classes scs,
    1219                 ast::Linkage::Spec linkage ) {
     904NamedTypeDecl * buildSymbolic( const TypeData * td, std::list< Attribute * > attributes, const string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) {
    1220905        assert( td->kind == TypeData::Symbolic );
    1221         ast::NamedTypeDecl * ret;
     906        NamedTypeDecl * ret;
    1222907        assert( td->base );
    1223908        if ( td->symbolic.isTypedef ) {
    1224                 ret = new ast::TypedefDecl(
    1225                         td->location,
    1226                         name,
    1227                         scs,
    1228                         typebuild( td->base ),
    1229                         linkage
    1230                 );
     909                ret = new TypedefDecl( name, td->location, scs, typebuild( td->base ), linkage );
    1231910        } else {
    1232                 ret = new ast::TypeDecl(
    1233                         td->location,
    1234                         name,
    1235                         scs,
    1236                         typebuild( td->base ),
    1237                         ast::TypeDecl::Dtype,
    1238                         true
    1239                 );
     911                ret = new TypeDecl( name, scs, typebuild( td->base ), TypeDecl::Dtype, true );
    1240912        } // if
    1241         buildList( td->symbolic.assertions, ret->assertions );
    1242         splice( ret->base.get_and_mutate()->attributes, attributes );
     913        buildList( td->symbolic.assertions, ret->get_assertions() );
     914        ret->base->attributes.splice( ret->base->attributes.end(), attributes );
    1243915        return ret;
    1244916} // buildSymbolic
    1245917
    1246918
    1247 ast::EnumDecl * buildEnum(
    1248                 const TypeData * td,
    1249                 std::vector<ast::ptr<ast::Attribute>> && attributes,
    1250                 ast::Linkage::Spec linkage ) {
     919EnumDecl * buildEnum( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
    1251920        assert( td->kind == TypeData::Enum );
    1252         ast::Type * baseType = td->base ? typebuild(td->base) : nullptr;
    1253         ast::EnumDecl * ret = new ast::EnumDecl(
    1254                 td->location,
    1255                 *td->enumeration.name,
    1256                 td->enumeration.typed,
    1257                 std::move( attributes ),
    1258                 linkage,
    1259                 baseType
    1260         );
    1261         buildList( td->enumeration.constants, ret->members );
    1262         auto members = ret->members.begin();
    1263         ret->hide = td->enumeration.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
     921        Type * baseType = td->base ? typebuild(td->base) : nullptr;
     922        EnumDecl * ret = new EnumDecl( *td->enumeration.name, attributes, td->enumeration.typed, linkage, baseType );
     923        buildList( td->enumeration.constants, ret->get_members() );
     924        list< Declaration * >::iterator members = ret->get_members().begin();
     925        ret->hide = td->enumeration.hiding == EnumHiding::Hide ? EnumDecl::EnumHiding::Hide : EnumDecl::EnumHiding::Visible;
    1264926        for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
    1265927                if ( cur->enumInLine ) {
     
    1268930                        SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
    1269931                } else if ( cur->has_enumeratorValue() ) {
    1270                         ast::Decl * member = members->get_and_mutate();
    1271                         ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
    1272                         object->init = new ast::SingleInit(
    1273                                 td->location,
    1274                                 maybeMoveBuild( cur->consume_enumeratorValue() ),
    1275                                 ast::NoConstruct
    1276                         );
     932                        ObjectDecl * member = dynamic_cast< ObjectDecl * >(* members);
     933                        member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_enumeratorValue() ) ) );
    1277934                } else if ( !cur->initializer ) {
    1278                         if ( baseType && (!dynamic_cast<ast::BasicType *>(baseType) || !dynamic_cast<ast::BasicType *>(baseType)->isInteger())) {
     935                        if ( baseType && (!dynamic_cast<BasicType *>(baseType) || !dynamic_cast<BasicType *>(baseType)->isInteger())) {
    1279936                                SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." );
    1280937                        }
     
    1283940                // if
    1284941        } // for
    1285         ret->body = td->enumeration.body;
     942        ret->set_body( td->enumeration.body );
    1286943        return ret;
    1287944} // buildEnum
    1288945
    1289946
    1290 ast::TypeInstType * buildSymbolicInst( const TypeData * td ) {
     947TypeInstType * buildSymbolicInst( const TypeData * td ) {
    1291948        assert( td->kind == TypeData::SymbolicInst );
    1292         ast::TypeInstType * ret = new ast::TypeInstType(
    1293                 *td->symbolic.name,
    1294                 ast::TypeDecl::Dtype,
    1295                 buildQualifiers( td )
    1296         );
    1297         buildList( td->symbolic.actuals, ret->params );
     949        TypeInstType * ret = new TypeInstType( buildQualifiers( td ), *td->symbolic.name, false );
     950        buildList( td->symbolic.actuals, ret->get_parameters() );
     951        buildForall( td->forall, ret->get_forall() );
    1298952        return ret;
    1299953} // buildSymbolicInst
    1300954
    1301955
    1302 ast::TupleType * buildTuple( const TypeData * td ) {
     956TupleType * buildTuple( const TypeData * td ) {
    1303957        assert( td->kind == TypeData::Tuple );
    1304         std::vector<ast::ptr<ast::Type>> types;
     958        std::list< Type * > types;
    1305959        buildTypeList( td->tuple, types );
    1306         ast::TupleType * ret = new ast::TupleType(
    1307                 std::move( types ),
    1308                 buildQualifiers( td )
    1309         );
     960        TupleType * ret = new TupleType( buildQualifiers( td ), types );
     961        buildForall( td->forall, ret->get_forall() );
    1310962        return ret;
    1311963} // buildTuple
    1312964
    1313965
    1314 ast::TypeofType * buildTypeof( const TypeData * td ) {
     966TypeofType * buildTypeof( const TypeData * td ) {
    1315967        assert( td->kind == TypeData::Typeof || td->kind == TypeData::Basetypeof );
    1316968        assert( td->typeexpr );
    1317         return new ast::TypeofType(
    1318                 td->typeexpr->build(),
    1319                 td->kind == TypeData::Typeof
    1320                         ? ast::TypeofType::Typeof : ast::TypeofType::Basetypeof,
    1321                 buildQualifiers( td )
    1322         );
     969        // assert( td->typeexpr->expr );
     970        return new TypeofType{ buildQualifiers( td ), td->typeexpr->build(), td->kind == TypeData::Basetypeof };
    1323971} // buildTypeof
    1324972
    1325973
    1326 ast::VTableType * buildVtable( const TypeData * td ) {
     974VTableType * buildVtable( const TypeData * td ) {
    1327975        assert( td->base );
    1328         return new ast::VTableType(
    1329                 typebuild( td->base ),
    1330                 buildQualifiers( td )
    1331         );
     976        return new VTableType{ buildQualifiers( td ), typebuild( td->base ) };
    1332977} // buildVtable
    1333978
    1334979
    1335 ast::FunctionDecl * buildFunctionDecl(
    1336                 const TypeData * td,
    1337                 const string &name,
    1338                 ast::Storage::Classes scs,
    1339                 ast::Function::Specs funcSpec,
    1340                 ast::Linkage::Spec linkage,
    1341                 ast::Expr * asmName,
    1342                 std::vector<ast::ptr<ast::Attribute>> && attributes ) {
    1343         assert( td->kind == TypeData::Function );
    1344         // For some reason FunctionDecl takes a bool instead of an ArgumentFlag.
    1345         bool isVarArgs = !td->function.params || td->function.params->hasEllipsis;
    1346         ast::CV::Qualifiers cvq = buildQualifiers( td );
    1347         std::vector<ast::ptr<ast::TypeDecl>> forall;
    1348         std::vector<ast::ptr<ast::DeclWithType>> assertions;
    1349         std::vector<ast::ptr<ast::DeclWithType>> params;
    1350         std::vector<ast::ptr<ast::DeclWithType>> returns;
    1351         buildList( td->function.params, params );
    1352         buildForall( td->forall, forall );
    1353         // Functions do not store their assertions there anymore.
    1354         for ( ast::ptr<ast::TypeDecl> & type_param : forall ) {
    1355                 auto mut = type_param.get_and_mutate();
    1356                 splice( assertions, mut->assertions );
    1357         }
    1358         if ( td->base ) {
    1359                 switch ( td->base->kind ) {
    1360                 case TypeData::Tuple:
    1361                         buildList( td->base->tuple, returns );
    1362                         break;
    1363                 default:
    1364                         returns.push_back( dynamic_cast<ast::DeclWithType *>(
    1365                                 buildDecl(
    1366                                         td->base,
    1367                                         "",
    1368                                         ast::Storage::Classes(),
    1369                                         (ast::Expr *)nullptr, // bitfieldWidth
    1370                                         ast::Function::Specs(),
    1371                                         ast::Linkage::Cforall,
    1372                                         (ast::Expr *)nullptr // asmName
    1373                                 )
    1374                         ) );
    1375                 } // switch
    1376         } else {
    1377                 returns.push_back( new ast::ObjectDecl(
    1378                         td->location,
    1379                         "",
    1380                         new ast::BasicType( ast::BasicType::SignedInt ),
    1381                         (ast::Init *)nullptr,
    1382                         ast::Storage::Classes(),
    1383                         ast::Linkage::Cforall
    1384                 ) );
    1385         } // if
    1386         ast::Stmt * stmt = maybeBuild( td->function.body );
    1387         ast::CompoundStmt * body = dynamic_cast<ast::CompoundStmt *>( stmt );
    1388         ast::FunctionDecl * decl = new ast::FunctionDecl( td->location,
    1389                 name,
    1390                 std::move( forall ),
    1391                 std::move( assertions ),
    1392                 std::move( params ),
    1393                 std::move( returns ),
    1394                 body,
    1395                 scs,
    1396                 linkage,
    1397                 std::move( attributes ),
    1398                 funcSpec,
    1399                 (isVarArgs) ? ast::VariableArgs : ast::FixedArgs
    1400         );
    1401         buildList( td->function.withExprs, decl->withExprs );
    1402         decl->asmName = asmName;
    1403         // This may be redundant on a declaration.
    1404         decl->type.get_and_mutate()->qualifiers = cvq;
    1405         return decl;
    1406 } // buildFunctionDecl
    1407 
    1408 
    1409 ast::Decl * buildDecl(
    1410                 const TypeData * td,
    1411                 const string &name,
    1412                 ast::Storage::Classes scs,
    1413                 ast::Expr * bitfieldWidth,
    1414                 ast::Function::Specs funcSpec,
    1415                 ast::Linkage::Spec linkage,
    1416                 ast::Expr * asmName,
    1417                 ast::Init * init,
    1418                 std::vector<ast::ptr<ast::Attribute>> && attributes ) {
     980Declaration * buildDecl( const TypeData * td, const string &name, Type::StorageClasses scs, Expression * bitfieldWidth, Type::FuncSpecifiers funcSpec, LinkageSpec::Spec linkage, Expression *asmName, Initializer * init, std::list< Attribute * > attributes ) {
    1419981        if ( td->kind == TypeData::Function ) {
    1420982                if ( td->function.idList ) {                                    // KR function ?
     
    1422984                } // if
    1423985
    1424                 return buildFunctionDecl(
    1425                         td, name, scs, funcSpec, linkage,
    1426                         asmName, std::move( attributes ) );
     986                FunctionDecl * decl;
     987                Statement * stmt = maybeBuild<Statement>( td->function.body );
     988                CompoundStmt * body = dynamic_cast< CompoundStmt * >( stmt );
     989                decl = new FunctionDecl( name, scs, linkage, buildFunction( td ), body, attributes, funcSpec );
     990                buildList( td->function.withExprs, decl->withExprs );
     991                return decl->set_asmName( asmName );
    1427992        } else if ( td->kind == TypeData::Aggregate ) {
    1428                 return buildAggregate( td, std::move( attributes ), linkage );
     993                return buildAggregate( td, attributes, linkage );
    1429994        } else if ( td->kind == TypeData::Enum ) {
    1430                 return buildEnum( td, std::move( attributes ), linkage );
     995                return buildEnum( td, attributes, linkage );
    1431996        } else if ( td->kind == TypeData::Symbolic ) {
    1432                 return buildSymbolic( td, std::move( attributes ), name, scs, linkage );
     997                return buildSymbolic( td, attributes, name, scs, linkage );
    1433998        } else {
    1434                 auto ret = new ast::ObjectDecl( td->location,
    1435                         name,
    1436                         typebuild( td ),
    1437                         init,
    1438                         scs,
    1439                         linkage,
    1440                         bitfieldWidth,
    1441                         std::move( attributes )
    1442                 );
    1443                 ret->asmName = asmName;
    1444                 return ret;
     999                return (new ObjectDecl( name, scs, linkage, bitfieldWidth, typebuild( td ), init, attributes ))->set_asmName( asmName );
    14451000        } // if
    14461001        return nullptr;
     
    14481003
    14491004
    1450 ast::FunctionType * buildFunctionType( const TypeData * td ) {
     1005FunctionType * buildFunction( const TypeData * td ) {
    14511006        assert( td->kind == TypeData::Function );
    1452         ast::FunctionType * ft = new ast::FunctionType(
    1453                 ( !td->function.params || td->function.params->hasEllipsis )
    1454                         ? ast::VariableArgs : ast::FixedArgs,
    1455                 buildQualifiers( td )
    1456         );
    1457         buildTypeList( td->function.params, ft->params );
     1007        FunctionType * ft = new FunctionType( buildQualifiers( td ), ! td->function.params || td->function.params->hasEllipsis );
     1008        buildList( td->function.params, ft->parameters );
    14581009        buildForall( td->forall, ft->forall );
    14591010        if ( td->base ) {
    14601011                switch ( td->base->kind ) {
    1461                 case TypeData::Tuple:
    1462                         buildTypeList( td->base->tuple, ft->returns );
     1012                  case TypeData::Tuple:
     1013                        buildList( td->base->tuple, ft->returnVals );
    14631014                        break;
    1464                 default:
    1465                         ft->returns.push_back( typebuild( td->base ) );
    1466                         break;
     1015                  default:
     1016                        ft->get_returnVals().push_back( dynamic_cast< DeclarationWithType * >( buildDecl( td->base, "", Type::StorageClasses(), nullptr, Type::FuncSpecifiers(), LinkageSpec::Cforall, nullptr ) ) );
    14671017                } // switch
    14681018        } else {
    1469                 ft->returns.push_back(
    1470                         new ast::BasicType( ast::BasicType::SignedInt ) );
     1019                ft->get_returnVals().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
    14711020        } // if
    14721021        return ft;
    1473 } // buildFunctionType
     1022} // buildFunction
    14741023
    14751024
     
    15021051                                param->type = decl->type;                               // set copy declaration type to parameter type
    15031052                                decl->type = nullptr;                                   // reset declaration type
    1504                                 // Copy and reset attributes from declaration to parameter:
    1505                                 splice( param->attributes, decl->attributes );
     1053                                param->attributes.splice( param->attributes.end(), decl->attributes ); // copy and reset attributes from declaration to parameter
    15061054                        } // if
    15071055                } // for
  • src/Parser/TypeData.h

    rb110bcc r2ed94a9  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 15:18:36 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Mar  1 10:44:00 2023
    13 // Update Count     : 206
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Tue May 10 22:18:49 2022
     13// Update Count     : 203
    1414//
    1515
    1616#pragma once
    1717
    18 #include <iosfwd>                                   // for ostream
    19 #include <list>                                     // for list
    20 #include <string>                                   // for string
     18#include <iosfwd>                                                                               // for ostream
     19#include <list>                                                                                 // for list
     20#include <string>                                                                               // for string
    2121
    22 #include "AST/Type.hpp"                             // for Type
    23 #include "DeclarationNode.h"                        // for DeclarationNode
     22#include "ParseNode.h"                                                                  // for DeclarationNode, DeclarationNode::Ag...
     23#include "SynTree/LinkageSpec.h"                                                // for Spec
     24#include "SynTree/Type.h"                                                               // for Type, ReferenceToType (ptr only)
     25#include "SynTree/SynTree.h"                                                    // for Visitor Nodes
    2426
    2527struct TypeData {
     
    2830
    2931        struct Aggregate_t {
    30                 ast::AggregateDecl::Aggregate kind;
     32                AggregateDecl::Aggregate kind;
    3133                const std::string * name = nullptr;
    3234                DeclarationNode * params = nullptr;
     
    3537                bool body;
    3638                bool anon;
     39
    3740                bool tagged;
    3841                const std::string * parent = nullptr;
     
    9194        DeclarationNode::BuiltinType builtintype = DeclarationNode::NoBuiltinType;
    9295
    93         ast::CV::Qualifiers qualifiers;
     96        Type::Qualifiers qualifiers;
    9497        DeclarationNode * forall = nullptr;
    9598
     
    112115};
    113116
    114 ast::Type * typebuild( const TypeData * );
     117Type * typebuild( const TypeData * );
    115118TypeData * typeextractAggregate( const TypeData * td, bool toplevel = true );
    116 ast::CV::Qualifiers buildQualifiers( const TypeData * td );
    117 ast::Type * buildBasicType( const TypeData * );
    118 ast::PointerType * buildPointer( const TypeData * );
    119 ast::ArrayType * buildArray( const TypeData * );
    120 ast::ReferenceType * buildReference( const TypeData * );
    121 ast::AggregateDecl * buildAggregate( const TypeData *, std::vector<ast::ptr<ast::Attribute>> );
    122 ast::BaseInstType * buildComAggInst( const TypeData *, std::vector<ast::ptr<ast::Attribute>> && attributes, ast::Linkage::Spec linkage );
    123 ast::BaseInstType * buildAggInst( const TypeData * );
    124 ast::TypeDecl * buildVariable( const TypeData * );
    125 ast::EnumDecl * buildEnum( const TypeData *, std::vector<ast::ptr<ast::Attribute>> &&, ast::Linkage::Spec );
    126 ast::TypeInstType * buildSymbolicInst( const TypeData * );
    127 ast::TupleType * buildTuple( const TypeData * );
    128 ast::TypeofType * buildTypeof( const TypeData * );
    129 ast::VTableType * buildVtable( const TypeData * );
    130 ast::Decl * buildDecl(
    131         const TypeData *, const std::string &, ast::Storage::Classes, ast::Expr *,
    132         ast::Function::Specs funcSpec, ast::Linkage::Spec, ast::Expr * asmName,
    133         ast::Init * init = nullptr, std::vector<ast::ptr<ast::Attribute>> && attributes = std::vector<ast::ptr<ast::Attribute>>() );
    134 ast::FunctionType * buildFunctionType( const TypeData * );
    135 ast::Decl * addEnumBase( Declaration *, const TypeData * );
     119Type::Qualifiers buildQualifiers( const TypeData * td );
     120Type * buildBasicType( const TypeData * );
     121PointerType * buildPointer( const TypeData * );
     122ArrayType * buildArray( const TypeData * );
     123ReferenceType * buildReference( const TypeData * );
     124AggregateDecl * buildAggregate( const TypeData *, std::list< Attribute * > );
     125ReferenceToType * buildComAggInst( const TypeData *, std::list< Attribute * > attributes, LinkageSpec::Spec linkage );
     126ReferenceToType * buildAggInst( const TypeData * );
     127TypeDecl * buildVariable( const TypeData * );
     128EnumDecl * buildEnum( const TypeData *, std::list< Attribute * >, LinkageSpec::Spec );
     129TypeInstType * buildSymbolicInst( const TypeData * );
     130TupleType * buildTuple( const TypeData * );
     131TypeofType * buildTypeof( const TypeData * );
     132VTableType * buildVtable( const TypeData * );
     133Declaration * buildDecl( const TypeData *, const std::string &, Type::StorageClasses, Expression *, Type::FuncSpecifiers funcSpec, LinkageSpec::Spec, Expression * asmName,
     134                                                 Initializer * init = nullptr, std::list< class Attribute * > attributes = std::list< class Attribute * >() );
     135FunctionType * buildFunction( const TypeData * );
     136Declaration * addEnumBase( Declaration *, const TypeData * );
    136137void buildKRFunction( const TypeData::Function_t & function );
    137138
  • src/Parser/TypedefTable.cc

    rb110bcc r2ed94a9  
    1616
    1717#include "TypedefTable.h"
    18 
    19 #include <cassert>                                // for assert
    20 #include <string>                                 // for string
    21 #include <iostream>                               // for iostream
    22 
    23 #include "ExpressionNode.h"                       // for LabelNode
    24 #include "ParserTypes.h"                          // for Token
    25 #include "StatementNode.h"                        // for CondCtl, ForCtrl
    26 // This (generated) header must come late as it is missing includes.
    27 #include "parser.hh"              // for IDENTIFIER, TYPEDEFname, TYPEGENname
    28 
     18#include <cassert>                                                                              // for assert
     19#include <iostream>
    2920using namespace std;
    3021
    3122#if 0
    3223#define debugPrint( code ) code
    33 
    34 static const char *kindName( int kind ) {
    35         switch ( kind ) {
    36         case IDENTIFIER: return "identifier";
    37         case TYPEDIMname: return "typedim";
    38         case TYPEDEFname: return "typedef";
    39         case TYPEGENname: return "typegen";
    40         default:
    41                 cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
    42                 abort();
    43         } // switch
    44 } // kindName
    4524#else
    4625#define debugPrint( code )
    4726#endif
     27
     28using namespace std;                                                                    // string, iostream
     29
     30debugPrint(
     31        static const char *kindName( int kind ) {
     32                switch ( kind ) {
     33                  case IDENTIFIER: return "identifier";
     34                  case TYPEDIMname: return "typedim";
     35                  case TYPEDEFname: return "typedef";
     36                  case TYPEGENname: return "typegen";
     37                  default:
     38                        cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
     39                        abort();
     40                } // switch
     41        } // kindName
     42);
    4843
    4944TypedefTable::~TypedefTable() {
     
    8378                typedefTable.addToEnclosingScope( name, kind, "MTD" );
    8479        } // if
    85 } // TypedefTable::makeTypedef
    86 
    87 void TypedefTable::makeTypedef( const string & name ) {
    88         return makeTypedef( name, TYPEDEFname );
    8980} // TypedefTable::makeTypedef
    9081
  • src/Parser/TypedefTable.h

    rb110bcc r2ed94a9  
    1919
    2020#include "Common/ScopedMap.h"                                                   // for ScopedMap
     21#include "ParserTypes.h"
     22#include "parser.hh"                                                                    // for IDENTIFIER, TYPEDEFname, TYPEGENname
    2123
    2224class TypedefTable {
    2325        struct Note { size_t level; bool forall; };
    2426        typedef ScopedMap< std::string, int, Note > KindTable;
    25         KindTable kindTable;
     27        KindTable kindTable;   
    2628        unsigned int level = 0;
    2729  public:
     
    3133        bool existsCurr( const std::string & identifier ) const;
    3234        int isKind( const std::string & identifier ) const;
    33         void makeTypedef( const std::string & name, int kind );
    34         void makeTypedef( const std::string & name );
     35        void makeTypedef( const std::string & name, int kind = TYPEDEFname );
    3536        void addToScope( const std::string & identifier, int kind, const char * );
    3637        void addToEnclosingScope( const std::string & identifier, int kind, const char * );
  • src/Parser/lex.ll

    rb110bcc r2ed94a9  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Sat Mar 25 08:09:03 2023
    13  * Update Count     : 768
     12 * Last Modified On : Mon Jan 30 19:03:34 2023
     13 * Update Count     : 767
    1414 */
    1515
     
    2323// line-number directives) and C/C++ style comments, which are ignored.
    2424
    25 // *************************** Includes and Defines ****************************
     25//**************************** Includes and Defines ****************************
    2626
    2727#ifdef __clang__
     
    4444
    4545#include "config.h"                                                                             // configure info
    46 #include "DeclarationNode.h"                            // for DeclarationNode
    47 #include "ExpressionNode.h"                             // for LabelNode
    48 #include "InitializerNode.h"                            // for InitializerNode
    4946#include "ParseNode.h"
    50 #include "ParserTypes.h"                                // for Token
    51 #include "StatementNode.h"                              // for CondCtl, ForCtrl
    5247#include "TypedefTable.h"
    53 // This (generated) header must come late as it is missing includes.
    54 #include "parser.hh"                                    // generated info
    5548
    5649string * build_postfix_name( string * name );
     
    221214__alignof               { KEYWORD_RETURN(ALIGNOF); }                    // GCC
    222215__alignof__             { KEYWORD_RETURN(ALIGNOF); }                    // GCC
    223 and                             { QKEYWORD_RETURN(WAND); }                              // CFA
    224216asm                             { KEYWORD_RETURN(ASM); }
    225217__asm                   { KEYWORD_RETURN(ASM); }                                // GCC
  • src/Parser/module.mk

    rb110bcc r2ed94a9  
    2121SRC += \
    2222       Parser/DeclarationNode.cc \
    23        Parser/DeclarationNode.h \
    2423       Parser/ExpressionNode.cc \
    25        Parser/ExpressionNode.h \
    2624       Parser/InitializerNode.cc \
    27        Parser/InitializerNode.h \
    2825       Parser/lex.ll \
    2926       Parser/ParseNode.cc \
     
    3633       Parser/RunParser.hpp \
    3734       Parser/StatementNode.cc \
    38        Parser/StatementNode.h \
    3935       Parser/TypeData.cc \
    4036       Parser/TypeData.h \
  • src/Parser/parser.yy

    rb110bcc r2ed94a9  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Sep  1 20:22:55 2001
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 14:02:00 2023
    13 // Update Count     : 6329
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb  2 21:36:16 2023
     13// Update Count     : 5865
    1414//
    1515
     
    4444
    4545#include <cstdio>
    46 #include <sstream>
    4746#include <stack>
    4847using namespace std;
    4948
    50 #include "SynTree/Type.h"                               // for Type
    51 #include "DeclarationNode.h"                            // for DeclarationNode, ...
    52 #include "ExpressionNode.h"                             // for ExpressionNode, ...
    53 #include "InitializerNode.h"                            // for InitializerNode, ...
    54 #include "ParserTypes.h"
    55 #include "StatementNode.h"                              // for build_...
     49#include "SynTree/Declaration.h"
     50#include "ParseNode.h"
    5651#include "TypedefTable.h"
    5752#include "TypeData.h"
     53#include "SynTree/LinkageSpec.h"
    5854#include "Common/SemanticError.h"                                               // error_str
    5955#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
    6056
    61 #include "SynTree/Attribute.h"                                                  // for Attribute
     57#include "SynTree/Attribute.h"     // for Attribute
    6258
    6359// lex uses __null in a boolean context, it's fine.
     
    6763
    6864extern DeclarationNode * parseTree;
    69 extern ast::Linkage::Spec linkage;
     65extern LinkageSpec::Spec linkage;
    7066extern TypedefTable typedefTable;
    7167
    72 stack<ast::Linkage::Spec> linkageStack;
     68stack<LinkageSpec::Spec> linkageStack;
    7369
    7470bool appendStr( string & to, string & from ) {
     
    203199} // fieldDecl
    204200
    205 #define NEW_ZERO new ExpressionNode( build_constantInteger( yylloc, *new string( "0" ) ) )
    206 #define NEW_ONE  new ExpressionNode( build_constantInteger( yylloc, *new string( "1" ) ) )
     201#define NEW_ZERO new ExpressionNode( build_constantInteger( *new string( "0" ) ) )
     202#define NEW_ONE  new ExpressionNode( build_constantInteger( *new string( "1" ) ) )
    207203#define UPDOWN( compop, left, right ) (compop == OperKinds::LThan || compop == OperKinds::LEThan ? left : right)
    208204#define MISSING_ANON_FIELD "Missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body."
     
    210206#define MISSING_HIGH "Missing high value for down-to range so index is uninitialized."
    211207
    212 static ForCtrl * makeForCtrl(
    213                 const CodeLocation & location,
    214                 DeclarationNode * init,
    215                 enum OperKinds compop,
    216                 ExpressionNode * comp,
    217                 ExpressionNode * inc ) {
    218         // Wrap both comp/inc if they are non-null.
    219         if ( comp ) comp = new ExpressionNode( build_binary_val( location,
    220                 compop,
    221                 new ExpressionNode( build_varref( location, new string( *init->name ) ) ),
    222                 comp ) );
    223         if ( inc ) inc = new ExpressionNode( build_binary_val( location,
    224                 // choose += or -= for upto/downto
    225                 compop == OperKinds::LThan || compop == OperKinds::LEThan ? OperKinds::PlusAssn : OperKinds::MinusAssn,
    226                 new ExpressionNode( build_varref( location, new string( *init->name ) ) ),
    227                 inc ) );
    228         // The StatementNode call frees init->name, it must happen later.
    229         return new ForCtrl( new StatementNode( init ), comp, inc );
    230 }
    231 
    232 ForCtrl * forCtrl( const CodeLocation & location, DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
     208ForCtrl * forCtrl( DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    233209        if ( index->initializer ) {
    234210                SemanticError( yylloc, "Direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." );
     
    237213                SemanticError( yylloc, "Multiple loop indexes disallowed in for-loop declaration." );
    238214        } // if
    239         DeclarationNode * initDecl = index->addInitializer( new InitializerNode( start ) );
    240         return makeForCtrl( location, initDecl, compop, comp, inc );
     215        return new ForCtrl( index->addInitializer( new InitializerNode( start ) ),
     216                // NULL comp/inc => leave blank
     217                comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index->name ) ) ), comp ) ) : nullptr,
     218                inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
     219                                                        OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index->name ) ) ), inc ) ) : nullptr );
    241220} // forCtrl
    242221
    243 ForCtrl * forCtrl( const CodeLocation & location, ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    244         ast::ConstantExpr * constant = dynamic_cast<ast::ConstantExpr *>(type->expr.get());
    245         if ( constant && (constant->rep == "0" || constant->rep == "1") ) {
    246                 type = new ExpressionNode( new ast::CastExpr( location, maybeMoveBuild(type), new ast::BasicType( ast::BasicType::SignedInt ) ) );
     222ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
     223        ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->expr.get());
     224        if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) {
     225                type = new ExpressionNode( new CastExpr( maybeMoveBuild<Expression>(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) );
    247226        } // if
    248         DeclarationNode * initDecl = distAttr(
    249                 DeclarationNode::newTypeof( type, true ),
    250                 DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) )
    251         );
    252         return makeForCtrl( location, initDecl, compop, comp, inc );
     227//      type = new ExpressionNode( build_func( new ExpressionNode( build_varref( new string( "__for_control_index_constraints__" ) ) ), type ) );
     228        return new ForCtrl(
     229                distAttr( DeclarationNode::newTypeof( type, true ), DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) ) ),
     230                // NULL comp/inc => leave blank
     231                comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ) : nullptr,
     232                inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
     233                                                        OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) : nullptr );
    253234} // forCtrl
    254235
    255 ForCtrl * forCtrl( const CodeLocation & location, ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    256         if ( auto identifier = dynamic_cast<ast::NameExpr *>(index->expr.get()) ) {
    257                 return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc );
    258         } else if ( auto commaExpr = dynamic_cast<ast::CommaExpr *>( index->expr.get() ) ) {
    259                 if ( auto identifier = commaExpr->arg1.as<ast::NameExpr>() ) {
    260                         return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc );
     236ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
     237        if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->expr.get()) ) {
     238                return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
     239        } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->expr.get()) ) {
     240                if ( NameExpr * identifier = dynamic_cast<NameExpr *>(commaExpr->arg1 ) ) {
     241                        return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    261242                } else {
    262243                        SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
     
    300281%union {
    301282        Token tok;
    302         ExpressionNode * expr;
     283        ParseNode * pn;
     284        ExpressionNode * en;
    303285        DeclarationNode * decl;
    304         ast::AggregateDecl::Aggregate aggKey;
    305         ast::TypeDecl::Kind tclass;
    306         StatementNode * stmt;
    307         ClauseNode * clause;
    308         ast::WaitForStmt * wfs;
     286        AggregateDecl::Aggregate aggKey;
     287        TypeDecl::Kind tclass;
     288        StatementNode * sn;
     289        WaitForStmt * wfs;
     290        Expression * constant;
    309291        CondCtl * ifctl;
    310         ForCtrl * forctl;
    311         LabelNode * labels;
    312         InitializerNode * init;
    313         OperKinds oper;
     292        ForCtrl * fctl;
     293        OperKinds compop;
     294        LabelNode * label;
     295        InitializerNode * in;
     296        OperKinds op;
    314297        std::string * str;
    315         bool is_volatile;
    316         EnumHiding enum_hiding;
    317         ast::ExceptionKind except_kind;
    318         ast::GenericExpr * genexpr;
     298        bool flag;
     299        EnumHiding hide;
     300        CatchStmt::Kind catch_kind;
     301        GenericExpr * genexpr;
    319302}
    320303
    321 // ************************ TERMINAL TOKENS ********************************
     304//************************* TERMINAL TOKENS ********************************
    322305
    323306// keywords
     
    354337
    355338// names and constants: lexer differentiates between identifier and typedef names
    356 %token<tok> IDENTIFIER          TYPEDIMname             TYPEDEFname             TYPEGENname
    357 %token<tok> TIMEOUT                     WAND    WOR                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
     339%token<tok> IDENTIFIER          QUOTED_IDENTIFIER       TYPEDIMname             TYPEDEFname             TYPEGENname
     340%token<tok> TIMEOUT                     WOR                                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
    358341%token<tok> INTEGERconstant     CHARACTERconstant       STRINGliteral
    359342%token<tok> DIRECTIVE
     
    381364%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    382365%type<tok> quasi_keyword
    383 %type<expr> string_literal
     366%type<constant> string_literal
    384367%type<str> string_literal_list
    385368
    386 %type<enum_hiding> hide_opt                                     visible_hide_opt
     369%type<hide> hide_opt                                    visible_hide_opt
    387370
    388371// expressions
    389 %type<expr> constant
    390 %type<expr> tuple                                                       tuple_expression_list
    391 %type<oper> ptrref_operator                             unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
    392 %type<expr> primary_expression                  postfix_expression                      unary_expression
    393 %type<expr> cast_expression_list                        cast_expression                         exponential_expression          multiplicative_expression       additive_expression
    394 %type<expr> shift_expression                            relational_expression           equality_expression
    395 %type<expr> AND_expression                              exclusive_OR_expression         inclusive_OR_expression
    396 %type<expr> logical_AND_expression              logical_OR_expression
    397 %type<expr> conditional_expression              constant_expression                     assignment_expression           assignment_expression_opt
    398 %type<expr> comma_expression                            comma_expression_opt
    399 %type<expr> argument_expression_list_opt        argument_expression_list        argument_expression                     default_initializer_opt
     372%type<en> constant
     373%type<en> tuple                                                 tuple_expression_list
     374%type<op> ptrref_operator                               unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
     375%type<en> primary_expression                    postfix_expression                      unary_expression
     376%type<en> cast_expression_list                  cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     377%type<en> shift_expression                              relational_expression           equality_expression
     378%type<en> AND_expression                                exclusive_OR_expression         inclusive_OR_expression
     379%type<en> logical_AND_expression                logical_OR_expression
     380%type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
     381%type<en> comma_expression                              comma_expression_opt
     382%type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
    400383%type<ifctl> conditional_declaration
    401 %type<forctl> for_control_expression            for_control_expression_list
    402 %type<oper> upupeq updown updowneq downupdowneq
    403 %type<expr> subrange
     384%type<fctl> for_control_expression              for_control_expression_list
     385%type<compop> upupeq updown updowneq downupdowneq
     386%type<en> subrange
    404387%type<decl> asm_name_opt
    405 %type<expr> asm_operands_opt                            asm_operands_list                       asm_operand
    406 %type<labels> label_list
    407 %type<expr> asm_clobbers_list_opt
    408 %type<is_volatile> asm_volatile_opt
    409 %type<expr> handler_predicate_opt
     388%type<en> asm_operands_opt                              asm_operands_list                       asm_operand
     389%type<label> label_list
     390%type<en> asm_clobbers_list_opt
     391%type<flag> asm_volatile_opt
     392%type<en> handler_predicate_opt
    410393%type<genexpr> generic_association              generic_assoc_list
    411394
    412395// statements
    413 %type<stmt> statement                                           labeled_statement                       compound_statement
    414 %type<stmt> statement_decl                              statement_decl_list                     statement_list_nodecl
    415 %type<stmt> selection_statement                 if_statement
    416 %type<clause> switch_clause_list_opt            switch_clause_list
    417 %type<expr> case_value
    418 %type<clause> case_clause                               case_value_list                         case_label                                      case_label_list
    419 %type<stmt> iteration_statement                 jump_statement
    420 %type<stmt> expression_statement                        asm_statement
    421 %type<stmt> with_statement
    422 %type<expr> with_clause_opt
    423 %type<stmt> exception_statement
    424 %type<clause> handler_clause                    finally_clause
    425 %type<except_kind> handler_key
    426 %type<stmt> mutex_statement
    427 %type<expr> when_clause                                 when_clause_opt                         waitfor         waituntil               timeout
    428 %type<stmt> waitfor_statement                           waituntil_statement
    429 %type<wfs> wor_waitfor_clause                   waituntil_clause                        wand_waituntil_clause   wor_waituntil_clause
     396%type<sn> statement                                             labeled_statement                       compound_statement
     397%type<sn> statement_decl                                statement_decl_list                     statement_list_nodecl
     398%type<sn> selection_statement                   if_statement
     399%type<sn> switch_clause_list_opt                switch_clause_list
     400%type<en> case_value
     401%type<sn> case_clause                                   case_value_list                         case_label                                      case_label_list
     402%type<sn> iteration_statement                   jump_statement
     403%type<sn> expression_statement                  asm_statement
     404%type<sn> with_statement
     405%type<en> with_clause_opt
     406%type<sn> exception_statement                   handler_clause                          finally_clause
     407%type<catch_kind> handler_key
     408%type<sn> mutex_statement
     409%type<en> when_clause                                   when_clause_opt                         waitfor                                         timeout
     410%type<sn> waitfor_statement
     411%type<wfs> waitfor_clause
    430412
    431413// declarations
     
    439421%type<decl> assertion assertion_list assertion_list_opt
    440422
    441 %type<expr> bit_subrange_size_opt bit_subrange_size
     423%type<en> bit_subrange_size_opt bit_subrange_size
    442424
    443425%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    452434
    453435%type<decl> enumerator_list enum_type enum_type_nobody
    454 %type<init> enumerator_value_opt
     436%type<in> enumerator_value_opt
    455437
    456438%type<decl> external_definition external_definition_list external_definition_list_opt
     
    459441
    460442%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
    461 %type<expr> field field_name_list field_name fraction_constants_opt
     443%type<en> field field_name_list field_name fraction_constants_opt
    462444
    463445%type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
     
    500482%type<decl> typedef_name typedef_declaration typedef_expression
    501483
    502 %type<decl> variable_type_redeclarator variable_type_ptr variable_type_array variable_type_function
    503 %type<decl> general_function_declarator function_type_redeclarator function_type_array function_type_no_ptr function_type_ptr
     484%type<decl> variable_type_redeclarator type_ptr type_array type_function
    504485
    505486%type<decl> type_parameter_redeclarator type_parameter_ptr type_parameter_array type_parameter_function
     
    508489%type<decl> type_parameter type_parameter_list type_initializer_opt
    509490
    510 %type<expr> type_parameters_opt type_list array_type_list
     491%type<en> type_parameters_opt type_list array_type_list
    511492
    512493%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     
    519500
    520501// initializers
    521 %type<init>  initializer initializer_list_opt initializer_opt
     502%type<in>  initializer initializer_list_opt initializer_opt
    522503
    523504// designators
    524 %type<expr>  designator designator_list designation
     505%type<en>  designator designator_list designation
    525506
    526507
     
    531512// Similar issues exit with the waitfor statement.
    532513
    533 // Order of these lines matters (low-to-high precedence). THEN is left associative over WAND/WOR/TIMEOUT/ELSE, WAND/WOR
    534 // is left associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE.
     514// Order of these lines matters (low-to-high precedence). THEN is left associative over WOR/TIMEOUT/ELSE, WOR is left
     515// associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE.
    535516%precedence THEN                // rule precedence for IF/WAITFOR statement
    536 %precedence ANDAND              // token precedence for start of WAND in WAITFOR statement
    537 %precedence WAND                // token precedence for start of WAND in WAITFOR statement
    538 %precedence OROR                // token precedence for start of WOR in WAITFOR statement
    539517%precedence WOR                 // token precedence for start of WOR in WAITFOR statement
    540518%precedence TIMEOUT             // token precedence for start of TIMEOUT in WAITFOR statement
     
    614592constant:
    615593                // ENUMERATIONconstant is not included here; it is treated as a variable with type "enumeration constant".
    616         INTEGERconstant                                                         { $$ = new ExpressionNode( build_constantInteger( yylloc, *$1 ) ); }
    617         | FLOATING_DECIMALconstant                                      { $$ = new ExpressionNode( build_constantFloat( yylloc, *$1 ) ); }
    618         | FLOATING_FRACTIONconstant                                     { $$ = new ExpressionNode( build_constantFloat( yylloc, *$1 ) ); }
    619         | FLOATINGconstant                                                      { $$ = new ExpressionNode( build_constantFloat( yylloc, *$1 ) ); }
    620         | CHARACTERconstant                                                     { $$ = new ExpressionNode( build_constantChar( yylloc, *$1 ) ); }
     594        INTEGERconstant                                                         { $$ = new ExpressionNode( build_constantInteger( *$1 ) ); }
     595        | FLOATING_DECIMALconstant                                      { $$ = new ExpressionNode( build_constantFloat( *$1 ) ); }
     596        | FLOATING_FRACTIONconstant                                     { $$ = new ExpressionNode( build_constantFloat( *$1 ) ); }
     597        | FLOATINGconstant                                                      { $$ = new ExpressionNode( build_constantFloat( *$1 ) ); }
     598        | CHARACTERconstant                                                     { $$ = new ExpressionNode( build_constantChar( *$1 ) ); }
    621599        ;
    622600
    623601quasi_keyword:                                                                                  // CFA
    624602        TIMEOUT
    625         | WAND
    626603        | WOR
    627604        | CATCH
     
    644621
    645622string_literal:
    646         string_literal_list                                                     { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); }
     623        string_literal_list                                                     { $$ = build_constantStr( *$1 ); }
    647624        ;
    648625
     
    661638primary_expression:
    662639        IDENTIFIER                                                                                      // typedef name cannot be used as a variable name
    663                 { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
     640                { $$ = new ExpressionNode( build_varref( $1 ) ); }
    664641        | quasi_keyword
    665                 { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
     642                { $$ = new ExpressionNode( build_varref( $1 ) ); }
    666643        | TYPEDIMname                                                                           // CFA, generic length argument
    667644                // { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( DeclarationNode::newFromTypedef( $1 ) ) ) ); }
    668645                // { $$ = new ExpressionNode( build_varref( $1 ) ); }
    669                 { $$ = new ExpressionNode( build_dimensionref( yylloc, $1 ) ); }
     646                { $$ = new ExpressionNode( build_dimensionref( $1 ) ); }
    670647        | tuple
    671648        | '(' comma_expression ')'
    672649                { $$ = $2; }
    673650        | '(' compound_statement ')'                                            // GCC, lambda expression
    674                 { $$ = new ExpressionNode( new ast::StmtExpr( yylloc, dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( $2 ) ) ) ); }
     651                { $$ = new ExpressionNode( new StmtExpr( dynamic_cast<CompoundStmt *>(maybeMoveBuild<Statement>($2) ) ) ); }
    675652        | type_name '.' identifier                                                      // CFA, nested type
    676                 { $$ = new ExpressionNode( build_qualified_expr( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
     653                { $$ = new ExpressionNode( build_qualified_expr( $1, build_varref( $3 ) ) ); }
    677654        | type_name '.' '[' field_name_list ']'                         // CFA, nested type / tuple field selector
    678655                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
     
    680657                {
    681658                        // add the missing control expression to the GenericExpr and return it
    682                         $5->control = maybeMoveBuild( $3 );
     659                        $5->control = maybeMoveBuild<Expression>( $3 );
    683660                        $$ = new ExpressionNode( $5 );
    684661                }
     
    706683                {
    707684                        // steal the association node from the singleton and delete the wrapper
    708                         assert( 1 == $3->associations.size() );
    709                         $1->associations.push_back( $3->associations.front() );
     685                        $1->associations.splice($1->associations.end(), $3->associations);
    710686                        delete $3;
    711687                        $$ = $1;
     
    717693                {
    718694                        // create a GenericExpr wrapper with one association pair
    719                         $$ = new ast::GenericExpr( yylloc, nullptr, { { maybeMoveBuildType( $1 ), maybeMoveBuild( $3 ) } } );
     695                        $$ = new GenericExpr( nullptr, { { maybeMoveBuildType($1), maybeMoveBuild<Expression>( $3 ) } } );
    720696                }
    721697        | DEFAULT ':' assignment_expression
    722                 { $$ = new ast::GenericExpr( yylloc, nullptr, { { maybeMoveBuild( $3 ) } } ); }
     698                { $$ = new GenericExpr( nullptr, { { maybeMoveBuild<Expression>( $3 ) } } ); }
    723699        ;
    724700
     
    729705                // Switching to this behaviour may help check if a C compatibilty case uses comma-exprs in subscripts.
    730706                // Current: Commas in subscripts make tuples.
    731                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
     707                { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
    732708        | postfix_expression '[' assignment_expression ']'
    733709                // CFA, comma_expression disallowed in this context because it results in a common user error: subscripting a
     
    735711                // little advantage to this feature and many disadvantages. It is possible to write x[(i,j)] in CFA, which is
    736712                // equivalent to the old x[i,j].
    737                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
     713                { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
    738714        | constant '[' assignment_expression ']'                        // 3[a], 'a'[a], 3.5[a]
    739                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
     715                { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
    740716        | string_literal '[' assignment_expression ']'          // "abc"[3], 3["abc"]
    741                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
     717                { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }
    742718        | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
    743719                {
    744720                        Token fn;
    745721                        fn.str = new std::string( "?{}" );                      // location undefined - use location of '{'?
    746                         $$ = new ExpressionNode( new ast::ConstructorExpr( yylloc, build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
     722                        $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
    747723                }
    748724        | postfix_expression '(' argument_expression_list_opt ')'
    749                 { $$ = new ExpressionNode( build_func( yylloc, $1, $3 ) ); }
     725                { $$ = new ExpressionNode( build_func( $1, $3 ) ); }
    750726        | VA_ARG '(' primary_expression ',' declaration_specifier_nobody abstract_parameter_declarator_opt ')'
    751727                // { SemanticError( yylloc, "va_arg is currently unimplemented." ); $$ = nullptr; }
    752                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, new string( "__builtin_va_arg") ) ),
     728                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( new string( "__builtin_va_arg") ) ),
    753729                                                                                           (ExpressionNode *)($3->set_last( (ExpressionNode *)($6 ? $6->addType( $5 ) : $5) )) ) ); }
    754730        | postfix_expression '`' identifier                                     // CFA, postfix call
    755                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
     731                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
    756732        | constant '`' identifier                                                       // CFA, postfix call
    757                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
     733                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
    758734        | string_literal '`' identifier                                         // CFA, postfix call
    759                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
     735                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
    760736        | postfix_expression '.' identifier
    761                 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
     737                { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
    762738        | postfix_expression '.' INTEGERconstant                        // CFA, tuple index
    763                 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_constantInteger( yylloc, *$3 ) ) ); }
     739                { $$ = new ExpressionNode( build_fieldSel( $1, build_constantInteger( *$3 ) ) ); }
    764740        | postfix_expression FLOATING_FRACTIONconstant          // CFA, tuple index
    765                 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_field_name_FLOATING_FRACTIONconstant( yylloc, *$2 ) ) ); }
     741                { $$ = new ExpressionNode( build_fieldSel( $1, build_field_name_FLOATING_FRACTIONconstant( *$2 ) ) ); }
    766742        | postfix_expression '.' '[' field_name_list ']'        // CFA, tuple field selector
    767                 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
     743                { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
    768744        | postfix_expression '.' aggregate_control
    769                 { $$ = new ExpressionNode( build_keyword_cast( yylloc, $3, $1 ) ); }
     745                { $$ = new ExpressionNode( build_keyword_cast( $3, $1 ) ); }
    770746        | postfix_expression ARROW identifier
    771                 { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
     747                { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
    772748        | postfix_expression ARROW INTEGERconstant                      // CFA, tuple index
    773                 { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_constantInteger( yylloc, *$3 ) ) ); }
     749                { $$ = new ExpressionNode( build_pfieldSel( $1, build_constantInteger( *$3 ) ) ); }
    774750        | postfix_expression ARROW '[' field_name_list ']'      // CFA, tuple field selector
    775                 { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
     751                { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
    776752        | postfix_expression ICR
    777                 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::IncrPost, $1 ) ); }
     753                { $$ = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, $1 ) ); }
    778754        | postfix_expression DECR
    779                 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::DecrPost, $1 ) ); }
     755                { $$ = new ExpressionNode( build_unary_ptr( OperKinds::DecrPost, $1 ) ); }
    780756        | '(' type_no_function ')' '{' initializer_list_opt comma_opt '}' // C99, compound-literal
    781                 { $$ = new ExpressionNode( build_compoundLiteral( yylloc, $2, new InitializerNode( $5, true ) ) ); }
     757                { $$ = new ExpressionNode( build_compoundLiteral( $2, new InitializerNode( $5, true ) ) ); }
    782758        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    783                 { $$ = new ExpressionNode( build_compoundLiteral( yylloc, $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
     759                { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    784760        | '^' primary_expression '{' argument_expression_list_opt '}' // CFA, destructor call
    785761                {
    786762                        Token fn;
    787763                        fn.str = new string( "^?{}" );                          // location undefined
    788                         $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) );
     764                        $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) );
    789765                }
    790766        ;
     
    805781        '@'                                                                                                     // CFA, default parameter
    806782                { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; }
    807                 // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
     783                // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
    808784        | assignment_expression
    809785        ;
     
    817793        field_name
    818794        | FLOATING_DECIMALconstant field
    819                 { $$ = new ExpressionNode( build_fieldSel( yylloc, new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( yylloc, *$1 ) ), maybeMoveBuild( $2 ) ) ); }
     795                { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), maybeMoveBuild<Expression>( $2 ) ) ); }
    820796        | FLOATING_DECIMALconstant '[' field_name_list ']'
    821                 { $$ = new ExpressionNode( build_fieldSel( yylloc, new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( yylloc, *$1 ) ), build_tuple( yylloc, $3 ) ) ); }
     797                { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), build_tuple( $3 ) ) ); }
    822798        | field_name '.' field
    823                 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); }
     799                { $$ = new ExpressionNode( build_fieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
    824800        | field_name '.' '[' field_name_list ']'
    825                 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
     801                { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
    826802        | field_name ARROW field
    827                 { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); }
     803                { $$ = new ExpressionNode( build_pfieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
    828804        | field_name ARROW '[' field_name_list ']'
    829                 { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
     805                { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
    830806        ;
    831807
    832808field_name:
    833809        INTEGERconstant fraction_constants_opt
    834                 { $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_constantInteger( yylloc, *$1 ), $2 ) ); }
     810                { $$ = new ExpressionNode( build_field_name_fraction_constants( build_constantInteger( *$1 ), $2 ) ); }
    835811        | FLOATINGconstant fraction_constants_opt
    836                 { $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_field_name_FLOATINGconstant( yylloc, *$1 ), $2 ) ); }
     812                { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); }
    837813        | identifier_at fraction_constants_opt                          // CFA, allow anonymous fields
    838814                {
    839                         $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_varref( yylloc, $1 ), $2 ) );
     815                        $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) );
    840816                }
    841817        ;
     
    846822        | fraction_constants_opt FLOATING_FRACTIONconstant
    847823                {
    848                         ast::Expr * constant = build_field_name_FLOATING_FRACTIONconstant( yylloc, *$2 );
    849                         $$ = $1 != nullptr ? new ExpressionNode( build_fieldSel( yylloc, $1, constant ) ) : new ExpressionNode( constant );
     824                        Expression * constant = build_field_name_FLOATING_FRACTIONconstant( *$2 );
     825                        $$ = $1 != nullptr ? new ExpressionNode( build_fieldSel( $1, constant ) ) : new ExpressionNode( constant );
    850826                }
    851827        ;
     
    857833        | constant
    858834        | string_literal
    859                 { $$ = $1; }
     835                { $$ = new ExpressionNode( $1 ); }
    860836        | EXTENSION cast_expression                                                     // GCC
    861837                { $$ = $2->set_extension( true ); }
     
    866842                {
    867843                        switch ( $1 ) {
    868                         case OperKinds::AddressOf:
    869                                 $$ = new ExpressionNode( new ast::AddressExpr( maybeMoveBuild( $2 ) ) );
     844                          case OperKinds::AddressOf:
     845                                $$ = new ExpressionNode( new AddressExpr( maybeMoveBuild<Expression>( $2 ) ) );
    870846                                break;
    871                         case OperKinds::PointTo:
    872                                 $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) );
     847                          case OperKinds::PointTo:
     848                                $$ = new ExpressionNode( build_unary_val( $1, $2 ) );
    873849                                break;
    874                         case OperKinds::And:
    875                                 $$ = new ExpressionNode( new ast::AddressExpr( new ast::AddressExpr( maybeMoveBuild( $2 ) ) ) );
     850                          case OperKinds::And:
     851                                $$ = new ExpressionNode( new AddressExpr( new AddressExpr( maybeMoveBuild<Expression>( $2 ) ) ) );
    876852                                break;
    877                         default:
     853                          default:
    878854                                assert( false );
    879855                        }
    880856                }
    881857        | unary_operator cast_expression
    882                 { $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) ); }
     858                { $$ = new ExpressionNode( build_unary_val( $1, $2 ) ); }
    883859        | ICR unary_expression
    884                 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Incr, $2 ) ); }
     860                { $$ = new ExpressionNode( build_unary_ptr( OperKinds::Incr, $2 ) ); }
    885861        | DECR unary_expression
    886                 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Decr, $2 ) ); }
     862                { $$ = new ExpressionNode( build_unary_ptr( OperKinds::Decr, $2 ) ); }
    887863        | SIZEOF unary_expression
    888                 { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuild( $2 ) ) ); }
     864                { $$ = new ExpressionNode( new SizeofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }
    889865        | SIZEOF '(' type_no_function ')'
    890                 { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
     866                { $$ = new ExpressionNode( new SizeofExpr( maybeMoveBuildType( $3 ) ) ); }
    891867        | ALIGNOF unary_expression                                                      // GCC, variable alignment
    892                 { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuild( $2 ) ) ); }
     868                { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }
    893869        | ALIGNOF '(' type_no_function ')'                                      // GCC, type alignment
    894                 { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
     870                { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuildType( $3 ) ) ); }
    895871        | OFFSETOF '(' type_no_function ',' identifier ')'
    896                 { $$ = new ExpressionNode( build_offsetOf( yylloc, $3, build_varref( yylloc, $5 ) ) ); }
     872                { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); }
    897873        | TYPEID '(' type_no_function ')'
    898874                {
     
    919895        unary_expression
    920896        | '(' type_no_function ')' cast_expression
    921                 { $$ = new ExpressionNode( build_cast( yylloc, $2, $4 ) ); }
     897                { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    922898        | '(' aggregate_control '&' ')' cast_expression         // CFA
    923                 { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); }
     899                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
    924900        | '(' aggregate_control '*' ')' cast_expression         // CFA
    925                 { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); }
     901                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
    926902        | '(' VIRTUAL ')' cast_expression                                       // CFA
    927                 { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $4 ), maybeMoveBuildType( nullptr ) ) ); }
     903                { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild<Expression>( $4 ), maybeMoveBuildType( nullptr ) ) ); }
    928904        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    929                 { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); }
     905                { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild<Expression>( $5 ), maybeMoveBuildType( $3 ) ) ); }
    930906        | '(' RETURN type_no_function ')' cast_expression       // CFA
    931907                { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }
     
    935911                { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; }
    936912//      | '(' type_no_function ')' tuple
    937 //              { $$ = new ast::ExpressionNode( build_cast( yylloc, $2, $4 ) ); }
     913//              { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    938914        ;
    939915
     
    953929        cast_expression
    954930        | exponential_expression '\\' cast_expression
    955                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Exp, $1, $3 ) ); }
     931                { $$ = new ExpressionNode( build_binary_val( OperKinds::Exp, $1, $3 ) ); }
    956932        ;
    957933
     
    959935        exponential_expression
    960936        | multiplicative_expression '*' exponential_expression
    961                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Mul, $1, $3 ) ); }
     937                { $$ = new ExpressionNode( build_binary_val( OperKinds::Mul, $1, $3 ) ); }
    962938        | multiplicative_expression '/' exponential_expression
    963                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Div, $1, $3 ) ); }
     939                { $$ = new ExpressionNode( build_binary_val( OperKinds::Div, $1, $3 ) ); }
    964940        | multiplicative_expression '%' exponential_expression
    965                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Mod, $1, $3 ) ); }
     941                { $$ = new ExpressionNode( build_binary_val( OperKinds::Mod, $1, $3 ) ); }
    966942        ;
    967943
     
    969945        multiplicative_expression
    970946        | additive_expression '+' multiplicative_expression
    971                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Plus, $1, $3 ) ); }
     947                { $$ = new ExpressionNode( build_binary_val( OperKinds::Plus, $1, $3 ) ); }
    972948        | additive_expression '-' multiplicative_expression
    973                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Minus, $1, $3 ) ); }
     949                { $$ = new ExpressionNode( build_binary_val( OperKinds::Minus, $1, $3 ) ); }
    974950        ;
    975951
     
    977953        additive_expression
    978954        | shift_expression LS additive_expression
    979                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LShift, $1, $3 ) ); }
     955                { $$ = new ExpressionNode( build_binary_val( OperKinds::LShift, $1, $3 ) ); }
    980956        | shift_expression RS additive_expression
    981                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::RShift, $1, $3 ) ); }
     957                { $$ = new ExpressionNode( build_binary_val( OperKinds::RShift, $1, $3 ) ); }
    982958        ;
    983959
     
    985961        shift_expression
    986962        | relational_expression '<' shift_expression
    987                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LThan, $1, $3 ) ); }
     963                { $$ = new ExpressionNode( build_binary_val( OperKinds::LThan, $1, $3 ) ); }
    988964        | relational_expression '>' shift_expression
    989                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::GThan, $1, $3 ) ); }
     965                { $$ = new ExpressionNode( build_binary_val( OperKinds::GThan, $1, $3 ) ); }
    990966        | relational_expression LE shift_expression
    991                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LEThan, $1, $3 ) ); }
     967                { $$ = new ExpressionNode( build_binary_val( OperKinds::LEThan, $1, $3 ) ); }
    992968        | relational_expression GE shift_expression
    993                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::GEThan, $1, $3 ) ); }
     969                { $$ = new ExpressionNode( build_binary_val( OperKinds::GEThan, $1, $3 ) ); }
    994970        ;
    995971
     
    997973        relational_expression
    998974        | equality_expression EQ relational_expression
    999                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Eq, $1, $3 ) ); }
     975                { $$ = new ExpressionNode( build_binary_val( OperKinds::Eq, $1, $3 ) ); }
    1000976        | equality_expression NE relational_expression
    1001                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Neq, $1, $3 ) ); }
     977                { $$ = new ExpressionNode( build_binary_val( OperKinds::Neq, $1, $3 ) ); }
    1002978        ;
    1003979
     
    1005981        equality_expression
    1006982        | AND_expression '&' equality_expression
    1007                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::BitAnd, $1, $3 ) ); }
     983                { $$ = new ExpressionNode( build_binary_val( OperKinds::BitAnd, $1, $3 ) ); }
    1008984        ;
    1009985
     
    1011987        AND_expression
    1012988        | exclusive_OR_expression '^' AND_expression
    1013                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Xor, $1, $3 ) ); }
     989                { $$ = new ExpressionNode( build_binary_val( OperKinds::Xor, $1, $3 ) ); }
    1014990        ;
    1015991
     
    1017993        exclusive_OR_expression
    1018994        | inclusive_OR_expression '|' exclusive_OR_expression
    1019                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::BitOr, $1, $3 ) ); }
     995                { $$ = new ExpressionNode( build_binary_val( OperKinds::BitOr, $1, $3 ) ); }
    1020996        ;
    1021997
     
    1023999        inclusive_OR_expression
    10241000        | logical_AND_expression ANDAND inclusive_OR_expression
    1025                 { $$ = new ExpressionNode( build_and_or( yylloc, $1, $3, ast::AndExpr ) ); }
     1001                { $$ = new ExpressionNode( build_and_or( $1, $3, true ) ); }
    10261002        ;
    10271003
     
    10291005        logical_AND_expression
    10301006        | logical_OR_expression OROR logical_AND_expression
    1031                 { $$ = new ExpressionNode( build_and_or( yylloc, $1, $3, ast::OrExpr ) ); }
     1007                { $$ = new ExpressionNode( build_and_or( $1, $3, false ) ); }
    10321008        ;
    10331009
     
    10351011        logical_OR_expression
    10361012        | logical_OR_expression '?' comma_expression ':' conditional_expression
    1037                 { $$ = new ExpressionNode( build_cond( yylloc, $1, $3, $5 ) ); }
     1013                { $$ = new ExpressionNode( build_cond( $1, $3, $5 ) ); }
    10381014                // FIX ME: computes $1 twice
    10391015        | logical_OR_expression '?' /* empty */ ':' conditional_expression // GCC, omitted first operand
    1040                 { $$ = new ExpressionNode( build_cond( yylloc, $1, $1, $4 ) ); }
     1016                { $$ = new ExpressionNode( build_cond( $1, $1, $4 ) ); }
    10411017        ;
    10421018
     
    10531029//                              SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr;
    10541030//                      } else {
    1055                                 $$ = new ExpressionNode( build_binary_val( yylloc, $2, $1, $3 ) );
     1031                                $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) );
    10561032//                      } // if
    10571033                }
     
    10981074//              { $$ = new ExpressionNode( build_tuple( $3 ) ); }
    10991075        '[' ',' tuple_expression_list ']'
    1100                 { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
     1076                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
    11011077        | '[' push assignment_expression pop ',' tuple_expression_list ']'
    1102                 { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $6 ) ) )); }
     1078                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $6 ) ) )); }
    11031079        ;
    11041080
     
    11161092        assignment_expression
    11171093        | comma_expression ',' assignment_expression
    1118                 { $$ = new ExpressionNode( new ast::CommaExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
     1094                { $$ = new ExpressionNode( new CommaExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
    11191095        ;
    11201096
     
    11371113        | mutex_statement
    11381114        | waitfor_statement
    1139         | waituntil_statement
    11401115        | exception_statement
    11411116        | enable_disable_statement
     
    11431118        | asm_statement
    11441119        | DIRECTIVE
    1145                 { $$ = new StatementNode( build_directive( yylloc, $1 ) ); }
     1120                { $$ = new StatementNode( build_directive( $1 ) ); }
    11461121        ;
    11471122
     
    11491124                // labels cannot be identifiers 0 or 1
    11501125        identifier_or_type_name ':' attribute_list_opt statement
    1151                 { $$ = $4->add_label( yylloc, $1, $3 ); }
     1126                { $$ = $4->add_label( $1, $3 ); }
    11521127        | identifier_or_type_name ':' attribute_list_opt error // syntax error
    11531128                {
     
    11611136compound_statement:
    11621137        '{' '}'
    1163                 { $$ = new StatementNode( build_compound( yylloc, (StatementNode *)0 ) ); }
     1138                { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); }
    11641139        | '{' push
    11651140          local_label_declaration_opt                                           // GCC, local labels appear at start of block
    11661141          statement_decl_list                                                           // C99, intermix declarations and statements
    11671142          pop '}'
    1168                 { $$ = new StatementNode( build_compound( yylloc, $4 ) ); }
     1143                { $$ = new StatementNode( build_compound( $4 ) ); }
    11691144        ;
    11701145
     
    11971172expression_statement:
    11981173        comma_expression_opt ';'
    1199                 { $$ = new StatementNode( build_expr( yylloc, $1 ) ); }
     1174                { $$ = new StatementNode( build_expr( $1 ) ); }
     1175        | MUTEX '(' ')' comma_expression ';'
     1176                { $$ = new StatementNode( build_mutex( nullptr, new StatementNode( build_expr( $4 ) ) ) ); }
    12001177        ;
    12011178
     
    12061183                { $$ = $2; }
    12071184        | SWITCH '(' comma_expression ')' case_clause
    1208                 { $$ = new StatementNode( build_switch( yylloc, true, $3, $5 ) ); }
     1185                { $$ = new StatementNode( build_switch( true, $3, $5 ) ); }
    12091186        | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA
    12101187                {
    1211                         StatementNode *sw = new StatementNode( build_switch( yylloc, true, $3, $8 ) );
     1188                        StatementNode *sw = new StatementNode( build_switch( true, $3, $8 ) );
    12121189                        // The semantics of the declaration list is changed to include associated initialization, which is performed
    12131190                        // *before* the transfer to the appropriate case clause by hoisting the declarations into a compound
     
    12151192                        // therefore, are removed from the grammar even though C allows it. The change also applies to choose
    12161193                        // statement.
    1217                         $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     1194                        $$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
    12181195                }
    12191196        | SWITCH '(' comma_expression ')' '{' error '}'         // CFA, syntax error
    12201197                { SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; }
    12211198        | CHOOSE '(' comma_expression ')' case_clause           // CFA
    1222                 { $$ = new StatementNode( build_switch( yylloc, false, $3, $5 ) ); }
     1199                { $$ = new StatementNode( build_switch( false, $3, $5 ) ); }
    12231200        | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA
    12241201                {
    1225                         StatementNode *sw = new StatementNode( build_switch( yylloc, false, $3, $8 ) );
    1226                         $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     1202                        StatementNode *sw = new StatementNode( build_switch( false, $3, $8 ) );
     1203                        $$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
    12271204                }
    12281205        | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, syntax error
     
    12331210        IF '(' conditional_declaration ')' statement            %prec THEN
    12341211                // explicitly deal with the shift/reduce conflict on if/else
    1235                 { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), nullptr ) ); }
     1212                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); }
    12361213        | IF '(' conditional_declaration ')' statement ELSE statement
    1237                 { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), maybe_build_compound( yylloc, $7 ) ) ); }
     1214                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
    12381215        ;
    12391216
     
    12471224        | declaration comma_expression                                          // semi-colon separated
    12481225                { $$ = new CondCtl( $1, $2 ); }
    1249         ;
     1226        ;
    12501227
    12511228// CASE and DEFAULT clauses are only allowed in the SWITCH statement, precluding Duff's device. In addition, a case
     
    12551232        constant_expression                                                     { $$ = $1; }
    12561233        | constant_expression ELLIPSIS constant_expression      // GCC, subrange
    1257                 { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
     1234                { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
    12581235        | subrange                                                                                      // CFA, subrange
    12591236        ;
    12601237
    12611238case_value_list:                                                                                // CFA
    1262         case_value                                                                      { $$ = new ClauseNode( build_case( yylloc, $1 ) ); }
     1239        case_value                                                                      { $$ = new StatementNode( build_case( $1 ) ); }
    12631240                // convert case list, e.g., "case 1, 3, 5:" into "case 1: case 3: case 5"
    1264         | case_value_list ',' case_value                        { $$ = $1->set_last( new ClauseNode( build_case( yylloc, $3 ) ) ); }
     1241        | case_value_list ',' case_value                        { $$ = (StatementNode *)($1->set_last( new StatementNode( build_case( $3 ) ) ) ); }
    12651242        ;
    12661243
     
    12711248        | CASE case_value_list error                                            // syntax error
    12721249                { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
    1273         | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
     1250        | DEFAULT ':'                                                           { $$ = new StatementNode( build_default() ); }
    12741251                // A semantic check is required to ensure only one default clause per switch/choose statement.
    12751252        | DEFAULT error                                                                         //  syntax error
     
    12791256case_label_list:                                                                                // CFA
    12801257        case_label
    1281         | case_label_list case_label                            { $$ = $1->set_last( $2 ); }
     1258        | case_label_list case_label                            { $$ = (StatementNode *)( $1->set_last( $2 )); }
    12821259        ;
    12831260
    12841261case_clause:                                                                                    // CFA
    1285         case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( yylloc, $2 ) ); }
     1262        case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); }
    12861263        ;
    12871264
     
    12941271switch_clause_list:                                                                             // CFA
    12951272        case_label_list statement_list_nodecl
    1296                 { $$ = $1->append_last_case( new StatementNode( build_compound( yylloc, $2 ) ) ); }
     1273                { $$ = $1->append_last_case( new StatementNode( build_compound( $2 ) ) ); }
    12971274        | switch_clause_list case_label_list statement_list_nodecl
    1298                 { $$ = $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ); }
     1275                { $$ = (StatementNode *)( $1->set_last( $2->append_last_case( new StatementNode( build_compound( $3 ) ) ) ) ); }
    12991276        ;
    13001277
    13011278iteration_statement:
    13021279        WHILE '(' ')' statement                                                         %prec THEN // CFA => while ( 1 )
    1303                 { $$ = new StatementNode( build_while( yylloc, new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( yylloc, $4 ) ) ); }
     1280                { $$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) ); }
    13041281        | WHILE '(' ')' statement ELSE statement                        // CFA
    13051282                {
    1306                         $$ = new StatementNode( build_while( yylloc, new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( yylloc, $4 ) ) );
    1307                         SemanticWarning( yylloc, Warning::SuperfluousElse );
     1283                        $$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) );
     1284                        SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
    13081285                }
    13091286        | WHILE '(' conditional_declaration ')' statement       %prec THEN
    1310                 { $$ = new StatementNode( build_while( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
     1287                { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
    13111288        | WHILE '(' conditional_declaration ')' statement ELSE statement // CFA
    1312                 { $$ = new StatementNode( build_while( yylloc, $3, maybe_build_compound( yylloc, $5 ), $7 ) ); }
     1289                { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ), $7 ) ); }
    13131290        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    1314                 { $$ = new StatementNode( build_do_while( yylloc, NEW_ONE, maybe_build_compound( yylloc, $2 ) ) ); }
     1291                { $$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) ); }
    13151292        | DO statement WHILE '(' ')' ELSE statement                     // CFA
    13161293                {
    1317                         $$ = new StatementNode( build_do_while( yylloc, NEW_ONE, maybe_build_compound( yylloc, $2 ) ) );
    1318                         SemanticWarning( yylloc, Warning::SuperfluousElse );
     1294                        $$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) );
     1295                        SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
    13191296                }
    13201297        | DO statement WHILE '(' comma_expression ')' ';'
    1321                 { $$ = new StatementNode( build_do_while( yylloc, $5, maybe_build_compound( yylloc, $2 ) ) ); }
     1298                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    13221299        | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
    1323                 { $$ = new StatementNode( build_do_while( yylloc, $5, maybe_build_compound( yylloc, $2 ), $8 ) ); }
     1300                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); }
    13241301        | FOR '(' ')' statement                                                         %prec THEN // CFA => for ( ;; )
    1325                 { $$ = new StatementNode( build_for( yylloc, new ForCtrl( nullptr, nullptr, nullptr ), maybe_build_compound( yylloc, $4 ) ) ); }
     1302                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
    13261303        | FOR '(' ')' statement ELSE statement                          // CFA
    13271304                {
    1328                         $$ = new StatementNode( build_for( yylloc, new ForCtrl( nullptr, nullptr, nullptr ), maybe_build_compound( yylloc, $4 ) ) );
    1329                         SemanticWarning( yylloc, Warning::SuperfluousElse );
     1305                        $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
     1306                        SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
    13301307                }
    13311308        | FOR '(' for_control_expression_list ')' statement     %prec THEN
    1332                 { $$ = new StatementNode( build_for( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
     1309                { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
    13331310        | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA
    1334                 { $$ = new StatementNode( build_for( yylloc, $3, maybe_build_compound( yylloc, $5 ), $7 ) ); }
     1311                { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ), $7 ) ); }
    13351312        ;
    13361313
     
    13461323                        if ( $1->condition ) {
    13471324                                if ( $3->condition ) {
    1348                                         $1->condition->expr.reset( new ast::LogicalExpr( yylloc, $1->condition->expr.release(), $3->condition->expr.release(), ast::AndExpr ) );
     1325                                        $1->condition->expr.reset( new LogicalExpr( $1->condition->expr.release(), $3->condition->expr.release(), true ) );
    13491326                                } // if
    13501327                        } else $1->condition = $3->condition;
    13511328                        if ( $1->change ) {
    13521329                                if ( $3->change ) {
    1353                                         $1->change->expr.reset( new ast::CommaExpr( yylloc, $1->change->expr.release(), $3->change->expr.release() ) );
     1330                                        $1->change->expr.reset( new CommaExpr( $1->change->expr.release(), $3->change->expr.release() ) );
    13541331                                } // if
    13551332                        } else $1->change = $3->change;
     
    13601337for_control_expression:
    13611338        ';' comma_expression_opt ';' comma_expression_opt
    1362                 { $$ = new ForCtrl( nullptr, $2, $4 ); }
     1339                { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); }
    13631340        | comma_expression ';' comma_expression_opt ';' comma_expression_opt
    1364                 {
    1365                         StatementNode * init = $1 ? new StatementNode( new ast::ExprStmt( yylloc, maybeMoveBuild( $1 ) ) ) : nullptr;
    1366                         $$ = new ForCtrl( init, $3, $5 );
    1367                 }
     1341                { $$ = new ForCtrl( $1, $3, $5 ); }
    13681342        | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';'
    1369                 { $$ = new ForCtrl( new StatementNode( $1 ), $2, $4 ); }
     1343                { $$ = new ForCtrl( $1, $2, $4 ); }
    13701344
    13711345        | '@' ';' comma_expression                                                      // CFA, empty loop-index
    1372                 { $$ = new ForCtrl( nullptr, $3, nullptr ); }
     1346                { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, nullptr ); }
    13731347        | '@' ';' comma_expression ';' comma_expression         // CFA, empty loop-index
    1374                 { $$ = new ForCtrl( nullptr, $3, $5 ); }
     1348                { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, $5 ); }
    13751349
    13761350        | comma_expression                                                                      // CFA, anonymous loop-index
    1377                 { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), NEW_ZERO, OperKinds::LThan, $1->clone(), NEW_ONE ); }
     1351                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), NEW_ZERO, OperKinds::LThan, $1->clone(), NEW_ONE ); }
    13781352        | downupdowneq comma_expression                                         // CFA, anonymous loop-index
    1379                 { $$ = forCtrl( yylloc, $2, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $1, NEW_ZERO, $2->clone() ), $1, UPDOWN( $1, $2->clone(), NEW_ZERO ), NEW_ONE ); }
     1353                { $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $1, NEW_ZERO, $2->clone() ), $1, UPDOWN( $1, $2->clone(), NEW_ZERO ), NEW_ONE ); }
    13801354
    13811355        | comma_expression updowneq comma_expression            // CFA, anonymous loop-index
    1382                 { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), NEW_ONE ); }
     1356                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), NEW_ONE ); }
    13831357        | '@' updowneq comma_expression                                         // CFA, anonymous loop-index
    13841358                {
    13851359                        if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1386                         else $$ = forCtrl( yylloc, $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, NEW_ONE );
     1360                        else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, NEW_ONE );
    13871361                }
    13881362        | comma_expression updowneq '@'                                         // CFA, anonymous loop-index
     
    13921366                }
    13931367        | comma_expression updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
    1394                 { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), $5 ); }
     1368                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), $5 ); }
    13951369        | '@' updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
    13961370                {
    13971371                        if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1398                         else $$ = forCtrl( yylloc, $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, $5 );
     1372                        else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, $5 );
    13991373                }
    14001374        | comma_expression updowneq '@' '~' comma_expression // CFA, anonymous loop-index
     
    14151389
    14161390        | comma_expression ';' comma_expression                         // CFA
    1417                 { $$ = forCtrl( yylloc, $3, $1, NEW_ZERO, OperKinds::LThan, $3->clone(), NEW_ONE ); }
     1391                { $$ = forCtrl( $3, $1, NEW_ZERO, OperKinds::LThan, $3->clone(), NEW_ONE ); }
    14181392        | comma_expression ';' downupdowneq comma_expression // CFA
    1419                 { $$ = forCtrl( yylloc, $4, $1, UPDOWN( $3, NEW_ZERO, $4->clone() ), $3, UPDOWN( $3, $4->clone(), NEW_ZERO ), NEW_ONE ); }
     1393                { $$ = forCtrl( $4, $1, UPDOWN( $3, NEW_ZERO, $4->clone() ), $3, UPDOWN( $3, $4->clone(), NEW_ZERO ), NEW_ONE ); }
    14201394
    14211395        | comma_expression ';' comma_expression updowneq comma_expression // CFA
    1422                 { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), NEW_ONE ); }
     1396                { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), NEW_ONE ); }
    14231397        | comma_expression ';' '@' updowneq comma_expression // CFA
    14241398                {
    14251399                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1426                         else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, NEW_ONE );
     1400                        else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, NEW_ONE );
    14271401                }
    14281402        | comma_expression ';' comma_expression updowneq '@' // CFA
     
    14301404                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14311405                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1432                         else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
     1406                        else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
    14331407                }
    14341408        | comma_expression ';' '@' updowneq '@'                         // CFA, error
     
    14361410
    14371411        | comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA
    1438                 { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
     1412                { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
    14391413        | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, error
    14401414                {
    14411415                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1442                         else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, $7 );
     1416                        else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, $7 );
    14431417                }
    14441418        | comma_expression ';' comma_expression updowneq '@' '~' comma_expression // CFA
     
    14461420                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14471421                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1448                         else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, $7 );
     1422                        else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, $7 );
    14491423                }
    14501424        | comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA
    1451                 { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
     1425                { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
    14521426        | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, error
    14531427                {
    14541428                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1455                         else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, nullptr );
     1429                        else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, nullptr );
    14561430                }
    14571431        | comma_expression ';' comma_expression updowneq '@' '~' '@' // CFA
     
    14591433                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14601434                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1461                         else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, nullptr );
     1435                        else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, nullptr );
    14621436                }
    14631437        | comma_expression ';' '@' updowneq '@' '~' '@' // CFA
     
    14651439
    14661440        | declaration comma_expression                                          // CFA
    1467                 { $$ = forCtrl( yylloc, $1, NEW_ZERO, OperKinds::LThan, $2, NEW_ONE ); }
     1441                { $$ = forCtrl( $1, NEW_ZERO, OperKinds::LThan, $2, NEW_ONE ); }
    14681442        | declaration downupdowneq comma_expression                     // CFA
    1469                 { $$ = forCtrl( yylloc, $1, UPDOWN( $2, NEW_ZERO, $3 ), $2, UPDOWN( $2, $3->clone(), NEW_ZERO ), NEW_ONE ); }
     1443                { $$ = forCtrl( $1, UPDOWN( $2, NEW_ZERO, $3 ), $2, UPDOWN( $2, $3->clone(), NEW_ZERO ), NEW_ONE ); }
    14701444
    14711445        | declaration comma_expression updowneq comma_expression // CFA
    1472                 { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2->clone(), $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), NEW_ONE ); }
     1446                { $$ = forCtrl( $1, UPDOWN( $3, $2->clone(), $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), NEW_ONE ); }
    14731447        | declaration '@' updowneq comma_expression                     // CFA
    14741448                {
    14751449                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1476                         else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, NEW_ONE );
     1450                        else $$ = forCtrl( $1, $4, $3, nullptr, NEW_ONE );
    14771451                }
    14781452        | declaration comma_expression updowneq '@'                     // CFA
     
    14801454                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14811455                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1482                         else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, NEW_ONE );
     1456                        else $$ = forCtrl( $1, $2, $3, nullptr, NEW_ONE );
    14831457                }
    14841458
    14851459        | declaration comma_expression updowneq comma_expression '~' comma_expression // CFA
    1486                 { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), $6 ); }
     1460                { $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), $6 ); }
    14871461        | declaration '@' updowneq comma_expression '~' comma_expression // CFA
    14881462                {
    14891463                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1490                         else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, $6 );
     1464                        else $$ = forCtrl( $1, $4, $3, nullptr, $6 );
    14911465                }
    14921466        | declaration comma_expression updowneq '@' '~' comma_expression // CFA
     
    14941468                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14951469                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1496                         else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, $6 );
     1470                        else $$ = forCtrl( $1, $2, $3, nullptr, $6 );
    14971471                }
    14981472        | declaration comma_expression updowneq comma_expression '~' '@' // CFA
    1499                 { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), nullptr ); }
     1473                { $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), nullptr ); }
    15001474        | declaration '@' updowneq comma_expression '~' '@' // CFA
    15011475                {
    15021476                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1503                         else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, nullptr );
     1477                        else $$ = forCtrl( $1, $4, $3, nullptr, nullptr );
    15041478                }
    15051479        | declaration comma_expression updowneq '@' '~' '@'     // CFA
     
    15071481                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    15081482                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1509                         else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, nullptr );
     1483                        else $$ = forCtrl( $1, $2, $3, nullptr, nullptr );
    15101484                }
    15111485        | declaration '@' updowneq '@' '~' '@'                          // CFA, error
     
    15221496                        SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr;
    15231497                }
    1524         ;
     1498        ;
    15251499
    15261500downupdowneq:
     
    15311505        | ErangeDownEq
    15321506                { $$ = OperKinds::GEThan; }
    1533         ;
     1507        ;
    15341508
    15351509updown:
     
    15381512        | ErangeDown
    15391513                { $$ = OperKinds::GThan; }
    1540         ;
     1514        ;
    15411515
    15421516updowneq:
     
    15461520        | ErangeDownEq
    15471521                { $$ = OperKinds::GEThan; }
    1548         ;
     1522        ;
    15491523
    15501524jump_statement:
    15511525        GOTO identifier_or_type_name ';'
    1552                 { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Goto ) ); }
     1526                { $$ = new StatementNode( build_branch( $2, BranchStmt::Goto ) ); }
    15531527        | GOTO '*' comma_expression ';'                                         // GCC, computed goto
    15541528                // The syntax for the GCC computed goto violates normal expression precedence, e.g., goto *i+3; => goto *(i+3);
     
    15571531                // A semantic check is required to ensure fallthru appears only in the body of a choose statement.
    15581532        | fall_through_name ';'                                                         // CFA
    1559                 { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThrough ) ); }
     1533                { $$ = new StatementNode( build_branch( BranchStmt::FallThrough ) ); }
    15601534        | fall_through_name identifier_or_type_name ';'         // CFA
    1561                 { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::FallThrough ) ); }
     1535                { $$ = new StatementNode( build_branch( $2, BranchStmt::FallThrough ) ); }
    15621536        | fall_through_name DEFAULT ';'                                         // CFA
    1563                 { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThroughDefault ) ); }
     1537                { $$ = new StatementNode( build_branch( BranchStmt::FallThroughDefault ) ); }
    15641538        | CONTINUE ';'
    15651539                // A semantic check is required to ensure this statement appears only in the body of an iteration statement.
    1566                 { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::Continue ) ); }
     1540                { $$ = new StatementNode( build_branch( BranchStmt::Continue ) ); }
    15671541        | CONTINUE identifier_or_type_name ';'                          // CFA, multi-level continue
    15681542                // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and
    15691543                // the target of the transfer appears only at the start of an iteration statement.
    1570                 { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Continue ) ); }
     1544                { $$ = new StatementNode( build_branch( $2, BranchStmt::Continue ) ); }
    15711545        | BREAK ';'
    15721546                // A semantic check is required to ensure this statement appears only in the body of an iteration statement.
    1573                 { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::Break ) ); }
     1547                { $$ = new StatementNode( build_branch( BranchStmt::Break ) ); }
    15741548        | BREAK identifier_or_type_name ';'                                     // CFA, multi-level exit
    15751549                // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and
    15761550                // the target of the transfer appears only at the start of an iteration statement.
    1577                 { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Break ) ); }
     1551                { $$ = new StatementNode( build_branch( $2, BranchStmt::Break ) ); }
    15781552        | RETURN comma_expression_opt ';'
    1579                 { $$ = new StatementNode( build_return( yylloc, $2 ) ); }
     1553                { $$ = new StatementNode( build_return( $2 ) ); }
    15801554        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    15811555                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    15821556        | SUSPEND ';'
    1583                 { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::None ) ); }
     1557                { $$ = new StatementNode( build_suspend( nullptr ) ); }
    15841558        | SUSPEND compound_statement
    1585                 { $$ = new StatementNode( build_suspend( yylloc, $2, ast::SuspendStmt::None ) ); }
     1559                { $$ = new StatementNode( build_suspend( $2 ) ); }
    15861560        | SUSPEND COROUTINE ';'
    1587                 { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Coroutine ) ); }
     1561                { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
    15881562        | SUSPEND COROUTINE compound_statement
    1589                 { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Coroutine ) ); }
     1563                { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
    15901564        | SUSPEND GENERATOR ';'
    1591                 { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Generator ) ); }
     1565                { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
    15921566        | SUSPEND GENERATOR compound_statement
    1593                 { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Generator ) ); }
     1567                { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
    15941568        | THROW assignment_expression_opt ';'                           // handles rethrow
    1595                 { $$ = new StatementNode( build_throw( yylloc, $2 ) ); }
     1569                { $$ = new StatementNode( build_throw( $2 ) ); }
    15961570        | THROWRESUME assignment_expression_opt ';'                     // handles reresume
    1597                 { $$ = new StatementNode( build_resume( yylloc, $2 ) ); }
     1571                { $$ = new StatementNode( build_resume( $2 ) ); }
    15981572        | THROWRESUME assignment_expression_opt AT assignment_expression ';' // handles reresume
    15991573                { $$ = new StatementNode( build_resume_at( $2, $4 ) ); }
     
    16071581with_statement:
    16081582        WITH '(' tuple_expression_list ')' statement
    1609                 { $$ = new StatementNode( build_with( yylloc, $3, $5 ) ); }
    1610         ;
    1611 
    1612 // If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so possibly change syntax to "with mutex".
     1583                { $$ = new StatementNode( build_with( $3, $5 ) ); }
     1584        ;
     1585
     1586// If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex".
    16131587mutex_statement:
    1614         MUTEX '(' argument_expression_list_opt ')' statement
    1615                 {
    1616                         if ( ! $3 ) { SemanticError( yylloc, "mutex argument list cannot be empty." ); $$ = nullptr; }
    1617                         $$ = new StatementNode( build_mutex( yylloc, $3, $5 ) );
    1618                 }
     1588        MUTEX '(' argument_expression_list ')' statement
     1589                { $$ = new StatementNode( build_mutex( $3, $5 ) ); }
    16191590        ;
    16201591
     
    16271598                { $$ = nullptr; }
    16281599        | when_clause
     1600        ;
     1601
     1602waitfor:
     1603        WAITFOR '(' cast_expression ')'
     1604                { $$ = $3; }
     1605//      | WAITFOR '(' cast_expression ',' argument_expression_list_opt ')'
     1606//              { $$ = (ExpressionNode *)$3->set_last( $5 ); }
     1607        | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
     1608                { $$ = (ExpressionNode *)($3->set_last( $5 )); }
    16291609        ;
    16301610
     
    16371617
    16381618timeout:
    1639         TIMEOUT '(' comma_expression ')'                        { $$ = $3; }
    1640         ;
    1641 
    1642 wor:
    1643         OROR
    1644         | WOR
    1645 
    1646 waitfor:
    1647         WAITFOR '(' cast_expression ')'
    1648                 { $$ = $3; }
    1649         | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
    1650                 { $$ = (ExpressionNode *)($3->set_last( $5 )); }
    1651         ;
    1652 
    1653 wor_waitfor_clause:
     1619        TIMEOUT '(' comma_expression ')'                        { $$ = $3; }
     1620        ;
     1621
     1622waitfor_clause:
    16541623        when_clause_opt waitfor statement                                       %prec THEN
    1655                 // Called first: create header for WaitForStmt.
    1656                 { $$ = build_waitfor( yylloc, new ast::WaitForStmt( yylloc ), $1, $2, maybe_build_compound( yylloc, $3 ) ); }
    1657         | wor_waitfor_clause wor when_clause_opt waitfor statement
    1658                 { $$ = build_waitfor( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); }
    1659         | wor_waitfor_clause wor when_clause_opt ELSE statement
    1660                 { $$ = build_waitfor_else( yylloc, $1, $3, maybe_build_compound( yylloc, $5 ) ); }
    1661         | wor_waitfor_clause wor when_clause_opt timeout statement      %prec THEN
    1662                 { $$ = build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); }
     1624                { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }
     1625        | when_clause_opt waitfor statement WOR waitfor_clause
     1626                { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); }
     1627        | when_clause_opt timeout statement                                     %prec THEN
     1628                { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }
     1629        | when_clause_opt ELSE statement
     1630                { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
    16631631        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1664         | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
     1632        | when_clause_opt timeout statement WOR ELSE statement // syntax error
    16651633                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    1666         | wor_waitfor_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
    1667                 { $$ = build_waitfor_else( yylloc, build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ), $7, maybe_build_compound( yylloc, $9 ) ); }
     1634        | when_clause_opt timeout statement WOR when_clause ELSE statement
     1635                { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); }
    16681636        ;
    16691637
    16701638waitfor_statement:
    1671         wor_waitfor_clause                                                                      %prec THEN
    1672                 { $$ = new StatementNode( $1 ); }
    1673         ;
    1674 
    1675 wand:
    1676         ANDAND
    1677         | WAND
    1678         ;
    1679 
    1680 waituntil:
    1681         WAITUNTIL '(' cast_expression ')'
    1682                 { $$ = $3; }
    1683         ;
    1684 
    1685 waituntil_clause:
    1686         when_clause_opt waituntil statement
    1687                 { printf( "waituntil_clause 1\n" ); $$ = nullptr; }
    1688         | '(' wor_waituntil_clause ')'
    1689                 { printf( "waituntil_clause 2\n" ); $$ = nullptr; }
    1690         ;
    1691 
    1692 wand_waituntil_clause:
    1693         waituntil_clause                                                                        %prec THEN
    1694                 { printf( "wand_waituntil_clause 1\n" ); $$ = nullptr; }
    1695         | waituntil_clause wand wand_waituntil_clause
    1696                 { printf( "wand_waituntil_clause 2\n" ); $$ = nullptr; }
    1697         ;
    1698 
    1699 wor_waituntil_clause:
    1700         wand_waituntil_clause
    1701                 { printf( "wor_waituntil_clause 1\n" ); $$ = nullptr; }
    1702         | wor_waituntil_clause wor wand_waituntil_clause
    1703                 { printf( "wor_waituntil_clause 2\n" ); $$ = nullptr; }
    1704         | wor_waituntil_clause wor when_clause_opt ELSE statement
    1705                 { printf( "wor_waituntil_clause 3\n" ); $$ = nullptr; }
    1706         | wor_waituntil_clause wor when_clause_opt timeout statement    %prec THEN
    1707                 { printf( "wor_waituntil_clause 4\n" ); $$ = nullptr; }
    1708         // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1709         | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
    1710                 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    1711         | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
    1712                 { printf( "wor_waituntil_clause 6\n" ); $$ = nullptr; }
    1713         ;
    1714 
    1715 waituntil_statement:
    1716         wor_waituntil_clause                                                            %prec THEN
    1717                 // SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement.
    1718                 { $$ = new StatementNode( build_compound( yylloc, nullptr ) ); }
     1639        when_clause_opt waitfor statement                                       %prec THEN
     1640                { $$ = new StatementNode( build_waitfor( $2, $3, $1 ) ); }
     1641        | when_clause_opt waitfor statement WOR waitfor_clause
     1642                { $$ = new StatementNode( build_waitfor( $2, $3, $1, $5 ) ); }
    17191643        ;
    17201644
    17211645exception_statement:
    1722         TRY compound_statement handler_clause                                   %prec THEN
    1723                 { $$ = new StatementNode( build_try( yylloc, $2, $3, nullptr ) ); }
     1646        TRY compound_statement handler_clause                                   %prec THEN
     1647                { $$ = new StatementNode( build_try( $2, $3, nullptr ) ); }
    17241648        | TRY compound_statement finally_clause
    1725                 { $$ = new StatementNode( build_try( yylloc, $2, nullptr, $3 ) ); }
     1649                { $$ = new StatementNode( build_try( $2, nullptr, $3 ) ); }
    17261650        | TRY compound_statement handler_clause finally_clause
    1727                 { $$ = new StatementNode( build_try( yylloc, $2, $3, $4 ) ); }
     1651                { $$ = new StatementNode( build_try( $2, $3, $4 ) ); }
    17281652        ;
    17291653
    17301654handler_clause:
    17311655        handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1732                 { $$ = new ClauseNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
     1656                { $$ = new StatementNode( build_catch( $1, $4, $6, $8 ) ); }
    17331657        | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1734                 { $$ = $1->set_last( new ClauseNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
     1658                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $5, $7, $9 ) ) ); }
    17351659        ;
    17361660
     
    17421666
    17431667handler_key:
    1744         CATCH                                                                           { $$ = ast::Terminate; }
    1745         | RECOVER                                                                       { $$ = ast::Terminate; }
    1746         | CATCHRESUME                                                           { $$ = ast::Resume; }
    1747         | FIXUP                                                                         { $$ = ast::Resume; }
     1668        CATCH                                                                           { $$ = CatchStmt::Terminate; }
     1669        | RECOVER                                                                       { $$ = CatchStmt::Terminate; }
     1670        | CATCHRESUME                                                           { $$ = CatchStmt::Resume; }
     1671        | FIXUP                                                                         { $$ = CatchStmt::Resume; }
    17481672        ;
    17491673
    17501674finally_clause:
    1751         FINALLY compound_statement                                      { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); }
     1675        FINALLY compound_statement                                      { $$ = new StatementNode( build_finally( $2 ) ); }
    17521676        ;
    17531677
     
    17751699asm_statement:
    17761700        ASM asm_volatile_opt '(' string_literal ')' ';'
    1777                 { $$ = new StatementNode( build_asm( yylloc, $2, $4, nullptr ) ); }
     1701                { $$ = new StatementNode( build_asm( $2, $4, nullptr ) ); }
    17781702        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ')' ';' // remaining GCC
    1779                 { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6 ) ); }
     1703                { $$ = new StatementNode( build_asm( $2, $4, $6 ) ); }
    17801704        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ':' asm_operands_opt ')' ';'
    1781                 { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6, $8 ) ); }
     1705                { $$ = new StatementNode( build_asm( $2, $4, $6, $8 ) ); }
    17821706        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ':' asm_operands_opt ':' asm_clobbers_list_opt ')' ';'
    1783                 { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6, $8, $10 ) ); }
     1707                { $$ = new StatementNode( build_asm( $2, $4, $6, $8, $10 ) ); }
    17841708        | ASM asm_volatile_opt GOTO '(' string_literal ':' ':' asm_operands_opt ':' asm_clobbers_list_opt ':' label_list ')' ';'
    1785                 { $$ = new StatementNode( build_asm( yylloc, $2, $5, nullptr, $8, $10, $12 ) ); }
     1709                { $$ = new StatementNode( build_asm( $2, $5, nullptr, $8, $10, $12 ) ); }
    17861710        ;
    17871711
     
    18071731asm_operand:                                                                                    // GCC
    18081732        string_literal '(' constant_expression ')'
    1809                 { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
     1733                { $$ = new ExpressionNode( new AsmExpr( nullptr, $1, maybeMoveBuild<Expression>( $3 ) ) ); }
    18101734        | '[' IDENTIFIER ']' string_literal '(' constant_expression ')'
    1811                 {
    1812                         $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, maybeMoveBuild( $4 ), maybeMoveBuild( $6 ) ) );
    1813                         delete $2.str;
    1814                 }
     1735                { $$ = new ExpressionNode( new AsmExpr( $2, $4, maybeMoveBuild<Expression>( $6 ) ) ); }
    18151736        ;
    18161737
     
    18191740                { $$ = nullptr; }                                                               // use default argument
    18201741        | string_literal
    1821                 { $$ = $1; }
     1742                { $$ = new ExpressionNode( $1 ); }
    18221743        | asm_clobbers_list_opt ',' string_literal
    1823                 { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); }
     1744                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
    18241745        ;
    18251746
     
    18271748        identifier
    18281749                {
    1829                         $$ = new LabelNode(); $$->labels.emplace_back( yylloc, *$1 );
     1750                        $$ = new LabelNode(); $$->labels.push_back( *$1 );
    18301751                        delete $1;                                                                      // allocated by lexer
    18311752                }
    18321753        | label_list ',' identifier
    18331754                {
    1834                         $$ = $1; $1->labels.emplace_back( yylloc, *$3 );
     1755                        $$ = $1; $1->labels.push_back( *$3 );
    18351756                        delete $3;                                                                      // allocated by lexer
    18361757                }
     
    18831804                {
    18841805                        // printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" );
    1885                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     1806                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    18861807                        //   printf( "\tattr %s\n", attr->name.c_str() );
    18871808                        // } // for
     
    18931814static_assert:
    18941815        STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11
    1895                 { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); }
     1816                { $$ = DeclarationNode::newStaticAssert( $3, $5 ); }
    18961817        | STATICASSERT '(' constant_expression ')' ';'          // CFA
    1897                 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); }
     1818                { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( *new string( "\"\"" ) ) ); }
    18981819
    18991820// C declaration syntax is notoriously confusing and error prone. Cforall provides its own type, variable and function
     
    20181939        TYPEDEF type_specifier declarator
    20191940                {
     1941                        // if type_specifier is an anon aggregate => name
    20201942                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "4" );
    2021                         if ( $2->type->forall || ($2->type->kind == TypeData::Aggregate && $2->type->aggregate.params) ) {
    2022                                 SemanticError( yylloc, "forall qualifier in typedef is currently unimplemented." ); $$ = nullptr;
    2023                         } else $$ = $3->addType( $2 )->addTypedef(); // watchout frees $2 and $3
     1943                        $$ = $3->addType( $2 )->addTypedef();
    20241944                }
    20251945        | typedef_declaration pop ',' push declarator
     
    20291949                }
    20301950        | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
    2031                 { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
     1951                {
     1952                        typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "6" );
     1953                        $$ = $4->addType( $3 )->addQualifiers( $1 )->addTypedef();
     1954                }
    20321955        | type_specifier TYPEDEF declarator
    2033                 { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
     1956                {
     1957                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "7" );
     1958                        $$ = $3->addType( $1 )->addTypedef();
     1959                }
    20341960        | type_specifier TYPEDEF type_qualifier_list declarator
    2035                 { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
     1961                {
     1962                        typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "8" );
     1963                        $$ = $4->addQualifiers( $1 )->addTypedef()->addType( $1 );
     1964                }
    20361965        ;
    20371966
     
    20401969        TYPEDEF identifier '=' assignment_expression
    20411970                {
    2042                         SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     1971                        SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    20431972                }
    20441973        | typedef_expression pop ',' push identifier '=' assignment_expression
    20451974                {
    2046                         SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     1975                        SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    20471976                }
    20481977        ;
     
    20541983        | typedef_expression                                                            // deprecated GCC, naming expression type
    20551984        | sue_declaration_specifier
    2056                 {
    2057                         assert( $1->type );
    2058                         if ( $1->type->qualifiers.any() ) {                     // CV qualifiers ?
    2059                                 SemanticError( yylloc, "Useless type qualifier(s) in empty declaration." ); $$ = nullptr;
    2060                         }
    2061                         // enums are never empty declarations because there must have at least one enumeration.
    2062                         if ( $1->type->kind == TypeData::AggregateInst && $1->storageClasses.any() ) { // storage class ?
    2063                                 SemanticError( yylloc, "Useless storage qualifier(s) in empty aggregate declaration." ); $$ = nullptr;
    2064                         }
    2065                 }
    20661985        ;
    20671986
     
    20691988                // A semantic check is required to ensure asm_name only appears on declarations with implicit or explicit static
    20701989                // storage-class
    2071         variable_declarator asm_name_opt initializer_opt
     1990        declarator asm_name_opt initializer_opt
    20721991                { $$ = $1->addAsmName( $2 )->addInitializer( $3 ); }
    2073         | variable_type_redeclarator asm_name_opt initializer_opt
    2074                 { $$ = $1->addAsmName( $2 )->addInitializer( $3 ); }
    2075 
    2076         | general_function_declarator asm_name_opt
    2077                 { $$ = $1->addAsmName( $2 )->addInitializer( nullptr ); }
    2078         | general_function_declarator asm_name_opt '=' VOID
    2079                 { $$ = $1->addAsmName( $2 )->addInitializer( new InitializerNode( true ) ); }
    2080 
    20811992        | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    20821993                { $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
    2083         ;
    2084 
    2085 general_function_declarator:
    2086         function_type_redeclarator
    2087         | function_declarator
    20881994        ;
    20891995
     
    20942000        | sue_declaration_specifier invalid_types
    20952001                {
    2096                         SemanticError( yylloc, ::toString( "Missing ';' after end of ",
    2097                                 $1->type->enumeration.name ? "enum" : ast::AggregateDecl::aggrString( $1->type->aggregate.kind ),
    2098                                 " declaration" ) );
     2002                        SemanticError( yylloc,
     2003                                                  ::toString( "Missing ';' after end of ",
     2004                                                                          $1->type->enumeration.name ? "enum" : AggregateDecl::aggrString( $1->type->aggregate.kind ),
     2005                                                                          " declaration" ) );
    20992006                        $$ = nullptr;
    21002007                }
     
    21212028        basic_type_specifier
    21222029        | sue_type_specifier
     2030                {
     2031                        // printf( "sue_type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2032                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2033                        //   printf( "\tattr %s\n", attr->name.c_str() );
     2034                        // } // for
     2035                }
    21232036        | type_type_specifier
    21242037        ;
     
    23292242                { $$ = DeclarationNode::newTypeof( $3 ); }
    23302243        | BASETYPEOF '(' type ')'                                                       // CFA: basetypeof( x ) y;
    2331                 { $$ = DeclarationNode::newTypeof( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ), true ); }
     2244                { $$ = DeclarationNode::newTypeof( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ), true ); }
    23322245        | BASETYPEOF '(' comma_expression ')'                           // CFA: basetypeof( a+b ) y;
    23332246                { $$ = DeclarationNode::newTypeof( $3, true ); }
     
    23422255                {
    23432256                        // printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2344                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2257                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    23452258                        //   printf( "\tattr %s\n", attr->name.c_str() );
    23462259                        // } // for
     
    23582271                {
    23592272                        // printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2360                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2273                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    23612274                        //   printf( "\tattr %s\n", attr->name.c_str() );
    23622275                        // } // for
     
    24362349                {
    24372350                        // printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2438                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2351                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    24392352                        //   printf( "\tattr %s\n", attr->name.c_str() );
    24402353                        // } // for
     
    24602373          '{' field_declaration_list_opt '}' type_parameters_opt
    24612374                {
     2375                        // printf( "aggregate_type1 %s\n", $3.str->c_str() );
     2376                        // if ( $2 )
     2377                        //      for ( Attribute * attr: reverseIterate( $2->attributes ) ) {
     2378                        //              printf( "copySpecifiers12 %s\n", attr->name.c_str() );
     2379                        //      } // for
    24622380                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     2381                        // printf( "aggregate_type2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2382                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2383                        //      printf( "aggregate_type3 %s\n", attr->name.c_str() );
     2384                        // } // for
    24632385                }
    24642386        | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
     
    24692391          '{' field_declaration_list_opt '}' type_parameters_opt
    24702392                {
     2393                        // printf( "AGG3\n" );
    24712394                        DeclarationNode::newFromTypedef( $3 );
    24722395                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    24792402          '{' field_declaration_list_opt '}' type_parameters_opt
    24802403                {
     2404                        // printf( "AGG4\n" );
    24812405                        DeclarationNode::newFromTypeGen( $3, nullptr );
    24822406                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    25052429                        // switched to a TYPEGENname. Link any generic arguments from typegen_name to new generic declaration and
    25062430                        // delete newFromTypeGen.
    2507                         if ( $3->type->kind == TypeData::SymbolicInst && ! $3->type->symbolic.isTypedef ) {
    2508                                 $$ = $3->addQualifiers( $2 );
    2509                         } else {
    2510                                 $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $3->type->symbolic.actuals, nullptr, false )->addQualifiers( $2 );
    2511                                 $3->type->symbolic.name = nullptr;                      // copied to $$
    2512                                 $3->type->symbolic.actuals = nullptr;
    2513                                 delete $3;
    2514                         }
     2431                        $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $3->type->symbolic.actuals, nullptr, false )->addQualifiers( $2 );
     2432                        $3->type->symbolic.name = nullptr;
     2433                        $3->type->symbolic.actuals = nullptr;
     2434                        delete $3;
    25152435                }
    25162436        ;
     
    25232443aggregate_data:
    25242444        STRUCT vtable_opt
    2525                 { $$ = ast::AggregateDecl::Struct; }
     2445                { $$ = AggregateDecl::Struct; }
    25262446        | UNION
    2527                 { $$ = ast::AggregateDecl::Union; }
     2447                { $$ = AggregateDecl::Union; }
    25282448        | EXCEPTION                                                                                     // CFA
    2529                 { $$ = ast::AggregateDecl::Exception; }
    2530           //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = ast::AggregateDecl::NoAggregate; }
     2449                { $$ = AggregateDecl::Exception; }
     2450          //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    25312451        ;
    25322452
    25332453aggregate_control:                                                                              // CFA
    25342454        MONITOR
    2535                 { $$ = ast::AggregateDecl::Monitor; }
     2455                { $$ = AggregateDecl::Monitor; }
    25362456        | MUTEX STRUCT
    2537                 { $$ = ast::AggregateDecl::Monitor; }
     2457                { $$ = AggregateDecl::Monitor; }
    25382458        | GENERATOR
    2539                 { $$ = ast::AggregateDecl::Generator; }
     2459                { $$ = AggregateDecl::Generator; }
    25402460        | MUTEX GENERATOR
    2541                 {
    2542                         SemanticError( yylloc, "monitor generator is currently unimplemented." );
    2543                         $$ = ast::AggregateDecl::NoAggregate;
    2544                 }
     2461                { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    25452462        | COROUTINE
    2546                 { $$ = ast::AggregateDecl::Coroutine; }
     2463                { $$ = AggregateDecl::Coroutine; }
    25472464        | MUTEX COROUTINE
    2548                 {
    2549                         SemanticError( yylloc, "monitor coroutine is currently unimplemented." );
    2550                         $$ = ast::AggregateDecl::NoAggregate;
    2551                 }
     2465                { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    25522466        | THREAD
    2553                 { $$ = ast::AggregateDecl::Thread; }
     2467                { $$ = AggregateDecl::Thread; }
    25542468        | MUTEX THREAD
    2555                 {
    2556                         SemanticError( yylloc, "monitor thread is currently unimplemented." );
    2557                         $$ = ast::AggregateDecl::NoAggregate;
    2558                 }
     2469                { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    25592470        ;
    25602471
     
    25722483                        $$ = fieldDecl( $1, $2 );
    25732484                        // printf( "type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2574                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2485                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    25752486                        //   printf( "\tattr %s\n", attr->name.c_str() );
    25762487                        // } // for
     
    25792490                { $$ = fieldDecl( $2, $3 ); distExt( $$ ); }
    25802491        | STATIC type_specifier field_declaring_list_opt ';' // CFA
    2581                 { SemanticError( yylloc, "STATIC aggregate field qualifier currently unimplemented." ); $$ = nullptr; }
     2492                { SemanticError( yylloc, "STATIC aggregate field qualifier currently unimplemented." ); $$ = nullptr; }
    25822493        | INLINE type_specifier field_abstract_list_opt ';'     // CFA
    25832494                {
     
    25902501                }
    25912502        | INLINE aggregate_control ';'                                          // CFA
    2592                 { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
     2503                { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
    25932504        | typedef_declaration ';'                                                       // CFA
    25942505        | cfa_field_declaring_list ';'                                          // CFA, new style field declaration
     
    26162527                { $$ = $1->addBitfield( $2 ); }
    26172528        | variable_type_redeclarator bit_subrange_size_opt
    2618                 // A semantic check is required to ensure bit_subrange only appears on integral types.
    2619                 { $$ = $1->addBitfield( $2 ); }
    2620         | function_type_redeclarator bit_subrange_size_opt
    26212529                // A semantic check is required to ensure bit_subrange only appears on integral types.
    26222530                { $$ = $1->addBitfield( $2 ); }
     
    26732581                { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); }
    26742582        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
    2675                 {
    2676                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() )
     2583                {
     2584                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 )
    26772585                        { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    26782586
     
    26812589        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    26822590                {
    2683                         if ( $3->storageClasses.any() || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
     2591                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    26842592                        typedefTable.makeTypedef( *$6 );
    26852593                }
     
    28492757type_no_function:                                                                               // sizeof, alignof, cast (constructor)
    28502758        cfa_abstract_declarator_tuple                                           // CFA
    2851         | type_specifier                                                                        // cannot be type_specifier_nobody, e.g., (struct S {}){} is a thing
     2759        | type_specifier
    28522760        | type_specifier abstract_declarator
    28532761                { $$ = $2->addType( $1 ); }
     
    28942802        designator_list ':'                                                                     // C99, CFA uses ":" instead of "="
    28952803        | identifier_at ':'                                                                     // GCC, field name
    2896                 { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
     2804                { $$ = new ExpressionNode( build_varref( $1 ) ); }
    28972805        ;
    28982806
     
    29062814designator:
    29072815        '.' identifier_at                                                                       // C99, field name
    2908                 { $$ = new ExpressionNode( build_varref( yylloc, $2 ) ); }
     2816                { $$ = new ExpressionNode( build_varref( $2 ) ); }
    29092817        | '[' push assignment_expression pop ']'                        // C99, single array element
    29102818                // assignment_expression used instead of constant_expression because of shift/reduce conflicts with tuple.
     
    29132821                { $$ = $3; }
    29142822        | '[' push constant_expression ELLIPSIS constant_expression pop ']' // GCC, multiple array elements
    2915                 { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $3 ), maybeMoveBuild( $5 ) ) ); }
     2823                { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $3 ), maybeMoveBuild<Expression>( $5 ) ) ); }
    29162824        | '.' '[' push field_name_list pop ']'                          // CFA, tuple field selector
    29172825                { $$ = $4; }
     
    29532861                {
    29542862                        typedefTable.addToScope( *$2, TYPEDEFname, "9" );
    2955                         if ( $1 == ast::TypeDecl::Otype ) { SemanticError( yylloc, "otype keyword is deprecated, use T " ); }
    2956                         if ( $1 == ast::TypeDecl::Dtype ) { SemanticError( yylloc, "dtype keyword is deprecated, use T &" ); }
    2957                         if ( $1 == ast::TypeDecl::Ttype ) { SemanticError( yylloc, "ttype keyword is deprecated, use T ..." ); }
     2863                        if ( $1 == TypeDecl::Otype ) { SemanticError( yylloc, "otype keyword is deprecated, use T " ); }
     2864                        if ( $1 == TypeDecl::Dtype ) { SemanticError( yylloc, "dtype keyword is deprecated, use T &" ); }
     2865                        if ( $1 == TypeDecl::Ttype ) { SemanticError( yylloc, "ttype keyword is deprecated, use T ..." ); }
    29582866                }
    29592867          type_initializer_opt assertion_list_opt
     
    29662874                {
    29672875                        typedefTable.addToScope( *$2, TYPEDIMname, "9" );
    2968                         $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dimension, $2 );
     2876                        $$ = DeclarationNode::newTypeParam( TypeDecl::Dimension, $2 );
    29692877                }
    29702878        // | type_specifier identifier_parameter_declarator
    29712879        | assertion_list
    2972                 { $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
     2880                { $$ = DeclarationNode::newTypeParam( TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
    29732881        ;
    29742882
    29752883new_type_class:                                                                                 // CFA
    29762884        // empty
    2977                 { $$ = ast::TypeDecl::Otype; }
     2885                { $$ = TypeDecl::Otype; }
    29782886        | '&'
    2979                 { $$ = ast::TypeDecl::Dtype; }
     2887                { $$ = TypeDecl::Dtype; }
    29802888        | '*'
    2981                 { $$ = ast::TypeDecl::DStype; }                                         // dtype + sized
     2889                { $$ = TypeDecl::DStype; }                                              // dtype + sized
    29822890        // | '(' '*' ')'
    2983         //      { $$ = ast::TypeDecl::Ftype; }
     2891        //      { $$ = TypeDecl::Ftype; }
    29842892        | ELLIPSIS
    2985                 { $$ = ast::TypeDecl::Ttype; }
     2893                { $$ = TypeDecl::Ttype; }
    29862894        ;
    29872895
    29882896type_class:                                                                                             // CFA
    29892897        OTYPE
    2990                 { $$ = ast::TypeDecl::Otype; }
     2898                { $$ = TypeDecl::Otype; }
    29912899        | DTYPE
    2992                 { $$ = ast::TypeDecl::Dtype; }
     2900                { $$ = TypeDecl::Dtype; }
    29932901        | FTYPE
    2994                 { $$ = ast::TypeDecl::Ftype; }
     2902                { $$ = TypeDecl::Ftype; }
    29952903        | TTYPE
    2996                 { $$ = ast::TypeDecl::Ttype; }
     2904                { $$ = TypeDecl::Ttype; }
    29972905        ;
    29982906
     
    30202928type_list:                                                                                              // CFA
    30212929        type
    3022                 { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
     2930                { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
    30232931        | assignment_expression
    30242932        | type_list ',' type
    3025                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
     2933                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
    30262934        | type_list ',' assignment_expression
    30272935                { $$ = (ExpressionNode *)( $1->set_last( $3 )); }
     
    30602968        TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' '}'
    30612969                {
    3062                         SemanticWarning( yylloc, Warning::DeprecTraitSyntax );
     2970                        SemanticWarning( yylloc, Warning::DeprecTraitSyntax, "" );
    30632971                        $$ = DeclarationNode::newTrait( $2, $4, nullptr );
    30642972                }
     
    30672975        | TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' push trait_declaration_list pop '}'
    30682976                {
    3069                         SemanticWarning( yylloc, Warning::DeprecTraitSyntax );
     2977                        SemanticWarning( yylloc, Warning::DeprecTraitSyntax, "" );
    30702978                        $$ = DeclarationNode::newTrait( $2, $4, $8 );
    30712979                }
     
    31303038external_definition:
    31313039        DIRECTIVE
    3132                 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( yylloc, $1 ) ) ); }
     3040                { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); }
    31333041        | declaration
    3134                 {
    3135                         // Variable declarations of anonymous types requires creating a unique type-name across multiple translation
    3136                         // unit, which is a dubious task, especially because C uses name rather than structural typing; hence it is
    3137                         // disallowed at the moment.
    3138                         if ( $1->linkage == ast::Linkage::Cforall && ! $1->storageClasses.is_static && $1->type && $1->type->kind == TypeData::AggregateInst ) {
    3139                                 if ( $1->type->aggInst.aggregate->kind == TypeData::Enum && $1->type->aggInst.aggregate->enumeration.anon ) {
    3140                                         SemanticError( yylloc, "extern anonymous enumeration is currently unimplemented." ); $$ = nullptr;
    3141                                 } else if ( $1->type->aggInst.aggregate->aggregate.anon ) { // handles struct or union
    3142                                         SemanticError( yylloc, "extern anonymous struct/union is currently unimplemented." ); $$ = nullptr;
    3143                                 }
    3144                         }
    3145                 }
    31463042        | IDENTIFIER IDENTIFIER
    31473043                { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; }
     
    31633059                }
    31643060        | ASM '(' string_literal ')' ';'                                        // GCC, global assembler statement
    3165                 { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( yylloc, false, $3, nullptr ) ) ); }
     3061                { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, nullptr ) ) ); }
    31663062        | EXTERN STRINGliteral
    31673063                {
    31683064                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    3169                         linkage = ast::Linkage::update( yylloc, linkage, $2 );
     3065                        linkage = LinkageSpec::update( yylloc, linkage, $2 );
    31703066                }
    31713067          up external_definition down
     
    31783074                {
    31793075                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    3180                         linkage = ast::Linkage::update( yylloc, linkage, $2 );
     3076                        linkage = LinkageSpec::update( yylloc, linkage, $2 );
    31813077                }
    31823078          '{' up external_definition_list_opt down '}'
     
    31893085        | type_qualifier_list
    31903086                {
    3191                         if ( $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3087                        if ( $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    31923088                        if ( $1->type->forall ) forall = true;          // remember generic type
    31933089                }
     
    31953091                {
    31963092                        distQual( $5, $1 );
    3197                         forall = false;
     3093                        forall = false;
    31983094                        $$ = $5;
    31993095                }
    32003096        | declaration_qualifier_list
    32013097                {
    3202                         if ( $1->type && $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3098                        if ( $1->type && $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    32033099                        if ( $1->type && $1->type->forall ) forall = true; // remember generic type
    32043100                }
     
    32063102                {
    32073103                        distQual( $5, $1 );
    3208                         forall = false;
     3104                        forall = false;
    32093105                        $$ = $5;
    32103106                }
    32113107        | declaration_qualifier_list type_qualifier_list
    32123108                {
    3213                         if ( ($1->type && $1->type->qualifiers.any()) || ($2->type && $2->type->qualifiers.any()) ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3109                        if ( ($1->type && $1->type->qualifiers.val) || ($2->type && $2->type->qualifiers.val) ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    32143110                        if ( ($1->type && $1->type->forall) || ($2->type && $2->type->forall) ) forall = true; // remember generic type
    32153111                }
     
    32173113                {
    32183114                        distQual( $6, $1->addQualifiers( $2 ) );
    3219                         forall = false;
     3115                        forall = false;
    32203116                        $$ = $6;
    32213117                }
     
    32613157                        $$ = $2->addFunctionBody( $4, $3 )->addType( $1 );
    32623158                }
    3263         | declaration_specifier function_type_redeclarator with_clause_opt compound_statement
     3159        | declaration_specifier variable_type_redeclarator with_clause_opt compound_statement
    32643160                {
    32653161                        rebindForall( $1, $2 );
     
    32973193        | variable_type_redeclarator
    32983194        | function_declarator
    3299         | function_type_redeclarator
    33003195        ;
    33013196
    33023197subrange:
    33033198        constant_expression '~' constant_expression                     // CFA, integer subrange
    3304                 { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
     3199                { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
    33053200        ;
    33063201
     
    33113206                {
    33123207                        DeclarationNode * name = new DeclarationNode();
    3313                         name->asmName = maybeMoveBuild( $3 );
     3208                        name->asmName = $3;
    33143209                        $$ = name->addQualifiers( $5 );
    33153210                }
     
    34243319        | '(' attribute_list variable_ptr ')' array_dimension
    34253320                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3426         | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
     3321        | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
    34273322                { $$ = $2->addArray( $4 ); }
    34283323        | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis
     
    35483443        ;
    35493444
    3550 // This pattern parses a declaration for a variable that redefines a type name, e.g.:
     3445// This pattern parses a declaration for a variable or function prototype that redefines a type name, e.g.:
    35513446//
    35523447//              typedef int foo;
     
    35543449//                 int foo; // redefine typedef name in new scope
    35553450//              }
     3451//
     3452// The pattern precludes declaring an array of functions versus a pointer to an array of functions, and returning arrays
     3453// and functions versus pointers to arrays and functions.
    35563454
    35573455paren_type:
     
    35683466        paren_type attribute_list_opt
    35693467                { $$ = $1->addQualifiers( $2 ); }
    3570         | variable_type_ptr
    3571         | variable_type_array attribute_list_opt
     3468        | type_ptr
     3469        | type_array attribute_list_opt
    35723470                { $$ = $1->addQualifiers( $2 ); }
    3573         | variable_type_function attribute_list_opt
     3471        | type_function attribute_list_opt
    35743472                { $$ = $1->addQualifiers( $2 ); }
    35753473        ;
    35763474
    3577 variable_type_ptr:
     3475type_ptr:
    35783476        ptrref_operator variable_type_redeclarator
    35793477                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    35803478        | ptrref_operator type_qualifier_list variable_type_redeclarator
    35813479                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3582         | '(' variable_type_ptr ')' attribute_list_opt          // redundant parenthesis
     3480        | '(' type_ptr ')' attribute_list_opt                           // redundant parenthesis
    35833481                { $$ = $2->addQualifiers( $4 ); }
    3584         | '(' attribute_list variable_type_ptr ')' attribute_list_opt // redundant parenthesis
     3482        | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis
    35853483                { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
    35863484        ;
    35873485
    3588 variable_type_array:
     3486type_array:
    35893487        paren_type array_dimension
    35903488                { $$ = $1->addArray( $2 ); }
    3591         | '(' variable_type_ptr ')' array_dimension
     3489        | '(' type_ptr ')' array_dimension
    35923490                { $$ = $2->addArray( $4 ); }
    3593         | '(' attribute_list variable_type_ptr ')' array_dimension
     3491        | '(' attribute_list type_ptr ')' array_dimension
    35943492                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3595         | '(' variable_type_array ')' multi_array_dimension     // redundant parenthesis
     3493        | '(' type_array ')' multi_array_dimension                      // redundant parenthesis
    35963494                { $$ = $2->addArray( $4 ); }
    3597         | '(' attribute_list variable_type_array ')' multi_array_dimension // redundant parenthesis
     3495        | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis
    35983496                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3599         | '(' variable_type_array ')'                                           // redundant parenthesis
     3497        | '(' type_array ')'                                                            // redundant parenthesis
    36003498                { $$ = $2; }
    3601         | '(' attribute_list variable_type_array ')'            // redundant parenthesis
     3499        | '(' attribute_list type_array ')'                                     // redundant parenthesis
    36023500                { $$ = $3->addQualifiers( $2 ); }
    36033501        ;
    36043502
    3605 variable_type_function:
    3606         '(' variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3607                 { $$ = $2->addParamList( $6 ); }
    3608         | '(' attribute_list variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3609                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    3610         | '(' variable_type_function ')'                                        // redundant parenthesis
    3611                 { $$ = $2; }
    3612         | '(' attribute_list variable_type_function ')'         // redundant parenthesis
    3613                 { $$ = $3->addQualifiers( $2 ); }
    3614         ;
    3615 
    3616 // This pattern parses a declaration for a function prototype that redefines a type name.  It precludes declaring an
    3617 // array of functions versus a pointer to an array of functions, and returning arrays and functions versus pointers to
    3618 // arrays and functions.
    3619 
    3620 function_type_redeclarator:
    3621         function_type_no_ptr attribute_list_opt
    3622                 { $$ = $1->addQualifiers( $2 ); }
    3623         | function_type_ptr
    3624         | function_type_array attribute_list_opt
    3625                 { $$ = $1->addQualifiers( $2 ); }
    3626         ;
    3627 
    3628 function_type_no_ptr:
     3503type_function:
    36293504        paren_type '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    36303505                { $$ = $1->addParamList( $4 ); }
    3631         | '(' function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
     3506        | '(' type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    36323507                { $$ = $2->addParamList( $6 ); }
    3633         | '(' attribute_list function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
     3508        | '(' attribute_list type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    36343509                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    3635         | '(' function_type_no_ptr ')'                                          // redundant parenthesis
     3510        | '(' type_function ')'                                                         // redundant parenthesis
    36363511                { $$ = $2; }
    3637         | '(' attribute_list function_type_no_ptr ')'           // redundant parenthesis
    3638                 { $$ = $3->addQualifiers( $2 ); }
    3639         ;
    3640 
    3641 function_type_ptr:
    3642         ptrref_operator function_type_redeclarator
    3643                 { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    3644         | ptrref_operator type_qualifier_list function_type_redeclarator
    3645                 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3646         | '(' function_type_ptr ')' attribute_list_opt
    3647                 { $$ = $2->addQualifiers( $4 ); }
    3648         | '(' attribute_list function_type_ptr ')' attribute_list_opt
    3649                 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
    3650         ;
    3651 
    3652 function_type_array:
    3653         '(' function_type_ptr ')' array_dimension
    3654                 { $$ = $2->addArray( $4 ); }
    3655         | '(' attribute_list function_type_ptr ')' array_dimension
    3656                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3657         | '(' function_type_array ')' multi_array_dimension     // redundant parenthesis
    3658                 { $$ = $2->addArray( $4 ); }
    3659         | '(' attribute_list function_type_array ')' multi_array_dimension // redundant parenthesis
    3660                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3661         | '(' function_type_array ')'                                           // redundant parenthesis
    3662                 { $$ = $2; }
    3663         | '(' attribute_list function_type_array ')'            // redundant parenthesis
     3512        | '(' attribute_list type_function ')'                          // redundant parenthesis
    36643513                { $$ = $3->addQualifiers( $2 ); }
    36653514        ;
     
    38313680array_type_list:
    38323681        basic_type_name
    3833                 { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
     3682                { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
    38343683        | type_name
    3835                 { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
     3684                { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
    38363685        | assignment_expression upupeq assignment_expression
    38373686        | array_type_list ',' basic_type_name
    3838                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
    3839         | array_type_list ',' type_name
    3840                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
     3687                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
     3688        | array_type_list ',' type_name 
     3689                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
    38413690        | array_type_list ',' assignment_expression upupeq assignment_expression
    38423691        ;
     
    38473696        | ErangeUpEq
    38483697                { $$ = OperKinds::LEThan; }
    3849         ;
     3698        ;
    38503699
    38513700multi_array_dimension:
  • src/Parser/parserutility.cc

    rb110bcc r2ed94a9  
    1010// Created On       : Sat May 16 15:30:39 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Mar  1 10:42:00 2023
    13 // Update Count     : 9
     12// Last Modified On : Tus Jul 18 10:12:00 2017
     13// Update Count     : 8
    1414//
    1515
     
    1919#include <string>                // for string
    2020
    21 #include "AST/Expr.hpp"          // for UntypedExpr, CastExpr, ConstantExpr
    22 #include "AST/Type.hpp"          // for BasicType, ZeroType, BasicType::Kind...
     21#include "SynTree/Constant.h"    // for Constant
     22#include "SynTree/Expression.h"  // for UntypedExpr, CastExpr, ConstantExpr
     23#include "SynTree/Type.h"        // for BasicType, ZeroType, BasicType::Kind...
    2324
    2425// rewrite
     
    2728//    if ( (int)(x != 0) ) ...
    2829
    29 ast::Expr * notZeroExpr( ast::Expr * orig ) {
    30         return ( !orig ) ? nullptr : new ast::CastExpr( orig->location,
    31                 ast::UntypedExpr::createCall( orig->location,
    32                         "?!=?",
    33                         {
    34                                 orig,
    35                                 new ast::ConstantExpr( orig->location,
    36                                         new ast::ZeroType(),
    37                                         "0",
    38                                         std::optional<unsigned long long>( 0 )
    39                                 ),
    40                         }
    41                 ),
    42                 new ast::BasicType( ast::BasicType::SignedInt )
    43         );
     30Expression *notZeroExpr( Expression *orig ) {
     31        if( !orig ) return nullptr;
     32        UntypedExpr *comparison = new UntypedExpr( new NameExpr( "?!=?" ) );
     33        comparison->get_args().push_back( orig );
     34        comparison->get_args().push_back( new ConstantExpr( Constant( new ZeroType( noQualifiers ), "0", (unsigned long long int)0 ) ) );
     35        return new CastExpr( comparison, new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    4436}
    4537
  • src/Parser/parserutility.h

    rb110bcc r2ed94a9  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // parserutility.h -- Collected utilities for the parser.
     7// parserutility.h --
    88//
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 15:31:46 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 14:03:00 2023
    13 // Update Count     : 7
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jul 22 09:32:58 2017
     13// Update Count     : 4
    1414//
    1515
    1616#pragma once
    1717
    18 #include "AST/Copy.hpp"            // for shallowCopy
    19 namespace ast {
    20         class Expr;
    21 }
     18class Expression;
    2219
    23 ast::Expr * notZeroExpr( ast::Expr *orig );
    24 
    25 template< typename T >
    26 static inline auto maybeBuild( T * orig ) -> decltype(orig->build()) {
    27         return (orig) ? orig->build() : nullptr;
    28 }
    29 
    30 template< typename T >
    31 static inline auto maybeMoveBuild( T * orig ) -> decltype(orig->build()) {
    32         auto ret = maybeBuild<T>(orig);
    33         delete orig;
    34         return ret;
    35 }
    36 
    37 template<typename node_t>
    38 node_t * maybeCopy( node_t const * node ) {
    39         return node ? ast::shallowCopy( node ) : nullptr;
    40 }
     20Expression *notZeroExpr( Expression *orig );
    4121
    4222// Local Variables: //
  • src/ResolvExpr/Candidate.cpp

    rb110bcc r2ed94a9  
    1717
    1818#include <iostream>
    19 #include <sstream>
    2019
    2120#include "AST/Print.hpp"
     
    4544        sorted.reserve(cands.size());
    4645        for(const auto & c : cands) {
    47                 std::ostringstream ss;
     46                std::stringstream ss;
    4847                print( ss, *c, indent );
    4948                sorted.push_back(ss.str());
  • src/ResolvExpr/CandidateFinder.cpp

    rb110bcc r2ed94a9  
    5555namespace ResolvExpr {
    5656
    57 /// Unique identifier for matching expression resolutions to their requesting expression
    58 UniqueId globalResnSlot = 0;
    59 
    60 namespace {
    61         /// First index is which argument, second is which alternative, third is which exploded element
    62         using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
    63 
    64         /// Returns a list of alternatives with the minimum cost in the given list
    65         CandidateList findMinCost( const CandidateList & candidates ) {
    66                 CandidateList out;
    67                 Cost minCost = Cost::infinity;
    68                 for ( const CandidateRef & r : candidates ) {
    69                         if ( r->cost < minCost ) {
    70                                 minCost = r->cost;
    71                                 out.clear();
    72                                 out.emplace_back( r );
    73                         } else if ( r->cost == minCost ) {
    74                                 out.emplace_back( r );
    75                         }
    76                 }
    77                 return out;
    78         }
    79 
    80         /// Computes conversion cost for a given expression to a given type
    81         const ast::Expr * computeExpressionConversionCost(
    82                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
    83         ) {
    84                 Cost convCost = computeConversionCost(
    85                                 arg->result, paramType, arg->get_lvalue(), symtab, env );
    86                 outCost += convCost;
    87 
    88                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
    89                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to
    90                 // infer parameters and this does not currently work for the reason stated below
    91                 Cost tmpCost = convCost;
    92                 tmpCost.incPoly( -tmpCost.get_polyCost() );
    93                 if ( tmpCost != Cost::zero ) {
    94                         ast::ptr< ast::Type > newType = paramType;
    95                         env.apply( newType );
    96                         return new ast::CastExpr{ arg, newType };
    97 
    98                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not
    99                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
    100                         // once this is fixed it should be possible to resolve the cast.
    101                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
    102                         // but it shouldn't be because this makes the conversion from DT* to DT* since
    103                         // commontype(zero_t, DT*) is DT*, rather than nothing
    104 
    105                         // CandidateFinder finder{ symtab, env };
    106                         // finder.find( arg, ResolvMode::withAdjustment() );
    107                         // assertf( finder.candidates.size() > 0,
    108                         //      "Somehow castable expression failed to find alternatives." );
    109                         // assertf( finder.candidates.size() == 1,
    110                         //      "Somehow got multiple alternatives for known cast expression." );
    111                         // return finder.candidates.front()->expr;
    112                 }
    113 
    114                 return arg;
    115         }
    116 
    117         /// Computes conversion cost for a given candidate
    118         Cost computeApplicationConversionCost(
    119                 CandidateRef cand, const ast::SymbolTable & symtab
    120         ) {
    121                 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
    122                 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    123                 auto function = pointer->base.strict_as< ast::FunctionType >();
    124 
    125                 Cost convCost = Cost::zero;
    126                 const auto & params = function->params;
    127                 auto param = params.begin();
    128                 auto & args = appExpr->args;
    129 
    130                 for ( unsigned i = 0; i < args.size(); ++i ) {
    131                         const ast::Type * argType = args[i]->result;
    132                         PRINT(
    133                                 std::cerr << "arg expression:" << std::endl;
    134                                 ast::print( std::cerr, args[i], 2 );
    135                                 std::cerr << "--- results are" << std::endl;
    136                                 ast::print( std::cerr, argType, 2 );
    137                         )
    138 
    139                         if ( param == params.end() ) {
    140                                 if ( function->isVarArgs ) {
    141                                         convCost.incUnsafe();
    142                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
    143                                                 << convCost << std::endl; ; )
    144                                         // convert reference-typed expressions into value-typed expressions
    145                                         cand->expr = ast::mutate_field_index(
    146                                                 appExpr, &ast::ApplicationExpr::args, i,
    147                                                 referenceToRvalueConversion( args[i], convCost ) );
    148                                         continue;
    149                                 } else return Cost::infinity;
    150                         }
    151 
    152                         if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
    153                                 // Default arguments should be free - don't include conversion cost.
    154                                 // Unwrap them here because they are not relevant to the rest of the system
    155                                 cand->expr = ast::mutate_field_index(
    156                                         appExpr, &ast::ApplicationExpr::args, i, def->expr );
    157                                 ++param;
    158                                 continue;
    159                         }
    160 
    161                         // mark conversion cost and also specialization cost of param type
    162                         // const ast::Type * paramType = (*param)->get_type();
    163                         cand->expr = ast::mutate_field_index(
    164                                 appExpr, &ast::ApplicationExpr::args, i,
    165                                 computeExpressionConversionCost(
    166                                         args[i], *param, symtab, cand->env, convCost ) );
    167                         convCost.decSpec( specCost( *param ) );
    168                         ++param;  // can't be in for-loop update because of the continue
    169                 }
    170 
    171                 if ( param != params.end() ) return Cost::infinity;
    172 
    173                 // specialization cost of return types can't be accounted for directly, it disables
    174                 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    175                 //
    176                 //   forall(otype OS) {
    177                 //     void ?|?(OS&, int);  // with newline
    178                 //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
    179                 //   }
    180 
    181                 // mark type variable and specialization cost of forall clause
    182                 convCost.incVar( function->forall.size() );
    183                 convCost.decSpec( function->assertions.size() );
    184 
    185                 return convCost;
    186         }
    187 
    188         void makeUnifiableVars(
    189                 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
    190                 ast::AssertionSet & need
    191         ) {
    192                 for ( auto & tyvar : type->forall ) {
    193                         unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
    194                 }
    195                 for ( auto & assn : type->assertions ) {
    196                         need[ assn ].isUsed = true;
    197                 }
    198         }
    199 
    200         /// Gets a default value from an initializer, nullptr if not present
    201         const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
    202                 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
    203                         if ( auto ce = si->value.as< ast::CastExpr >() ) {
    204                                 return ce->arg.as< ast::ConstantExpr >();
    205                         } else {
    206                                 return si->value.as< ast::ConstantExpr >();
    207                         }
    208                 }
    209                 return nullptr;
    210         }
    211 
    212         /// State to iteratively build a match of parameter expressions to arguments
    213         struct ArgPack {
    214                 std::size_t parent;          ///< Index of parent pack
    215                 ast::ptr< ast::Expr > expr;  ///< The argument stored here
    216                 Cost cost;                   ///< The cost of this argument
    217                 ast::TypeEnvironment env;    ///< Environment for this pack
    218                 ast::AssertionSet need;      ///< Assertions outstanding for this pack
    219                 ast::AssertionSet have;      ///< Assertions found for this pack
    220                 ast::OpenVarSet open;        ///< Open variables for this pack
    221                 unsigned nextArg;            ///< Index of next argument in arguments list
    222                 unsigned tupleStart;         ///< Number of tuples that start at this index
    223                 unsigned nextExpl;           ///< Index of next exploded element
    224                 unsigned explAlt;            ///< Index of alternative for nextExpl > 0
    225 
    226                 ArgPack()
    227                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
    228                   tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    229 
    230                 ArgPack(
    231                         const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    232                         const ast::AssertionSet & have, const ast::OpenVarSet & open )
    233                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    234                   open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    235 
    236                 ArgPack(
    237                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
    238                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
    239                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    240                         unsigned nextExpl = 0, unsigned explAlt = 0 )
    241                 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
    242                   have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    243                   nextExpl( nextExpl ), explAlt( explAlt ) {}
    244 
    245                 ArgPack(
    246                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
    247                         ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    248                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
    249                   need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
    250                   tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    251 
    252                 /// true if this pack is in the middle of an exploded argument
    253                 bool hasExpl() const { return nextExpl > 0; }
    254 
    255                 /// Gets the list of exploded candidates for this pack
    256                 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
    257                         return args[ nextArg-1 ][ explAlt ];
    258                 }
    259 
    260                 /// Ends a tuple expression, consolidating the appropriate args
    261                 void endTuple( const std::vector< ArgPack > & packs ) {
    262                         // add all expressions in tuple to list, summing cost
    263                         std::deque< const ast::Expr * > exprs;
    264                         const ArgPack * pack = this;
    265                         if ( expr ) { exprs.emplace_front( expr ); }
    266                         while ( pack->tupleStart == 0 ) {
    267                                 pack = &packs[pack->parent];
    268                                 exprs.emplace_front( pack->expr );
    269                                 cost += pack->cost;
    270                         }
    271                         // reset pack to appropriate tuple
    272                         std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
    273                         expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
    274                         tupleStart = pack->tupleStart - 1;
    275                         parent = pack->parent;
    276                 }
    277         };
    278 
    279         /// Instantiates an argument to match a parameter, returns false if no matching results left
    280         bool instantiateArgument(
    281                 const CodeLocation & location,
    282                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
    283                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    284                 unsigned nTuples = 0
    285         ) {
    286                 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
    287                         // paramType is a TupleType -- group args into a TupleExpr
    288                         ++nTuples;
    289                         for ( const ast::Type * type : *tupleType ) {
    290                                 // xxx - dropping initializer changes behaviour from previous, but seems correct
    291                                 // ^^^ need to handle the case where a tuple has a default argument
    292                                 if ( ! instantiateArgument( location,
    293                                         type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    294                                 nTuples = 0;
    295                         }
    296                         // re-constitute tuples for final generation
    297                         for ( auto i = genStart; i < results.size(); ++i ) {
    298                                 results[i].endTuple( results );
    299                         }
    300                         return true;
    301                 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    302                         // paramType is a ttype, consumes all remaining arguments
    303 
    304                         // completed tuples; will be spliced to end of results to finish
    305                         std::vector< ArgPack > finalResults{};
    306 
    307                         // iterate until all results completed
    308                         std::size_t genEnd;
    309                         ++nTuples;
    310                         do {
    311                                 genEnd = results.size();
    312 
    313                                 // add another argument to results
    314                                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    315                                         unsigned nextArg = results[i].nextArg;
    316 
    317                                         // use next element of exploded tuple if present
    318                                         if ( results[i].hasExpl() ) {
    319                                                 const ExplodedArg & expl = results[i].getExpl( args );
    320 
    321                                                 unsigned nextExpl = results[i].nextExpl + 1;
    322                                                 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    323 
    324                                                 results.emplace_back(
    325                                                         i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    326                                                         copy( results[i].need ), copy( results[i].have ),
    327                                                         copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    328                                                         results[i].explAlt );
    329 
    330                                                 continue;
    331                                         }
    332 
    333                                         // finish result when out of arguments
    334                                         if ( nextArg >= args.size() ) {
    335                                                 ArgPack newResult{
    336                                                         results[i].env, results[i].need, results[i].have, results[i].open };
    337                                                 newResult.nextArg = nextArg;
    338                                                 const ast::Type * argType = nullptr;
    339 
    340                                                 if ( nTuples > 0 || ! results[i].expr ) {
    341                                                         // first iteration or no expression to clone,
    342                                                         // push empty tuple expression
    343                                                         newResult.parent = i;
    344                                                         newResult.expr = new ast::TupleExpr( location, {} );
    345                                                         argType = newResult.expr->result;
    346                                                 } else {
    347                                                         // clone result to collect tuple
    348                                                         newResult.parent = results[i].parent;
    349                                                         newResult.cost = results[i].cost;
    350                                                         newResult.tupleStart = results[i].tupleStart;
    351                                                         newResult.expr = results[i].expr;
    352                                                         argType = newResult.expr->result;
    353 
    354                                                         if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
    355                                                                 // the case where a ttype value is passed directly is special,
    356                                                                 // e.g. for argument forwarding purposes
    357                                                                 // xxx - what if passing multiple arguments, last of which is
    358                                                                 //       ttype?
    359                                                                 // xxx - what would happen if unify was changed so that unifying
    360                                                                 //       tuple
    361                                                                 // types flattened both before unifying lists? then pass in
    362                                                                 // TupleType (ttype) below.
    363                                                                 --newResult.tupleStart;
    364                                                         } else {
    365                                                                 // collapse leftover arguments into tuple
    366                                                                 newResult.endTuple( results );
    367                                                                 argType = newResult.expr->result;
    368                                                         }
    369                                                 }
    370 
    371                                                 // check unification for ttype before adding to final
    372                                                 if (
    373                                                         unify(
    374                                                                 ttype, argType, newResult.env, newResult.need, newResult.have,
    375                                                                 newResult.open, symtab )
    376                                                 ) {
    377                                                         finalResults.emplace_back( std::move( newResult ) );
    378                                                 }
    379 
    380                                                 continue;
    381                                         }
    382 
    383                                         // add each possible next argument
    384                                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    385                                                 const ExplodedArg & expl = args[nextArg][j];
    386 
    387                                                 // fresh copies of parent parameters for this iteration
    388                                                 ast::TypeEnvironment env = results[i].env;
    389                                                 ast::OpenVarSet open = results[i].open;
    390 
    391                                                 env.addActual( expl.env, open );
    392 
    393                                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    394                                                 if ( expl.exprs.empty() ) {
    395                                                         results.emplace_back(
    396                                                                 results[i], std::move( env ), copy( results[i].need ),
    397                                                                 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
    398 
    399                                                         continue;
    400                                                 }
    401 
    402                                                 // add new result
    403                                                 results.emplace_back(
    404                                                         i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    405                                                         copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
    406                                                         expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    407                                         }
    408                                 }
    409 
    410                                 // reset for next round
    411                                 genStart = genEnd;
    412                                 nTuples = 0;
    413                         } while ( genEnd != results.size() );
    414 
    415                         // splice final results onto results
    416                         for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
    417                                 results.emplace_back( std::move( finalResults[i] ) );
    418                         }
    419                         return ! finalResults.empty();
    420                 }
    421 
    422                 // iterate each current subresult
    423                 std::size_t genEnd = results.size();
    424                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    425                         unsigned nextArg = results[i].nextArg;
    426 
    427                         // use remainder of exploded tuple if present
    428                         if ( results[i].hasExpl() ) {
    429                                 const ExplodedArg & expl = results[i].getExpl( args );
    430                                 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
    431 
    432                                 ast::TypeEnvironment env = results[i].env;
    433                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    434                                 ast::OpenVarSet open = results[i].open;
    435 
    436                                 const ast::Type * argType = expr->result;
    437 
    438                                 PRINT(
    439                                         std::cerr << "param type is ";
    440                                         ast::print( std::cerr, paramType );
    441                                         std::cerr << std::endl << "arg type is ";
    442                                         ast::print( std::cerr, argType );
    443                                         std::cerr << std::endl;
    444                                 )
    445 
    446                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    447                                         unsigned nextExpl = results[i].nextExpl + 1;
    448                                         if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    449 
    450                                         results.emplace_back(
    451                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
    452                                                 nTuples, Cost::zero, nextExpl, results[i].explAlt );
    453                                 }
    454 
    455                                 continue;
    456                         }
    457 
    458                         // use default initializers if out of arguments
    459                         if ( nextArg >= args.size() ) {
    460                                 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
    461                                         ast::TypeEnvironment env = results[i].env;
    462                                         ast::AssertionSet need = results[i].need, have = results[i].have;
    463                                         ast::OpenVarSet open = results[i].open;
    464 
    465                                         if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    466                                                 results.emplace_back(
    467                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
    468                                                         std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
    469                                         }
    470                                 }
    471 
    472                                 continue;
    473                         }
    474 
    475                         // Check each possible next argument
    476                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    477                                 const ExplodedArg & expl = args[nextArg][j];
    478 
    479                                 // fresh copies of parent parameters for this iteration
    480                                 ast::TypeEnvironment env = results[i].env;
    481                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    482                                 ast::OpenVarSet open = results[i].open;
    483 
    484                                 env.addActual( expl.env, open );
    485 
    486                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    487                                 if ( expl.exprs.empty() ) {
    488                                         results.emplace_back(
    489                                                 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    490                                                 nextArg + 1, expl.cost );
    491 
    492                                         continue;
    493                                 }
    494 
    495                                 // consider only first exploded arg
    496                                 const ast::Expr * expr = expl.exprs.front();
    497                                 const ast::Type * argType = expr->result;
    498 
    499                                 PRINT(
    500                                         std::cerr << "param type is ";
    501                                         ast::print( std::cerr, paramType );
    502                                         std::cerr << std::endl << "arg type is ";
    503                                         ast::print( std::cerr, argType );
    504                                         std::cerr << std::endl;
    505                                 )
    506 
    507                                 // attempt to unify types
    508                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    509                                         // add new result
    510                                         results.emplace_back(
    511                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    512                                                 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    513                                 }
    514                         }
    515                 }
    516 
    517                 // reset for next parameter
    518                 genStart = genEnd;
    519 
    520                 return genEnd != results.size();  // were any new results added?
    521         }
    522 
    523         /// Generate a cast expression from `arg` to `toType`
    524         const ast::Expr * restructureCast(
    525                 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    526         ) {
    527                 if (
    528                         arg->result->size() > 1
    529                         && ! toType->isVoid()
    530                         && ! dynamic_cast< const ast::ReferenceType * >( toType )
    531                 ) {
    532                         // Argument is a tuple and the target type is neither void nor a reference. Cast each
    533                         // member of the tuple to its corresponding target type, producing the tuple of those
    534                         // cast expressions. If there are more components of the tuple than components in the
    535                         // target type, then excess components do not come out in the result expression (but
    536                         // UniqueExpr ensures that the side effects will still be produced)
    537                         if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    538                                 // expressions which may contain side effects require a single unique instance of
    539                                 // the expression
    540                                 arg = new ast::UniqueExpr{ arg->location, arg };
    541                         }
    542                         std::vector< ast::ptr< ast::Expr > > components;
    543                         for ( unsigned i = 0; i < toType->size(); ++i ) {
    544                                 // cast each component
    545                                 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    546                                 components.emplace_back(
    547                                         restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    548                         }
    549                         return new ast::TupleExpr{ arg->location, std::move( components ) };
    550                 } else {
    551                         // handle normally
    552                         return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
    553                 }
    554         }
    555 
    556         /// Gets the name from an untyped member expression (must be NameExpr)
    557         const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
    558                 if ( memberExpr->member.as< ast::ConstantExpr >() ) {
    559                         SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
    560                 }
    561 
    562                 return memberExpr->member.strict_as< ast::NameExpr >()->name;
    563         }
    564 
    565         /// Actually visits expressions to find their candidate interpretations
    566         class Finder final : public ast::WithShortCircuiting {
    567                 const ResolveContext & context;
    568                 const ast::SymbolTable & symtab;
    569         public:
    570                 // static size_t traceId;
    571                 CandidateFinder & selfFinder;
    572                 CandidateList & candidates;
    573                 const ast::TypeEnvironment & tenv;
    574                 ast::ptr< ast::Type > & targetType;
    575 
    576                 enum Errors {
    577                         NotFound,
    578                         NoMatch,
    579                         ArgsToFew,
    580                         ArgsToMany,
    581                         RetsToFew,
    582                         RetsToMany,
    583                         NoReason
    584                 };
    585 
    586                 struct {
    587                         Errors code = NotFound;
    588                 } reason;
    589 
    590                 Finder( CandidateFinder & f )
    591                 : context( f.context ), symtab( context.symtab ), selfFinder( f ),
    592                   candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
    593 
    594                 void previsit( const ast::Node * ) { visit_children = false; }
    595 
    596                 /// Convenience to add candidate to list
    597                 template<typename... Args>
    598                 void addCandidate( Args &&... args ) {
    599                         candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
    600                         reason.code = NoReason;
    601                 }
    602 
    603                 void postvisit( const ast::ApplicationExpr * applicationExpr ) {
    604                         addCandidate( applicationExpr, tenv );
    605                 }
    606 
    607                 /// Set up candidate assertions for inference
    608                 void inferParameters( CandidateRef & newCand, CandidateList & out );
    609 
    610                 /// Completes a function candidate with arguments located
    611                 void validateFunctionCandidate(
    612                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    613                         CandidateList & out );
    614 
    615                 /// Builds a list of candidates for a function, storing them in out
    616                 void makeFunctionCandidates(
    617                         const CodeLocation & location,
    618                         const CandidateRef & func, const ast::FunctionType * funcType,
    619                         const ExplodedArgs_new & args, CandidateList & out );
    620 
    621                 /// Adds implicit struct-conversions to the alternative list
    622                 void addAnonConversions( const CandidateRef & cand );
    623 
    624                 /// Adds aggregate member interpretations
    625                 void addAggMembers(
    626                         const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    627                         const Candidate & cand, const Cost & addedCost, const std::string & name
    628                 );
    629 
    630                 /// Adds tuple member interpretations
    631                 void addTupleMembers(
    632                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    633                         const Cost & addedCost, const ast::Expr * member
    634                 );
    635 
    636                 /// true if expression is an lvalue
    637                 static bool isLvalue( const ast::Expr * x ) {
    638                         return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
    639                 }
    640 
    641                 void postvisit( const ast::UntypedExpr * untypedExpr );
    642                 void postvisit( const ast::VariableExpr * variableExpr );
    643                 void postvisit( const ast::ConstantExpr * constantExpr );
    644                 void postvisit( const ast::SizeofExpr * sizeofExpr );
    645                 void postvisit( const ast::AlignofExpr * alignofExpr );
    646                 void postvisit( const ast::AddressExpr * addressExpr );
    647                 void postvisit( const ast::LabelAddressExpr * labelExpr );
    648                 void postvisit( const ast::CastExpr * castExpr );
    649                 void postvisit( const ast::VirtualCastExpr * castExpr );
    650                 void postvisit( const ast::KeywordCastExpr * castExpr );
    651                 void postvisit( const ast::UntypedMemberExpr * memberExpr );
    652                 void postvisit( const ast::MemberExpr * memberExpr );
    653                 void postvisit( const ast::NameExpr * nameExpr );
    654                 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr );
    655                 void postvisit( const ast::OffsetofExpr * offsetofExpr );
    656                 void postvisit( const ast::OffsetPackExpr * offsetPackExpr );
    657                 void postvisit( const ast::LogicalExpr * logicalExpr );
    658                 void postvisit( const ast::ConditionalExpr * conditionalExpr );
    659                 void postvisit( const ast::CommaExpr * commaExpr );
    660                 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr );
    661                 void postvisit( const ast::ConstructorExpr * ctorExpr );
    662                 void postvisit( const ast::RangeExpr * rangeExpr );
    663                 void postvisit( const ast::UntypedTupleExpr * tupleExpr );
    664                 void postvisit( const ast::TupleExpr * tupleExpr );
    665                 void postvisit( const ast::TupleIndexExpr * tupleExpr );
    666                 void postvisit( const ast::TupleAssignExpr * tupleExpr );
    667                 void postvisit( const ast::UniqueExpr * unqExpr );
    668                 void postvisit( const ast::StmtExpr * stmtExpr );
    669                 void postvisit( const ast::UntypedInitExpr * initExpr );
    670 
    671                 void postvisit( const ast::InitExpr * ) {
    672                         assertf( false, "CandidateFinder should never see a resolved InitExpr." );
    673                 }
    674 
    675                 void postvisit( const ast::DeletedExpr * ) {
    676                         assertf( false, "CandidateFinder should never see a DeletedExpr." );
    677                 }
    678 
    679                 void postvisit( const ast::GenericExpr * ) {
    680                         assertf( false, "_Generic is not yet supported." );
    681                 }
    682         };
    683 
    684         /// Set up candidate assertions for inference
    685         void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) {
    686                 // Set need bindings for any unbound assertions
    687                 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
    688                 for ( auto & assn : newCand->need ) {
    689                         // skip already-matched assertions
    690                         if ( assn.second.resnSlot != 0 ) continue;
    691                         // assign slot for expression if needed
    692                         if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
    693                         // fix slot to assertion
    694                         assn.second.resnSlot = crntResnSlot;
    695                 }
    696                 // pair slot to expression
    697                 if ( crntResnSlot != 0 ) {
    698                         newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
    699                 }
    700 
    701                 // add to output list; assertion satisfaction will occur later
    702                 out.emplace_back( newCand );
    703         }
    704 
    705         /// Completes a function candidate with arguments located
    706         void Finder::validateFunctionCandidate(
    707                 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    708                 CandidateList & out
    709         ) {
    710                 ast::ApplicationExpr * appExpr =
    711                         new ast::ApplicationExpr{ func->expr->location, func->expr };
    712                 // sum cost and accumulate arguments
    713                 std::deque< const ast::Expr * > args;
    714                 Cost cost = func->cost;
    715                 const ArgPack * pack = &result;
    716                 while ( pack->expr ) {
    717                         args.emplace_front( pack->expr );
    718                         cost += pack->cost;
    719                         pack = &results[pack->parent];
    720                 }
    721                 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
    722                 appExpr->args = std::move( vargs );
    723                 // build and validate new candidate
    724                 auto newCand =
    725                         std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    726                 PRINT(
    727                         std::cerr << "instantiate function success: " << appExpr << std::endl;
    728                         std::cerr << "need assertions:" << std::endl;
    729                         ast::print( std::cerr, result.need, 2 );
    730                 )
    731                 inferParameters( newCand, out );
    732         }
    733 
    734         /// Builds a list of candidates for a function, storing them in out
    735         void Finder::makeFunctionCandidates(
    736                 const CodeLocation & location,
    737                 const CandidateRef & func, const ast::FunctionType * funcType,
    738                 const ExplodedArgs_new & args, CandidateList & out
    739         ) {
    740                 ast::OpenVarSet funcOpen;
    741                 ast::AssertionSet funcNeed, funcHave;
    742                 ast::TypeEnvironment funcEnv{ func->env };
    743                 makeUnifiableVars( funcType, funcOpen, funcNeed );
    744                 // add all type variables as open variables now so that those not used in the
    745                 // parameter list are still considered open
    746                 funcEnv.add( funcType->forall );
    747 
    748                 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
    749                         // attempt to narrow based on expected target type
    750                         const ast::Type * returnType = funcType->returns.front();
    751                         if ( ! unify(
    752                                 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
    753                         ) {
    754                                 // unification failed, do not pursue this candidate
    755                                 return;
    756                         }
    757                 }
    758 
    759                 // iteratively build matches, one parameter at a time
    760                 std::vector< ArgPack > results;
    761                 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
    762                 std::size_t genStart = 0;
    763 
    764                 // xxx - how to handle default arg after change to ftype representation?
    765                 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
    766                         if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
    767                                 // function may have default args only if directly calling by name
    768                                 // must use types on candidate however, due to RenameVars substitution
    769                                 auto nParams = funcType->params.size();
    770 
    771                                 for (size_t i=0; i<nParams; ++i) {
    772                                         auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    773                                         if (!instantiateArgument( location,
    774                                                 funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    775                                 }
    776                                 goto endMatch;
    777                         }
    778                 }
    779                 for ( const auto & param : funcType->params ) {
    780                         // Try adding the arguments corresponding to the current parameter to the existing
    781                         // matches
    782                         // no default args for indirect calls
    783                         if ( ! instantiateArgument( location,
    784                                 param, nullptr, args, results, genStart, symtab ) ) return;
    785                 }
    786 
    787                 endMatch:
    788                 if ( funcType->isVarArgs ) {
    789                         // append any unused arguments to vararg pack
    790                         std::size_t genEnd;
    791                         do {
    792                                 genEnd = results.size();
    793 
    794                                 // iterate results
    795                                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    796                                         unsigned nextArg = results[i].nextArg;
    797 
    798                                         // use remainder of exploded tuple if present
    799                                         if ( results[i].hasExpl() ) {
    800                                                 const ExplodedArg & expl = results[i].getExpl( args );
    801 
    802                                                 unsigned nextExpl = results[i].nextExpl + 1;
    803                                                 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    804 
    805                                                 results.emplace_back(
    806                                                         i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    807                                                         copy( results[i].need ), copy( results[i].have ),
    808                                                         copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
    809                                                         results[i].explAlt );
    810 
    811                                                 continue;
    812                                         }
    813 
    814                                         // finish result when out of arguments
    815                                         if ( nextArg >= args.size() ) {
    816                                                 validateFunctionCandidate( func, results[i], results, out );
    817 
    818                                                 continue;
    819                                         }
    820 
    821                                         // add each possible next argument
    822                                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    823                                                 const ExplodedArg & expl = args[nextArg][j];
    824 
    825                                                 // fresh copies of parent parameters for this iteration
    826                                                 ast::TypeEnvironment env = results[i].env;
    827                                                 ast::OpenVarSet open = results[i].open;
    828 
    829                                                 env.addActual( expl.env, open );
    830 
    831                                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    832                                                 if ( expl.exprs.empty() ) {
    833                                                         results.emplace_back(
    834                                                                 results[i], std::move( env ), copy( results[i].need ),
    835                                                                 copy( results[i].have ), std::move( open ), nextArg + 1,
    836                                                                 expl.cost );
    837 
    838                                                         continue;
    839                                                 }
    840 
    841                                                 // add new result
    842                                                 results.emplace_back(
    843                                                         i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    844                                                         copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
    845                                                         expl.exprs.size() == 1 ? 0 : 1, j );
    846                                         }
    847                                 }
    848 
    849                                 genStart = genEnd;
    850                         } while( genEnd != results.size() );
    851                 } else {
    852                         // filter out the results that don't use all the arguments
    853                         for ( std::size_t i = genStart; i < results.size(); ++i ) {
    854                                 ArgPack & result = results[i];
    855                                 if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
    856                                         validateFunctionCandidate( func, result, results, out );
    857                                 }
    858                         }
    859                 }
    860         }
    861 
    862         /// Adds implicit struct-conversions to the alternative list
    863         void Finder::addAnonConversions( const CandidateRef & cand ) {
    864                 // adds anonymous member interpretations whenever an aggregate value type is seen.
    865                 // it's okay for the aggregate expression to have reference type -- cast it to the
    866                 // base type to treat the aggregate as the referenced value
    867                 ast::ptr< ast::Expr > aggrExpr( cand->expr );
    868                 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    869                 cand->env.apply( aggrType );
    870 
    871                 if ( aggrType.as< ast::ReferenceType >() ) {
    872                         aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
    873                 }
    874 
    875                 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    876                         addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
    877                 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    878                         addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
    879                 }
    880         }
    881 
    882         /// Adds aggregate member interpretations
    883         void Finder::addAggMembers(
    884                 const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    885                 const Candidate & cand, const Cost & addedCost, const std::string & name
    886         ) {
    887                 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    888                         auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    889                         CandidateRef newCand = std::make_shared<Candidate>(
    890                                 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    891                         // add anonymous member interpretations whenever an aggregate value type is seen
    892                         // as a member expression
    893                         addAnonConversions( newCand );
    894                         candidates.emplace_back( std::move( newCand ) );
    895                 }
    896         }
    897 
    898         /// Adds tuple member interpretations
    899         void Finder::addTupleMembers(
    900                 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    901                 const Cost & addedCost, const ast::Expr * member
    902         ) {
    903                 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    904                         // get the value of the constant expression as an int, must be between 0 and the
    905                         // length of the tuple to have meaning
    906                         long long val = constantExpr->intValue();
    907                         if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    908                                 addCandidate(
    909                                         cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
    910                                         addedCost );
    911                         }
    912                 }
    913         }
    914 
    915         void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) {
    916                 std::vector< CandidateFinder > argCandidates =
    917                         selfFinder.findSubExprs( untypedExpr->args );
    918 
    919                 // take care of possible tuple assignments
    920                 // if not tuple assignment, handled as normal function call
    921                 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
    922 
    923                 CandidateFinder funcFinder( context, tenv );
    924                 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
    925                         auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    926                         if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    927                                 assertf(!argCandidates.empty(), "special function call without argument");
    928                                 for (auto & firstArgCand: argCandidates[0]) {
    929                                         ast::ptr<ast::Type> argType = firstArgCand->expr->result;
    930                                         firstArgCand->env.apply(argType);
    931                                         // strip references
    932                                         // xxx - is this correct?
    933                                         while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
    934 
    935                                         // convert 1-tuple to plain type
    936                                         if (auto tuple = argType.as<ast::TupleType>()) {
    937                                                 if (tuple->size() == 1) {
    938                                                         argType = tuple->types[0];
    939                                                 }
    940                                         }
    941 
    942                                         // if argType is an unbound type parameter, all special functions need to be searched.
    943                                         if (isUnboundType(argType)) {
    944                                                 funcFinder.otypeKeys.clear();
    945                                                 break;
    946                                         }
    947 
    948                                         if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
    949                                         // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
    950                                         //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
    951                                         //      if ( const ast::Type* enumType = enumDecl->base ) {
    952                                         //              // instance of enum (T) is a instance of type (T)
    953                                         //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
    954                                         //      } else {
    955                                         //              // instance of an untyped enum is techically int
    956                                         //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
    957                                         //      }
    958                                         // }
    959                                         else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    960                                 }
    961                         }
    962                 }
    963                 // if candidates are already produced, do not fail
    964                 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    965                 // this means there exists ctor/assign functions with a tuple as first parameter.
    966                 ResolvMode mode = {
    967                         true, // adjust
    968                         !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
    969                         selfFinder.candidates.empty() // failfast if other options are not found
    970                 };
    971                 funcFinder.find( untypedExpr->func, mode );
    972                 // short-circuit if no candidates
    973                 // if ( funcFinder.candidates.empty() ) return;
    974 
    975                 reason.code = NoMatch;
    976 
    977                 // find function operators
    978                 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
    979                 CandidateFinder opFinder( context, tenv );
    980                 // okay if there aren't any function operations
    981                 opFinder.find( opExpr, ResolvMode::withoutFailFast() );
    982                 PRINT(
    983                         std::cerr << "known function ops:" << std::endl;
    984                         print( std::cerr, opFinder.candidates, 1 );
    985                 )
    986 
    987                 // pre-explode arguments
    988                 ExplodedArgs_new argExpansions;
    989                 for ( const CandidateFinder & args : argCandidates ) {
    990                         argExpansions.emplace_back();
    991                         auto & argE = argExpansions.back();
    992                         for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
    993                 }
    994 
    995                 // Find function matches
    996                 CandidateList found;
    997                 SemanticErrorException errors;
    998                 for ( CandidateRef & func : funcFinder ) {
    999                         try {
    1000                                 PRINT(
    1001                                         std::cerr << "working on alternative:" << std::endl;
    1002                                         print( std::cerr, *func, 2 );
    1003                                 )
    1004 
    1005                                 // check if the type is a pointer to function
    1006                                 const ast::Type * funcResult = func->expr->result->stripReferences();
    1007                                 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
    1008                                         if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    1009                                                 CandidateRef newFunc{ new Candidate{ *func } };
    1010                                                 newFunc->expr =
    1011                                                         referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    1012                                                 makeFunctionCandidates( untypedExpr->location,
    1013                                                         newFunc, function, argExpansions, found );
    1014                                         }
    1015                                 } else if (
    1016                                         auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    1017                                 ) {
    1018                                         if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    1019                                                 if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    1020                                                         CandidateRef newFunc{ new Candidate{ *func } };
    1021                                                         newFunc->expr =
    1022                                                                 referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    1023                                                         makeFunctionCandidates( untypedExpr->location,
    1024                                                                 newFunc, function, argExpansions, found );
    1025                                                 }
    1026                                         }
    1027                                 }
    1028                         } catch ( SemanticErrorException & e ) { errors.append( e ); }
    1029                 }
    1030 
    1031                 // Find matches on function operators `?()`
    1032                 if ( ! opFinder.candidates.empty() ) {
    1033                         // add exploded function alternatives to front of argument list
    1034                         std::vector< ExplodedArg > funcE;
    1035                         funcE.reserve( funcFinder.candidates.size() );
    1036                         for ( const CandidateRef & func : funcFinder ) {
    1037                                 funcE.emplace_back( *func, symtab );
    1038                         }
    1039                         argExpansions.emplace_front( std::move( funcE ) );
    1040 
    1041                         for ( const CandidateRef & op : opFinder ) {
    1042                                 try {
    1043                                         // check if type is pointer-to-function
    1044                                         const ast::Type * opResult = op->expr->result->stripReferences();
    1045                                         if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
    1046                                                 if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    1047                                                         CandidateRef newOp{ new Candidate{ *op} };
    1048                                                         newOp->expr =
    1049                                                                 referenceToRvalueConversion( newOp->expr, newOp->cost );
    1050                                                         makeFunctionCandidates( untypedExpr->location,
    1051                                                                 newOp, function, argExpansions, found );
    1052                                                 }
    1053                                         }
    1054                                 } catch ( SemanticErrorException & e ) { errors.append( e ); }
    1055                         }
    1056                 }
    1057 
    1058                 // Implement SFINAE; resolution errors are only errors if there aren't any non-error
    1059                 // candidates
    1060                 if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
    1061 
    1062                 // Compute conversion costs
    1063                 for ( CandidateRef & withFunc : found ) {
    1064                         Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
    1065 
    1066                         PRINT(
    1067                                 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
    1068                                 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    1069                                 auto function = pointer->base.strict_as< ast::FunctionType >();
    1070 
    1071                                 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    1072                                 std::cerr << "parameters are:" << std::endl;
    1073                                 ast::printAll( std::cerr, function->params, 2 );
    1074                                 std::cerr << "arguments are:" << std::endl;
    1075                                 ast::printAll( std::cerr, appExpr->args, 2 );
    1076                                 std::cerr << "bindings are:" << std::endl;
    1077                                 ast::print( std::cerr, withFunc->env, 2 );
    1078                                 std::cerr << "cost is: " << withFunc->cost << std::endl;
    1079                                 std::cerr << "cost of conversion is:" << cvtCost << std::endl;
    1080                         )
    1081 
    1082                         if ( cvtCost != Cost::infinity ) {
    1083                                 withFunc->cvtCost = cvtCost;
    1084                                 candidates.emplace_back( std::move( withFunc ) );
    1085                         }
    1086                 }
    1087                 found = std::move( candidates );
    1088 
    1089                 // use a new list so that candidates are not examined by addAnonConversions twice
    1090                 CandidateList winners = findMinCost( found );
    1091                 promoteCvtCost( winners );
    1092 
    1093                 // function may return a struct/union value, in which case we need to add candidates
    1094                 // for implicit conversions to each of the anonymous members, which must happen after
    1095                 // `findMinCost`, since anon conversions are never the cheapest
    1096                 for ( const CandidateRef & c : winners ) {
    1097                         addAnonConversions( c );
    1098                 }
    1099                 spliceBegin( candidates, winners );
    1100 
    1101                 if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    1102                         // If resolution is unsuccessful with a target type, try again without, since it
    1103                         // will sometimes succeed when it wouldn't with a target type binding.
    1104                         // For example:
    1105                         //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
    1106                         //   const char * x = "hello world";
    1107                         //   unsigned char ch = x[0];
    1108                         // Fails with simple return type binding (xxx -- check this!) as follows:
    1109                         // * T is bound to unsigned char
    1110                         // * (x: const char *) is unified with unsigned char *, which fails
    1111                         // xxx -- fix this better
    1112                         targetType = nullptr;
    1113                         postvisit( untypedExpr );
    1114                 }
    1115         }
    1116 
    1117         void Finder::postvisit( const ast::AddressExpr * addressExpr ) {
    1118                 CandidateFinder finder( context, tenv );
    1119                 finder.find( addressExpr->arg );
    1120 
    1121                 if ( finder.candidates.empty() ) return;
    1122 
    1123                 reason.code = NoMatch;
    1124 
    1125                 for ( CandidateRef & r : finder.candidates ) {
    1126                         if ( ! isLvalue( r->expr ) ) continue;
    1127                         addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
    1128                 }
    1129         }
    1130 
    1131         void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) {
    1132                 addCandidate( labelExpr, tenv );
    1133         }
    1134 
    1135         void Finder::postvisit( const ast::CastExpr * castExpr ) {
    1136                 ast::ptr< ast::Type > toType = castExpr->result;
    1137                 assert( toType );
    1138                 toType = resolveTypeof( toType, context );
    1139                 toType = adjustExprType( toType, tenv, symtab );
    1140 
    1141                 CandidateFinder finder( context, tenv, toType );
    1142                 finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    1143 
    1144                 if ( !finder.candidates.empty() ) reason.code = NoMatch;
    1145 
    1146                 CandidateList matches;
    1147                 for ( CandidateRef & cand : finder.candidates ) {
    1148                         ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1149                         ast::OpenVarSet open( cand->open );
    1150 
    1151                         cand->env.extractOpenVars( open );
    1152 
    1153                         // It is possible that a cast can throw away some values in a multiply-valued
    1154                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
    1155                         // subexpression results that are cast directly. The candidate is invalid if it
    1156                         // has fewer results than there are types to cast to.
    1157                         int discardedValues = cand->expr->result->size() - toType->size();
    1158                         if ( discardedValues < 0 ) continue;
    1159 
    1160                         // unification run for side-effects
    1161                         unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1162                         Cost thisCost =
    1163                                 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
    1164                                         ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    1165                                         : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
    1166 
    1167                         PRINT(
    1168                                 std::cerr << "working on cast with result: " << toType << std::endl;
    1169                                 std::cerr << "and expr type: " << cand->expr->result << std::endl;
    1170                                 std::cerr << "env: " << cand->env << std::endl;
    1171                         )
    1172                         if ( thisCost != Cost::infinity ) {
    1173                                 PRINT(
    1174                                         std::cerr << "has finite cost." << std::endl;
    1175                                 )
    1176                                 // count one safe conversion for each value that is thrown away
    1177                                 thisCost.incSafe( discardedValues );
    1178                                 CandidateRef newCand = std::make_shared<Candidate>(
    1179                                         restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1180                                         copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
    1181                                         cand->cost + thisCost );
    1182                                 inferParameters( newCand, matches );
    1183                         }
    1184                 }
    1185 
    1186                 // select first on argument cost, then conversion cost
    1187                 CandidateList minArgCost = findMinCost( matches );
    1188                 promoteCvtCost( minArgCost );
    1189                 candidates = findMinCost( minArgCost );
    1190         }
    1191 
    1192         void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) {
    1193                 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
    1194                 CandidateFinder finder( context, tenv );
    1195                 // don't prune here, all alternatives guaranteed to have same type
    1196                 finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    1197                 for ( CandidateRef & r : finder.candidates ) {
    1198                         addCandidate(
    1199                                 *r,
    1200                                 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    1201                 }
    1202         }
    1203 
    1204         void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) {
    1205                 const auto & loc = castExpr->location;
    1206                 assertf( castExpr->result, "Cast target should have been set in Validate." );
    1207                 auto ref = castExpr->result.strict_as<ast::ReferenceType>();
    1208                 auto inst = ref->base.strict_as<ast::StructInstType>();
    1209                 auto target = inst->base.get();
    1210 
    1211                 CandidateFinder finder( context, tenv );
    1212 
    1213                 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
    1214                         for (auto & cand : found) {
    1215                                 const ast::Type * expr = cand->expr->result.get();
    1216                                 if (expect_ref) {
    1217                                         auto res = dynamic_cast<const ast::ReferenceType*>(expr);
    1218                                         if (!res) { continue; }
    1219                                         expr = res->base.get();
    1220                                 }
    1221 
    1222                                 if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1223                                         auto td = cand->env.lookup(*insttype);
    1224                                         if (!td) { continue; }
    1225                                         expr = td->bound.get();
    1226                                 }
    1227 
    1228                                 if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
    1229                                         if (base->base == target) {
    1230                                                 candidates.push_back( std::move(cand) );
    1231                                                 reason.code = NoReason;
    1232                                         }
    1233                                 }
    1234                         }
    1235                 };
    1236 
    1237                 try {
    1238                         // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
    1239                         // Clone is purely for memory management
    1240                         std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
    1241 
    1242                         // don't prune here, since it's guaranteed all alternatives will have the same type
    1243                         finder.find( tech1.get(), ResolvMode::withoutPrune() );
    1244                         pick_alternatives(finder.candidates, false);
    1245 
    1246                         return;
    1247                 } catch(SemanticErrorException & ) {}
    1248 
    1249                 // Fallback : turn (thread&)X into (thread$&)get_thread(X)
    1250                 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
    1251                 // don't prune here, since it's guaranteed all alternatives will have the same type
    1252                 finder.find( fallback.get(), ResolvMode::withoutPrune() );
    1253 
    1254                 pick_alternatives(finder.candidates, true);
    1255 
    1256                 // Whatever happens here, we have no more fallbacks
    1257         }
    1258 
    1259         void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) {
    1260                 CandidateFinder aggFinder( context, tenv );
    1261                 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    1262                 for ( CandidateRef & agg : aggFinder.candidates ) {
    1263                         // it's okay for the aggregate expression to have reference type -- cast it to the
    1264                         // base type to treat the aggregate as the referenced value
    1265                         Cost addedCost = Cost::zero;
    1266                         agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
    1267 
    1268                         // find member of the given type
    1269                         if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1270                                 addAggMembers(
    1271                                         structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1272                         } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1273                                 addAggMembers(
    1274                                         unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1275                         } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
    1276                                 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
    1277                         }
    1278                 }
    1279         }
    1280 
    1281         void Finder::postvisit( const ast::MemberExpr * memberExpr ) {
    1282                 addCandidate( memberExpr, tenv );
    1283         }
    1284 
    1285         void Finder::postvisit( const ast::NameExpr * nameExpr ) {
    1286                 std::vector< ast::SymbolTable::IdData > declList;
    1287                 if (!selfFinder.otypeKeys.empty()) {
    1288                         auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    1289                         assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
    1290 
    1291                         for (auto & otypeKey: selfFinder.otypeKeys) {
    1292                                 auto result = symtab.specialLookupId(kind, otypeKey);
    1293                                 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
    1294                         }
    1295                 } else {
    1296                         declList = symtab.lookupId( nameExpr->name );
    1297                 }
    1298                 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
    1299 
    1300                 if ( declList.empty() ) return;
    1301 
    1302                 reason.code = NoMatch;
    1303 
    1304                 for ( auto & data : declList ) {
    1305                         Cost cost = Cost::zero;
    1306                         ast::Expr * newExpr = data.combine( nameExpr->location, cost );
    1307 
    1308                         CandidateRef newCand = std::make_shared<Candidate>(
    1309                                 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
    1310                                 cost );
    1311 
    1312                         if (newCand->expr->env) {
    1313                                 newCand->env.add(*newCand->expr->env);
    1314                                 auto mutExpr = newCand->expr.get_and_mutate();
    1315                                 mutExpr->env  = nullptr;
    1316                                 newCand->expr = mutExpr;
    1317                         }
    1318 
    1319                         PRINT(
    1320                                 std::cerr << "decl is ";
    1321                                 ast::print( std::cerr, data.id );
    1322                                 std::cerr << std::endl;
    1323                                 std::cerr << "newExpr is ";
    1324                                 ast::print( std::cerr, newExpr );
    1325                                 std::cerr << std::endl;
    1326                         )
    1327                         newCand->expr = ast::mutate_field(
    1328                                 newCand->expr.get(), &ast::Expr::result,
    1329                                 renameTyVars( newCand->expr->result ) );
    1330                         // add anonymous member interpretations whenever an aggregate value type is seen
    1331                         // as a name expression
    1332                         addAnonConversions( newCand );
    1333                         candidates.emplace_back( std::move( newCand ) );
    1334                 }
    1335         }
    1336 
    1337         void Finder::postvisit( const ast::VariableExpr * variableExpr ) {
    1338                 // not sufficient to just pass `variableExpr` here, type might have changed since
    1339                 // creation
    1340                 addCandidate(
    1341                         new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    1342         }
    1343 
    1344         void Finder::postvisit( const ast::ConstantExpr * constantExpr ) {
    1345                 addCandidate( constantExpr, tenv );
    1346         }
    1347 
    1348         void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) {
    1349                 if ( sizeofExpr->type ) {
    1350                         addCandidate(
    1351                                 new ast::SizeofExpr{
    1352                                         sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
    1353                                 tenv );
    1354                 } else {
    1355                         // find all candidates for the argument to sizeof
    1356                         CandidateFinder finder( context, tenv );
    1357                         finder.find( sizeofExpr->expr );
    1358                         // find the lowest-cost candidate, otherwise ambiguous
    1359                         CandidateList winners = findMinCost( finder.candidates );
    1360                         if ( winners.size() != 1 ) {
    1361                                 SemanticError(
    1362                                         sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    1363                         }
    1364                         // return the lowest-cost candidate
    1365                         CandidateRef & choice = winners.front();
    1366                         choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1367                         choice->cost = Cost::zero;
    1368                         addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
    1369                 }
    1370         }
    1371 
    1372         void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) {
    1373                 if ( alignofExpr->type ) {
    1374                         addCandidate(
    1375                                 new ast::AlignofExpr{
    1376                                         alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
    1377                                 tenv );
    1378                 } else {
    1379                         // find all candidates for the argument to alignof
    1380                         CandidateFinder finder( context, tenv );
    1381                         finder.find( alignofExpr->expr );
    1382                         // find the lowest-cost candidate, otherwise ambiguous
    1383                         CandidateList winners = findMinCost( finder.candidates );
    1384                         if ( winners.size() != 1 ) {
    1385                                 SemanticError(
    1386                                         alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    1387                         }
    1388                         // return the lowest-cost candidate
    1389                         CandidateRef & choice = winners.front();
    1390                         choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1391                         choice->cost = Cost::zero;
    1392                         addCandidate(
    1393                                 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    1394                 }
    1395         }
    1396 
    1397         void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1398                 const ast::BaseInstType * aggInst;
    1399                 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
    1400                 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
    1401                 else return;
    1402 
    1403                 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    1404                         auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1405                         addCandidate(
    1406                                 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    1407                 }
    1408         }
    1409 
    1410         void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) {
    1411                 addCandidate( offsetofExpr, tenv );
    1412         }
    1413 
    1414         void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
    1415                 addCandidate( offsetPackExpr, tenv );
    1416         }
    1417 
    1418         void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
    1419                 CandidateFinder finder1( context, tenv );
    1420                 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
    1421                 if ( finder1.candidates.empty() ) return;
    1422 
    1423                 CandidateFinder finder2( context, tenv );
    1424                 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    1425                 if ( finder2.candidates.empty() ) return;
    1426 
    1427                 reason.code = NoMatch;
    1428 
    1429                 for ( const CandidateRef & r1 : finder1.candidates ) {
    1430                         for ( const CandidateRef & r2 : finder2.candidates ) {
    1431                                 ast::TypeEnvironment env{ r1->env };
    1432                                 env.simpleCombine( r2->env );
    1433                                 ast::OpenVarSet open{ r1->open };
    1434                                 mergeOpenVars( open, r2->open );
    1435                                 ast::AssertionSet need;
    1436                                 mergeAssertionSet( need, r1->need );
    1437                                 mergeAssertionSet( need, r2->need );
    1438 
    1439                                 addCandidate(
    1440                                         new ast::LogicalExpr{
    1441                                                 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    1442                                         std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
    1443                         }
    1444                 }
    1445         }
    1446 
    1447         void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
    1448                 // candidates for condition
    1449                 CandidateFinder finder1( context, tenv );
    1450                 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
    1451                 if ( finder1.candidates.empty() ) return;
    1452 
    1453                 // candidates for true result
    1454                 CandidateFinder finder2( context, tenv );
    1455                 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
    1456                 if ( finder2.candidates.empty() ) return;
    1457 
    1458                 // candidates for false result
    1459                 CandidateFinder finder3( context, tenv );
    1460                 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    1461                 if ( finder3.candidates.empty() ) return;
    1462 
    1463                 reason.code = NoMatch;
    1464 
    1465                 for ( const CandidateRef & r1 : finder1.candidates ) {
    1466                         for ( const CandidateRef & r2 : finder2.candidates ) {
    1467                                 for ( const CandidateRef & r3 : finder3.candidates ) {
    1468                                         ast::TypeEnvironment env{ r1->env };
    1469                                         env.simpleCombine( r2->env );
    1470                                         env.simpleCombine( r3->env );
    1471                                         ast::OpenVarSet open{ r1->open };
    1472                                         mergeOpenVars( open, r2->open );
    1473                                         mergeOpenVars( open, r3->open );
    1474                                         ast::AssertionSet need;
    1475                                         mergeAssertionSet( need, r1->need );
    1476                                         mergeAssertionSet( need, r2->need );
    1477                                         mergeAssertionSet( need, r3->need );
    1478                                         ast::AssertionSet have;
    1479 
    1480                                         // unify true and false results, then infer parameters to produce new
    1481                                         // candidates
    1482                                         ast::ptr< ast::Type > common;
    1483                                         if (
    1484                                                 unify(
    1485                                                         r2->expr->result, r3->expr->result, env, need, have, open, symtab,
    1486                                                         common )
    1487                                         ) {
    1488                                                 // generate typed expression
    1489                                                 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
    1490                                                         conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    1491                                                 newExpr->result = common ? common : r2->expr->result;
    1492                                                 // convert both options to result type
    1493                                                 Cost cost = r1->cost + r2->cost + r3->cost;
    1494                                                 newExpr->arg2 = computeExpressionConversionCost(
    1495                                                         newExpr->arg2, newExpr->result, symtab, env, cost );
    1496                                                 newExpr->arg3 = computeExpressionConversionCost(
    1497                                                         newExpr->arg3, newExpr->result, symtab, env, cost );
    1498                                                 // output candidate
    1499                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1500                                                         newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
    1501                                                 inferParameters( newCand, candidates );
    1502                                         }
    1503                                 }
    1504                         }
    1505                 }
    1506         }
    1507 
    1508         void Finder::postvisit( const ast::CommaExpr * commaExpr ) {
    1509                 ast::TypeEnvironment env{ tenv };
    1510                 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
    1511 
    1512                 CandidateFinder finder2( context, env );
    1513                 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
    1514 
    1515                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1516                         addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
    1517                 }
    1518         }
    1519 
    1520         void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
    1521                 addCandidate( ctorExpr, tenv );
    1522         }
    1523 
    1524         void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) {
    1525                 CandidateFinder finder( context, tenv );
    1526                 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
    1527                 for ( CandidateRef & r : finder.candidates ) {
    1528                         addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
    1529                 }
    1530         }
    1531 
    1532         void Finder::postvisit( const ast::RangeExpr * rangeExpr ) {
    1533                 // resolve low and high, accept candidates where low and high types unify
    1534                 CandidateFinder finder1( context, tenv );
    1535                 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
    1536                 if ( finder1.candidates.empty() ) return;
    1537 
    1538                 CandidateFinder finder2( context, tenv );
    1539                 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    1540                 if ( finder2.candidates.empty() ) return;
    1541 
    1542                 reason.code = NoMatch;
    1543 
    1544                 for ( const CandidateRef & r1 : finder1.candidates ) {
    1545                         for ( const CandidateRef & r2 : finder2.candidates ) {
    1546                                 ast::TypeEnvironment env{ r1->env };
    1547                                 env.simpleCombine( r2->env );
    1548                                 ast::OpenVarSet open{ r1->open };
    1549                                 mergeOpenVars( open, r2->open );
    1550                                 ast::AssertionSet need;
    1551                                 mergeAssertionSet( need, r1->need );
    1552                                 mergeAssertionSet( need, r2->need );
    1553                                 ast::AssertionSet have;
    1554 
    1555                                 ast::ptr< ast::Type > common;
    1556                                 if (
    1557                                         unify(
    1558                                                 r1->expr->result, r2->expr->result, env, need, have, open, symtab,
    1559                                                 common )
    1560                                 ) {
    1561                                         // generate new expression
    1562                                         ast::RangeExpr * newExpr =
    1563                                                 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    1564                                         newExpr->result = common ? common : r1->expr->result;
    1565                                         // add candidate
    1566                                         CandidateRef newCand = std::make_shared<Candidate>(
    1567                                                 newExpr, std::move( env ), std::move( open ), std::move( need ),
    1568                                                 r1->cost + r2->cost );
    1569                                         inferParameters( newCand, candidates );
    1570                                 }
    1571                         }
    1572                 }
    1573         }
    1574 
    1575         void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1576                 std::vector< CandidateFinder > subCandidates =
    1577                         selfFinder.findSubExprs( tupleExpr->exprs );
    1578                 std::vector< CandidateList > possibilities;
    1579                 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
    1580 
    1581                 for ( const CandidateList & subs : possibilities ) {
    1582                         std::vector< ast::ptr< ast::Expr > > exprs;
    1583                         exprs.reserve( subs.size() );
    1584                         for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
    1585 
    1586                         ast::TypeEnvironment env;
    1587                         ast::OpenVarSet open;
    1588                         ast::AssertionSet need;
    1589                         for ( const CandidateRef & sub : subs ) {
    1590                                 env.simpleCombine( sub->env );
    1591                                 mergeOpenVars( open, sub->open );
    1592                                 mergeAssertionSet( need, sub->need );
    1593                         }
    1594 
    1595                         addCandidate(
    1596                                 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
    1597                                 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
    1598                 }
    1599         }
    1600 
    1601         void Finder::postvisit( const ast::TupleExpr * tupleExpr ) {
    1602                 addCandidate( tupleExpr, tenv );
    1603         }
    1604 
    1605         void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) {
    1606                 addCandidate( tupleExpr, tenv );
    1607         }
    1608 
    1609         void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) {
    1610                 addCandidate( tupleExpr, tenv );
    1611         }
    1612 
    1613         void Finder::postvisit( const ast::UniqueExpr * unqExpr ) {
    1614                 CandidateFinder finder( context, tenv );
    1615                 finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
    1616                 for ( CandidateRef & r : finder.candidates ) {
    1617                         // ensure that the the id is passed on so that the expressions are "linked"
    1618                         addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
    1619                 }
    1620         }
    1621 
    1622         void Finder::postvisit( const ast::StmtExpr * stmtExpr ) {
    1623                 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
    1624         }
    1625 
    1626         void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) {
    1627                 // handle each option like a cast
    1628                 CandidateList matches;
    1629                 PRINT(
    1630                         std::cerr << "untyped init expr: " << initExpr << std::endl;
    1631                 )
    1632                 // O(n^2) checks of d-types with e-types
    1633                 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
    1634                         // calculate target type
    1635                         const ast::Type * toType = resolveTypeof( initAlt.type, context );
    1636                         toType = adjustExprType( toType, tenv, symtab );
    1637                         // The call to find must occur inside this loop, otherwise polymorphic return
    1638                         // types are not bound to the initialization type, since return type variables are
    1639                         // only open for the duration of resolving the UntypedExpr.
    1640                         CandidateFinder finder( context, tenv, toType );
    1641                         finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    1642                         for ( CandidateRef & cand : finder.candidates ) {
    1643                                 if (reason.code == NotFound) reason.code = NoMatch;
    1644 
    1645                                 ast::TypeEnvironment env{ cand->env };
    1646                                 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1647                                 ast::OpenVarSet open{ cand->open };
    1648 
    1649                                 PRINT(
    1650                                         std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    1651                                 )
    1652 
    1653                                 // It is possible that a cast can throw away some values in a multiply-valued
    1654                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
    1655                                 // the subexpression results that are cast directly. The candidate is invalid
    1656                                 // if it has fewer results than there are types to cast to.
    1657                                 int discardedValues = cand->expr->result->size() - toType->size();
    1658                                 if ( discardedValues < 0 ) continue;
    1659 
    1660                                 // unification run for side-effects
    1661                                 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
    1662                                 (void) canUnify;
    1663                                 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1664                                         symtab, env );
    1665                                 PRINT(
    1666                                         Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1667                                                 symtab, env );
    1668                                         std::cerr << "Considering initialization:";
    1669                                         std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
    1670                                         std::cerr << std::endl << "  TO: "   << toType             << std::endl;
    1671                                         std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
    1672                                         std::cerr << std::endl << "  Legacy cost " << legacyCost;
    1673                                         std::cerr << std::endl << "  New cost " << thisCost;
    1674                                         std::cerr << std::endl;
    1675                                 )
    1676                                 if ( thisCost != Cost::infinity ) {
    1677                                         // count one safe conversion for each value that is thrown away
    1678                                         thisCost.incSafe( discardedValues );
    1679                                         CandidateRef newCand = std::make_shared<Candidate>(
    1680                                                 new ast::InitExpr{
    1681                                                         initExpr->location, restructureCast( cand->expr, toType ),
    1682                                                         initAlt.designation },
    1683                                                 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
    1684                                         inferParameters( newCand, matches );
    1685                                 }
    1686                         }
    1687                 }
    1688 
    1689                 // select first on argument cost, then conversion cost
    1690                 CandidateList minArgCost = findMinCost( matches );
    1691                 promoteCvtCost( minArgCost );
    1692                 candidates = findMinCost( minArgCost );
    1693         }
    1694 
    1695         // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
    1696         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    1697         /// return type. Skips ambiguous candidates.
    1698 
    1699 } // anonymous namespace
    1700 
    1701 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
    1702         struct PruneStruct {
    1703                 CandidateRef candidate;
    1704                 bool ambiguous;
    1705 
    1706                 PruneStruct() = default;
    1707                 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
    1708         };
    1709 
    1710         // find lowest-cost candidate for each type
    1711         std::unordered_map< std::string, PruneStruct > selected;
    1712         // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
    1713         std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
    1714         for ( CandidateRef & candidate : candidates ) {
    1715                 std::string mangleName;
    1716                 {
    1717                         ast::ptr< ast::Type > newType = candidate->expr->result;
    1718                         assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    1719                         candidate->env.apply( newType );
    1720                         mangleName = Mangle::mangle( newType );
    1721                 }
    1722 
    1723                 auto found = selected.find( mangleName );
    1724                 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
    1725                         PRINT(
    1726                                 std::cerr << "cost " << candidate->cost << " loses to "
    1727                                         << found->second.candidate->cost << std::endl;
    1728                         )
    1729                         continue;
    1730                 }
    1731 
    1732                 // xxx - when do satisfyAssertions produce more than 1 result?
    1733                 // this should only happen when initial result type contains
    1734                 // unbound type parameters, then it should never be pruned by
    1735                 // the previous step, since renameTyVars guarantees the mangled name
    1736                 // is unique.
    1737                 CandidateList satisfied;
    1738                 bool needRecomputeKey = false;
    1739                 if (candidate->need.empty()) {
    1740                         satisfied.emplace_back(candidate);
    1741                 }
    1742                 else {
    1743                         satisfyAssertions(candidate, context.symtab, satisfied, errors);
    1744                         needRecomputeKey = true;
    1745                 }
    1746 
    1747                 for (auto & newCand : satisfied) {
    1748                         // recomputes type key, if satisfyAssertions changed it
    1749                         if (needRecomputeKey)
    1750                         {
    1751                                 ast::ptr< ast::Type > newType = newCand->expr->result;
    1752                                 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
    1753                                 newCand->env.apply( newType );
    1754                                 mangleName = Mangle::mangle( newType );
    1755                         }
    1756                         auto found = selected.find( mangleName );
    1757                         if ( found != selected.end() ) {
    1758                                 if ( newCand->cost < found->second.candidate->cost ) {
    1759                                         PRINT(
    1760                                                 std::cerr << "cost " << newCand->cost << " beats "
    1761                                                         << found->second.candidate->cost << std::endl;
    1762                                         )
    1763 
    1764                                         found->second = PruneStruct{ newCand };
    1765                                 } else if ( newCand->cost == found->second.candidate->cost ) {
    1766                                         // if one of the candidates contains a deleted identifier, can pick the other,
    1767                                         // since deleted expressions should not be ambiguous if there is another option
    1768                                         // that is at least as good
    1769                                         if ( findDeletedExpr( newCand->expr ) ) {
    1770                                                 // do nothing
    1771                                                 PRINT( std::cerr << "candidate is deleted" << std::endl; )
    1772                                         } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
    1773                                                 PRINT( std::cerr << "current is deleted" << std::endl; )
    1774                                                 found->second = PruneStruct{ newCand };
    1775                                         } else {
    1776                                                 PRINT( std::cerr << "marking ambiguous" << std::endl; )
    1777                                                 found->second.ambiguous = true;
    1778                                         }
    1779                                 } else {
    1780                                         // xxx - can satisfyAssertions increase the cost?
    1781                                         PRINT(
    1782                                                 std::cerr << "cost " << newCand->cost << " loses to "
    1783                                                         << found->second.candidate->cost << std::endl;
    1784                                         )
    1785                                 }
    1786                         } else {
    1787                                 selected.emplace_hint( found, mangleName, newCand );
    1788                         }
    1789                 }
    1790         }
    1791 
    1792         // report unambiguous min-cost candidates
    1793         // CandidateList out;
    1794         for ( auto & target : selected ) {
    1795                 if ( target.second.ambiguous ) continue;
    1796 
    1797                 CandidateRef cand = target.second.candidate;
    1798 
    1799                 ast::ptr< ast::Type > newResult = cand->expr->result;
    1800                 cand->env.applyFree( newResult );
    1801                 cand->expr = ast::mutate_field(
    1802                         cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
    1803 
    1804                 out.emplace_back( cand );
    1805         }
    1806         // if everything is lost in satisfyAssertions, report the error
    1807         return !selected.empty();
    1808 }
    1809 
    1810 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
    1811         // Find alternatives for expression
    1812         ast::Pass<Finder> finder{ *this };
    1813         expr->accept( finder );
    1814 
    1815         if ( mode.failFast && candidates.empty() ) {
    1816                 switch(finder.core.reason.code) {
    1817                 case Finder::NotFound:
    1818                         { SemanticError( expr, "No alternatives for expression " ); break; }
    1819                 case Finder::NoMatch:
    1820                         { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
    1821                 case Finder::ArgsToFew:
    1822                 case Finder::ArgsToMany:
    1823                 case Finder::RetsToFew:
    1824                 case Finder::RetsToMany:
    1825                 case Finder::NoReason:
    1826                 default:
    1827                         { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
    1828                 }
    1829         }
    1830 
    1831         /*
    1832         if ( mode.satisfyAssns || mode.prune ) {
    1833                 // trim candidates to just those where the assertions are satisfiable
    1834                 // - necessary pre-requisite to pruning
    1835                 CandidateList satisfied;
    1836                 std::vector< std::string > errors;
    1837                 for ( CandidateRef & candidate : candidates ) {
    1838                         satisfyAssertions( candidate, localSyms, satisfied, errors );
    1839                 }
    1840 
    1841                 // fail early if none such
    1842                 if ( mode.failFast && satisfied.empty() ) {
    1843                         std::ostringstream stream;
    1844                         stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1845                         for ( const auto& err : errors ) {
    1846                                 stream << err;
    1847                         }
    1848                         SemanticError( expr->location, stream.str() );
    1849                 }
    1850 
    1851                 // reset candidates
    1852                 candidates = move( satisfied );
    1853         }
    1854         */
    1855 
    1856         if ( mode.prune ) {
    1857                 // trim candidates to single best one
    1858                 PRINT(
    1859                         std::cerr << "alternatives before prune:" << std::endl;
    1860                         print( std::cerr, candidates );
    1861                 )
    1862 
    1863                 CandidateList pruned;
    1864                 std::vector<std::string> errors;
    1865                 bool found = pruneCandidates( candidates, pruned, errors );
    1866 
    1867                 if ( mode.failFast && pruned.empty() ) {
    1868                         std::ostringstream stream;
    1869                         if (found) {
    1870                                 CandidateList winners = findMinCost( candidates );
    1871                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    1872                                         "expression\n";
    1873                                 ast::print( stream, expr );
    1874                                 stream << " Alternatives are:\n";
    1875                                 print( stream, winners, 1 );
    1876                                 SemanticError( expr->location, stream.str() );
    1877                         }
    1878                         else {
    1879                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1880                                 for ( const auto& err : errors ) {
    1881                                         stream << err;
    1882                                 }
    1883                                 SemanticError( expr->location, stream.str() );
    1884                         }
    1885                 }
    1886 
    1887                 auto oldsize = candidates.size();
    1888                 candidates = std::move( pruned );
    1889 
    1890                 PRINT(
    1891                         std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
    1892                 )
    1893                 PRINT(
    1894                         std::cerr << "there are " << candidates.size() << " alternatives after elimination"
    1895                                 << std::endl;
    1896                 )
    1897         }
    1898 
    1899         // adjust types after pruning so that types substituted by pruneAlternatives are correctly
    1900         // adjusted
    1901         if ( mode.adjust ) {
    1902                 for ( CandidateRef & r : candidates ) {
    1903                         r->expr = ast::mutate_field(
    1904                                 r->expr.get(), &ast::Expr::result,
    1905                                 adjustExprType( r->expr->result, r->env, context.symtab ) );
    1906                 }
    1907         }
    1908 
    1909         // Central location to handle gcc extension keyword, etc. for all expressions
    1910         for ( CandidateRef & r : candidates ) {
    1911                 if ( r->expr->extension != expr->extension ) {
    1912                         r->expr.get_and_mutate()->extension = expr->extension;
    1913                 }
    1914         }
    1915 }
    1916 
    1917 std::vector< CandidateFinder > CandidateFinder::findSubExprs(
    1918         const std::vector< ast::ptr< ast::Expr > > & xs
    1919 ) {
    1920         std::vector< CandidateFinder > out;
    1921 
    1922         for ( const auto & x : xs ) {
    1923                 out.emplace_back( context, env );
    1924                 out.back().find( x, ResolvMode::withAdjustment() );
    1925 
    1926                 PRINT(
    1927                         std::cerr << "findSubExprs" << std::endl;
    1928                         print( std::cerr, out.back().candidates );
    1929                 )
    1930         }
    1931 
    1932         return out;
    1933 }
    1934 
    193557const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
    193658        if ( expr->result.as< ast::ReferenceType >() ) {
     
    194264        return expr;
    194365}
     66
     67/// Unique identifier for matching expression resolutions to their requesting expression
     68UniqueId globalResnSlot = 0;
    194469
    194570Cost computeConversionCost(
     
    196893}
    196994
     95namespace {
     96        /// First index is which argument, second is which alternative, third is which exploded element
     97        using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
     98
     99        /// Returns a list of alternatives with the minimum cost in the given list
     100        CandidateList findMinCost( const CandidateList & candidates ) {
     101                CandidateList out;
     102                Cost minCost = Cost::infinity;
     103                for ( const CandidateRef & r : candidates ) {
     104                        if ( r->cost < minCost ) {
     105                                minCost = r->cost;
     106                                out.clear();
     107                                out.emplace_back( r );
     108                        } else if ( r->cost == minCost ) {
     109                                out.emplace_back( r );
     110                        }
     111                }
     112                return out;
     113        }
     114
     115        /// Computes conversion cost for a given expression to a given type
     116        const ast::Expr * computeExpressionConversionCost(
     117                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
     118        ) {
     119                Cost convCost = computeConversionCost(
     120                                arg->result, paramType, arg->get_lvalue(), symtab, env );
     121                outCost += convCost;
     122
     123                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
     124                // conversion. Ignore poly cost for now, since this requires resolution of the cast to
     125                // infer parameters and this does not currently work for the reason stated below
     126                Cost tmpCost = convCost;
     127                tmpCost.incPoly( -tmpCost.get_polyCost() );
     128                if ( tmpCost != Cost::zero ) {
     129                        ast::ptr< ast::Type > newType = paramType;
     130                        env.apply( newType );
     131                        return new ast::CastExpr{ arg, newType };
     132
     133                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     134                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
     135                        // once this is fixed it should be possible to resolve the cast.
     136                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
     137                        // but it shouldn't be because this makes the conversion from DT* to DT* since
     138                        // commontype(zero_t, DT*) is DT*, rather than nothing
     139
     140                        // CandidateFinder finder{ symtab, env };
     141                        // finder.find( arg, ResolvMode::withAdjustment() );
     142                        // assertf( finder.candidates.size() > 0,
     143                        //      "Somehow castable expression failed to find alternatives." );
     144                        // assertf( finder.candidates.size() == 1,
     145                        //      "Somehow got multiple alternatives for known cast expression." );
     146                        // return finder.candidates.front()->expr;
     147                }
     148
     149                return arg;
     150        }
     151
     152        /// Computes conversion cost for a given candidate
     153        Cost computeApplicationConversionCost(
     154                CandidateRef cand, const ast::SymbolTable & symtab
     155        ) {
     156                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     157                auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     158                auto function = pointer->base.strict_as< ast::FunctionType >();
     159
     160                Cost convCost = Cost::zero;
     161                const auto & params = function->params;
     162                auto param = params.begin();
     163                auto & args = appExpr->args;
     164
     165                for ( unsigned i = 0; i < args.size(); ++i ) {
     166                        const ast::Type * argType = args[i]->result;
     167                        PRINT(
     168                                std::cerr << "arg expression:" << std::endl;
     169                                ast::print( std::cerr, args[i], 2 );
     170                                std::cerr << "--- results are" << std::endl;
     171                                ast::print( std::cerr, argType, 2 );
     172                        )
     173
     174                        if ( param == params.end() ) {
     175                                if ( function->isVarArgs ) {
     176                                        convCost.incUnsafe();
     177                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
     178                                                << convCost << std::endl; ; )
     179                                        // convert reference-typed expressions into value-typed expressions
     180                                        cand->expr = ast::mutate_field_index(
     181                                                appExpr, &ast::ApplicationExpr::args, i,
     182                                                referenceToRvalueConversion( args[i], convCost ) );
     183                                        continue;
     184                                } else return Cost::infinity;
     185                        }
     186
     187                        if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
     188                                // Default arguments should be free - don't include conversion cost.
     189                                // Unwrap them here because they are not relevant to the rest of the system
     190                                cand->expr = ast::mutate_field_index(
     191                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
     192                                ++param;
     193                                continue;
     194                        }
     195
     196                        // mark conversion cost and also specialization cost of param type
     197                        // const ast::Type * paramType = (*param)->get_type();
     198                        cand->expr = ast::mutate_field_index(
     199                                appExpr, &ast::ApplicationExpr::args, i,
     200                                computeExpressionConversionCost(
     201                                        args[i], *param, symtab, cand->env, convCost ) );
     202                        convCost.decSpec( specCost( *param ) );
     203                        ++param;  // can't be in for-loop update because of the continue
     204                }
     205
     206                if ( param != params.end() ) return Cost::infinity;
     207
     208                // specialization cost of return types can't be accounted for directly, it disables
     209                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
     210                //
     211                //   forall(otype OS) {
     212                //     void ?|?(OS&, int);  // with newline
     213                //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
     214                //   }
     215
     216                // mark type variable and specialization cost of forall clause
     217                convCost.incVar( function->forall.size() );
     218                convCost.decSpec( function->assertions.size() );
     219
     220                return convCost;
     221        }
     222
     223        void makeUnifiableVars(
     224                const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
     225                ast::AssertionSet & need
     226        ) {
     227                for ( auto & tyvar : type->forall ) {
     228                        unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
     229                }
     230                for ( auto & assn : type->assertions ) {
     231                        need[ assn ].isUsed = true;
     232                }
     233        }
     234
     235        /// Gets a default value from an initializer, nullptr if not present
     236        const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
     237                if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
     238                        if ( auto ce = si->value.as< ast::CastExpr >() ) {
     239                                return ce->arg.as< ast::ConstantExpr >();
     240                        } else {
     241                                return si->value.as< ast::ConstantExpr >();
     242                        }
     243                }
     244                return nullptr;
     245        }
     246
     247        /// State to iteratively build a match of parameter expressions to arguments
     248        struct ArgPack {
     249                std::size_t parent;          ///< Index of parent pack
     250                ast::ptr< ast::Expr > expr;  ///< The argument stored here
     251                Cost cost;                   ///< The cost of this argument
     252                ast::TypeEnvironment env;    ///< Environment for this pack
     253                ast::AssertionSet need;      ///< Assertions outstanding for this pack
     254                ast::AssertionSet have;      ///< Assertions found for this pack
     255                ast::OpenVarSet open;        ///< Open variables for this pack
     256                unsigned nextArg;            ///< Index of next argument in arguments list
     257                unsigned tupleStart;         ///< Number of tuples that start at this index
     258                unsigned nextExpl;           ///< Index of next exploded element
     259                unsigned explAlt;            ///< Index of alternative for nextExpl > 0
     260
     261                ArgPack()
     262                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
     263                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     264
     265                ArgPack(
     266                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
     267                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
     268                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
     269                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     270
     271                ArgPack(
     272                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     273                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     274                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
     275                        unsigned nextExpl = 0, unsigned explAlt = 0 )
     276                : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
     277                  have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
     278                  nextExpl( nextExpl ), explAlt( explAlt ) {}
     279
     280                ArgPack(
     281                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
     282                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
     283                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
     284                  need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
     285                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
     286
     287                /// true if this pack is in the middle of an exploded argument
     288                bool hasExpl() const { return nextExpl > 0; }
     289
     290                /// Gets the list of exploded candidates for this pack
     291                const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
     292                        return args[ nextArg-1 ][ explAlt ];
     293                }
     294
     295                /// Ends a tuple expression, consolidating the appropriate args
     296                void endTuple( const std::vector< ArgPack > & packs ) {
     297                        // add all expressions in tuple to list, summing cost
     298                        std::deque< const ast::Expr * > exprs;
     299                        const ArgPack * pack = this;
     300                        if ( expr ) { exprs.emplace_front( expr ); }
     301                        while ( pack->tupleStart == 0 ) {
     302                                pack = &packs[pack->parent];
     303                                exprs.emplace_front( pack->expr );
     304                                cost += pack->cost;
     305                        }
     306                        // reset pack to appropriate tuple
     307                        std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
     308                        expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
     309                        tupleStart = pack->tupleStart - 1;
     310                        parent = pack->parent;
     311                }
     312        };
     313
     314        /// Instantiates an argument to match a parameter, returns false if no matching results left
     315        bool instantiateArgument(
     316                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     317                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
     318                unsigned nTuples = 0
     319        ) {
     320                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     321                        // paramType is a TupleType -- group args into a TupleExpr
     322                        ++nTuples;
     323                        for ( const ast::Type * type : *tupleType ) {
     324                                // xxx - dropping initializer changes behaviour from previous, but seems correct
     325                                // ^^^ need to handle the case where a tuple has a default argument
     326                                if ( ! instantiateArgument(
     327                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
     328                                nTuples = 0;
     329                        }
     330                        // re-constitute tuples for final generation
     331                        for ( auto i = genStart; i < results.size(); ++i ) {
     332                                results[i].endTuple( results );
     333                        }
     334                        return true;
     335                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
     336                        // paramType is a ttype, consumes all remaining arguments
     337
     338                        // completed tuples; will be spliced to end of results to finish
     339                        std::vector< ArgPack > finalResults{};
     340
     341                        // iterate until all results completed
     342                        std::size_t genEnd;
     343                        ++nTuples;
     344                        do {
     345                                genEnd = results.size();
     346
     347                                // add another argument to results
     348                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     349                                        unsigned nextArg = results[i].nextArg;
     350
     351                                        // use next element of exploded tuple if present
     352                                        if ( results[i].hasExpl() ) {
     353                                                const ExplodedArg & expl = results[i].getExpl( args );
     354
     355                                                unsigned nextExpl = results[i].nextExpl + 1;
     356                                                if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     357
     358                                                results.emplace_back(
     359                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     360                                                        copy( results[i].need ), copy( results[i].have ),
     361                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
     362                                                        results[i].explAlt );
     363
     364                                                continue;
     365                                        }
     366
     367                                        // finish result when out of arguments
     368                                        if ( nextArg >= args.size() ) {
     369                                                ArgPack newResult{
     370                                                        results[i].env, results[i].need, results[i].have, results[i].open };
     371                                                newResult.nextArg = nextArg;
     372                                                const ast::Type * argType = nullptr;
     373
     374                                                if ( nTuples > 0 || ! results[i].expr ) {
     375                                                        // first iteration or no expression to clone,
     376                                                        // push empty tuple expression
     377                                                        newResult.parent = i;
     378                                                        newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
     379                                                        argType = newResult.expr->result;
     380                                                } else {
     381                                                        // clone result to collect tuple
     382                                                        newResult.parent = results[i].parent;
     383                                                        newResult.cost = results[i].cost;
     384                                                        newResult.tupleStart = results[i].tupleStart;
     385                                                        newResult.expr = results[i].expr;
     386                                                        argType = newResult.expr->result;
     387
     388                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
     389                                                                // the case where a ttype value is passed directly is special,
     390                                                                // e.g. for argument forwarding purposes
     391                                                                // xxx - what if passing multiple arguments, last of which is
     392                                                                //       ttype?
     393                                                                // xxx - what would happen if unify was changed so that unifying
     394                                                                //       tuple
     395                                                                // types flattened both before unifying lists? then pass in
     396                                                                // TupleType (ttype) below.
     397                                                                --newResult.tupleStart;
     398                                                        } else {
     399                                                                // collapse leftover arguments into tuple
     400                                                                newResult.endTuple( results );
     401                                                                argType = newResult.expr->result;
     402                                                        }
     403                                                }
     404
     405                                                // check unification for ttype before adding to final
     406                                                if (
     407                                                        unify(
     408                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
     409                                                                newResult.open, symtab )
     410                                                ) {
     411                                                        finalResults.emplace_back( std::move( newResult ) );
     412                                                }
     413
     414                                                continue;
     415                                        }
     416
     417                                        // add each possible next argument
     418                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     419                                                const ExplodedArg & expl = args[nextArg][j];
     420
     421                                                // fresh copies of parent parameters for this iteration
     422                                                ast::TypeEnvironment env = results[i].env;
     423                                                ast::OpenVarSet open = results[i].open;
     424
     425                                                env.addActual( expl.env, open );
     426
     427                                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     428                                                if ( expl.exprs.empty() ) {
     429                                                        results.emplace_back(
     430                                                                results[i], std::move( env ), copy( results[i].need ),
     431                                                                copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
     432
     433                                                        continue;
     434                                                }
     435
     436                                                // add new result
     437                                                results.emplace_back(
     438                                                        i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     439                                                        copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
     440                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     441                                        }
     442                                }
     443
     444                                // reset for next round
     445                                genStart = genEnd;
     446                                nTuples = 0;
     447                        } while ( genEnd != results.size() );
     448
     449                        // splice final results onto results
     450                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
     451                                results.emplace_back( std::move( finalResults[i] ) );
     452                        }
     453                        return ! finalResults.empty();
     454                }
     455
     456                // iterate each current subresult
     457                std::size_t genEnd = results.size();
     458                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     459                        unsigned nextArg = results[i].nextArg;
     460
     461                        // use remainder of exploded tuple if present
     462                        if ( results[i].hasExpl() ) {
     463                                const ExplodedArg & expl = results[i].getExpl( args );
     464                                const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
     465
     466                                ast::TypeEnvironment env = results[i].env;
     467                                ast::AssertionSet need = results[i].need, have = results[i].have;
     468                                ast::OpenVarSet open = results[i].open;
     469
     470                                const ast::Type * argType = expr->result;
     471
     472                                PRINT(
     473                                        std::cerr << "param type is ";
     474                                        ast::print( std::cerr, paramType );
     475                                        std::cerr << std::endl << "arg type is ";
     476                                        ast::print( std::cerr, argType );
     477                                        std::cerr << std::endl;
     478                                )
     479
     480                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     481                                        unsigned nextExpl = results[i].nextExpl + 1;
     482                                        if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     483
     484                                        results.emplace_back(
     485                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
     486                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
     487                                }
     488
     489                                continue;
     490                        }
     491
     492                        // use default initializers if out of arguments
     493                        if ( nextArg >= args.size() ) {
     494                                if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
     495                                        ast::TypeEnvironment env = results[i].env;
     496                                        ast::AssertionSet need = results[i].need, have = results[i].have;
     497                                        ast::OpenVarSet open = results[i].open;
     498
     499                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
     500                                                results.emplace_back(
     501                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
     502                                                        std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
     503                                        }
     504                                }
     505
     506                                continue;
     507                        }
     508
     509                        // Check each possible next argument
     510                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     511                                const ExplodedArg & expl = args[nextArg][j];
     512
     513                                // fresh copies of parent parameters for this iteration
     514                                ast::TypeEnvironment env = results[i].env;
     515                                ast::AssertionSet need = results[i].need, have = results[i].have;
     516                                ast::OpenVarSet open = results[i].open;
     517
     518                                env.addActual( expl.env, open );
     519
     520                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     521                                if ( expl.exprs.empty() ) {
     522                                        results.emplace_back(
     523                                                results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     524                                                nextArg + 1, expl.cost );
     525
     526                                        continue;
     527                                }
     528
     529                                // consider only first exploded arg
     530                                const ast::Expr * expr = expl.exprs.front();
     531                                const ast::Type * argType = expr->result;
     532
     533                                PRINT(
     534                                        std::cerr << "param type is ";
     535                                        ast::print( std::cerr, paramType );
     536                                        std::cerr << std::endl << "arg type is ";
     537                                        ast::print( std::cerr, argType );
     538                                        std::cerr << std::endl;
     539                                )
     540
     541                                // attempt to unify types
     542                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     543                                        // add new result
     544                                        results.emplace_back(
     545                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     546                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     547                                }
     548                        }
     549                }
     550
     551                // reset for next parameter
     552                genStart = genEnd;
     553
     554                return genEnd != results.size();  // were any new results added?
     555        }
     556
     557        /// Generate a cast expression from `arg` to `toType`
     558        const ast::Expr * restructureCast(
     559                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
     560        ) {
     561                if (
     562                        arg->result->size() > 1
     563                        && ! toType->isVoid()
     564                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
     565                ) {
     566                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     567                        // member of the tuple to its corresponding target type, producing the tuple of those
     568                        // cast expressions. If there are more components of the tuple than components in the
     569                        // target type, then excess components do not come out in the result expression (but
     570                        // UniqueExpr ensures that the side effects will still be produced)
     571                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
     572                                // expressions which may contain side effects require a single unique instance of
     573                                // the expression
     574                                arg = new ast::UniqueExpr{ arg->location, arg };
     575                        }
     576                        std::vector< ast::ptr< ast::Expr > > components;
     577                        for ( unsigned i = 0; i < toType->size(); ++i ) {
     578                                // cast each component
     579                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
     580                                components.emplace_back(
     581                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
     582                        }
     583                        return new ast::TupleExpr{ arg->location, std::move( components ) };
     584                } else {
     585                        // handle normally
     586                        return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
     587                }
     588        }
     589
     590        /// Gets the name from an untyped member expression (must be NameExpr)
     591        const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
     592                if ( memberExpr->member.as< ast::ConstantExpr >() ) {
     593                        SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
     594                }
     595
     596                return memberExpr->member.strict_as< ast::NameExpr >()->name;
     597        }
     598
     599        /// Actually visits expressions to find their candidate interpretations
     600        class Finder final : public ast::WithShortCircuiting {
     601                const ResolveContext & context;
     602                const ast::SymbolTable & symtab;
     603        public:
     604                // static size_t traceId;
     605                CandidateFinder & selfFinder;
     606                CandidateList & candidates;
     607                const ast::TypeEnvironment & tenv;
     608                ast::ptr< ast::Type > & targetType;
     609
     610                enum Errors {
     611                        NotFound,
     612                        NoMatch,
     613                        ArgsToFew,
     614                        ArgsToMany,
     615                        RetsToFew,
     616                        RetsToMany,
     617                        NoReason
     618                };
     619
     620                struct {
     621                        Errors code = NotFound;
     622                } reason;
     623
     624                Finder( CandidateFinder & f )
     625                : context( f.context ), symtab( context.symtab ), selfFinder( f ),
     626                  candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
     627
     628                void previsit( const ast::Node * ) { visit_children = false; }
     629
     630                /// Convenience to add candidate to list
     631                template<typename... Args>
     632                void addCandidate( Args &&... args ) {
     633                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     634                        reason.code = NoReason;
     635                }
     636
     637                void postvisit( const ast::ApplicationExpr * applicationExpr ) {
     638                        addCandidate( applicationExpr, tenv );
     639                }
     640
     641                /// Set up candidate assertions for inference
     642                void inferParameters( CandidateRef & newCand, CandidateList & out ) {
     643                        // Set need bindings for any unbound assertions
     644                        UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
     645                        for ( auto & assn : newCand->need ) {
     646                                // skip already-matched assertions
     647                                if ( assn.second.resnSlot != 0 ) continue;
     648                                // assign slot for expression if needed
     649                                if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
     650                                // fix slot to assertion
     651                                assn.second.resnSlot = crntResnSlot;
     652                        }
     653                        // pair slot to expression
     654                        if ( crntResnSlot != 0 ) {
     655                                newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
     656                        }
     657
     658                        // add to output list; assertion satisfaction will occur later
     659                        out.emplace_back( newCand );
     660                }
     661
     662                /// Completes a function candidate with arguments located
     663                void validateFunctionCandidate(
     664                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     665                        CandidateList & out
     666                ) {
     667                        ast::ApplicationExpr * appExpr =
     668                                new ast::ApplicationExpr{ func->expr->location, func->expr };
     669                        // sum cost and accumulate arguments
     670                        std::deque< const ast::Expr * > args;
     671                        Cost cost = func->cost;
     672                        const ArgPack * pack = &result;
     673                        while ( pack->expr ) {
     674                                args.emplace_front( pack->expr );
     675                                cost += pack->cost;
     676                                pack = &results[pack->parent];
     677                        }
     678                        std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
     679                        appExpr->args = std::move( vargs );
     680                        // build and validate new candidate
     681                        auto newCand =
     682                                std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
     683                        PRINT(
     684                                std::cerr << "instantiate function success: " << appExpr << std::endl;
     685                                std::cerr << "need assertions:" << std::endl;
     686                                ast::print( std::cerr, result.need, 2 );
     687                        )
     688                        inferParameters( newCand, out );
     689                }
     690
     691                /// Builds a list of candidates for a function, storing them in out
     692                void makeFunctionCandidates(
     693                        const CandidateRef & func, const ast::FunctionType * funcType,
     694                        const ExplodedArgs_new & args, CandidateList & out
     695                ) {
     696                        ast::OpenVarSet funcOpen;
     697                        ast::AssertionSet funcNeed, funcHave;
     698                        ast::TypeEnvironment funcEnv{ func->env };
     699                        makeUnifiableVars( funcType, funcOpen, funcNeed );
     700                        // add all type variables as open variables now so that those not used in the
     701                        // parameter list are still considered open
     702                        funcEnv.add( funcType->forall );
     703
     704                        if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
     705                                // attempt to narrow based on expected target type
     706                                const ast::Type * returnType = funcType->returns.front();
     707                                if ( ! unify(
     708                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     709                                ) {
     710                                        // unification failed, do not pursue this candidate
     711                                        return;
     712                                }
     713                        }
     714
     715                        // iteratively build matches, one parameter at a time
     716                        std::vector< ArgPack > results;
     717                        results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
     718                        std::size_t genStart = 0;
     719
     720                        // xxx - how to handle default arg after change to ftype representation?
     721                        if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
     722                                if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
     723                                        // function may have default args only if directly calling by name
     724                                        // must use types on candidate however, due to RenameVars substitution
     725                                        auto nParams = funcType->params.size();
     726
     727                                        for (size_t i=0; i<nParams; ++i) {
     728                                                auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
     729                                                if (!instantiateArgument(
     730                                                        funcType->params[i], obj->init, args, results, genStart, symtab)) return;
     731                                        }
     732                                        goto endMatch;
     733                                }
     734                        }
     735                        for ( const auto & param : funcType->params ) {
     736                                // Try adding the arguments corresponding to the current parameter to the existing
     737                                // matches
     738                                // no default args for indirect calls
     739                                if ( ! instantiateArgument(
     740                                        param, nullptr, args, results, genStart, symtab ) ) return;
     741                        }
     742
     743                        endMatch:
     744                        if ( funcType->isVarArgs ) {
     745                                // append any unused arguments to vararg pack
     746                                std::size_t genEnd;
     747                                do {
     748                                        genEnd = results.size();
     749
     750                                        // iterate results
     751                                        for ( std::size_t i = genStart; i < genEnd; ++i ) {
     752                                                unsigned nextArg = results[i].nextArg;
     753
     754                                                // use remainder of exploded tuple if present
     755                                                if ( results[i].hasExpl() ) {
     756                                                        const ExplodedArg & expl = results[i].getExpl( args );
     757
     758                                                        unsigned nextExpl = results[i].nextExpl + 1;
     759                                                        if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     760
     761                                                        results.emplace_back(
     762                                                                i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     763                                                                copy( results[i].need ), copy( results[i].have ),
     764                                                                copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
     765                                                                results[i].explAlt );
     766
     767                                                        continue;
     768                                                }
     769
     770                                                // finish result when out of arguments
     771                                                if ( nextArg >= args.size() ) {
     772                                                        validateFunctionCandidate( func, results[i], results, out );
     773
     774                                                        continue;
     775                                                }
     776
     777                                                // add each possible next argument
     778                                                for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     779                                                        const ExplodedArg & expl = args[nextArg][j];
     780
     781                                                        // fresh copies of parent parameters for this iteration
     782                                                        ast::TypeEnvironment env = results[i].env;
     783                                                        ast::OpenVarSet open = results[i].open;
     784
     785                                                        env.addActual( expl.env, open );
     786
     787                                                        // skip empty tuple arguments by (nearly) cloning parent into next gen
     788                                                        if ( expl.exprs.empty() ) {
     789                                                                results.emplace_back(
     790                                                                        results[i], std::move( env ), copy( results[i].need ),
     791                                                                        copy( results[i].have ), std::move( open ), nextArg + 1,
     792                                                                        expl.cost );
     793
     794                                                                continue;
     795                                                        }
     796
     797                                                        // add new result
     798                                                        results.emplace_back(
     799                                                                i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     800                                                                copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
     801                                                                expl.exprs.size() == 1 ? 0 : 1, j );
     802                                                }
     803                                        }
     804
     805                                        genStart = genEnd;
     806                                } while( genEnd != results.size() );
     807                        } else {
     808                                // filter out the results that don't use all the arguments
     809                                for ( std::size_t i = genStart; i < results.size(); ++i ) {
     810                                        ArgPack & result = results[i];
     811                                        if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
     812                                                validateFunctionCandidate( func, result, results, out );
     813                                        }
     814                                }
     815                        }
     816                }
     817
     818                /// Adds implicit struct-conversions to the alternative list
     819                void addAnonConversions( const CandidateRef & cand ) {
     820                        // adds anonymous member interpretations whenever an aggregate value type is seen.
     821                        // it's okay for the aggregate expression to have reference type -- cast it to the
     822                        // base type to treat the aggregate as the referenced value
     823                        ast::ptr< ast::Expr > aggrExpr( cand->expr );
     824                        ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
     825                        cand->env.apply( aggrType );
     826
     827                        if ( aggrType.as< ast::ReferenceType >() ) {
     828                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     829                        }
     830
     831                        if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
     832                                addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
     833                        } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
     834                                addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
     835                        }
     836                }
     837
     838                /// Adds aggregate member interpretations
     839                void addAggMembers(
     840                        const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     841                        const Candidate & cand, const Cost & addedCost, const std::string & name
     842                ) {
     843                        for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
     844                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
     845                                CandidateRef newCand = std::make_shared<Candidate>(
     846                                        cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
     847                                // add anonymous member interpretations whenever an aggregate value type is seen
     848                                // as a member expression
     849                                addAnonConversions( newCand );
     850                                candidates.emplace_back( std::move( newCand ) );
     851                        }
     852                }
     853
     854                /// Adds tuple member interpretations
     855                void addTupleMembers(
     856                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     857                        const Cost & addedCost, const ast::Expr * member
     858                ) {
     859                        if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
     860                                // get the value of the constant expression as an int, must be between 0 and the
     861                                // length of the tuple to have meaning
     862                                long long val = constantExpr->intValue();
     863                                if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
     864                                        addCandidate(
     865                                                cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     866                                                addedCost );
     867                                }
     868                        }
     869                }
     870
     871                void postvisit( const ast::UntypedExpr * untypedExpr ) {
     872                        std::vector< CandidateFinder > argCandidates =
     873                                selfFinder.findSubExprs( untypedExpr->args );
     874
     875                        // take care of possible tuple assignments
     876                        // if not tuple assignment, handled as normal function call
     877                        Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
     878
     879                        CandidateFinder funcFinder( context, tenv );
     880                        if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
     881                                auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     882                                if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
     883                                        assertf(!argCandidates.empty(), "special function call without argument");
     884                                        for (auto & firstArgCand: argCandidates[0]) {
     885                                                ast::ptr<ast::Type> argType = firstArgCand->expr->result;
     886                                                firstArgCand->env.apply(argType);
     887                                                // strip references
     888                                                // xxx - is this correct?
     889                                                while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
     890
     891                                                // convert 1-tuple to plain type
     892                                                if (auto tuple = argType.as<ast::TupleType>()) {
     893                                                        if (tuple->size() == 1) {
     894                                                                argType = tuple->types[0];
     895                                                        }
     896                                                }
     897
     898                                                // if argType is an unbound type parameter, all special functions need to be searched.
     899                                                if (isUnboundType(argType)) {
     900                                                        funcFinder.otypeKeys.clear();
     901                                                        break;
     902                                                }
     903
     904                                                if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
     905                                                // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
     906                                                //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
     907                                                //      if ( const ast::Type* enumType = enumDecl->base ) {
     908                                                //              // instance of enum (T) is a instance of type (T)
     909                                                //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
     910                                                //      } else {
     911                                                //              // instance of an untyped enum is techically int
     912                                                //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
     913                                                //      }
     914                                                // }
     915                                                else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
     916                                        }
     917                                }
     918                        }
     919                        // if candidates are already produced, do not fail
     920                        // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
     921                        // this means there exists ctor/assign functions with a tuple as first parameter.
     922                        ResolvMode mode = {
     923                                true, // adjust
     924                                !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
     925                                selfFinder.candidates.empty() // failfast if other options are not found
     926                        };
     927                        funcFinder.find( untypedExpr->func, mode );
     928                        // short-circuit if no candidates
     929                        // if ( funcFinder.candidates.empty() ) return;
     930
     931                        reason.code = NoMatch;
     932
     933                        // find function operators
     934                        ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
     935                        CandidateFinder opFinder( context, tenv );
     936                        // okay if there aren't any function operations
     937                        opFinder.find( opExpr, ResolvMode::withoutFailFast() );
     938                        PRINT(
     939                                std::cerr << "known function ops:" << std::endl;
     940                                print( std::cerr, opFinder.candidates, 1 );
     941                        )
     942
     943                        // pre-explode arguments
     944                        ExplodedArgs_new argExpansions;
     945                        for ( const CandidateFinder & args : argCandidates ) {
     946                                argExpansions.emplace_back();
     947                                auto & argE = argExpansions.back();
     948                                for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
     949                        }
     950
     951                        // Find function matches
     952                        CandidateList found;
     953                        SemanticErrorException errors;
     954                        for ( CandidateRef & func : funcFinder ) {
     955                                try {
     956                                        PRINT(
     957                                                std::cerr << "working on alternative:" << std::endl;
     958                                                print( std::cerr, *func, 2 );
     959                                        )
     960
     961                                        // check if the type is a pointer to function
     962                                        const ast::Type * funcResult = func->expr->result->stripReferences();
     963                                        if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
     964                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     965                                                        CandidateRef newFunc{ new Candidate{ *func } };
     966                                                        newFunc->expr =
     967                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     968                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
     969                                                }
     970                                        } else if (
     971                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     972                                        ) {
     973                                                if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
     974                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
     975                                                                CandidateRef newFunc{ new Candidate{ *func } };
     976                                                                newFunc->expr =
     977                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     978                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     979                                                        }
     980                                                }
     981                                        }
     982                                } catch ( SemanticErrorException & e ) { errors.append( e ); }
     983                        }
     984
     985                        // Find matches on function operators `?()`
     986                        if ( ! opFinder.candidates.empty() ) {
     987                                // add exploded function alternatives to front of argument list
     988                                std::vector< ExplodedArg > funcE;
     989                                funcE.reserve( funcFinder.candidates.size() );
     990                                for ( const CandidateRef & func : funcFinder ) {
     991                                        funcE.emplace_back( *func, symtab );
     992                                }
     993                                argExpansions.emplace_front( std::move( funcE ) );
     994
     995                                for ( const CandidateRef & op : opFinder ) {
     996                                        try {
     997                                                // check if type is pointer-to-function
     998                                                const ast::Type * opResult = op->expr->result->stripReferences();
     999                                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
     1000                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1001                                                                CandidateRef newOp{ new Candidate{ *op} };
     1002                                                                newOp->expr =
     1003                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
     1004                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     1005                                                        }
     1006                                                }
     1007                                        } catch ( SemanticErrorException & e ) { errors.append( e ); }
     1008                                }
     1009                        }
     1010
     1011                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     1012                        // candidates
     1013                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     1014
     1015                        // Compute conversion costs
     1016                        for ( CandidateRef & withFunc : found ) {
     1017                                Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
     1018
     1019                                PRINT(
     1020                                        auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
     1021                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     1022                                        auto function = pointer->base.strict_as< ast::FunctionType >();
     1023
     1024                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
     1025                                        std::cerr << "parameters are:" << std::endl;
     1026                                        ast::printAll( std::cerr, function->params, 2 );
     1027                                        std::cerr << "arguments are:" << std::endl;
     1028                                        ast::printAll( std::cerr, appExpr->args, 2 );
     1029                                        std::cerr << "bindings are:" << std::endl;
     1030                                        ast::print( std::cerr, withFunc->env, 2 );
     1031                                        std::cerr << "cost is: " << withFunc->cost << std::endl;
     1032                                        std::cerr << "cost of conversion is:" << cvtCost << std::endl;
     1033                                )
     1034
     1035                                if ( cvtCost != Cost::infinity ) {
     1036                                        withFunc->cvtCost = cvtCost;
     1037                                        candidates.emplace_back( std::move( withFunc ) );
     1038                                }
     1039                        }
     1040                        found = std::move( candidates );
     1041
     1042                        // use a new list so that candidates are not examined by addAnonConversions twice
     1043                        CandidateList winners = findMinCost( found );
     1044                        promoteCvtCost( winners );
     1045
     1046                        // function may return a struct/union value, in which case we need to add candidates
     1047                        // for implicit conversions to each of the anonymous members, which must happen after
     1048                        // `findMinCost`, since anon conversions are never the cheapest
     1049                        for ( const CandidateRef & c : winners ) {
     1050                                addAnonConversions( c );
     1051                        }
     1052                        spliceBegin( candidates, winners );
     1053
     1054                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     1055                                // If resolution is unsuccessful with a target type, try again without, since it
     1056                                // will sometimes succeed when it wouldn't with a target type binding.
     1057                                // For example:
     1058                                //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
     1059                                //   const char * x = "hello world";
     1060                                //   unsigned char ch = x[0];
     1061                                // Fails with simple return type binding (xxx -- check this!) as follows:
     1062                                // * T is bound to unsigned char
     1063                                // * (x: const char *) is unified with unsigned char *, which fails
     1064                                // xxx -- fix this better
     1065                                targetType = nullptr;
     1066                                postvisit( untypedExpr );
     1067                        }
     1068                }
     1069
     1070                /// true if expression is an lvalue
     1071                static bool isLvalue( const ast::Expr * x ) {
     1072                        return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
     1073                }
     1074
     1075                void postvisit( const ast::AddressExpr * addressExpr ) {
     1076                        CandidateFinder finder( context, tenv );
     1077                        finder.find( addressExpr->arg );
     1078
     1079                        if( finder.candidates.empty() ) return;
     1080
     1081                        reason.code = NoMatch;
     1082
     1083                        for ( CandidateRef & r : finder.candidates ) {
     1084                                if ( ! isLvalue( r->expr ) ) continue;
     1085                                addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
     1086                        }
     1087                }
     1088
     1089                void postvisit( const ast::LabelAddressExpr * labelExpr ) {
     1090                        addCandidate( labelExpr, tenv );
     1091                }
     1092
     1093                void postvisit( const ast::CastExpr * castExpr ) {
     1094                        ast::ptr< ast::Type > toType = castExpr->result;
     1095                        assert( toType );
     1096                        toType = resolveTypeof( toType, context );
     1097                        toType = adjustExprType( toType, tenv, symtab );
     1098
     1099                        CandidateFinder finder( context, tenv, toType );
     1100                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
     1101
     1102                        if( !finder.candidates.empty() ) reason.code = NoMatch;
     1103
     1104                        CandidateList matches;
     1105                        for ( CandidateRef & cand : finder.candidates ) {
     1106                                ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1107                                ast::OpenVarSet open( cand->open );
     1108
     1109                                cand->env.extractOpenVars( open );
     1110
     1111                                // It is possible that a cast can throw away some values in a multiply-valued
     1112                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
     1113                                // subexpression results that are cast directly. The candidate is invalid if it
     1114                                // has fewer results than there are types to cast to.
     1115                                int discardedValues = cand->expr->result->size() - toType->size();
     1116                                if ( discardedValues < 0 ) continue;
     1117
     1118                                // unification run for side-effects
     1119                                unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
     1120                                Cost thisCost =
     1121                                        (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
     1122                            ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
     1123                            : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
     1124
     1125                                PRINT(
     1126                                        std::cerr << "working on cast with result: " << toType << std::endl;
     1127                                        std::cerr << "and expr type: " << cand->expr->result << std::endl;
     1128                                        std::cerr << "env: " << cand->env << std::endl;
     1129                                )
     1130                                if ( thisCost != Cost::infinity ) {
     1131                                        PRINT(
     1132                                                std::cerr << "has finite cost." << std::endl;
     1133                                        )
     1134                                        // count one safe conversion for each value that is thrown away
     1135                                        thisCost.incSafe( discardedValues );
     1136                                        CandidateRef newCand = std::make_shared<Candidate>(
     1137                                                restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1138                                                copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
     1139                                                cand->cost + thisCost );
     1140                                        inferParameters( newCand, matches );
     1141                                }
     1142                        }
     1143
     1144                        // select first on argument cost, then conversion cost
     1145                        CandidateList minArgCost = findMinCost( matches );
     1146                        promoteCvtCost( minArgCost );
     1147                        candidates = findMinCost( minArgCost );
     1148                }
     1149
     1150                void postvisit( const ast::VirtualCastExpr * castExpr ) {
     1151                        assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
     1152                        CandidateFinder finder( context, tenv );
     1153                        // don't prune here, all alternatives guaranteed to have same type
     1154                        finder.find( castExpr->arg, ResolvMode::withoutPrune() );
     1155                        for ( CandidateRef & r : finder.candidates ) {
     1156                                addCandidate(
     1157                                        *r,
     1158                                        new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
     1159                        }
     1160                }
     1161
     1162                void postvisit( const ast::KeywordCastExpr * castExpr ) {
     1163                        const auto & loc = castExpr->location;
     1164                        assertf( castExpr->result, "Cast target should have been set in Validate." );
     1165                        auto ref = castExpr->result.strict_as<ast::ReferenceType>();
     1166                        auto inst = ref->base.strict_as<ast::StructInstType>();
     1167                        auto target = inst->base.get();
     1168
     1169                        CandidateFinder finder( context, tenv );
     1170
     1171                        auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
     1172                                for(auto & cand : found) {
     1173                                        const ast::Type * expr = cand->expr->result.get();
     1174                                        if(expect_ref) {
     1175                                                auto res = dynamic_cast<const ast::ReferenceType*>(expr);
     1176                                                if(!res) { continue; }
     1177                                                expr = res->base.get();
     1178                                        }
     1179
     1180                                        if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
     1181                                                auto td = cand->env.lookup(*insttype);
     1182                                                if(!td) { continue; }
     1183                                                expr = td->bound.get();
     1184                                        }
     1185
     1186                                        if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
     1187                                                if(base->base == target) {
     1188                                                        candidates.push_back( std::move(cand) );
     1189                                                        reason.code = NoReason;
     1190                                                }
     1191                                        }
     1192                                }
     1193                        };
     1194
     1195                        try {
     1196                                // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
     1197                                // Clone is purely for memory management
     1198                                std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
     1199
     1200                                // don't prune here, since it's guaranteed all alternatives will have the same type
     1201                                finder.find( tech1.get(), ResolvMode::withoutPrune() );
     1202                                pick_alternatives(finder.candidates, false);
     1203
     1204                                return;
     1205                        } catch(SemanticErrorException & ) {}
     1206
     1207                        // Fallback : turn (thread&)X into (thread$&)get_thread(X)
     1208                        std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
     1209                        // don't prune here, since it's guaranteed all alternatives will have the same type
     1210                        finder.find( fallback.get(), ResolvMode::withoutPrune() );
     1211
     1212                        pick_alternatives(finder.candidates, true);
     1213
     1214                        // Whatever happens here, we have no more fallbacks
     1215                }
     1216
     1217                void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
     1218                        CandidateFinder aggFinder( context, tenv );
     1219                        aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
     1220                        for ( CandidateRef & agg : aggFinder.candidates ) {
     1221                                // it's okay for the aggregate expression to have reference type -- cast it to the
     1222                                // base type to treat the aggregate as the referenced value
     1223                                Cost addedCost = Cost::zero;
     1224                                agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
     1225
     1226                                // find member of the given type
     1227                                if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
     1228                                        addAggMembers(
     1229                                                structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1230                                } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
     1231                                        addAggMembers(
     1232                                                unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1233                                } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     1234                                        addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
     1235                                }
     1236                        }
     1237                }
     1238
     1239                void postvisit( const ast::MemberExpr * memberExpr ) {
     1240                        addCandidate( memberExpr, tenv );
     1241                }
     1242
     1243                void postvisit( const ast::NameExpr * nameExpr ) {
     1244                        std::vector< ast::SymbolTable::IdData > declList;
     1245                        if (!selfFinder.otypeKeys.empty()) {
     1246                                auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     1247                                assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
     1248
     1249                                for (auto & otypeKey: selfFinder.otypeKeys) {
     1250                                        auto result = symtab.specialLookupId(kind, otypeKey);
     1251                                        declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
     1252                                }
     1253                        }
     1254                        else {
     1255                                declList = symtab.lookupId( nameExpr->name );
     1256                        }
     1257                        PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     1258
     1259                        if( declList.empty() ) return;
     1260
     1261                        reason.code = NoMatch;
     1262
     1263                        for ( auto & data : declList ) {
     1264                                Cost cost = Cost::zero;
     1265                                ast::Expr * newExpr = data.combine( nameExpr->location, cost );
     1266
     1267                                CandidateRef newCand = std::make_shared<Candidate>(
     1268                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1269                                        cost );
     1270
     1271                                if (newCand->expr->env) {
     1272                                        newCand->env.add(*newCand->expr->env);
     1273                                        auto mutExpr = newCand->expr.get_and_mutate();
     1274                                        mutExpr->env  = nullptr;
     1275                                        newCand->expr = mutExpr;
     1276                                }
     1277
     1278                                PRINT(
     1279                                        std::cerr << "decl is ";
     1280                                        ast::print( std::cerr, data.id );
     1281                                        std::cerr << std::endl;
     1282                                        std::cerr << "newExpr is ";
     1283                                        ast::print( std::cerr, newExpr );
     1284                                        std::cerr << std::endl;
     1285                                )
     1286                                newCand->expr = ast::mutate_field(
     1287                                        newCand->expr.get(), &ast::Expr::result,
     1288                                        renameTyVars( newCand->expr->result ) );
     1289                                // add anonymous member interpretations whenever an aggregate value type is seen
     1290                                // as a name expression
     1291                                addAnonConversions( newCand );
     1292                                candidates.emplace_back( std::move( newCand ) );
     1293                        }
     1294                }
     1295
     1296                void postvisit( const ast::VariableExpr * variableExpr ) {
     1297                        // not sufficient to just pass `variableExpr` here, type might have changed since
     1298                        // creation
     1299                        addCandidate(
     1300                                new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
     1301                }
     1302
     1303                void postvisit( const ast::ConstantExpr * constantExpr ) {
     1304                        addCandidate( constantExpr, tenv );
     1305                }
     1306
     1307                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
     1308                        if ( sizeofExpr->type ) {
     1309                                addCandidate(
     1310                                        new ast::SizeofExpr{
     1311                                                sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
     1312                                        tenv );
     1313                        } else {
     1314                                // find all candidates for the argument to sizeof
     1315                                CandidateFinder finder( context, tenv );
     1316                                finder.find( sizeofExpr->expr );
     1317                                // find the lowest-cost candidate, otherwise ambiguous
     1318                                CandidateList winners = findMinCost( finder.candidates );
     1319                                if ( winners.size() != 1 ) {
     1320                                        SemanticError(
     1321                                                sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
     1322                                }
     1323                                // return the lowest-cost candidate
     1324                                CandidateRef & choice = winners.front();
     1325                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1326                                choice->cost = Cost::zero;
     1327                                addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
     1328                        }
     1329                }
     1330
     1331                void postvisit( const ast::AlignofExpr * alignofExpr ) {
     1332                        if ( alignofExpr->type ) {
     1333                                addCandidate(
     1334                                        new ast::AlignofExpr{
     1335                                                alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
     1336                                        tenv );
     1337                        } else {
     1338                                // find all candidates for the argument to alignof
     1339                                CandidateFinder finder( context, tenv );
     1340                                finder.find( alignofExpr->expr );
     1341                                // find the lowest-cost candidate, otherwise ambiguous
     1342                                CandidateList winners = findMinCost( finder.candidates );
     1343                                if ( winners.size() != 1 ) {
     1344                                        SemanticError(
     1345                                                alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
     1346                                }
     1347                                // return the lowest-cost candidate
     1348                                CandidateRef & choice = winners.front();
     1349                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1350                                choice->cost = Cost::zero;
     1351                                addCandidate(
     1352                                        *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
     1353                        }
     1354                }
     1355
     1356                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
     1357                        const ast::BaseInstType * aggInst;
     1358                        if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
     1359                        else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     1360                        else return;
     1361
     1362                        for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
     1363                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
     1364                                addCandidate(
     1365                                        new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
     1366                        }
     1367                }
     1368
     1369                void postvisit( const ast::OffsetofExpr * offsetofExpr ) {
     1370                        addCandidate( offsetofExpr, tenv );
     1371                }
     1372
     1373                void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
     1374                        addCandidate( offsetPackExpr, tenv );
     1375                }
     1376
     1377                void postvisit( const ast::LogicalExpr * logicalExpr ) {
     1378                        CandidateFinder finder1( context, tenv );
     1379                        finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
     1380                        if ( finder1.candidates.empty() ) return;
     1381
     1382                        CandidateFinder finder2( context, tenv );
     1383                        finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
     1384                        if ( finder2.candidates.empty() ) return;
     1385
     1386                        reason.code = NoMatch;
     1387
     1388                        for ( const CandidateRef & r1 : finder1.candidates ) {
     1389                                for ( const CandidateRef & r2 : finder2.candidates ) {
     1390                                        ast::TypeEnvironment env{ r1->env };
     1391                                        env.simpleCombine( r2->env );
     1392                                        ast::OpenVarSet open{ r1->open };
     1393                                        mergeOpenVars( open, r2->open );
     1394                                        ast::AssertionSet need;
     1395                                        mergeAssertionSet( need, r1->need );
     1396                                        mergeAssertionSet( need, r2->need );
     1397
     1398                                        addCandidate(
     1399                                                new ast::LogicalExpr{
     1400                                                        logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
     1401                                                std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
     1402                                }
     1403                        }
     1404                }
     1405
     1406                void postvisit( const ast::ConditionalExpr * conditionalExpr ) {
     1407                        // candidates for condition
     1408                        CandidateFinder finder1( context, tenv );
     1409                        finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
     1410                        if ( finder1.candidates.empty() ) return;
     1411
     1412                        // candidates for true result
     1413                        CandidateFinder finder2( context, tenv );
     1414                        finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
     1415                        if ( finder2.candidates.empty() ) return;
     1416
     1417                        // candidates for false result
     1418                        CandidateFinder finder3( context, tenv );
     1419                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
     1420                        if ( finder3.candidates.empty() ) return;
     1421
     1422                        reason.code = NoMatch;
     1423
     1424                        for ( const CandidateRef & r1 : finder1.candidates ) {
     1425                                for ( const CandidateRef & r2 : finder2.candidates ) {
     1426                                        for ( const CandidateRef & r3 : finder3.candidates ) {
     1427                                                ast::TypeEnvironment env{ r1->env };
     1428                                                env.simpleCombine( r2->env );
     1429                                                env.simpleCombine( r3->env );
     1430                                                ast::OpenVarSet open{ r1->open };
     1431                                                mergeOpenVars( open, r2->open );
     1432                                                mergeOpenVars( open, r3->open );
     1433                                                ast::AssertionSet need;
     1434                                                mergeAssertionSet( need, r1->need );
     1435                                                mergeAssertionSet( need, r2->need );
     1436                                                mergeAssertionSet( need, r3->need );
     1437                                                ast::AssertionSet have;
     1438
     1439                                                // unify true and false results, then infer parameters to produce new
     1440                                                // candidates
     1441                                                ast::ptr< ast::Type > common;
     1442                                                if (
     1443                                                        unify(
     1444                                                                r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     1445                                                                common )
     1446                                                ) {
     1447                                                        // generate typed expression
     1448                                                        ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1449                                                                conditionalExpr->location, r1->expr, r2->expr, r3->expr };
     1450                                                        newExpr->result = common ? common : r2->expr->result;
     1451                                                        // convert both options to result type
     1452                                                        Cost cost = r1->cost + r2->cost + r3->cost;
     1453                                                        newExpr->arg2 = computeExpressionConversionCost(
     1454                                                                newExpr->arg2, newExpr->result, symtab, env, cost );
     1455                                                        newExpr->arg3 = computeExpressionConversionCost(
     1456                                                                newExpr->arg3, newExpr->result, symtab, env, cost );
     1457                                                        // output candidate
     1458                                                        CandidateRef newCand = std::make_shared<Candidate>(
     1459                                                                newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
     1460                                                        inferParameters( newCand, candidates );
     1461                                                }
     1462                                        }
     1463                                }
     1464                        }
     1465                }
     1466
     1467                void postvisit( const ast::CommaExpr * commaExpr ) {
     1468                        ast::TypeEnvironment env{ tenv };
     1469                        ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
     1470
     1471                        CandidateFinder finder2( context, env );
     1472                        finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     1473
     1474                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1475                                addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
     1476                        }
     1477                }
     1478
     1479                void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
     1480                        addCandidate( ctorExpr, tenv );
     1481                }
     1482
     1483                void postvisit( const ast::ConstructorExpr * ctorExpr ) {
     1484                        CandidateFinder finder( context, tenv );
     1485                        finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
     1486                        for ( CandidateRef & r : finder.candidates ) {
     1487                                addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
     1488                        }
     1489                }
     1490
     1491                void postvisit( const ast::RangeExpr * rangeExpr ) {
     1492                        // resolve low and high, accept candidates where low and high types unify
     1493                        CandidateFinder finder1( context, tenv );
     1494                        finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
     1495                        if ( finder1.candidates.empty() ) return;
     1496
     1497                        CandidateFinder finder2( context, tenv );
     1498                        finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
     1499                        if ( finder2.candidates.empty() ) return;
     1500
     1501                        reason.code = NoMatch;
     1502
     1503                        for ( const CandidateRef & r1 : finder1.candidates ) {
     1504                                for ( const CandidateRef & r2 : finder2.candidates ) {
     1505                                        ast::TypeEnvironment env{ r1->env };
     1506                                        env.simpleCombine( r2->env );
     1507                                        ast::OpenVarSet open{ r1->open };
     1508                                        mergeOpenVars( open, r2->open );
     1509                                        ast::AssertionSet need;
     1510                                        mergeAssertionSet( need, r1->need );
     1511                                        mergeAssertionSet( need, r2->need );
     1512                                        ast::AssertionSet have;
     1513
     1514                                        ast::ptr< ast::Type > common;
     1515                                        if (
     1516                                                unify(
     1517                                                        r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     1518                                                        common )
     1519                                        ) {
     1520                                                // generate new expression
     1521                                                ast::RangeExpr * newExpr =
     1522                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
     1523                                                newExpr->result = common ? common : r1->expr->result;
     1524                                                // add candidate
     1525                                                CandidateRef newCand = std::make_shared<Candidate>(
     1526                                                        newExpr, std::move( env ), std::move( open ), std::move( need ),
     1527                                                        r1->cost + r2->cost );
     1528                                                inferParameters( newCand, candidates );
     1529                                        }
     1530                                }
     1531                        }
     1532                }
     1533
     1534                void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
     1535                        std::vector< CandidateFinder > subCandidates =
     1536                                selfFinder.findSubExprs( tupleExpr->exprs );
     1537                        std::vector< CandidateList > possibilities;
     1538                        combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
     1539
     1540                        for ( const CandidateList & subs : possibilities ) {
     1541                                std::vector< ast::ptr< ast::Expr > > exprs;
     1542                                exprs.reserve( subs.size() );
     1543                                for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
     1544
     1545                                ast::TypeEnvironment env;
     1546                                ast::OpenVarSet open;
     1547                                ast::AssertionSet need;
     1548                                for ( const CandidateRef & sub : subs ) {
     1549                                        env.simpleCombine( sub->env );
     1550                                        mergeOpenVars( open, sub->open );
     1551                                        mergeAssertionSet( need, sub->need );
     1552                                }
     1553
     1554                                addCandidate(
     1555                                        new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
     1556                                        std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
     1557                        }
     1558                }
     1559
     1560                void postvisit( const ast::TupleExpr * tupleExpr ) {
     1561                        addCandidate( tupleExpr, tenv );
     1562                }
     1563
     1564                void postvisit( const ast::TupleIndexExpr * tupleExpr ) {
     1565                        addCandidate( tupleExpr, tenv );
     1566                }
     1567
     1568                void postvisit( const ast::TupleAssignExpr * tupleExpr ) {
     1569                        addCandidate( tupleExpr, tenv );
     1570                }
     1571
     1572                void postvisit( const ast::UniqueExpr * unqExpr ) {
     1573                        CandidateFinder finder( context, tenv );
     1574                        finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
     1575                        for ( CandidateRef & r : finder.candidates ) {
     1576                                // ensure that the the id is passed on so that the expressions are "linked"
     1577                                addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
     1578                        }
     1579                }
     1580
     1581                void postvisit( const ast::StmtExpr * stmtExpr ) {
     1582                        addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
     1583                }
     1584
     1585                void postvisit( const ast::UntypedInitExpr * initExpr ) {
     1586                        // handle each option like a cast
     1587                        CandidateList matches;
     1588                        PRINT(
     1589                                std::cerr << "untyped init expr: " << initExpr << std::endl;
     1590                        )
     1591                        // O(n^2) checks of d-types with e-types
     1592                        for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
     1593                                // calculate target type
     1594                                const ast::Type * toType = resolveTypeof( initAlt.type, context );
     1595                                toType = adjustExprType( toType, tenv, symtab );
     1596                                // The call to find must occur inside this loop, otherwise polymorphic return
     1597                                // types are not bound to the initialization type, since return type variables are
     1598                                // only open for the duration of resolving the UntypedExpr.
     1599                                CandidateFinder finder( context, tenv, toType );
     1600                                finder.find( initExpr->expr, ResolvMode::withAdjustment() );
     1601                                for ( CandidateRef & cand : finder.candidates ) {
     1602                                        if(reason.code == NotFound) reason.code = NoMatch;
     1603
     1604                                        ast::TypeEnvironment env{ cand->env };
     1605                                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1606                                        ast::OpenVarSet open{ cand->open };
     1607
     1608                                        PRINT(
     1609                                                std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
     1610                                        )
     1611
     1612                                        // It is possible that a cast can throw away some values in a multiply-valued
     1613                                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
     1614                                        // the subexpression results that are cast directly. The candidate is invalid
     1615                                        // if it has fewer results than there are types to cast to.
     1616                                        int discardedValues = cand->expr->result->size() - toType->size();
     1617                                        if ( discardedValues < 0 ) continue;
     1618
     1619                                        // unification run for side-effects
     1620                                        bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
     1621                                        (void) canUnify;
     1622                                        Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1623                                                symtab, env );
     1624                                        PRINT(
     1625                                                Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1626                                                        symtab, env );
     1627                                                std::cerr << "Considering initialization:";
     1628                                                std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
     1629                                                std::cerr << std::endl << "  TO: "   << toType             << std::endl;
     1630                                                std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
     1631                                                std::cerr << std::endl << "  Legacy cost " << legacyCost;
     1632                                                std::cerr << std::endl << "  New cost " << thisCost;
     1633                                                std::cerr << std::endl;
     1634                                        )
     1635                                        if ( thisCost != Cost::infinity ) {
     1636                                                // count one safe conversion for each value that is thrown away
     1637                                                thisCost.incSafe( discardedValues );
     1638                                                CandidateRef newCand = std::make_shared<Candidate>(
     1639                                                        new ast::InitExpr{
     1640                                                                initExpr->location, restructureCast( cand->expr, toType ),
     1641                                                                initAlt.designation },
     1642                                                        std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
     1643                                                inferParameters( newCand, matches );
     1644                                        }
     1645                                }
     1646
     1647                        }
     1648
     1649                        // select first on argument cost, then conversion cost
     1650                        CandidateList minArgCost = findMinCost( matches );
     1651                        promoteCvtCost( minArgCost );
     1652                        candidates = findMinCost( minArgCost );
     1653                }
     1654
     1655                void postvisit( const ast::InitExpr * ) {
     1656                        assertf( false, "CandidateFinder should never see a resolved InitExpr." );
     1657                }
     1658
     1659                void postvisit( const ast::DeletedExpr * ) {
     1660                        assertf( false, "CandidateFinder should never see a DeletedExpr." );
     1661                }
     1662
     1663                void postvisit( const ast::GenericExpr * ) {
     1664                        assertf( false, "_Generic is not yet supported." );
     1665                }
     1666        };
     1667
     1668        // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
     1669        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1670        /// return type. Skips ambiguous candidates.
     1671
     1672} // anonymous namespace
     1673
     1674bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
     1675        struct PruneStruct {
     1676                CandidateRef candidate;
     1677                bool ambiguous;
     1678
     1679                PruneStruct() = default;
     1680                PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     1681        };
     1682
     1683        // find lowest-cost candidate for each type
     1684        std::unordered_map< std::string, PruneStruct > selected;
     1685        // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
     1686        std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
     1687        for ( CandidateRef & candidate : candidates ) {
     1688                std::string mangleName;
     1689                {
     1690                        ast::ptr< ast::Type > newType = candidate->expr->result;
     1691                        assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
     1692                        candidate->env.apply( newType );
     1693                        mangleName = Mangle::mangle( newType );
     1694                }
     1695
     1696                auto found = selected.find( mangleName );
     1697                if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
     1698                        PRINT(
     1699                                std::cerr << "cost " << candidate->cost << " loses to "
     1700                                        << found->second.candidate->cost << std::endl;
     1701                        )
     1702                        continue;
     1703                }
     1704
     1705                // xxx - when do satisfyAssertions produce more than 1 result?
     1706                // this should only happen when initial result type contains
     1707                // unbound type parameters, then it should never be pruned by
     1708                // the previous step, since renameTyVars guarantees the mangled name
     1709                // is unique.
     1710                CandidateList satisfied;
     1711                bool needRecomputeKey = false;
     1712                if (candidate->need.empty()) {
     1713                        satisfied.emplace_back(candidate);
     1714                }
     1715                else {
     1716                        satisfyAssertions(candidate, context.symtab, satisfied, errors);
     1717                        needRecomputeKey = true;
     1718                }
     1719
     1720                for (auto & newCand : satisfied) {
     1721                        // recomputes type key, if satisfyAssertions changed it
     1722                        if (needRecomputeKey)
     1723                        {
     1724                                ast::ptr< ast::Type > newType = newCand->expr->result;
     1725                                assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
     1726                                newCand->env.apply( newType );
     1727                                mangleName = Mangle::mangle( newType );
     1728                        }
     1729                        auto found = selected.find( mangleName );
     1730                        if ( found != selected.end() ) {
     1731                                if ( newCand->cost < found->second.candidate->cost ) {
     1732                                        PRINT(
     1733                                                std::cerr << "cost " << newCand->cost << " beats "
     1734                                                        << found->second.candidate->cost << std::endl;
     1735                                        )
     1736
     1737                                        found->second = PruneStruct{ newCand };
     1738                                } else if ( newCand->cost == found->second.candidate->cost ) {
     1739                                        // if one of the candidates contains a deleted identifier, can pick the other,
     1740                                        // since deleted expressions should not be ambiguous if there is another option
     1741                                        // that is at least as good
     1742                                        if ( findDeletedExpr( newCand->expr ) ) {
     1743                                                // do nothing
     1744                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
     1745                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
     1746                                                PRINT( std::cerr << "current is deleted" << std::endl; )
     1747                                                found->second = PruneStruct{ newCand };
     1748                                        } else {
     1749                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
     1750                                                found->second.ambiguous = true;
     1751                                        }
     1752                                } else {
     1753                                        // xxx - can satisfyAssertions increase the cost?
     1754                                        PRINT(
     1755                                                std::cerr << "cost " << newCand->cost << " loses to "
     1756                                                        << found->second.candidate->cost << std::endl;
     1757                                        )
     1758                                }
     1759                        } else {
     1760                                selected.emplace_hint( found, mangleName, newCand );
     1761                        }
     1762                }
     1763        }
     1764
     1765        // report unambiguous min-cost candidates
     1766        // CandidateList out;
     1767        for ( auto & target : selected ) {
     1768                if ( target.second.ambiguous ) continue;
     1769
     1770                CandidateRef cand = target.second.candidate;
     1771
     1772                ast::ptr< ast::Type > newResult = cand->expr->result;
     1773                cand->env.applyFree( newResult );
     1774                cand->expr = ast::mutate_field(
     1775                        cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
     1776
     1777                out.emplace_back( cand );
     1778        }
     1779        // if everything is lost in satisfyAssertions, report the error
     1780        return !selected.empty();
     1781}
     1782
     1783void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
     1784        // Find alternatives for expression
     1785        ast::Pass<Finder> finder{ *this };
     1786        expr->accept( finder );
     1787
     1788        if ( mode.failFast && candidates.empty() ) {
     1789                switch(finder.core.reason.code) {
     1790                case Finder::NotFound:
     1791                        { SemanticError( expr, "No alternatives for expression " ); break; }
     1792                case Finder::NoMatch:
     1793                        { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
     1794                case Finder::ArgsToFew:
     1795                case Finder::ArgsToMany:
     1796                case Finder::RetsToFew:
     1797                case Finder::RetsToMany:
     1798                case Finder::NoReason:
     1799                default:
     1800                        { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
     1801                }
     1802        }
     1803
     1804        /*
     1805        if ( mode.satisfyAssns || mode.prune ) {
     1806                // trim candidates to just those where the assertions are satisfiable
     1807                // - necessary pre-requisite to pruning
     1808                CandidateList satisfied;
     1809                std::vector< std::string > errors;
     1810                for ( CandidateRef & candidate : candidates ) {
     1811                        satisfyAssertions( candidate, localSyms, satisfied, errors );
     1812                }
     1813
     1814                // fail early if none such
     1815                if ( mode.failFast && satisfied.empty() ) {
     1816                        std::ostringstream stream;
     1817                        stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1818                        for ( const auto& err : errors ) {
     1819                                stream << err;
     1820                        }
     1821                        SemanticError( expr->location, stream.str() );
     1822                }
     1823
     1824                // reset candidates
     1825                candidates = move( satisfied );
     1826        }
     1827        */
     1828
     1829        if ( mode.prune ) {
     1830                // trim candidates to single best one
     1831                PRINT(
     1832                        std::cerr << "alternatives before prune:" << std::endl;
     1833                        print( std::cerr, candidates );
     1834                )
     1835
     1836                CandidateList pruned;
     1837                std::vector<std::string> errors;
     1838                bool found = pruneCandidates( candidates, pruned, errors );
     1839
     1840                if ( mode.failFast && pruned.empty() ) {
     1841                        std::ostringstream stream;
     1842                        if (found) {
     1843                                CandidateList winners = findMinCost( candidates );
     1844                                stream << "Cannot choose between " << winners.size() << " alternatives for "
     1845                                        "expression\n";
     1846                                ast::print( stream, expr );
     1847                                stream << " Alternatives are:\n";
     1848                                print( stream, winners, 1 );
     1849                                SemanticError( expr->location, stream.str() );
     1850                        }
     1851                        else {
     1852                                stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1853                                for ( const auto& err : errors ) {
     1854                                        stream << err;
     1855                                }
     1856                                SemanticError( expr->location, stream.str() );
     1857                        }
     1858                }
     1859
     1860                auto oldsize = candidates.size();
     1861                candidates = std::move( pruned );
     1862
     1863                PRINT(
     1864                        std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
     1865                )
     1866                PRINT(
     1867                        std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     1868                                << std::endl;
     1869                )
     1870        }
     1871
     1872        // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     1873        // adjusted
     1874        if ( mode.adjust ) {
     1875                for ( CandidateRef & r : candidates ) {
     1876                        r->expr = ast::mutate_field(
     1877                                r->expr.get(), &ast::Expr::result,
     1878                                adjustExprType( r->expr->result, r->env, context.symtab ) );
     1879                }
     1880        }
     1881
     1882        // Central location to handle gcc extension keyword, etc. for all expressions
     1883        for ( CandidateRef & r : candidates ) {
     1884                if ( r->expr->extension != expr->extension ) {
     1885                        r->expr.get_and_mutate()->extension = expr->extension;
     1886                }
     1887        }
     1888}
     1889
     1890std::vector< CandidateFinder > CandidateFinder::findSubExprs(
     1891        const std::vector< ast::ptr< ast::Expr > > & xs
     1892) {
     1893        std::vector< CandidateFinder > out;
     1894
     1895        for ( const auto & x : xs ) {
     1896                out.emplace_back( context, env );
     1897                out.back().find( x, ResolvMode::withAdjustment() );
     1898
     1899                PRINT(
     1900                        std::cerr << "findSubExprs" << std::endl;
     1901                        print( std::cerr, out.back().candidates );
     1902                )
     1903        }
     1904
     1905        return out;
     1906}
     1907
    19701908} // namespace ResolvExpr
    19711909
  • src/ResolvExpr/CurrentObject.cc

    rb110bcc r2ed94a9  
    99// Author           : Rob Schluntz
    1010// Created On       : Tue Jun 13 15:28:32 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Apr 10  9:40:00 2023
    13 // Update Count     : 18
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Jul  1 09:16:01 2022
     13// Update Count     : 15
    1414//
    1515
     
    2626#include "AST/Init.hpp"                // for Designation
    2727#include "AST/Node.hpp"                // for readonly
    28 #include "AST/Print.hpp"               // for readonly
     28#include "AST/Print.hpp"                // for readonly
    2929#include "AST/Type.hpp"
    30 #include "Common/Eval.h"               // for eval
    3130#include "Common/Indenter.h"           // for Indenter, operator<<
    3231#include "Common/SemanticError.h"      // for SemanticError
     
    593592
    594593namespace ast {
    595         /// Iterates members of a type by initializer.
    596         class MemberIterator {
    597         public:
    598                 virtual ~MemberIterator() {}
    599 
    600                 /// Internal set position based on iterator ranges.
    601                 virtual void setPosition(
    602                         std::deque< ptr< Expr > >::const_iterator it,
    603                         std::deque< ptr< Expr > >::const_iterator end ) = 0;
    604 
    605                 /// Walks the current object using the given designators as a guide.
    606                 void setPosition( const std::deque< ptr< Expr > > & designators ) {
    607                         setPosition( designators.begin(), designators.end() );
    608                 }
    609 
    610                 /// Retrieve the list of possible (Type,Designation) pairs for the
    611                 /// current position in the current object.
    612                 virtual std::deque< InitAlternative > operator* () const = 0;
    613 
    614                 /// True if the iterator is not currently at the end.
    615                 virtual operator bool() const = 0;
    616 
    617                 /// Moves the iterator by one member in the current object.
    618                 virtual MemberIterator & bigStep() = 0;
    619 
    620                 /// Moves the iterator by one member in the current subobject.
    621                 virtual MemberIterator & smallStep() = 0;
    622 
    623                 /// The type of the current object.
    624                 virtual const Type * getType() = 0;
    625 
    626                 /// The type of the current subobject.
    627                 virtual const Type * getNext() = 0;
    628 
    629                 /// Helper for operator*; aggregates must add designator to each init
    630                 /// alternative, but adding designators in operator* creates duplicates.
    631                 virtual std::deque< InitAlternative > first() const = 0;
    632         };
    633 
    634594        /// create a new MemberIterator that traverses a type correctly
    635595        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
     
    671631        };
    672632
    673         /// Iterates over an indexed type:
    674         class IndexIterator : public MemberIterator {
    675         protected:
     633        /// Iterates array types
     634        class ArrayIterator final : public MemberIterator {
    676635                CodeLocation location;
     636                const ArrayType * array = nullptr;
     637                const Type * base = nullptr;
    677638                size_t index = 0;
    678639                size_t size = 0;
    679                 std::unique_ptr<MemberIterator> memberIter;
    680         public:
    681                 IndexIterator( const CodeLocation & loc, size_t size ) :
    682                         location( loc ), size( size )
    683                 {}
     640                std::unique_ptr< MemberIterator > memberIter;
     641
     642                void setSize( const Expr * expr ) {
     643                        auto res = eval( expr );
     644                        if ( ! res.second ) {
     645                                SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
     646                        }
     647                        size = res.first;
     648                }
     649
     650        public:
     651                ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : location( loc ), array( at ), base( at->base ) {
     652                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     653                        memberIter.reset( createMemberIterator( loc, base ) );
     654                        if ( at->isVarLen ) {
     655                                SemanticError( location, at, "VLA initialization does not support @=: " );
     656                        }
     657                        setSize( at->dimension );
     658                }
    684659
    685660                void setPosition( const Expr * expr ) {
     
    690665                        auto arg = eval( expr );
    691666                        index = arg.first;
     667                        return;
    692668
    693669                        // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    707683
    708684                void setPosition(
    709                         std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
    710                         std::deque<ast::ptr<ast::Expr>>::const_iterator end
     685                        std::deque< ptr< Expr > >::const_iterator begin,
     686                        std::deque< ptr< Expr > >::const_iterator end
    711687                ) override {
    712688                        if ( begin == end ) return;
     
    719695
    720696                operator bool() const override { return index < size; }
    721         };
    722 
    723         /// Iterates over the members of array types:
    724         class ArrayIterator final : public IndexIterator {
    725                 const ArrayType * array = nullptr;
    726                 const Type * base = nullptr;
    727 
    728                 size_t getSize( const Expr * expr ) {
    729                         auto res = eval( expr );
    730                         if ( !res.second ) {
    731                                 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
    732                         }
    733                         return res.first;
    734                 }
    735 
    736         public:
    737                 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
    738                                 IndexIterator( loc, getSize( at->dimension) ),
    739                                 array( at ), base( at->base ) {
    740                         PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    741                         memberIter.reset( createMemberIterator( loc, base ) );
    742                         if ( at->isVarLen ) {
    743                                 SemanticError( location, at, "VLA initialization does not support @=: " );
    744                         }
    745                 }
    746697
    747698                ArrayIterator & bigStep() override {
     
    882833
    883834                const Type * getNext() final {
    884                         bool hasMember = memberIter && *memberIter;
    885                         return hasMember ? memberIter->getType() : nullptr;
     835                        return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr;
    886836                }
    887837
     
    947897        };
    948898
    949         /// Iterates across the positions in a tuple:
    950         class TupleIterator final : public IndexIterator {
    951                 ast::TupleType const * const tuple;
    952 
    953                 const ast::Type * typeAtIndex() const {
    954                         assert( index < size );
    955                         return tuple->types[ index ].get();
    956                 }
    957 
    958         public:
    959                 TupleIterator( const CodeLocation & loc, const TupleType * type )
    960                 : IndexIterator( loc, type->size() ), tuple( type ) {
    961                         PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
    962                         memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
     899        class TupleIterator final : public AggregateIterator {
     900        public:
     901                TupleIterator( const CodeLocation & loc, const TupleType * inst )
     902                : AggregateIterator(
     903                        loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
     904                ) {}
     905
     906                operator bool() const override {
     907                        return curMember != members.end() || (memberIter && *memberIter);
    963908                }
    964909
    965910                TupleIterator & bigStep() override {
    966                         ++index;
    967                         memberIter.reset( index < size ?
    968                                 createMemberIterator( location, typeAtIndex() ) : nullptr );
     911                        PRINT( std::cerr << "bigStep in " << kind << std::endl; )
     912                        atbegin = false;
     913                        memberIter = nullptr;
     914                        curType = nullptr;
     915                        while ( curMember != members.end() ) {
     916                                ++curMember;
     917                                if ( init() ) return *this;
     918                        }
    969919                        return *this;
    970                 }
    971 
    972                 TupleIterator & smallStep() override {
    973                         if ( memberIter ) {
    974                                 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
    975                                 memberIter->smallStep();
    976                                 if ( !memberIter ) {
    977                                         PRINT( std::cerr << "has valid member iter" << std::endl; )
    978                                         return *this;
    979                                 }
    980                         }
    981                         return bigStep();
    982                 }
    983 
    984                 const ast::Type * getType() override {
    985                         return tuple;
    986                 }
    987 
    988                 const ast::Type * getNext() override {
    989                         bool hasMember = memberIter && *memberIter;
    990                         return hasMember ? memberIter->getType() : nullptr;
    991                 }
    992 
    993                 std::deque< InitAlternative > first() const override {
    994                         PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
    995                         if ( memberIter && *memberIter ) {
    996                                 std::deque< InitAlternative > ret = memberIter->first();
    997                                 for ( InitAlternative & alt : ret ) {
    998                                         alt.designation.get_and_mutate()->designators.emplace_front(
    999                                                 ConstantExpr::from_ulong( location, index ) );
    1000                                 }
    1001                                 return ret;
    1002                         }
    1003                         return {};
    1004920                }
    1005921        };
  • src/ResolvExpr/CurrentObject.h

    rb110bcc r2ed94a9  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jun  8 11:07:25 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Apr  6 16:14:00 2023
    13 // Update Count     : 4
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jul 22 09:36:48 2017
     13// Update Count     : 3
    1414//
    1515
     
    6565
    6666        /// Iterates members of a type by initializer
    67         class MemberIterator;
     67        class MemberIterator {
     68        public:
     69                virtual ~MemberIterator() {}
     70
     71                /// Internal set position based on iterator ranges
     72                virtual void setPosition(
     73                        std::deque< ptr< Expr > >::const_iterator it,
     74                        std::deque< ptr< Expr > >::const_iterator end ) = 0;
     75
     76                /// walks the current object using the given designators as a guide
     77                void setPosition( const std::deque< ptr< Expr > > & designators ) {
     78                        setPosition( designators.begin(), designators.end() );
     79                }
     80
     81                /// retrieve the list of possible (Type,Designation) pairs for the current position in the
     82                /// current object
     83                virtual std::deque< InitAlternative > operator* () const = 0;
     84
     85                /// true if the iterator is not currently at the end
     86                virtual operator bool() const = 0;
     87
     88                /// moves the iterator by one member in the current object
     89                virtual MemberIterator & bigStep() = 0;
     90
     91                /// moves the iterator by one member in the current subobject
     92                virtual MemberIterator & smallStep() = 0;
     93
     94                /// the type of the current object
     95                virtual const Type * getType() = 0;
     96
     97                /// the type of the current subobject
     98                virtual const Type * getNext() = 0;
     99       
     100                /// helper for operator*; aggregates must add designator to each init alternative, but
     101                /// adding designators in operator* creates duplicates
     102                virtual std::deque< InitAlternative > first() const = 0;
     103        };
    68104
    69105        /// Builds initializer lists in resolution
  • src/ResolvExpr/ExplodedArg.hpp

    rb110bcc r2ed94a9  
    3535        ExplodedArg() : env(), cost( Cost::zero ), exprs() {}
    3636        ExplodedArg( const Candidate & arg, const ast::SymbolTable & symtab );
    37 
     37       
    3838        ExplodedArg( ExplodedArg && ) = default;
    3939        ExplodedArg & operator= ( ExplodedArg && ) = default;
  • src/ResolvExpr/ResolveAssertions.cc

    rb110bcc r2ed94a9  
    3030#include "Common/FilterCombos.h"    // for filterCombos
    3131#include "Common/Indenter.h"        // for Indenter
     32#include "Common/utility.h"         // for sort_mins
    3233#include "GenPoly/GenPoly.h"        // for getFunctionType
    3334#include "ResolvExpr/AlternativeFinder.h"  // for computeConversionCost
  • src/ResolvExpr/Resolver.cc

    rb110bcc r2ed94a9  
    3838#include "AST/SymbolTable.hpp"
    3939#include "AST/Type.hpp"
    40 #include "Common/Eval.h"                 // for eval
    41 #include "Common/Iterate.hpp"            // for group_iterate
    4240#include "Common/PassVisitor.h"          // for PassVisitor
    4341#include "Common/SemanticError.h"        // for SemanticError
    4442#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    45 #include "Common/ToString.hpp"           // for toCString
     43#include "Common/utility.h"              // for ValueGuard, group_iterate
    4644#include "InitTweak/GenInit.h"
    4745#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
  • src/ResolvExpr/Resolver.h

    rb110bcc r2ed94a9  
    3434        class Decl;
    3535        class DeletedExpr;
    36         class Expr;
    3736        class Init;
    3837        class StmtExpr;
  • src/SymTab/Autogen.cc

    rb110bcc r2ed94a9  
    1010// Created On       : Thu Mar 03 15:45:56 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 14 15:03:00 2023
    13 // Update Count     : 64
     12// Last Modified On : Fri Apr 27 14:39:06 2018
     13// Update Count     : 63
    1414//
    1515
     
    211211        }
    212212
     213        bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
     214                return obj && obj->name.empty() && obj->bitfieldWidth;
     215        }
     216
    213217        /// inserts a forward declaration for functionDecl into declsToAdd
    214218        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
     
    230234        }
    231235
     236        // shallow copy the pointer list for return
     237        std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) {
     238                if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) {
     239                        return structInst->base->params;
     240                }
     241                if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) {
     242                        return unionInst->base->params;
     243                }
     244                return {};
     245        }
     246
    232247        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    233248        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    241256                ftype->parameters.push_back( dstParam );
    242257                return ftype;
     258        }
     259
     260        /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
     261        ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {
     262                std::vector<ast::ptr<ast::TypeDecl>> typeParams;
     263                if (maybePolymorphic) typeParams = getGenericParams(paramType);
     264                auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);
     265                return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc), {}, ast::Linkage::Cforall);
    243266        }
    244267
  • src/SymTab/Autogen.h

    rb110bcc r2ed94a9  
    99// Author           : Rob Schluntz
    1010// Created On       : Sun May 17 21:53:34 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Apr 14 15:06:00 2023
    13 // Update Count     : 17
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 16:38:06 2019
     13// Update Count     : 16
    1414//
    1515
     
    4545        /// returns true if obj's name is the empty string and it has a bitfield width
    4646        bool isUnnamedBitfield( ObjectDecl * obj );
     47        bool isUnnamedBitfield( const ast::ObjectDecl * obj );
    4748
    4849        /// generate the type of an assignment function for paramType.
     
    5455        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
    5556
     57        ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
     58
    5659        /// generate the type of a copy constructor for paramType.
    5760        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     
    6467        template< typename OutputIterator >
    6568        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
     69
     70        template< typename OutIter >
     71        ast::ptr< ast::Stmt > genCall(
     72                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     73                const CodeLocation & loc, const std::string & fname, OutIter && out,
     74                const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
    6675
    6776        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
     
    112121
    113122                *out++ = new ExprStmt( fExpr );
     123
     124                srcParam.clearArrayIndices();
     125
     126                return listInit;
     127        }
     128
     129        /// inserts into out a generated call expression to function fname with arguments dstParam and
     130        /// srcParam. Should only be called with non-array types.
     131        /// optionally returns a statement which must be inserted prior to the containing loop, if
     132        /// there is one
     133        template< typename OutIter >
     134        ast::ptr< ast::Stmt > genScalarCall(
     135                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     136                const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
     137                const ast::Type * addCast = nullptr
     138        ) {
     139                bool isReferenceCtorDtor = false;
     140                if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
     141                        // reference constructors are essentially application of the rebind operator.
     142                        // apply & to both arguments, do not need a cast
     143                        fname = "?=?";
     144                        dstParam = new ast::AddressExpr{ dstParam };
     145                        addCast = nullptr;
     146                        isReferenceCtorDtor = true;
     147                }
     148
     149                // want to be able to generate assignment, ctor, and dtor generically, so fname is one of
     150                // "?=?", "?{}", or "^?{}"
     151                ast::UntypedExpr * fExpr = new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, fname } };
     152
     153                if ( addCast ) {
     154                        // cast to T& with qualifiers removed, so that qualified objects can be constructed and
     155                        // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
     156                        // is considered a qualifier - for AddressExpr to resolve, its argument must have an
     157                        // lvalue-qualified type, so remove all qualifiers except lvalue.
     158                        // xxx -- old code actually removed lvalue too...
     159                        ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
     160                        ast::ptr< ast::Type > castType = addCast;
     161                        ast::remove_qualifiers(
     162                                castType,
     163                                ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
     164                        dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
     165                }
     166                fExpr->args.emplace_back( dstParam );
     167
     168                ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
     169
     170                // fetch next set of arguments
     171                ++srcParam;
     172
     173                // return if adding reference fails -- will happen on default ctor and dtor
     174                if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;
     175
     176                std::vector< ast::ptr< ast::Expr > > args = *srcParam;
     177                splice( fExpr->args, args );
     178
     179                *out++ = new ast::ExprStmt{ loc, fExpr };
    114180
    115181                srcParam.clearArrayIndices();
     
    182248        }
    183249
     250        /// Store in out a loop which calls fname on each element of the array with srcParam and
     251        /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
     252        template< typename OutIter >
     253        void genArrayCall(
     254                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     255                const CodeLocation & loc, const std::string & fname, OutIter && out,
     256                const ast::ArrayType * array, const ast::Type * addCast = nullptr,
     257                LoopDirection forward = LoopForward
     258        ) {
     259                static UniqueName indexName( "_index" );
     260
     261                // for a flexible array member nothing is done -- user must define own assignment
     262                if ( ! array->dimension ) return;
     263
     264                if ( addCast ) {
     265                        // peel off array layer from cast
     266                        addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;
     267                }
     268
     269                ast::ptr< ast::Expr > begin, end;
     270                std::string cmp, update;
     271
     272                if ( forward ) {
     273                        // generate: for ( int i = 0; i < N; ++i )
     274                        begin = ast::ConstantExpr::from_int( loc, 0 );
     275                        end = array->dimension;
     276                        cmp = "?<?";
     277                        update = "++?";
     278                } else {
     279                        // generate: for ( int i = N-1; i >= 0; --i )
     280                        begin = ast::UntypedExpr::createCall( loc, "?-?",
     281                                { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
     282                        end = ast::ConstantExpr::from_int( loc, 0 );
     283                        cmp = "?>=?";
     284                        update = "--?";
     285                }
     286
     287                ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{
     288                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
     289                        new ast::SingleInit{ loc, begin } };
     290                ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
     291
     292                ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(
     293                        loc, cmp, { indexVar, end } );
     294
     295                ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(
     296                        loc, update, { indexVar } );
     297
     298                ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(
     299                        loc, "?[?]", { dstParam, indexVar } );
     300
     301                // srcParam must keep track of the array indices to build the source parameter and/or
     302                // array list initializer
     303                srcParam.addArrayIndex( indexVar, array->dimension );
     304
     305                // for stmt's body, eventually containing call
     306                ast::CompoundStmt * body = new ast::CompoundStmt{ loc };
     307                ast::ptr< ast::Stmt > listInit = genCall(
     308                        srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
     309                        forward );
     310
     311                // block containing the stmt and index variable
     312                ast::CompoundStmt * block = new ast::CompoundStmt{ loc };
     313                block->push_back( new ast::DeclStmt{ loc, index } );
     314                if ( listInit ) { block->push_back( listInit ); }
     315                block->push_back( new ast::ForStmt{ loc, {}, cond, inc, body } );
     316
     317                *out++ = block;
     318        }
     319
    184320        template< typename OutputIterator >
    185321        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
     
    189325                } else {
    190326                        return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
     327                }
     328        }
     329
     330        template< typename OutIter >
     331        ast::ptr< ast::Stmt > genCall(
     332                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     333                const CodeLocation & loc, const std::string & fname, OutIter && out,
     334                const ast::Type * type, const ast::Type * addCast, LoopDirection forward
     335        ) {
     336                if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
     337                        genArrayCall(
     338                                srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
     339                                forward );
     340                        return {};
     341                } else {
     342                        return genScalarCall(
     343                                srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
    191344                }
    192345        }
     
    226379        }
    227380
     381        static inline ast::ptr< ast::Stmt > genImplicitCall(
     382                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     383                const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
     384                LoopDirection forward = LoopForward
     385        ) {
     386                // unnamed bit fields are not copied as they cannot be accessed
     387                if ( isUnnamedBitfield( obj ) ) return {};
     388
     389                ast::ptr< ast::Type > addCast;
     390                if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
     391                        assert( dstParam->result );
     392                        addCast = dstParam->result;
     393                }
     394
     395                std::vector< ast::ptr< ast::Stmt > > stmts;
     396                genCall(
     397                        srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
     398
     399                if ( stmts.empty() ) {
     400                        return {};
     401                } else if ( stmts.size() == 1 ) {
     402                        const ast::Stmt * callStmt = stmts.front();
     403                        if ( addCast ) {
     404                                // implicitly generated ctor/dtor calls should be wrapped so that later passes are
     405                                // aware they were generated.
     406                                callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };
     407                        }
     408                        return callStmt;
     409                } else {
     410                        assert( false );
     411                        return {};
     412                }
     413        }
    228414} // namespace SymTab
    229415
  • src/SymTab/FixFunction.cc

    rb110bcc r2ed94a9  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
    23 #include "Common/utility.h"       // for copy
     23#include "Common/utility.h"       // for maybeClone, copy
    2424#include "SynTree/Declaration.h"  // for FunctionDecl, ObjectDecl, Declarati...
    2525#include "SynTree/Expression.h"   // for Expression
  • src/SymTab/Mangler.cc

    rb110bcc r2ed94a9  
    2424#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
    2525#include "Common/PassVisitor.h"
    26 #include "Common/ToString.hpp"           // for toCString
    2726#include "Common/SemanticError.h"        // for SemanticError
     27#include "Common/utility.h"              // for toString
    2828#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    2929#include "SynTree/LinkageSpec.h"         // for Spec, isOverridable, AutoGen, Int...
  • src/SymTab/Validate.cc

    rb110bcc r2ed94a9  
    5555#include "Common/ScopedMap.h"          // for ScopedMap
    5656#include "Common/SemanticError.h"      // for SemanticError
    57 #include "Common/ToString.hpp"         // for toCString
    5857#include "Common/UniqueName.h"         // for UniqueName
    59 #include "Common/utility.h"            // for cloneAll, deleteAll
     58#include "Common/utility.h"            // for operator+, cloneAll, deleteAll
    6059#include "CompilationState.h"          // skip some passes in new-ast build
    6160#include "Concurrency/Keywords.h"      // for applyKeywords
  • src/SymTab/ValidateType.cc

    rb110bcc r2ed94a9  
    1818#include "CodeGen/OperatorTable.h"
    1919#include "Common/PassVisitor.h"
    20 #include "Common/ToString.hpp"
    2120#include "SymTab/FixFunction.h"
    2221#include "SynTree/Declaration.h"
  • src/SymTab/module.mk

    rb110bcc r2ed94a9  
    2020        SymTab/FixFunction.cc \
    2121        SymTab/FixFunction.h \
    22         SymTab/GenImplicitCall.cpp \
    23         SymTab/GenImplicitCall.hpp \
    2422        SymTab/Indexer.cc \
    2523        SymTab/Indexer.h \
  • src/SynTree/AggregateDecl.cc

    rb110bcc r2ed94a9  
    1919
    2020#include "Attribute.h"           // for Attribute
    21 #include "Common/Eval.h"         // for eval
    2221#include "Common/utility.h"      // for printAll, cloneAll, deleteAll
    2322#include "Declaration.h"         // for AggregateDecl, TypeDecl, Declaration
  • src/SynTree/FunctionDecl.cc

    rb110bcc r2ed94a9  
    8787        } // if
    8888
    89         if ( !withExprs.empty() ) {
    90                 os << indent << "... with clause" << std::endl;
    91                 os << indent + 1;
    92                 printAll( withExprs, os, indent + 1 );
    93         }
    94 
    9589        if ( statements ) {
    9690                os << indent << "... with body" << endl << indent+1;
  • src/SynTree/Type.cc

    rb110bcc r2ed94a9  
    1616
    1717#include "Attribute.h"                // for Attribute
    18 #include "Common/ToString.hpp"        // for toCString
    1918#include "Common/utility.h"           // for cloneAll, deleteAll, printAll
    2019#include "InitTweak/InitTweak.h"      // for getPointerBase
     
    106105int Type::referenceDepth() const { return 0; }
    107106
    108 AggregateDecl * Type::getAggr() const {
    109         assertf( false, "Non-aggregate type: %s", toCString( this ) );
    110 }
    111 
    112107TypeSubstitution Type::genericSubstitution() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
    113108
  • src/SynTree/Type.h

    rb110bcc r2ed94a9  
    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 : Sun Feb 19 22:37:10 2023
    13 // Update Count     : 176
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jul 14 15:40:00 2021
     13// Update Count     : 171
    1414//
    1515
     
    2323
    2424#include "BaseSyntaxNode.h"  // for BaseSyntaxNode
    25 #include "Common/Iterate.hpp"// for operator+
     25#include "Common/utility.h"  // for operator+
    2626#include "Mutator.h"         // for Mutator
    2727#include "SynTree.h"         // for AST nodes
     
    124124                bool operator!=( Qualifiers other ) const { return (val & Mask) != (other.val & Mask); }
    125125                bool operator<=( Qualifiers other ) const {
    126                         return is_const    <= other.is_const        // Any non-const converts to const without cost
    127                                 && is_volatile <= other.is_volatile             // Any non-volatile converts to volatile without cost
    128                                 && is_mutex    >= other.is_mutex                // Any mutex converts to non-mutex without cost
    129                                 && is_atomic   == other.is_atomic;              // No conversion from atomic to non atomic is free
     126                        return is_const    <= other.is_const        //Any non-const converts to const without cost
     127                                        && is_volatile <= other.is_volatile     //Any non-volatile converts to volatile without cost
     128                                        && is_mutex    >= other.is_mutex        //Any mutex converts to non-mutex without cost
     129                                        && is_atomic   == other.is_atomic;      //No conversion from atomic to non atomic is free
    130130                }
    131131                bool operator<( Qualifiers other ) const { return *this != other && *this <= other; }
     
    185185        virtual bool isComplete() const { return true; }
    186186
    187         virtual AggregateDecl * getAggr() const;
     187        virtual AggregateDecl * getAggr() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
    188188
    189189        virtual TypeSubstitution genericSubstitution() const;
    190190
    191         virtual Type * clone() const = 0;
     191        virtual Type *clone() const = 0;
    192192        virtual void accept( Visitor & v ) = 0;
    193193        virtual void accept( Visitor & v ) const = 0;
    194         virtual Type * acceptMutator( Mutator & m ) = 0;
     194        virtual Type *acceptMutator( Mutator & m ) = 0;
    195195        virtual void print( std::ostream & os, Indenter indent = {} ) const;
    196196};
     
    207207        virtual bool isComplete() const override { return false; }
    208208
    209         virtual VoidType * clone() const override { return new VoidType( *this ); }
    210         virtual void accept( Visitor & v ) override { v.visit( this ); }
    211         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    212         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     209        virtual VoidType *clone() const override { return new VoidType( *this ); }
     210        virtual void accept( Visitor & v ) override { v.visit( this ); }
     211        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     212        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    213213        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    214214};
     
    259259        // GENERATED END
    260260
    261         static const char * typeNames[];                                        // string names for basic types, MUST MATCH with Kind
     261        static const char *typeNames[];                                         // string names for basic types, MUST MATCH with Kind
    262262
    263263        BasicType( const Type::Qualifiers & tq, Kind bt, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     
    266266        void set_kind( Kind newValue ) { kind = newValue; }
    267267
    268         virtual BasicType * clone() const override { return new BasicType( *this ); }
    269         virtual void accept( Visitor & v ) override { v.visit( this ); }
    270         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    271         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     268        virtual BasicType *clone() const override { return new BasicType( *this ); }
     269        virtual void accept( Visitor & v ) override { v.visit( this ); }
     270        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     271        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    272272        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    273273        bool isInteger() const;
     
    279279
    280280        // In C99, pointer types can be qualified in many ways e.g., int f( int a[ static 3 ] )
    281         Expression * dimension;
     281        Expression *dimension;
    282282        bool isVarLen;
    283283        bool isStatic;
    284284
    285         PointerType( const Type::Qualifiers & tq, Type * base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    286         PointerType( const Type::Qualifiers & tq, Type * base, Expression * dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     285        PointerType( const Type::Qualifiers & tq, Type *base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     286        PointerType( const Type::Qualifiers & tq, Type *base, Expression *dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    287287        PointerType( const PointerType& );
    288288        virtual ~PointerType();
    289289
    290         Type * get_base() { return base; }
    291         void set_base( Type * newValue ) { base = newValue; }
    292         Expression * get_dimension() { return dimension; }
    293         void set_dimension( Expression * newValue ) { dimension = newValue; }
     290        Type *get_base() { return base; }
     291        void set_base( Type *newValue ) { base = newValue; }
     292        Expression *get_dimension() { return dimension; }
     293        void set_dimension( Expression *newValue ) { dimension = newValue; }
    294294        bool get_isVarLen() { return isVarLen; }
    295295        void set_isVarLen( bool newValue ) { isVarLen = newValue; }
     
    301301        virtual bool isComplete() const override { return ! isVarLen; }
    302302
    303         virtual PointerType * clone() const override { return new PointerType( * this ); }
    304         virtual void accept( Visitor & v ) override { v.visit( this ); }
    305         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    306         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     303        virtual PointerType *clone() const override { return new PointerType( *this ); }
     304        virtual void accept( Visitor & v ) override { v.visit( this ); }
     305        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     306        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    307307        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    308308};
     
    310310class ArrayType : public Type {
    311311  public:
    312         Type * base;
    313         Expression * dimension;
     312        Type *base;
     313        Expression *dimension;
    314314        bool isVarLen;
    315315        bool isStatic;
    316316
    317         ArrayType( const Type::Qualifiers & tq, Type * base, Expression * dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     317        ArrayType( const Type::Qualifiers & tq, Type *base, Expression *dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    318318        ArrayType( const ArrayType& );
    319319        virtual ~ArrayType();
    320320
    321         Type * get_base() { return base; }
    322         void set_base( Type * newValue ) { base = newValue; }
    323         Expression * get_dimension() { return dimension; }
    324         void set_dimension( Expression * newValue ) { dimension = newValue; }
     321        Type *get_base() { return base; }
     322        void set_base( Type *newValue ) { base = newValue; }
     323        Expression *get_dimension() { return dimension; }
     324        void set_dimension( Expression *newValue ) { dimension = newValue; }
    325325        bool get_isVarLen() { return isVarLen; }
    326326        void set_isVarLen( bool newValue ) { isVarLen = newValue; }
     
    333333        virtual bool isComplete() const override { return dimension || isVarLen; }
    334334
    335         virtual ArrayType * clone() const override { return new ArrayType( *this ); }
    336         virtual void accept( Visitor & v ) override { v.visit( this ); }
    337         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    338         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     335        virtual ArrayType *clone() const override { return new ArrayType( *this ); }
     336        virtual void accept( Visitor & v ) override { v.visit( this ); }
     337        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     338        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    339339        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    340340};
     
    348348        virtual ~QualifiedType();
    349349
    350         virtual QualifiedType * clone() const override { return new QualifiedType( *this ); }
    351         virtual void accept( Visitor & v ) override { v.visit( this ); }
    352         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    353         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     350        virtual QualifiedType *clone() const override { return new QualifiedType( *this ); }
     351        virtual void accept( Visitor & v ) override { v.visit( this ); }
     352        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     353        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    354354        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    355355};
     
    357357class ReferenceType : public Type {
    358358public:
    359         Type * base;
    360 
    361         ReferenceType( const Type::Qualifiers & tq, Type * base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     359        Type *base;
     360
     361        ReferenceType( const Type::Qualifiers & tq, Type *base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    362362        ReferenceType( const ReferenceType & );
    363363        virtual ~ReferenceType();
    364364
    365         Type * get_base() { return base; }
    366         void set_base( Type * newValue ) { base = newValue; }
     365        Type *get_base() { return base; }
     366        void set_base( Type *newValue ) { base = newValue; }
    367367
    368368        virtual int referenceDepth() const override;
     
    375375        virtual TypeSubstitution genericSubstitution() const override;
    376376
    377         virtual ReferenceType * clone() const override { return new ReferenceType( *this ); }
    378         virtual void accept( Visitor & v ) override { v.visit( this ); }
    379         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    380         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     377        virtual ReferenceType *clone() const override { return new ReferenceType( *this ); }
     378        virtual void accept( Visitor & v ) override { v.visit( this ); }
     379        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     380        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    381381        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    382382};
     
    405405        bool isUnprototyped() const { return isVarArgs && parameters.size() == 0; }
    406406
    407         virtual FunctionType * clone() const override { return new FunctionType( *this ); }
    408         virtual void accept( Visitor & v ) override { v.visit( this ); }
    409         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    410         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     407        virtual FunctionType *clone() const override { return new FunctionType( *this ); }
     408        virtual void accept( Visitor & v ) override { v.visit( this ); }
     409        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     410        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    411411        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    412412};
     
    414414class ReferenceToType : public Type {
    415415  public:
    416         std::list< Expression * > parameters;
     416        std::list< Expression* > parameters;
    417417        std::string name;
    418418        bool hoistType;
     
    428428        void set_hoistType( bool newValue ) { hoistType = newValue; }
    429429
    430         virtual ReferenceToType * clone() const override = 0;
     430        virtual ReferenceToType *clone() const override = 0;
    431431        virtual void accept( Visitor & v ) override = 0;
    432         virtual Type * acceptMutator( Mutator & m ) override = 0;
     432        virtual Type *acceptMutator( Mutator & m ) override = 0;
    433433        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    434434
     
    443443        // this decl is not "owned" by the struct inst; it is merely a pointer to elsewhere in the tree,
    444444        // where the structure used in this type is actually defined
    445         StructDecl * baseStruct;
     445        StructDecl *baseStruct;
    446446
    447447        StructInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >()  ) : Parent( tq, name, attributes ), baseStruct( 0 ) {}
     
    449449        StructInstType( const StructInstType & other ) : Parent( other ), baseStruct( other.baseStruct ) {}
    450450
    451         StructDecl * get_baseStruct() const { return baseStruct; }
    452         void set_baseStruct( StructDecl * newValue ) { baseStruct = newValue; }
     451        StructDecl *get_baseStruct() const { return baseStruct; }
     452        void set_baseStruct( StructDecl *newValue ) { baseStruct = newValue; }
    453453
    454454        /// Accesses generic parameters of base struct (NULL if none such)
     
    466466        void lookup( const std::string & name, std::list< Declaration* > & foundDecls ) const override;
    467467
    468         virtual StructInstType * clone() const override { return new StructInstType( *this ); }
    469         virtual void accept( Visitor & v ) override { v.visit( this ); }
    470         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    471         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     468        virtual StructInstType *clone() const override { return new StructInstType( *this ); }
     469        virtual void accept( Visitor & v ) override { v.visit( this ); }
     470        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     471        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    472472
    473473        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     
    481481        // this decl is not "owned" by the union inst; it is merely a pointer to elsewhere in the tree,
    482482        // where the union used in this type is actually defined
    483         UnionDecl * baseUnion;
     483        UnionDecl *baseUnion;
    484484
    485485        UnionInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >()  ) : Parent( tq, name, attributes ), baseUnion( 0 ) {}
     
    487487        UnionInstType( const UnionInstType & other ) : Parent( other ), baseUnion( other.baseUnion ) {}
    488488
    489         UnionDecl * get_baseUnion() const { return baseUnion; }
     489        UnionDecl *get_baseUnion() const { return baseUnion; }
    490490        void set_baseUnion( UnionDecl * newValue ) { baseUnion = newValue; }
    491491
     
    504504        void lookup( const std::string & name, std::list< Declaration* > & foundDecls ) const override;
    505505
    506         virtual UnionInstType * clone() const override { return new UnionInstType( *this ); }
    507         virtual void accept( Visitor & v ) override { v.visit( this ); }
    508         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    509         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     506        virtual UnionInstType *clone() const override { return new UnionInstType( *this ); }
     507        virtual void accept( Visitor & v ) override { v.visit( this ); }
     508        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     509        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    510510
    511511        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     
    519519        // this decl is not "owned" by the enum inst; it is merely a pointer to elsewhere in the tree,
    520520        // where the enum used in this type is actually defined
    521         EnumDecl * baseEnum = nullptr;
     521        EnumDecl *baseEnum = nullptr;
    522522
    523523        EnumInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >()  ) : Parent( tq, name, attributes ) {}
     
    525525        EnumInstType( const EnumInstType & other ) : Parent( other ), baseEnum( other.baseEnum ) {}
    526526
    527         EnumDecl * get_baseEnum() const { return baseEnum; }
    528         void set_baseEnum( EnumDecl * newValue ) { baseEnum = newValue; }
     527        EnumDecl *get_baseEnum() const { return baseEnum; }
     528        void set_baseEnum( EnumDecl *newValue ) { baseEnum = newValue; }
    529529
    530530        virtual bool isComplete() const override;
     
    532532        virtual AggregateDecl * getAggr() const override;
    533533
    534         virtual EnumInstType * clone() const override { return new EnumInstType( *this ); }
    535         virtual void accept( Visitor & v ) override { v.visit( this ); }
    536         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    537         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     534        virtual EnumInstType *clone() const override { return new EnumInstType( *this ); }
     535        virtual void accept( Visitor & v ) override { v.visit( this ); }
     536        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     537        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    538538
    539539        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     
    556556        virtual bool isComplete() const override;
    557557
    558         virtual TraitInstType * clone() const override { return new TraitInstType( *this ); }
    559         virtual void accept( Visitor & v ) override { v.visit( this ); }
    560         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    561         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     558        virtual TraitInstType *clone() const override { return new TraitInstType( *this ); }
     559        virtual void accept( Visitor & v ) override { v.visit( this ); }
     560        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     561        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    562562  private:
    563563        virtual std::string typeString() const override;
     
    569569        // this decl is not "owned" by the type inst; it is merely a pointer to elsewhere in the tree,
    570570        // where the type used here is actually defined
    571         TypeDecl * baseType;
     571        TypeDecl *baseType;
    572572        bool isFtype;
    573573
    574         TypeInstType( const Type::Qualifiers & tq, const std::string & name, TypeDecl * baseType, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
     574        TypeInstType( const Type::Qualifiers & tq, const std::string & name, TypeDecl *baseType, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    575575        TypeInstType( const Type::Qualifiers & tq, const std::string & name, bool isFtype, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    576576        TypeInstType( const TypeInstType & other );
    577577        ~TypeInstType();
    578578
    579         TypeDecl * get_baseType() const { return baseType; }
    580         void set_baseType( TypeDecl * newValue );
     579        TypeDecl *get_baseType() const { return baseType; }
     580        void set_baseType( TypeDecl *newValue );
    581581        bool get_isFtype() const { return isFtype; }
    582582        void set_isFtype( bool newValue ) { isFtype = newValue; }
     
    584584        virtual bool isComplete() const override;
    585585
    586         virtual TypeInstType * clone() const override { return new TypeInstType( *this ); }
    587         virtual void accept( Visitor & v ) override { v.visit( this ); }
    588         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    589         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     586        virtual TypeInstType *clone() const override { return new TypeInstType( *this ); }
     587        virtual void accept( Visitor & v ) override { v.visit( this ); }
     588        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     589        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    590590        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    591591  private:
     
    622622        // virtual bool isComplete() const override { return true; } // xxx - not sure if this is right, might need to recursively check complete-ness
    623623
    624         virtual TupleType * clone() const override { return new TupleType( *this ); }
    625         virtual void accept( Visitor & v ) override { v.visit( this ); }
    626         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    627         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     624        virtual TupleType *clone() const override { return new TupleType( *this ); }
     625        virtual void accept( Visitor & v ) override { v.visit( this ); }
     626        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     627        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    628628        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    629629};
     
    631631class TypeofType : public Type {
    632632  public:
    633         Expression * expr;              ///< expression to take the type of
    634         bool is_basetypeof;             ///< true iff is basetypeof type
    635 
    636         TypeofType( const Type::Qualifiers & tq, Expression * expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    637         TypeofType( const Type::Qualifiers & tq, Expression * expr, bool is_basetypeof,
     633        Expression *expr;    ///< expression to take the type of
     634        bool is_basetypeof;  ///< true iff is basetypeof type
     635
     636        TypeofType( const Type::Qualifiers & tq, Expression *expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     637        TypeofType( const Type::Qualifiers & tq, Expression *expr, bool is_basetypeof,
    638638                const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    639639        TypeofType( const TypeofType& );
    640640        virtual ~TypeofType();
    641641
    642         Expression * get_expr() const { return expr; }
    643         void set_expr( Expression * newValue ) { expr = newValue; }
     642        Expression *get_expr() const { return expr; }
     643        void set_expr( Expression *newValue ) { expr = newValue; }
    644644
    645645        virtual bool isComplete() const override { assert( false ); return false; }
    646646
    647         virtual TypeofType * clone() const override { return new TypeofType( *this ); }
    648         virtual void accept( Visitor & v ) override { v.visit( this ); }
    649         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    650         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     647        virtual TypeofType *clone() const override { return new TypeofType( *this ); }
     648        virtual void accept( Visitor & v ) override { v.visit( this ); }
     649        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     650        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    651651        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    652652};
     
    654654class VTableType : public Type {
    655655public:
    656         Type * base;
    657 
    658         VTableType( const Type::Qualifiers & tq, Type * base,
     656        Type *base;
     657
     658        VTableType( const Type::Qualifiers & tq, Type *base,
    659659                const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    660660        VTableType( const VTableType & );
    661661        virtual ~VTableType();
    662662
    663         Type * get_base() { return base; }
    664         void set_base( Type * newValue ) { base = newValue; }
    665 
    666         virtual VTableType * clone() const override { return new VTableType( *this ); }
    667         virtual void accept( Visitor & v ) override { v.visit( this ); }
    668         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    669         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     663        Type *get_base() { return base; }
     664        void set_base( Type *newValue ) { base = newValue; }
     665
     666        virtual VTableType *clone() const override { return new VTableType( *this ); }
     667        virtual void accept( Visitor & v ) override { v.visit( this ); }
     668        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     669        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    670670        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    671671};
     
    674674  public:
    675675        std::string name;
    676         Expression * expr;
    677         Type * type;
     676        Expression *expr;
     677        Type *type;
    678678        bool isType;
    679679
    680         AttrType( const Type::Qualifiers & tq, const std::string & name, Expression * expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    681         AttrType( const Type::Qualifiers & tq, const std::string & name, Type * type, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
     680        AttrType( const Type::Qualifiers & tq, const std::string & name, Expression *expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     681        AttrType( const Type::Qualifiers & tq, const std::string & name, Type *type, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    682682        AttrType( const AttrType& );
    683683        virtual ~AttrType();
     
    685685        const std::string & get_name() const { return name; }
    686686        void set_name( const std::string & newValue ) { name = newValue; }
    687         Expression * get_expr() const { return expr; }
    688         void set_expr( Expression * newValue ) { expr = newValue; }
    689         Type * get_type() const { return type; }
    690         void set_type( Type * newValue ) { type = newValue; }
     687        Expression *get_expr() const { return expr; }
     688        void set_expr( Expression *newValue ) { expr = newValue; }
     689        Type *get_type() const { return type; }
     690        void set_type( Type *newValue ) { type = newValue; }
    691691        bool get_isType() const { return isType; }
    692692        void set_isType( bool newValue ) { isType = newValue; }
     
    694694        virtual bool isComplete() const override { assert( false ); } // xxx - not sure what to do here
    695695
    696         virtual AttrType * clone() const override { return new AttrType( *this ); }
    697         virtual void accept( Visitor & v ) override { v.visit( this ); }
    698         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    699         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     696        virtual AttrType *clone() const override { return new AttrType( *this ); }
     697        virtual void accept( Visitor & v ) override { v.visit( this ); }
     698        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     699        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    700700        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    701701};
     
    709709        virtual bool isComplete() const override{ return true; } // xxx - is this right?
    710710
    711         virtual VarArgsType * clone() const override { return new VarArgsType( *this ); }
    712         virtual void accept( Visitor & v ) override { v.visit( this ); }
    713         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    714         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     711        virtual VarArgsType *clone() const override { return new VarArgsType( *this ); }
     712        virtual void accept( Visitor & v ) override { v.visit( this ); }
     713        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     714        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    715715        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    716716};
     
    722722        ZeroType( Type::Qualifiers tq, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    723723
    724         virtual ZeroType * clone() const override { return new ZeroType( *this ); }
    725         virtual void accept( Visitor & v ) override { v.visit( this ); }
    726         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    727         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     724        virtual ZeroType *clone() const override { return new ZeroType( *this ); }
     725        virtual void accept( Visitor & v ) override { v.visit( this ); }
     726        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     727        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    728728        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    729729};
     
    735735        OneType( Type::Qualifiers tq, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    736736
    737         virtual OneType * clone() const override { return new OneType( *this ); }
    738         virtual void accept( Visitor & v ) override { v.visit( this ); }
    739         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    740         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     737        virtual OneType *clone() const override { return new OneType( *this ); }
     738        virtual void accept( Visitor & v ) override { v.visit( this ); }
     739        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     740        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    741741        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    742742};
     
    746746        GlobalScopeType();
    747747
    748         virtual GlobalScopeType * clone() const override { return new GlobalScopeType( *this ); }
    749         virtual void accept( Visitor & v ) override { v.visit( this ); }
    750         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    751         virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     748        virtual GlobalScopeType *clone() const override { return new GlobalScopeType( *this ); }
     749        virtual void accept( Visitor & v ) override { v.visit( this ); }
     750        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     751        virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    752752        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    753753};
  • src/Validate/Autogen.cpp

    rb110bcc r2ed94a9  
    3939#include "InitTweak/GenInit.h"     // for fixReturnStatements
    4040#include "InitTweak/InitTweak.h"   // for isAssignment, isCopyConstructor
    41 #include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4241#include "SymTab/Mangler.h"        // for Mangler
    4342#include "CompilationState.h"
     
    424423        for ( unsigned int index = 0 ; index < fields ; ++index ) {
    425424                auto member = aggr->members[index].strict_as<ast::DeclWithType>();
    426                 if ( ast::isUnnamedBitfield(
     425                if ( SymTab::isUnnamedBitfield(
    427426                                dynamic_cast<const ast::ObjectDecl *>( member ) ) ) {
    428427                        if ( index == fields - 1 ) {
     
    600599                // Not sure why it could be null.
    601600                // Don't make a function for a parameter that is an unnamed bitfield.
    602                 if ( nullptr == field || ast::isUnnamedBitfield( field ) ) {
     601                if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {
    603602                        continue;
    604603                // Matching Parameter: Initialize the field by copy.
  • src/Validate/FixQualifiedTypes.cpp

    rb110bcc r2ed94a9  
    1616#include "Validate/FixQualifiedTypes.hpp"
    1717
    18 #include "AST/LinkageSpec.hpp"             // for Linkage
    1918#include "AST/Pass.hpp"
    2019#include "AST/TranslationUnit.hpp"
    21 #include "Common/ToString.hpp"             // for toString
    22 #include "SymTab/Mangler.h"                // for Mangler
    2320#include "Validate/NoIdSymbolTable.hpp"
     21#include "SymTab/Mangler.h"            // for Mangler
     22#include "AST/LinkageSpec.hpp"                     // for Linkage
    2423
    2524namespace Validate {
  • src/Validate/ForallPointerDecay.cpp

    rb110bcc r2ed94a9  
    2222#include "CodeGen/OperatorTable.h"
    2323#include "Common/CodeLocation.h"
    24 #include "Common/ToString.hpp"
    2524#include "SymTab/FixFunction.h"
    2625
  • src/Validate/HandleAttributes.cc

    rb110bcc r2ed94a9  
    1717
    1818#include "CompilationState.h"
    19 #include "Common/Eval.h"
    2019#include "Common/PassVisitor.h"
    21 #include "Common/ToString.hpp"
    2220#include "Common/SemanticError.h"
    2321#include "ResolvExpr/Resolver.h"
  • src/Validate/HoistStruct.cpp

    rb110bcc r2ed94a9  
    1616#include "Validate/HoistStruct.hpp"
    1717
    18 #include <sstream>
    19 
    2018#include "AST/Pass.hpp"
    2119#include "AST/TranslationUnit.hpp"
     20#include "Common/utility.h"
    2221
    2322namespace Validate {
  • src/Virtual/module.mk

    rb110bcc r2ed94a9  
    1919        Virtual/ExpandCasts.h \
    2020        Virtual/Tables.cc \
    21         Virtual/Tables.h \
    22         Virtual/VirtualDtor.cpp \
    23         Virtual/VirtualDtor.hpp
     21        Virtual/Tables.h
  • src/include/cassert

    rb110bcc r2ed94a9  
    2020#include_next <cassert>
    2121
    22 #include "Common/ToString.hpp"
     22#include <string>
     23
     24template < typename ... Params >
     25std::string toString( const Params & ... params );
    2326
    2427#ifdef NDEBUG
  • src/main.cc

    rb110bcc r2ed94a9  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 21:12:17 2023
    13 // Update Count     : 682
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Oct  5 12:06:00 2022
     13// Update Count     : 679
    1414//
    1515
     
    3232
    3333#include "AST/Convert.hpp"
    34 #include "AST/Util.hpp"                     // for checkInvariants
    3534#include "CompilationState.h"
    3635#include "../config.h"                      // for CFA_LIBDIR
     
    4140#include "CodeTools/TrackLoc.h"             // for fillLocations
    4241#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
     42#include "Common/CompilerError.h"           // for CompilerError
    4343#include "Common/DeclStats.hpp"             // for printDeclStats
    4444#include "Common/ResolvProtoDump.hpp"       // for dumpAsResolverProto
    4545#include "Common/Stats.h"                   // for Stats
     46#include "Common/UnimplementedError.h"      // for UnimplementedError
    4647#include "Common/utility.h"                 // for deleteAll, filter, printAll
    4748#include "Concurrency/Actors.hpp"           // for implementActors
     
    8384#include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign
    8485#include "Virtual/ExpandCasts.h"            // for expandCasts
    85 #include "Virtual/VirtualDtor.hpp"           // for implementVirtDtors
    8686
    8787static void NewPass( const char * const name ) {
     
    102102}
    103103
    104 // Helpers for checkInvariant:
    105 void checkInvariants( std::list< Declaration * > & ) {}
    106 using ast::checkInvariants;
    107 
    108 #define PASS( name, pass, unit, ... )       \
     104#define PASS( name, pass )                  \
    109105        if ( errorp ) { cerr << name << endl; } \
    110106        NewPass(name);                          \
    111107        Stats::Time::StartBlock(name);          \
    112         pass(unit,##__VA_ARGS__);               \
    113         Stats::Time::StopBlock();               \
    114         if ( invariant ) {                      \
    115                 checkInvariants(unit);              \
    116         }
    117 
    118 #define DUMP( cond, unit )                  \
    119         if ( cond ) {                           \
    120                 dump(unit);                         \
    121                 return EXIT_SUCCESS;                \
    122         }
     108        pass;                                   \
     109        Stats::Time::StopBlock();
    123110
    124111static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
     
    287274                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" );
    288275                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
    289                         parse( gcc_builtins, ast::Linkage::Compiler );
     276                        parse( gcc_builtins, LinkageSpec::Compiler );
    290277
    291278                        // read the extra prelude in, if not generating the cfa library
    292279                        FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" );
    293280                        assertf( extras, "cannot open extras.cf\n" );
    294                         parse( extras, ast::Linkage::BuiltinC );
     281                        parse( extras, LinkageSpec::BuiltinC );
    295282
    296283                        if ( ! libcfap ) {
     
    298285                                FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" );
    299286                                assertf( prelude, "cannot open prelude.cfa\n" );
    300                                 parse( prelude, ast::Linkage::Intrinsic );
     287                                parse( prelude, LinkageSpec::Intrinsic );
    301288
    302289                                // Read to cfa builtins, if not generating the cfa library
    303290                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" );
    304291                                assertf( builtins, "cannot open builtins.cf\n" );
    305                                 parse( builtins, ast::Linkage::BuiltinCFA );
    306                         } // if
    307                 } // if
    308 
    309                 parse( input, libcfap ? ast::Linkage::Intrinsic : ast::Linkage::Cforall, yydebug );
     292                                parse( builtins, LinkageSpec::BuiltinCFA );
     293                        } // if
     294                } // if
     295
     296                parse( input, libcfap ? LinkageSpec::Intrinsic : LinkageSpec::Cforall, yydebug );
    310297
    311298                transUnit = buildUnit();
    312299
    313                 DUMP( astp, std::move( transUnit ) );
     300                if ( astp ) {
     301                        dump( std::move( transUnit ) );
     302                        return EXIT_SUCCESS;
     303                } // if
    314304
    315305                Stats::Time::StopBlock();
     
    320310                }
    321311
    322                 PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
    323 
    324                 PASS( "Translate Exception Declarations", ControlStruct::translateExcept, transUnit );
    325                 DUMP( exdeclp, std::move( transUnit ) );
    326                 PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign, transUnit );
    327                 PASS( "Replace Typedefs", Validate::replaceTypedef, transUnit );
    328                 PASS( "Fix Return Types", Validate::fixReturnTypes, transUnit );
    329                 PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers, transUnit );
    330 
    331                 PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit );
    332 
    333                 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
    334                 PASS( "Hoist Struct", Validate::hoistStruct, transUnit );
    335                 PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
    336                 PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit );
    337                 PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit );
    338                 PASS( "Check Function Returns", Validate::checkReturnStatements, transUnit );
    339                 PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit );
    340                 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
    341                 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
    342                 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
    343 
    344                 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines, transUnit );
    345 
    346                 PASS( "Implement Actors", Concurrency::implementActors, transUnit );
    347                 PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors, transUnit );
    348                 PASS( "Implement Mutex", Concurrency::implementMutex, transUnit );
    349                 PASS( "Implement Thread Start", Concurrency::implementThreadStarter, transUnit );
    350                 PASS( "Compound Literal", Validate::handleCompoundLiterals, transUnit );
    351                 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer, transUnit );
    352                 PASS( "Find Global Decls", Validate::findGlobalDecls, transUnit );
    353                 PASS( "Fix Label Address", Validate::fixLabelAddresses, transUnit );
     312                PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) );
     313                // Hoist Type Decls pulls some declarations out of contexts where
     314                // locations are not tracked. Perhaps they should be, but for now
     315                // the full fill solves it.
     316                forceFillCodeLocations( transUnit );
     317
     318                PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) );
     319                if ( exdeclp ) {
     320                        dump( std::move( transUnit ) );
     321                        return EXIT_SUCCESS;
     322                }
     323
     324                PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) );
     325                PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) );
     326                PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
     327                PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
     328
     329                PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) );
     330
     331                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
     332                PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
     333                PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
     334                PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) );
     335                PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) );
     336                PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) );
     337                PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) );
     338                PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
     339                PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
     340                PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
     341
     342                PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
     343
     344        PASS( "Implement Actors", Concurrency::implementActors( transUnit ) );
     345
     346                PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
     347                PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
     348                PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) );
     349                PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
     350                PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
     351                PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) );
    354352
    355353                if ( symtabp ) {
     
    362360                } // if
    363361
    364                 DUMP( validp, std::move( transUnit ) );
    365 
    366                 PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
    367                 PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
    368                 PASS( "Fix Names", CodeGen::fixNames, transUnit );
    369                 PASS( "Gen Init", InitTweak::genInit, transUnit );
    370                 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples, transUnit );
     362                if ( validp ) {
     363                        dump( std::move( transUnit ) );
     364                        return EXIT_SUCCESS;
     365                } // if
     366
     367                PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
     368                PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
     369                PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
     370                PASS( "Gen Init", InitTweak::genInit( transUnit ) );
     371                PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
    371372
    372373                if ( libcfap ) {
     
    380381                } // if
    381382
    382                 DUMP( bresolvep, std::move( transUnit ) );
     383                if ( bresolvep ) {
     384                        dump( std::move( transUnit ) );
     385                        return EXIT_SUCCESS;
     386                } // if
    383387
    384388                if ( resolvprotop ) {
     
    387391                } // if
    388392
    389                 PASS( "Resolve", ResolvExpr::resolve, transUnit );
    390                 DUMP( exprp, std::move( transUnit ) );
    391 
    392                 PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
     393                PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
     394                if ( exprp ) {
     395                        dump( std::move( transUnit ) );
     396                        return EXIT_SUCCESS;
     397                } // if
     398
     399                forceFillCodeLocations( transUnit );
     400
     401                PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
    393402
    394403                // fix ObjectDecl - replaces ConstructorInit nodes
    395                 DUMP( ctorinitp, std::move( transUnit ) );
     404                if ( ctorinitp ) {
     405                        dump( std::move( transUnit ) );
     406                        return EXIT_SUCCESS;
     407                } // if
    396408
    397409                // Currently not working due to unresolved issues with UniqueExpr
    398                 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr, transUnit ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    399 
    400                 PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
    401                 PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
     410                PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
     411
     412                PASS( "Translate Tries", ControlStruct::translateTries( transUnit ) );
     413                PASS( "Gen Waitfor", Concurrency::generateWaitFor( transUnit ) );
    402414
    403415                // Needs to happen before tuple types are expanded.
    404                 PASS( "Convert Specializations",  GenPoly::convertSpecializations, transUnit );
    405 
    406                 PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
    407                 DUMP( tuplep, std::move( transUnit ) );
     416                PASS( "Convert Specializations",  GenPoly::convertSpecializations( transUnit ) );
     417
     418                PASS( "Expand Tuples", Tuples::expandTuples( transUnit ) );
     419
     420                if ( tuplep ) {
     421                        dump( std::move( transUnit ) );
     422                        return EXIT_SUCCESS;
     423                } // if
    408424
    409425                // Must come after Translate Tries.
    410                 PASS( "Virtual Expand Casts", Virtual::expandCasts, transUnit );
    411 
    412                 PASS( "Instantiate Generics", GenPoly::instantiateGeneric, transUnit );
    413                 DUMP( genericsp, std::move( transUnit ) );
    414 
    415                 PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit );
     426                PASS( "Virtual Expand Casts", Virtual::expandCasts( transUnit ) );
     427
     428                PASS( "Instantiate Generics", GenPoly::instantiateGeneric( transUnit ) );
     429                if ( genericsp ) {
     430                        dump( std::move( transUnit ) );
     431                        return EXIT_SUCCESS;
     432                } // if
     433
     434                PASS( "Convert L-Value", GenPoly::convertLvalue( transUnit ) );
    416435
    417436                translationUnit = convert( std::move( transUnit ) );
    418437
    419                 DUMP( bboxp, translationUnit );
    420                 PASS( "Box", GenPoly::box, translationUnit );
    421 
    422                 PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit );
     438                if ( bboxp ) {
     439                        dump( translationUnit );
     440                        return EXIT_SUCCESS;
     441                } // if
     442                PASS( "Box", GenPoly::box( translationUnit ) );
     443
     444                PASS( "Link-Once", CodeGen::translateLinkOnce( translationUnit ) );
    423445
    424446                // Code has been lowered to C, now we can start generation.
    425447
    426                 DUMP( bcodegenp, translationUnit );
     448                if ( bcodegenp ) {
     449                        dump( translationUnit );
     450                        return EXIT_SUCCESS;
     451                } // if
    427452
    428453                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    431456
    432457                CodeTools::fillLocations( translationUnit );
    433                 PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
     458                PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
    434459
    435460                CodeGen::FixMain::fix( translationUnit, *output,
     
    451476                } // if
    452477                e.print();
     478                if ( output != &cout ) {
     479                        delete output;
     480                } // if
     481                return EXIT_FAILURE;
     482        } catch ( UnimplementedError & e ) {
     483                cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl;
     484                if ( output != &cout ) {
     485                        delete output;
     486                } // if
     487                return EXIT_FAILURE;
     488        } catch ( CompilerError & e ) {
     489                cerr << "Compiler Error: " << e.get_what() << endl;
     490                cerr << "(please report bugs to [REDACTED])" << endl;
    453491                if ( output != &cout ) {
    454492                        delete output;
     
    479517
    480518
    481 static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
     519static const char optstring[] = ":c:ghlLmNnpdP:S:twW:D:";
    482520
    483521enum { PreludeDir = 128 };
     
    486524        { "gdb", no_argument, nullptr, 'g' },
    487525        { "help", no_argument, nullptr, 'h' },
    488         { "invariant", no_argument, nullptr, 'i' },
    489526        { "libcfa", no_argument, nullptr, 'l' },
    490527        { "linemarks", no_argument, nullptr, 'L' },
    491         { "no-main", no_argument, nullptr, 'm' },
     528        { "no-main", no_argument, 0, 'm' },
    492529        { "no-linemarks", no_argument, nullptr, 'N' },
    493530        { "no-prelude", no_argument, nullptr, 'n' },
     
    508545        "wait for gdb to attach",                                                       // -g
    509546        "print translator help message",                                        // -h
    510         "invariant checking during AST passes",                         // -i
    511547        "generate libcfa.c",                                                            // -l
    512548        "generate line marks",                                                          // -L
     
    602638                        usage( argv );                                                          // no return
    603639                        break;
    604                   case 'i':                                                                             // invariant checking
    605                         invariant = true;
    606                         break;
    607640                  case 'l':                                                                             // generate libcfa.c
    608641                        libcfap = true;
  • tests/.expect/PRNG.x64.txt

    rb110bcc r2ed94a9  
    1 
    2 CFA xoshiro256pp
    31
    42                    PRNG()     PRNG(5)   PRNG(0,5)
    5       13944458589275087071           3           2
    6         129977468648444256           0           4
    7        2357727400298891021           2           2
    8        8855179187835660146           3           3
    9        9957620185645882382           4           1
    10       13396406983727409795           0           5
    11        3342782395220265920           0           5
    12        1707651271867677937           1           0
    13       16402561450140881681           0           1
    14       17838519215740313729           4           2
    15        7425936020594490136           4           0
    16        4174865704721714670           3           5
    17       16055269689200152092           0           2
    18       15091270195803594018           1           5
    19       11807315541476180798           1           1
    20       10697186588988060306           4           1
    21       14665526411527044929           3           2
    22       11289342279096164771           2           5
    23       16126980828050300615           1           4
    24        7821578301767524260           4           1
     3                8464106481           4           4
     4       5215204710507639537           1           2
     5       1880401021892145483           0           4
     6      12503840966285181348           2           5
     7        801971300205459356           0           2
     8       6123812066052045228           3           1
     9       7691074772031490538           4           3
     10       4793575011534070065           0           0
     11      10647551928893428440           1           3
     12      10865128702974868079           0           3
     13        530720947131684825           3           0
     14      10520125295812061287           1           5
     15       7539957561855178679           4           4
     16      13739826796006269835           0           2
     17       4289714351582916365           3           2
     18      16911914987551424434           2           1
     19       5327155553462670435           4           0
     20      16251986870929071204           4           4
     21      13394433706240223001           0           3
     22       4814982023332666924           4           0
    2523seed 1009
    2624
    2725Sequential
    28 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     26trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    2927
    3028Concurrent
    31 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    32 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    33 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    34 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     29trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     30trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     31trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     32trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    3533
    3634                    prng()     prng(5)   prng(0,5)
    37       13944458589275087071           3           2
    38         129977468648444256           0           4
    39        2357727400298891021           2           2
    40        8855179187835660146           3           3
    41        9957620185645882382           4           1
    42       13396406983727409795           0           5
    43        3342782395220265920           0           5
    44        1707651271867677937           1           0
    45       16402561450140881681           0           1
    46       17838519215740313729           4           2
    47        7425936020594490136           4           0
    48        4174865704721714670           3           5
    49       16055269689200152092           0           2
    50       15091270195803594018           1           5
    51       11807315541476180798           1           1
    52       10697186588988060306           4           1
    53       14665526411527044929           3           2
    54       11289342279096164771           2           5
    55       16126980828050300615           1           4
    56        7821578301767524260           4           1
     35                8464106481           4           4
     36       5215204710507639537           1           2
     37       1880401021892145483           0           4
     38      12503840966285181348           2           5
     39        801971300205459356           0           2
     40       6123812066052045228           3           1
     41       7691074772031490538           4           3
     42       4793575011534070065           0           0
     43      10647551928893428440           1           3
     44      10865128702974868079           0           3
     45        530720947131684825           3           0
     46      10520125295812061287           1           5
     47       7539957561855178679           4           4
     48      13739826796006269835           0           2
     49       4289714351582916365           3           2
     50      16911914987551424434           2           1
     51       5327155553462670435           4           0
     52      16251986870929071204           4           4
     53      13394433706240223001           0           3
     54       4814982023332666924           4           0
    5755seed 1009
    5856
    5957Sequential
    60 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     58trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    6159
    6260Concurrent
    63 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    64 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    65 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    66 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     61trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     62trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     63trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     64trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    6765
    6866                   prng(t)   prng(t,5) prng(t,0,5)
    69       13944458589275087071           3           2
    70         129977468648444256           0           4
    71        2357727400298891021           2           2
    72        8855179187835660146           3           3
    73        9957620185645882382           4           1
    74       13396406983727409795           0           5
    75        3342782395220265920           0           5
    76        1707651271867677937           1           0
    77       16402561450140881681           0           1
    78       17838519215740313729           4           2
    79        7425936020594490136           4           0
    80        4174865704721714670           3           5
    81       16055269689200152092           0           2
    82       15091270195803594018           1           5
    83       11807315541476180798           1           1
    84       10697186588988060306           4           1
    85       14665526411527044929           3           2
    86       11289342279096164771           2           5
    87       16126980828050300615           1           4
    88        7821578301767524260           4           1
     67                8464106481           4           4
     68       5215204710507639537           1           2
     69       1880401021892145483           0           4
     70      12503840966285181348           2           5
     71        801971300205459356           0           2
     72       6123812066052045228           3           1
     73       7691074772031490538           4           3
     74       4793575011534070065           0           0
     75      10647551928893428440           1           3
     76      10865128702974868079           0           3
     77        530720947131684825           3           0
     78      10520125295812061287           1           5
     79       7539957561855178679           4           4
     80      13739826796006269835           0           2
     81       4289714351582916365           3           2
     82      16911914987551424434           2           1
     83       5327155553462670435           4           0
     84      16251986870929071204           4           4
     85      13394433706240223001           0           3
     86       4814982023332666924           4           0
    8987seed 1009
    9088
    9189Sequential
    92 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     90trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    9391
    9492Concurrent
    95 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    96 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    97 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    98 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     93trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     94trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     95trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     96trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
  • tests/.expect/PRNG.x86.txt

    rb110bcc r2ed94a9  
    1 
    2 CFA xoshiro128pp
    31
    42                    PRNG()     PRNG(5)   PRNG(0,5)
    5                 2884683541           0           0
    6                 3465286746           2           4
    7                 3268922916           0           1
    8                 2396374907           3           0
    9                 2135076892           4           1
    10                  944377718           3           1
    11                 2204845346           3           3
    12                 3736609533           0           4
    13                 4063231336           0           2
    14                 1075394776           0           2
    15                  712844808           4           0
    16                 4246343110           3           1
    17                 3793873837           2           1
    18                 3690340337           1           4
    19                  319207944           1           4
    20                 1815791072           3           5
    21                 2581617261           1           5
    22                 3873329448           1           3
    23                  832631329           4           0
    24                  651551615           3           5
     3                    130161           1           1
     4                4074541490           0           0
     5                 927506267           0           3
     6                1991273445           1           3
     7                 669918146           2           3
     8                 519546860           1           1
     9                1136699882           4           3
     10                2130185384           3           1
     11                 992239050           0           5
     12                2250903111           0           1
     13                1544429724           3           2
     14                1591091660           3           3
     15                2511657707           2           4
     16                1065770984           2           4
     17                2412763405           4           4
     18                1834447239           4           2
     19                 360289337           0           4
     20                2449452027           1           1
     21                3370425396           2           1
     22                3109103043           0           3
    2523seed 1009
    2624
    2725Sequential
    28 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     26trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    2927
    3028Concurrent
    31 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    32 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    33 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    34 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     29trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     30trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     31trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     32trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    3533
    3634                    prng()     prng(5)   prng(0,5)
    37                 2884683541           0           0
    38                 3465286746           2           4
    39                 3268922916           0           1
    40                 2396374907           3           0
    41                 2135076892           4           1
    42                  944377718           3           1
    43                 2204845346           3           3
    44                 3736609533           0           4
    45                 4063231336           0           2
    46                 1075394776           0           2
    47                  712844808           4           0
    48                 4246343110           3           1
    49                 3793873837           2           1
    50                 3690340337           1           4
    51                  319207944           1           4
    52                 1815791072           3           5
    53                 2581617261           1           5
    54                 3873329448           1           3
    55                  832631329           4           0
    56                  651551615           3           5
     35                    130161           1           1
     36                4074541490           0           0
     37                 927506267           0           3
     38                1991273445           1           3
     39                 669918146           2           3
     40                 519546860           1           1
     41                1136699882           4           3
     42                2130185384           3           1
     43                 992239050           0           5
     44                2250903111           0           1
     45                1544429724           3           2
     46                1591091660           3           3
     47                2511657707           2           4
     48                1065770984           2           4
     49                2412763405           4           4
     50                1834447239           4           2
     51                 360289337           0           4
     52                2449452027           1           1
     53                3370425396           2           1
     54                3109103043           0           3
    5755seed 1009
    5856
    5957Sequential
    60 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     58trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    6159
    6260Concurrent
    63 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    64 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    65 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    66 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     61trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     62trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     63trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     64trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    6765
    6866                   prng(t)   prng(t,5) prng(t,0,5)
    69                 2884683541           0           0
    70                 3465286746           2           4
    71                 3268922916           0           1
    72                 2396374907           3           0
    73                 2135076892           4           1
    74                  944377718           3           1
    75                 2204845346           3           3
    76                 3736609533           0           4
    77                 4063231336           0           2
    78                 1075394776           0           2
    79                  712844808           4           0
    80                 4246343110           3           1
    81                 3793873837           2           1
    82                 3690340337           1           4
    83                  319207944           1           4
    84                 1815791072           3           5
    85                 2581617261           1           5
    86                 3873329448           1           3
    87                  832631329           4           0
    88                  651551615           3           5
     67                    130161           1           1
     68                4074541490           0           0
     69                 927506267           0           3
     70                1991273445           1           3
     71                 669918146           2           3
     72                 519546860           1           1
     73                1136699882           4           3
     74                2130185384           3           1
     75                 992239050           0           5
     76                2250903111           0           1
     77                1544429724           3           2
     78                1591091660           3           3
     79                2511657707           2           4
     80                1065770984           2           4
     81                2412763405           4           4
     82                1834447239           4           2
     83                 360289337           0           4
     84                2449452027           1           1
     85                3370425396           2           1
     86                3109103043           0           3
    8987seed 1009
    9088
    9189Sequential
    92 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     90trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    9391
    9492Concurrent
    95 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    96 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    97 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    98 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     93trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     94trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     95trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     96trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
  • tests/.expect/attributes.arm64.txt

    rb110bcc r2ed94a9  
    2626    return _X4_retS12__anonymous0_1;
    2727}
    28 __attribute__ ((unused)) static struct __anonymous0 _X5DummyS12__anonymous0_1;
     28__attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
    2929struct __attribute__ ((unused)) Agn1;
    3030struct __attribute__ ((unused)) Agn2 {
     
    13511351signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
    13521352signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
    1353 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(__attribute__ ((unused)) signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __param_0));
     1353signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
    13541354struct Vad {
    13551355    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.x64.txt

    rb110bcc r2ed94a9  
    2626    return _X4_retS12__anonymous0_1;
    2727}
    28 __attribute__ ((unused)) static struct __anonymous0 _X5DummyS12__anonymous0_1;
     28__attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
    2929struct __attribute__ ((unused)) Agn1;
    3030struct __attribute__ ((unused)) Agn2 {
     
    13511351signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
    13521352signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
    1353 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(__attribute__ ((unused)) signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __param_0));
     1353signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
    13541354struct Vad {
    13551355    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.x86.txt

    rb110bcc r2ed94a9  
    2626    return _X4_retS12__anonymous0_1;
    2727}
    28 __attribute__ ((unused)) static struct __anonymous0 _X5DummyS12__anonymous0_1;
     28__attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
    2929struct __attribute__ ((unused)) Agn1;
    3030struct __attribute__ ((unused)) Agn2 {
     
    13511351signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
    13521352signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
    1353 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(__attribute__ ((unused)) signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __param_0));
     1353signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
    13541354struct Vad {
    13551355    __attribute__ ((unused)) signed int :4;
  • tests/.expect/declarationSpecifier.arm64.txt

    rb110bcc r2ed94a9  
    5151
    5252}
    53 static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
     53volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
    5454struct __anonymous1 {
    5555    signed int _X1ii_1;
     
    9696
    9797}
    98 static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
     98volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
    9999struct __anonymous2 {
    100100    signed int _X1ii_1;
     
    141141
    142142}
    143 static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
     143volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
    144144struct __anonymous3 {
    145145    signed int _X1ii_1;
     
    322322}
    323323static volatile const struct __anonymous6 _X3x16KVS12__anonymous6_1;
     324struct __anonymous7 {
     325    signed int _X1ii_1;
     326};
     327static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     328static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     329static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     330static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     331static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1);
     332static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
     333    {
     334        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1) /* ?{} */);
     335    }
     336
     337}
     338static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
     339    {
     340        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X4_srcS12__anonymous7_1._X1ii_1) /* ?{} */);
     341    }
     342
     343}
     344static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
     345    {
     346        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1) /* ^?{} */);
     347    }
     348
     349}
     350static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
     351    struct __anonymous7 _X4_retS12__anonymous7_1;
     352    {
     353        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X4_srcS12__anonymous7_1._X1ii_1));
     354    }
     355
     356    {
     357        ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1)));
     358    }
     359
     360    return _X4_retS12__anonymous7_1;
     361}
     362static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1){
     363    {
     364        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X1ii_1) /* ?{} */);
     365    }
     366
     367}
     368static volatile const struct __anonymous7 _X3x17KVS12__anonymous7_1;
    324369volatile const signed short int _X3x20KVs_1;
    325370static volatile const signed short int _X3x21KVs_1;
     
    330375static volatile const signed short int _X3x26KVs_1;
    331376static volatile const signed short int _X3x27KVs_1;
    332 struct __anonymous7 {
    333     signed short int _X1is_1;
    334 };
    335 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    336 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    337 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    338 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    339 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1);
    340 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
    341     {
    342         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ?{} */);
    343     }
    344 
    345 }
    346 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
    347     {
    348         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1) /* ?{} */);
    349     }
    350 
    351 }
    352 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
    353     {
    354         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ^?{} */);
    355     }
    356 
    357 }
    358 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
    359     struct __anonymous7 _X4_retS12__anonymous7_1;
    360     {
    361         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1));
    362     }
    363 
    364     {
    365         ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1)));
    366     }
    367 
    368     return _X4_retS12__anonymous7_1;
    369 }
    370 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1){
    371     {
    372         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X1is_1) /* ?{} */);
    373     }
    374 
    375 }
    376 static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1;
    377377struct __anonymous8 {
    378378    signed short int _X1is_1;
     
    419419
    420420}
    421 static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1;
     421volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;
    422422struct __anonymous9 {
    423423    signed short int _X1is_1;
     
    464464
    465465}
    466 static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1;
     466volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;
    467467struct __anonymous10 {
    468468    signed short int _X1is_1;
     
    509509
    510510}
    511 static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1;
     511volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;
    512512struct __anonymous11 {
    513513    signed short int _X1is_1;
     
    554554
    555555}
    556 static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1;
     556static volatile const struct __anonymous11 _X3x32KVS13__anonymous11_1;
    557557struct __anonymous12 {
    558558    signed short int _X1is_1;
     
    599599
    600600}
    601 static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1;
     601static volatile const struct __anonymous12 _X3x33KVS13__anonymous12_1;
    602602struct __anonymous13 {
    603603    signed short int _X1is_1;
     
    644644
    645645}
    646 static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1;
     646static volatile const struct __anonymous13 _X3x34KVS13__anonymous13_1;
     647struct __anonymous14 {
     648    signed short int _X1is_1;
     649};
     650static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     651static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     652static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     653static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     654static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1);
     655static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
     656    {
     657        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1) /* ?{} */);
     658    }
     659
     660}
     661static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
     662    {
     663        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X4_srcS13__anonymous14_1._X1is_1) /* ?{} */);
     664    }
     665
     666}
     667static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
     668    {
     669        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1) /* ^?{} */);
     670    }
     671
     672}
     673static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
     674    struct __anonymous14 _X4_retS13__anonymous14_1;
     675    {
     676        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X4_srcS13__anonymous14_1._X1is_1));
     677    }
     678
     679    {
     680        ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1)));
     681    }
     682
     683    return _X4_retS13__anonymous14_1;
     684}
     685static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1){
     686    {
     687        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X1is_1) /* ?{} */);
     688    }
     689
     690}
     691static volatile const struct __anonymous14 _X3x35KVS13__anonymous14_1;
     692struct __anonymous15 {
     693    signed short int _X1is_1;
     694};
     695static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     696static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     697static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     698static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     699static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1);
     700static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
     701    {
     702        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1) /* ?{} */);
     703    }
     704
     705}
     706static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
     707    {
     708        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X4_srcS13__anonymous15_1._X1is_1) /* ?{} */);
     709    }
     710
     711}
     712static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
     713    {
     714        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1) /* ^?{} */);
     715    }
     716
     717}
     718static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
     719    struct __anonymous15 _X4_retS13__anonymous15_1;
     720    {
     721        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X4_srcS13__anonymous15_1._X1is_1));
     722    }
     723
     724    {
     725        ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1)));
     726    }
     727
     728    return _X4_retS13__anonymous15_1;
     729}
     730static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1){
     731    {
     732        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X1is_1) /* ?{} */);
     733    }
     734
     735}
     736static volatile const struct __anonymous15 _X3x36KVS13__anonymous15_1;
    647737_Thread_local signed int _X3x37i_1;
    648738__thread signed int _X3x38i_1;
     
    663753static inline volatile const signed short int _X3f27Fs___1();
    664754static inline volatile const signed short int _X3f28Fs___1();
    665 struct __anonymous14 {
    666     signed int _X1ii_1;
    667 };
    668 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    669 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    670 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    671 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    672 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1);
    673 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
    674     {
    675         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ?{} */);
    676     }
    677 
    678 }
    679 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
    680     {
    681         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1) /* ?{} */);
    682     }
    683 
    684 }
    685 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
    686     {
    687         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ^?{} */);
    688     }
    689 
    690 }
    691 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
    692     struct __anonymous14 _X4_retS13__anonymous14_1;
    693     {
    694         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1));
    695     }
    696 
    697     {
    698         ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1)));
    699     }
    700 
    701     return _X4_retS13__anonymous14_1;
    702 }
    703 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1){
    704     {
    705         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X1ii_1) /* ?{} */);
    706     }
    707 
    708 }
    709 static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1();
    710 struct __anonymous15 {
    711     signed int _X1ii_1;
    712 };
    713 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    714 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    715 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    716 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    717 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1);
    718 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
    719     {
    720         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ?{} */);
    721     }
    722 
    723 }
    724 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
    725     {
    726         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1) /* ?{} */);
    727     }
    728 
    729 }
    730 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
    731     {
    732         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ^?{} */);
    733     }
    734 
    735 }
    736 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
    737     struct __anonymous15 _X4_retS13__anonymous15_1;
    738     {
    739         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1));
    740     }
    741 
    742     {
    743         ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1)));
    744     }
    745 
    746     return _X4_retS13__anonymous15_1;
    747 }
    748 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1){
    749     {
    750         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X1ii_1) /* ?{} */);
    751     }
    752 
    753 }
    754 static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1();
    755755struct __anonymous16 {
    756756    signed int _X1ii_1;
     
    797797
    798798}
    799 static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1();
     799static inline volatile const struct __anonymous16 _X3f31FS13__anonymous16___1();
    800800struct __anonymous17 {
    801801    signed int _X1ii_1;
     
    842842
    843843}
    844 static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1();
     844static inline volatile const struct __anonymous17 _X3f32FS13__anonymous17___1();
    845845struct __anonymous18 {
    846846    signed int _X1ii_1;
     
    887887
    888888}
    889 static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1();
     889static inline volatile const struct __anonymous18 _X3f33FS13__anonymous18___1();
    890890struct __anonymous19 {
    891891    signed int _X1ii_1;
     
    932932
    933933}
    934 static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1();
     934static inline volatile const struct __anonymous19 _X3f34FS13__anonymous19___1();
    935935struct __anonymous20 {
    936936    signed int _X1ii_1;
     
    977977
    978978}
    979 static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1();
     979static inline volatile const struct __anonymous20 _X3f35FS13__anonymous20___1();
    980980struct __anonymous21 {
    981981    signed int _X1ii_1;
     
    10221022
    10231023}
    1024 static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1();
     1024static inline volatile const struct __anonymous21 _X3f36FS13__anonymous21___1();
     1025struct __anonymous22 {
     1026    signed int _X1ii_1;
     1027};
     1028static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
     1029static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
     1030static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
     1031static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
     1032static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1);
     1033static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1){
     1034    {
     1035        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1) /* ?{} */);
     1036    }
     1037
     1038}
     1039static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1){
     1040    {
     1041        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X4_srcS13__anonymous22_1._X1ii_1) /* ?{} */);
     1042    }
     1043
     1044}
     1045static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1){
     1046    {
     1047        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1) /* ^?{} */);
     1048    }
     1049
     1050}
     1051static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1){
     1052    struct __anonymous22 _X4_retS13__anonymous22_1;
     1053    {
     1054        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X4_srcS13__anonymous22_1._X1ii_1));
     1055    }
     1056
     1057    {
     1058        ((void)_X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1((&_X4_retS13__anonymous22_1), (*_X4_dstS13__anonymous22_1)));
     1059    }
     1060
     1061    return _X4_retS13__anonymous22_1;
     1062}
     1063static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1){
     1064    {
     1065        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X1ii_1) /* ?{} */);
     1066    }
     1067
     1068}
     1069static inline volatile const struct __anonymous22 _X3f37FS13__anonymous22___1();
     1070struct __anonymous23 {
     1071    signed int _X1ii_1;
     1072};
     1073static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
     1074static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
     1075static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
     1076static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
     1077static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1);
     1078static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1){
     1079    {
     1080        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1) /* ?{} */);
     1081    }
     1082
     1083}
     1084static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1){
     1085    {
     1086        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X4_srcS13__anonymous23_1._X1ii_1) /* ?{} */);
     1087    }
     1088
     1089}
     1090static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1){
     1091    {
     1092        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1) /* ^?{} */);
     1093    }
     1094
     1095}
     1096static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1){
     1097    struct __anonymous23 _X4_retS13__anonymous23_1;
     1098    {
     1099        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X4_srcS13__anonymous23_1._X1ii_1));
     1100    }
     1101
     1102    {
     1103        ((void)_X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1((&_X4_retS13__anonymous23_1), (*_X4_dstS13__anonymous23_1)));
     1104    }
     1105
     1106    return _X4_retS13__anonymous23_1;
     1107}
     1108static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1){
     1109    {
     1110        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X1ii_1) /* ?{} */);
     1111    }
     1112
     1113}
     1114static inline volatile const struct __anonymous23 _X3f38FS13__anonymous23___1();
    10251115static inline volatile const signed short int _X3f41Fs___1();
    10261116static inline volatile const signed short int _X3f42Fs___1();
  • tests/.expect/declarationSpecifier.x64.txt

    rb110bcc r2ed94a9  
    5151
    5252}
    53 static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
     53volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
    5454struct __anonymous1 {
    5555    signed int _X1ii_1;
     
    9696
    9797}
    98 static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
     98volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
    9999struct __anonymous2 {
    100100    signed int _X1ii_1;
     
    141141
    142142}
    143 static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
     143volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
    144144struct __anonymous3 {
    145145    signed int _X1ii_1;
     
    322322}
    323323static volatile const struct __anonymous6 _X3x16KVS12__anonymous6_1;
     324struct __anonymous7 {
     325    signed int _X1ii_1;
     326};
     327static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     328static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     329static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     330static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     331static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1);
     332static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
     333    {
     334        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1) /* ?{} */);
     335    }
     336
     337}
     338static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
     339    {
     340        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X4_srcS12__anonymous7_1._X1ii_1) /* ?{} */);
     341    }
     342
     343}
     344static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
     345    {
     346        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1) /* ^?{} */);
     347    }
     348
     349}
     350static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
     351    struct __anonymous7 _X4_retS12__anonymous7_1;
     352    {
     353        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X4_srcS12__anonymous7_1._X1ii_1));
     354    }
     355
     356    {
     357        ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1)));
     358    }
     359
     360    return _X4_retS12__anonymous7_1;
     361}
     362static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1){
     363    {
     364        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X1ii_1) /* ?{} */);
     365    }
     366
     367}
     368static volatile const struct __anonymous7 _X3x17KVS12__anonymous7_1;
    324369volatile const signed short int _X3x20KVs_1;
    325370static volatile const signed short int _X3x21KVs_1;
     
    330375static volatile const signed short int _X3x26KVs_1;
    331376static volatile const signed short int _X3x27KVs_1;
    332 struct __anonymous7 {
    333     signed short int _X1is_1;
    334 };
    335 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    336 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    337 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    338 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    339 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1);
    340 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
    341     {
    342         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ?{} */);
    343     }
    344 
    345 }
    346 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
    347     {
    348         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1) /* ?{} */);
    349     }
    350 
    351 }
    352 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
    353     {
    354         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ^?{} */);
    355     }
    356 
    357 }
    358 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
    359     struct __anonymous7 _X4_retS12__anonymous7_1;
    360     {
    361         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1));
    362     }
    363 
    364     {
    365         ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1)));
    366     }
    367 
    368     return _X4_retS12__anonymous7_1;
    369 }
    370 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1){
    371     {
    372         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X1is_1) /* ?{} */);
    373     }
    374 
    375 }
    376 static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1;
    377377struct __anonymous8 {
    378378    signed short int _X1is_1;
     
    419419
    420420}
    421 static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1;
     421volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;
    422422struct __anonymous9 {
    423423    signed short int _X1is_1;
     
    464464
    465465}
    466 static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1;
     466volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;
    467467struct __anonymous10 {
    468468    signed short int _X1is_1;
     
    509509
    510510}
    511 static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1;
     511volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;
    512512struct __anonymous11 {
    513513    signed short int _X1is_1;
     
    554554
    555555}
    556 static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1;
     556static volatile const struct __anonymous11 _X3x32KVS13__anonymous11_1;
    557557struct __anonymous12 {
    558558    signed short int _X1is_1;
     
    599599
    600600}
    601 static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1;
     601static volatile const struct __anonymous12 _X3x33KVS13__anonymous12_1;
    602602struct __anonymous13 {
    603603    signed short int _X1is_1;
     
    644644
    645645}
    646 static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1;
     646static volatile const struct __anonymous13 _X3x34KVS13__anonymous13_1;
     647struct __anonymous14 {
     648    signed short int _X1is_1;
     649};
     650static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     651static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     652static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     653static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     654static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1);
     655static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
     656    {
     657        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1) /* ?{} */);
     658    }
     659
     660}
     661static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
     662    {
     663        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X4_srcS13__anonymous14_1._X1is_1) /* ?{} */);
     664    }
     665
     666}
     667static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
     668    {
     669        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1) /* ^?{} */);
     670    }
     671
     672}
     673static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
     674    struct __anonymous14 _X4_retS13__anonymous14_1;
     675    {
     676        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X4_srcS13__anonymous14_1._X1is_1));
     677    }
     678
     679    {
     680        ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1)));
     681    }
     682
     683    return _X4_retS13__anonymous14_1;
     684}
     685static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1){
     686    {
     687        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X1is_1) /* ?{} */);
     688    }
     689
     690}
     691static volatile const struct __anonymous14 _X3x35KVS13__anonymous14_1;
     692struct __anonymous15 {
     693    signed short int _X1is_1;
     694};
     695static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     696static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     697static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     698static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     699static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1);
     700static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
     701    {
     702        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1) /* ?{} */);
     703    }
     704
     705}
     706static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
     707    {
     708        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X4_srcS13__anonymous15_1._X1is_1) /* ?{} */);
     709    }
     710
     711}
     712static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
     713    {
     714        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1) /* ^?{} */);
     715    }
     716
     717}
     718static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
     719    struct __anonymous15 _X4_retS13__anonymous15_1;
     720    {
     721        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X4_srcS13__anonymous15_1._X1is_1));
     722    }
     723
     724    {
     725        ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1)));
     726    }
     727
     728    return _X4_retS13__anonymous15_1;
     729}
     730static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1){
     731    {
     732        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X1is_1) /* ?{} */);
     733    }
     734
     735}
     736static volatile const struct __anonymous15 _X3x36KVS13__anonymous15_1;
    647737_Thread_local signed int _X3x37i_1;
    648738__thread signed int _X3x38i_1;
     
    663753static inline volatile const signed short int _X3f27Fs___1();
    664754static inline volatile const signed short int _X3f28Fs___1();
    665 struct __anonymous14 {
    666     signed int _X1ii_1;
    667 };
    668 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    669 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    670 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    671 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    672 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1);
    673 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
    674     {
    675         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ?{} */);
    676     }
    677 
    678 }
    679 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
    680     {
    681         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1) /* ?{} */);
    682     }
    683 
    684 }
    685 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
    686     {
    687         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ^?{} */);
    688     }
    689 
    690 }
    691 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
    692     struct __anonymous14 _X4_retS13__anonymous14_1;
    693     {
    694         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1));
    695     }
    696 
    697     {
    698         ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1)));
    699     }
    700 
    701     return _X4_retS13__anonymous14_1;
    702 }
    703 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1){
    704     {
    705         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X1ii_1) /* ?{} */);
    706     }
    707 
    708 }
    709 static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1();
    710 struct __anonymous15 {
    711     signed int _X1ii_1;
    712 };
    713 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    714 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    715 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    716 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    717 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1);
    718 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
    719     {
    720         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ?{} */);
    721     }
    722 
    723 }
    724 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
    725     {
    726         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1) /* ?{} */);
    727     }
    728 
    729 }
    730 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
    731     {
    732         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ^?{} */);
    733     }
    734 
    735 }
    736 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
    737     struct __anonymous15 _X4_retS13__anonymous15_1;
    738     {
    739         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1));
    740     }
    741 
    742     {
    743         ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1)));
    744     }
    745 
    746     return _X4_retS13__anonymous15_1;
    747 }
    748 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1){
    749     {
    750         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X1ii_1) /* ?{} */);
    751     }
    752 
    753 }
    754 static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1();
    755755struct __anonymous16 {
    756756    signed int _X1ii_1;
     
    797797
    798798}
    799 static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1();
     799static inline volatile const struct __anonymous16 _X3f31FS13__anonymous16___1();
    800800struct __anonymous17 {
    801801    signed int _X1ii_1;
     
    842842
    843843}
    844 static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1();
     844static inline volatile const struct __anonymous17 _X3f32FS13__anonymous17___1();
    845845struct __anonymous18 {
    846846    signed int _X1ii_1;
     
    887887
    888888}
    889 static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1();
     889static inline volatile const struct __anonymous18 _X3f33FS13__anonymous18___1();
    890890struct __anonymous19 {
    891891    signed int _X1ii_1;
     
    932932
    933933}
    934 static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1();
     934static inline volatile const struct __anonymous19 _X3f34FS13__anonymous19___1();
    935935struct __anonymous20 {
    936936    signed int _X1ii_1;
     
    977977
    978978}
    979 static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1();
     979static inline volatile const struct __anonymous20 _X3f35FS13__anonymous20___1();
    980980struct __anonymous21 {
    981981    signed int _X1ii_1;
     
    10221022
    10231023}
    1024 static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1();
     1024static inline volatile const struct __anonymous21 _X3f36FS13__anonymous21___1();
     1025struct __anonymous22 {
     1026    signed int _X1ii_1;
     1027};
     1028static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
     1029static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
     1030static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
     1031static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
     1032static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1);
     1033static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1){
     1034    {
     1035        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1) /* ?{} */);
     1036    }
     1037
     1038}
     1039static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1){
     1040    {
     1041        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X4_srcS13__anonymous22_1._X1ii_1) /* ?{} */);
     1042    }
     1043
     1044}
     1045static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1){
     1046    {
     1047        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1) /* ^?{} */);
     1048    }
     1049
     1050}
     1051static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1){
     1052    struct __anonymous22 _X4_retS13__anonymous22_1;
     1053    {
     1054        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X4_srcS13__anonymous22_1._X1ii_1));
     1055    }
     1056
     1057    {
     1058        ((void)_X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1((&_X4_retS13__anonymous22_1), (*_X4_dstS13__anonymous22_1)));
     1059    }
     1060
     1061    return _X4_retS13__anonymous22_1;
     1062}
     1063static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1){
     1064    {
     1065        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X1ii_1) /* ?{} */);
     1066    }
     1067
     1068}
     1069static inline volatile const struct __anonymous22 _X3f37FS13__anonymous22___1();
     1070struct __anonymous23 {
     1071    signed int _X1ii_1;
     1072};
     1073static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
     1074static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
     1075static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
     1076static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
     1077static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1);
     1078static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1){
     1079    {
     1080        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1) /* ?{} */);
     1081    }
     1082
     1083}
     1084static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1){
     1085    {
     1086        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X4_srcS13__anonymous23_1._X1ii_1) /* ?{} */);
     1087    }
     1088
     1089}
     1090static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1){
     1091    {
     1092        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1) /* ^?{} */);
     1093    }
     1094
     1095}
     1096static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1){
     1097    struct __anonymous23 _X4_retS13__anonymous23_1;
     1098    {
     1099        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X4_srcS13__anonymous23_1._X1ii_1));
     1100    }
     1101
     1102    {
     1103        ((void)_X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1((&_X4_retS13__anonymous23_1), (*_X4_dstS13__anonymous23_1)));
     1104    }
     1105
     1106    return _X4_retS13__anonymous23_1;
     1107}
     1108static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1){
     1109    {
     1110        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X1ii_1) /* ?{} */);
     1111    }
     1112
     1113}
     1114static inline volatile const struct __anonymous23 _X3f38FS13__anonymous23___1();
    10251115static inline volatile const signed short int _X3f41Fs___1();
    10261116static inline volatile const signed short int _X3f42Fs___1();
  • tests/.expect/declarationSpecifier.x86.txt

    rb110bcc r2ed94a9  
    5151
    5252}
    53 static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
     53volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
    5454struct __anonymous1 {
    5555    signed int _X1ii_1;
     
    9696
    9797}
    98 static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
     98volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
    9999struct __anonymous2 {
    100100    signed int _X1ii_1;
     
    141141
    142142}
    143 static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
     143volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
    144144struct __anonymous3 {
    145145    signed int _X1ii_1;
     
    322322}
    323323static volatile const struct __anonymous6 _X3x16KVS12__anonymous6_1;
     324struct __anonymous7 {
     325    signed int _X1ii_1;
     326};
     327static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     328static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     329static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     330static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     331static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1);
     332static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
     333    {
     334        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1) /* ?{} */);
     335    }
     336
     337}
     338static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
     339    {
     340        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X4_srcS12__anonymous7_1._X1ii_1) /* ?{} */);
     341    }
     342
     343}
     344static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
     345    {
     346        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1) /* ^?{} */);
     347    }
     348
     349}
     350static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
     351    struct __anonymous7 _X4_retS12__anonymous7_1;
     352    {
     353        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X4_srcS12__anonymous7_1._X1ii_1));
     354    }
     355
     356    {
     357        ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1)));
     358    }
     359
     360    return _X4_retS12__anonymous7_1;
     361}
     362static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1){
     363    {
     364        ((void)((*_X4_dstS12__anonymous7_1)._X1ii_1=_X1ii_1) /* ?{} */);
     365    }
     366
     367}
     368static volatile const struct __anonymous7 _X3x17KVS12__anonymous7_1;
    324369volatile const signed short int _X3x20KVs_1;
    325370static volatile const signed short int _X3x21KVs_1;
     
    330375static volatile const signed short int _X3x26KVs_1;
    331376static volatile const signed short int _X3x27KVs_1;
    332 struct __anonymous7 {
    333     signed short int _X1is_1;
    334 };
    335 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    336 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    337 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    338 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    339 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1);
    340 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
    341     {
    342         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ?{} */);
    343     }
    344 
    345 }
    346 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
    347     {
    348         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1) /* ?{} */);
    349     }
    350 
    351 }
    352 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){
    353     {
    354         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ^?{} */);
    355     }
    356 
    357 }
    358 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){
    359     struct __anonymous7 _X4_retS12__anonymous7_1;
    360     {
    361         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1));
    362     }
    363 
    364     {
    365         ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1)));
    366     }
    367 
    368     return _X4_retS12__anonymous7_1;
    369 }
    370 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1){
    371     {
    372         ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X1is_1) /* ?{} */);
    373     }
    374 
    375 }
    376 static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1;
    377377struct __anonymous8 {
    378378    signed short int _X1is_1;
     
    419419
    420420}
    421 static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1;
     421volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;
    422422struct __anonymous9 {
    423423    signed short int _X1is_1;
     
    464464
    465465}
    466 static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1;
     466volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;
    467467struct __anonymous10 {
    468468    signed short int _X1is_1;
     
    509509
    510510}
    511 static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1;
     511volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;
    512512struct __anonymous11 {
    513513    signed short int _X1is_1;
     
    554554
    555555}
    556 static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1;
     556static volatile const struct __anonymous11 _X3x32KVS13__anonymous11_1;
    557557struct __anonymous12 {
    558558    signed short int _X1is_1;
     
    599599
    600600}
    601 static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1;
     601static volatile const struct __anonymous12 _X3x33KVS13__anonymous12_1;
    602602struct __anonymous13 {
    603603    signed short int _X1is_1;
     
    644644
    645645}
    646 static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1;
     646static volatile const struct __anonymous13 _X3x34KVS13__anonymous13_1;
     647struct __anonymous14 {
     648    signed short int _X1is_1;
     649};
     650static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     651static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     652static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     653static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     654static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1);
     655static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
     656    {
     657        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1) /* ?{} */);
     658    }
     659
     660}
     661static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
     662    {
     663        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X4_srcS13__anonymous14_1._X1is_1) /* ?{} */);
     664    }
     665
     666}
     667static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
     668    {
     669        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1) /* ^?{} */);
     670    }
     671
     672}
     673static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
     674    struct __anonymous14 _X4_retS13__anonymous14_1;
     675    {
     676        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X4_srcS13__anonymous14_1._X1is_1));
     677    }
     678
     679    {
     680        ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1)));
     681    }
     682
     683    return _X4_retS13__anonymous14_1;
     684}
     685static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1){
     686    {
     687        ((void)((*_X4_dstS13__anonymous14_1)._X1is_1=_X1is_1) /* ?{} */);
     688    }
     689
     690}
     691static volatile const struct __anonymous14 _X3x35KVS13__anonymous14_1;
     692struct __anonymous15 {
     693    signed short int _X1is_1;
     694};
     695static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     696static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     697static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     698static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     699static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1);
     700static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
     701    {
     702        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1) /* ?{} */);
     703    }
     704
     705}
     706static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
     707    {
     708        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X4_srcS13__anonymous15_1._X1is_1) /* ?{} */);
     709    }
     710
     711}
     712static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
     713    {
     714        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1) /* ^?{} */);
     715    }
     716
     717}
     718static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
     719    struct __anonymous15 _X4_retS13__anonymous15_1;
     720    {
     721        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X4_srcS13__anonymous15_1._X1is_1));
     722    }
     723
     724    {
     725        ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1)));
     726    }
     727
     728    return _X4_retS13__anonymous15_1;
     729}
     730static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1){
     731    {
     732        ((void)((*_X4_dstS13__anonymous15_1)._X1is_1=_X1is_1) /* ?{} */);
     733    }
     734
     735}
     736static volatile const struct __anonymous15 _X3x36KVS13__anonymous15_1;
    647737_Thread_local signed int _X3x37i_1;
    648738__thread signed int _X3x38i_1;
     
    663753static inline volatile const signed short int _X3f27Fs___1();
    664754static inline volatile const signed short int _X3f28Fs___1();
    665 struct __anonymous14 {
    666     signed int _X1ii_1;
    667 };
    668 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    669 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    670 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    671 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    672 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1);
    673 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
    674     {
    675         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ?{} */);
    676     }
    677 
    678 }
    679 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
    680     {
    681         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1) /* ?{} */);
    682     }
    683 
    684 }
    685 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){
    686     {
    687         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ^?{} */);
    688     }
    689 
    690 }
    691 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){
    692     struct __anonymous14 _X4_retS13__anonymous14_1;
    693     {
    694         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1));
    695     }
    696 
    697     {
    698         ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1)));
    699     }
    700 
    701     return _X4_retS13__anonymous14_1;
    702 }
    703 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1){
    704     {
    705         ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X1ii_1) /* ?{} */);
    706     }
    707 
    708 }
    709 static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1();
    710 struct __anonymous15 {
    711     signed int _X1ii_1;
    712 };
    713 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    714 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    715 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    716 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    717 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1);
    718 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
    719     {
    720         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ?{} */);
    721     }
    722 
    723 }
    724 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
    725     {
    726         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1) /* ?{} */);
    727     }
    728 
    729 }
    730 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){
    731     {
    732         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ^?{} */);
    733     }
    734 
    735 }
    736 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){
    737     struct __anonymous15 _X4_retS13__anonymous15_1;
    738     {
    739         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1));
    740     }
    741 
    742     {
    743         ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1)));
    744     }
    745 
    746     return _X4_retS13__anonymous15_1;
    747 }
    748 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1){
    749     {
    750         ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X1ii_1) /* ?{} */);
    751     }
    752 
    753 }
    754 static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1();
    755755struct __anonymous16 {
    756756    signed int _X1ii_1;
     
    797797
    798798}
    799 static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1();
     799static inline volatile const struct __anonymous16 _X3f31FS13__anonymous16___1();
    800800struct __anonymous17 {
    801801    signed int _X1ii_1;
     
    842842
    843843}
    844 static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1();
     844static inline volatile const struct __anonymous17 _X3f32FS13__anonymous17___1();
    845845struct __anonymous18 {
    846846    signed int _X1ii_1;
     
    887887
    888888}
    889 static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1();
     889static inline volatile const struct __anonymous18 _X3f33FS13__anonymous18___1();
    890890struct __anonymous19 {
    891891    signed int _X1ii_1;
     
    932932
    933933}
    934 static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1();
     934static inline volatile const struct __anonymous19 _X3f34FS13__anonymous19___1();
    935935struct __anonymous20 {
    936936    signed int _X1ii_1;
     
    977977
    978978}
    979 static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1();
     979static inline volatile const struct __anonymous20 _X3f35FS13__anonymous20___1();
    980980struct __anonymous21 {
    981981    signed int _X1ii_1;
     
    10221022
    10231023}
    1024 static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1();
     1024static inline volatile const struct __anonymous21 _X3f36FS13__anonymous21___1();
     1025struct __anonymous22 {
     1026    signed int _X1ii_1;
     1027};
     1028static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
     1029static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
     1030static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
     1031static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
     1032static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1);
     1033static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1){
     1034    {
     1035        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1) /* ?{} */);
     1036    }
     1037
     1038}
     1039static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1){
     1040    {
     1041        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X4_srcS13__anonymous22_1._X1ii_1) /* ?{} */);
     1042    }
     1043
     1044}
     1045static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1){
     1046    {
     1047        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1) /* ^?{} */);
     1048    }
     1049
     1050}
     1051static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1){
     1052    struct __anonymous22 _X4_retS13__anonymous22_1;
     1053    {
     1054        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X4_srcS13__anonymous22_1._X1ii_1));
     1055    }
     1056
     1057    {
     1058        ((void)_X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1((&_X4_retS13__anonymous22_1), (*_X4_dstS13__anonymous22_1)));
     1059    }
     1060
     1061    return _X4_retS13__anonymous22_1;
     1062}
     1063static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1){
     1064    {
     1065        ((void)((*_X4_dstS13__anonymous22_1)._X1ii_1=_X1ii_1) /* ?{} */);
     1066    }
     1067
     1068}
     1069static inline volatile const struct __anonymous22 _X3f37FS13__anonymous22___1();
     1070struct __anonymous23 {
     1071    signed int _X1ii_1;
     1072};
     1073static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
     1074static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
     1075static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
     1076static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
     1077static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1);
     1078static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1){
     1079    {
     1080        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1) /* ?{} */);
     1081    }
     1082
     1083}
     1084static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1){
     1085    {
     1086        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X4_srcS13__anonymous23_1._X1ii_1) /* ?{} */);
     1087    }
     1088
     1089}
     1090static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1){
     1091    {
     1092        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1) /* ^?{} */);
     1093    }
     1094
     1095}
     1096static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1){
     1097    struct __anonymous23 _X4_retS13__anonymous23_1;
     1098    {
     1099        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X4_srcS13__anonymous23_1._X1ii_1));
     1100    }
     1101
     1102    {
     1103        ((void)_X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1((&_X4_retS13__anonymous23_1), (*_X4_dstS13__anonymous23_1)));
     1104    }
     1105
     1106    return _X4_retS13__anonymous23_1;
     1107}
     1108static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1){
     1109    {
     1110        ((void)((*_X4_dstS13__anonymous23_1)._X1ii_1=_X1ii_1) /* ?{} */);
     1111    }
     1112
     1113}
     1114static inline volatile const struct __anonymous23 _X3f38FS13__anonymous23___1();
    10251115static inline volatile const signed short int _X3f41Fs___1();
    10261116static inline volatile const signed short int _X3f42Fs___1();
  • tests/.expect/nested_function.x64.txt

    rb110bcc r2ed94a9  
    1 total 145
     1total 155
  • tests/.expect/nested_function.x86.txt

    rb110bcc r2ed94a9  
    1 total 245
     1total 105
  • tests/Makefile.am

    rb110bcc r2ed94a9  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Apr 10 23:24:02 2023
    14 ## Update Count     : 96
     13## Last Modified On : Fri Feb  3 23:06:44 2023
     14## Update Count     : 94
    1515###############################################################################
    1616
     
    184184
    185185SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator \
    186         init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment concurrent/waitfor/parse
     186        init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment
    187187$(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    188188        $(CFACOMPILE_SYNTAX)
  • tests/PRNG.cfa

    rb110bcc r2ed94a9  
    88// Created On       : Wed Dec 29 09:38:12 2021
    99// Last Modified By : Peter A. Buhr
    10 // Last Modified On : Sat Apr 15 16:44:31 2023
    11 // Update Count     : 419
     10// Last Modified On : Wed Dec 21 20:39:59 2022
     11// Update Count     : 406
    1212//
    1313
     
    1515#include <stdlib.hfa>                                                                   // PRNG
    1616#include <clock.hfa>
     17#include <thread.hfa>
    1718#include <limits.hfa>                                                                   // MAX
    1819#include <math.hfa>                                                                             // sqrt
    1920#include <malloc.h>                                                                             // malloc_stats
    2021#include <locale.h>                                                                             // setlocale
    21 #include <thread.hfa>
    2222#include <mutex_stmt.hfa>
    2323
    24 #define xstr(s) str(s)
    25 #define str(s) #s
    26 
    27 #if defined( __x86_64__ ) || defined( __aarch64__ )             // 64-bit architecture
     24#ifdef __x86_64__                                                                               // 64-bit architecture
    2825#define PRNG PRNG64
    2926#else                                                                                                   // 32-bit architecture
    3027#define PRNG PRNG32
    3128#endif // __x86_64__
    32 
    33 //#define TIME
    3429
    3530#ifdef TIME                                                                                             // use -O2 -nodebug
     
    4338#endif // TIME
    4439
    45 static void avgstd( size_t trials, size_t buckets[] ) {
    46         size_t min = MAX, max = 0;
     40void avgstd( unsigned int buckets[] ) {
     41        unsigned int min = MAX, max = 0;
    4742        double sum = 0.0, diff;
    4843        for ( i; BUCKETS ) {
     
    5954        } // for
    6055        double std = sqrt( sum / BUCKETS );
    61         mutex( sout ) sout | "trials"  | trials | "buckets" | BUCKETS
     56        mutex( sout ) sout | "trials"  | TRIALS | "buckets" | BUCKETS
    6257                | "min" | min | "max" | max
    6358                | "avg" | wd(0,1, avg) | "std" | wd(0,1, std) | "rstd" | wd(0,1, (avg == 0 ? 0.0 : std / avg * 100)) | "%";
     
    6964thread T1 {};
    7065void main( T1 & ) {
    71         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    72         for ( TRIALS / 50 ) {
     66        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     67        for ( TRIALS / 100 ) {
    7368                buckets[rand() % BUCKETS] += 1;                                 // concurrent
    7469        } // for
    75         avgstd( TRIALS / 50, buckets );
     70        avgstd( buckets );
    7671        free( buckets );
    7772} // main
     
    8176        PRNG prng;
    8277        if ( seed != 0 ) set_seed( prng, seed );
    83         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     78        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    8479        for ( TRIALS ) {
    8580                buckets[prng( prng ) % BUCKETS] += 1;                   // concurrent
    8681        } // for
    87         avgstd( TRIALS, buckets );
     82        avgstd( buckets );
    8883        free( buckets );
    8984} // main
     
    9186thread T3 {};
    9287void main( T3 & th ) {
    93         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    94         for ( TRIALS / 5 ) {
     88        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     89        for ( TRIALS ) {
    9590                buckets[prng() % BUCKETS] += 1;                                 // concurrent
    9691        } // for
    97         avgstd( TRIALS / 5, buckets );
     92        avgstd( buckets );
    9893        free( buckets );
    9994} // main
     
    10196thread T4 {};
    10297void main( T4 & th ) {
    103         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     98        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    10499        for ( TRIALS ) {
    105                 buckets[prng( th ) % BUCKETS] += 1;                             // concurrent
    106         } // for
    107         avgstd( TRIALS, buckets );
     100                buckets[prng( th ) % BUCKETS] += 1;     // concurrent
     101        } // for
     102        avgstd( buckets );
    108103        free( buckets );
    109104} // main
     
    113108static void dummy( thread$ & th ) __attribute__(( noinline ));
    114109static void dummy( thread$ & th ) {
    115         size_t * buckets = (size_t *)calloc( BUCKETS, sizeof(size_t) ); // too big for task stack
    116         for ( size_t i = 0; i < TRIALS; i += 1 ) {
     110        unsigned int * buckets = (unsigned int *)calloc( BUCKETS, sizeof(unsigned int) ); // too big for task stack
     111        for ( unsigned int i = 0; i < TRIALS; i += 1 ) {
    117112                buckets[prng( th ) % BUCKETS] += 1;                             // sequential
    118113        } // for
    119         avgstd( TRIALS, buckets );
     114        avgstd( buckets );
    120115        free( buckets );
    121116} // dummy
     
    131126        enum { TASKS = 4 };
    132127        Time start;
    133 
    134128#ifdef TIME                                                                                             // too slow for test and generates non-repeatable results
    135129#if 1
    136         sout | "glib rand" | nl | nl;
    137 
    138         size_t rseed;
     130        unsigned int rseed;
    139131        if ( seed != 0 ) rseed = seed;
    140132        else rseed = rdtscl();
     
    142134
    143135        sout | sepDisable;
    144         sout | nl | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
     136        sout | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
    145137        for ( 20 ) {
    146138                sout | wd(26, rand()) | nonl;
     
    154146        STARTTIME;
    155147        {
    156                 size_t * buckets = calloc( BUCKETS );                   // too big for task stack
    157                 for ( i; TRIALS / 5 ) {
     148                unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
     149                for ( i; TRIALS / 10 ) {
    158150                        buckets[rand() % BUCKETS] += 1;                         // sequential
    159151                } // for
    160                 avgstd( TRIALS / 5, buckets );
     152                avgstd( buckets );
    161153                free( buckets );
    162154        }
    163         ENDTIME( " x 5 " );
     155        ENDTIME( " x 10 " );
    164156
    165157        sout | nl | "Concurrent";
     
    171163                } // wait for threads to complete
    172164        }
    173         ENDTIME( " x 50 " );
     165        ENDTIME( " x 100 " );
    174166#endif // 0
    175167#endif // TIME
    176 
    177         sout | nl | "CFA " xstr(PRNG_NAME);
    178 
    179168#if 1
    180169        PRNG prng;
     
    195184        STARTTIME;
    196185        {
    197                 size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     186                unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    198187                for ( TRIALS ) {
    199188                        buckets[prng( prng ) % BUCKETS] += 1;           // sequential
    200189                } // for
    201                 avgstd( TRIALS, buckets );
     190                avgstd( buckets );
    202191                free( buckets );
    203192        }
     
    230219        STARTTIME;
    231220        {
    232                 size_t * buckets = calloc( BUCKETS );                   // too big for task stack
    233                 for ( TRIALS / 5 ) {
     221                unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
     222                for ( TRIALS ) {
    234223                        buckets[prng() % BUCKETS] += 1;
    235224                } // for
    236                 avgstd( TRIALS / 5, buckets );
     225                avgstd( buckets );
    237226                free( buckets );
    238227        }
    239         ENDTIME( " x 5 " );
     228        ENDTIME();
    240229
    241230        sout | nl | "Concurrent";
     
    247236                } // wait for threads to complete
    248237        }
    249         ENDTIME( " x 5 " );
     238        ENDTIME();
    250239#endif // 0
    251240#if 1
  • tests/attributes.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Mon Feb  6 16:07:02 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 23 20:33:07 2023
    13 // Update Count     : 39
     12// Last Modified On : Mon Mar 15 13:53:31 2021
     13// Update Count     : 38
    1414//
    1515
     
    2222
    2323// aggregate_name
    24 static struct __attribute__(( unused )) {} Dummy;
     24struct __attribute__(( unused )) {} Dummy;
    2525struct __attribute__(( unused )) Agn1;
    2626struct __attribute__(( unused )) Agn2 {};
  • tests/avltree/avl.h

    rb110bcc r2ed94a9  
    99// #include <lib.h>
    1010
    11 forall(T)
    12 trait Comparable {
     11trait Comparable(T) {
    1312  int ?<?(T, T);
    1413};
  • tests/concurrent/actors/.expect/types.txt

    rb110bcc r2ed94a9  
    1212-1
    13135
    14 nested inheritance actor test
    15 -1
    16 5
    1714end
  • tests/concurrent/actors/dynamic.cfa

    rb110bcc r2ed94a9  
    77int Times = 1000000;                                                            // default values
    88
    9 struct derived_actor { inline actor; };
     9struct derived_actor {
     10    inline actor;
     11};
     12void ?{}( derived_actor & this ) { ((actor &)this){}; }
     13
    1014struct derived_msg {
    1115    inline message;
     
    1923void ?{}( derived_msg & this ) { ((derived_msg &)this){ 0 }; }
    2024
     25
    2126Allocation receive( derived_actor & receiver, derived_msg & msg ) {
    2227    if ( msg.cnt >= Times ) {
     
    2833    derived_actor * d_actor = alloc();
    2934    (*d_actor){};
    30     *d_actor << *d_msg;
     35    *d_actor | *d_msg;
    3136    return Delete;
    3237}
     
    5863    derived_actor * d_actor = alloc();
    5964    (*d_actor){};
    60     *d_actor << *d_msg;
     65    *d_actor | *d_msg;
    6166
    6267    printf("stopping\n");
  • tests/concurrent/actors/executor.cfa

    rb110bcc r2ed94a9  
    1515};
    1616void ?{}( d_actor & this ) with(this) {
     17    ((actor &)this){};
    1718    id = ids++;
    1819    gstart = (&this + (id / Set * Set - id)); // remember group-start array-element
     
    2324
    2425struct d_msg { inline message; } shared_msg;
     26void ?{}( d_msg & this ) { ((message &) this){ Nodelete }; }
    2527
    2628Allocation receive( d_actor & this, d_msg & msg ) with( this ) {
     
    2830    if ( recs % Batch == 0 ) {
    2931        for ( i; Batch ) {
    30             gstart[sends % Set] << shared_msg;
     32            gstart[sends % Set] | shared_msg;
    3133            sends += 1;
    3234        }
     
    8385        } // switch
    8486
     87   
    8588    executor e{ Processors, Processors, Processors == 1 ? 1 : Processors * 512, true };
    8689
     
    9497
    9598        for ( i; Actors ) {
    96                 actors[i] << shared_msg;
     99                actors[i] | shared_msg;
    97100        } // for
    98101
  • tests/concurrent/actors/matrix.cfa

    rb110bcc r2ed94a9  
    77unsigned int xr = 500, xc = 500, yc = 500, Processors = 1; // default values
    88
    9 struct derived_actor { inline actor; };
     9struct derived_actor {
     10    inline actor;
     11};
     12void ?{}( derived_actor & this ) { ((actor &)this){}; }
    1013
    1114struct derived_msg {
     
    1821void ?{}( derived_msg & this ) {}
    1922void ?{}( derived_msg & this, int * Z, int * X, int ** Y ) {
    20     ((message &) this){ Nodelete };
     23    ((message &) this){ Finished };
    2124    this.Z = Z;
    2225    this.X = X;
     
    105108
    106109        for ( unsigned int r = 0; r < xr; r += 1 ) {
    107                 actors[r] << messages[r];
     110                actors[r] | messages[r];
    108111        } // for
    109112
  • tests/concurrent/actors/pingpong.cfa

    rb110bcc r2ed94a9  
    66#include <actor.hfa>
    77
    8 struct ping { inline actor; };
    9 struct pong { inline actor; };
     8struct ping {
     9    inline actor;
     10};
     11static inline void ?{}( ping & this ) { ((actor &)this){}; }
     12
     13struct pong {
     14    inline actor;
     15};
     16static inline void ?{}( pong & this ) { ((actor &)this){}; }
    1017
    1118struct p_msg {
     
    2532    Allocation retval = Nodelete;
    2633    if ( msg.count == times ) retval = Finished;
    27     *po << msg;
     34    *po | msg;
    2835    return retval;
    2936}
     
    3542    Allocation retval = Nodelete;
    3643    if ( msg.count == times ) retval = Finished;
    37     *pi << msg;
     44    *pi | msg;
    3845    return retval;
    3946}
     
    5360    pi = &pi_actor;
    5461    p_msg m;
    55     pi_actor << m;
     62    pi_actor | m;
    5663    stop_actor_system();
    5764
  • tests/concurrent/actors/static.cfa

    rb110bcc r2ed94a9  
    77int Times = 1000000;                                                            // default values
    88
    9 struct derived_actor { inline actor; };
     9struct derived_actor {
     10    inline actor;
     11};
     12void ?{}( derived_actor & this ) { ((actor &)this){}; }
     13
    1014struct derived_msg {
    1115    inline message;
     
    1923void ?{}( derived_msg & this ) { ((derived_msg &)this){ 0 }; }
    2024
     25
    2126Allocation receive( derived_actor & receiver, derived_msg & msg ) {
    2227    if ( msg.cnt >= Times ) {
     
    2530    }
    2631    msg.cnt++;
    27     receiver << msg;
     32    receiver | msg;
    2833    return Nodelete;
    2934}
     
    5560    derived_actor actor;
    5661
    57     actor << msg;
     62    actor | msg;
    5863
    5964    printf("stopping\n");
  • tests/concurrent/actors/types.cfa

    rb110bcc r2ed94a9  
    1818    int num;
    1919};
     20static inline void ?{}( d_msg & this ) { ((message &)this){}; }
    2021
    2122// this isn't a valid receive routine since int is not a message type
     
    3536    inline actor;
    3637};
     38static inline void ?{}( derived_actor2 & this ) { ((actor &)this){}; }
    3739
    3840Allocation receive( derived_actor2 & receiver, d_msg & msg ) {
     
    4143}
    4244
    43 struct derived_actor3 { inline actor; };
    44 struct derived_actor4 { inline derived_actor3; };
     45struct derived_actor3 {
     46    inline actor;
     47};
     48static inline void ?{}( derived_actor3 & this ) { ((actor &)this){}; }
     49
    4550struct d_msg2 {
    4651    inline message;
    4752    int num;
    4853};
     54static inline void ?{}( d_msg2 & this ) { ((message &)this){}; }
    4955
    5056Allocation receive( derived_actor3 & receiver, d_msg & msg ) {
     
    7278    b.num = 1;
    7379    c.num = 2;
    74     a << b << c;
     80    a | b | c;
    7581    stop_actor_system();
    7682
     
    8086    d_msg d_ac2_msg;
    8187    d_ac2_msg.num = 3;
    82     d_ac2_0 << d_ac2_msg;
    83     d_ac2_1 << d_ac2_msg;
     88    d_ac2_0 | d_ac2_msg;
     89    d_ac2_1 | d_ac2_msg;
    8490    stop_actor_system();
    8591
     
    9399        d_msg d_ac23_msg;
    94100        d_ac23_msg.num = 4;
    95         d_ac3_0 << d_ac23_msg;
    96         d_ac2_2 << d_ac23_msg;
     101        d_ac3_0 | d_ac23_msg;
     102        d_ac2_2 | d_ac23_msg;
    97103        stop_actor_system();
    98104    } // RAII to clean up executor
     
    107113        b1.num = -1;
    108114        c2.num = 5;
    109         a3 << b1 << c2;
    110         stop_actor_system();
    111     } // RAII to clean up executor
    112 
    113     {
    114         printf("nested inheritance actor test\n");
    115         executor e{ 1, Processors, Processors == 1 ? 1 : Processors * 4, true };
    116         start_actor_system( Processors );
    117         derived_actor4 a4;
    118         d_msg b1;
    119         d_msg2 c2;
    120         b1.num = -1;
    121         c2.num = 5;
    122         a4 << b1 << c2;
     115        a3 | b1 | c2;
    123116        stop_actor_system();
    124117    } // RAII to clean up executor
  • tests/concurrent/channels/parallel_harness.hfa

    rb110bcc r2ed94a9  
    100100
    101101int test( size_t Processors, size_t Channels, size_t Producers, size_t Consumers, size_t ChannelSize ) {
    102     size_t Clusters = Processors;
     102    size_t Clusters = 1;
    103103    // create a cluster
    104104    cluster clus[Clusters];
     
    108108    }
    109109
    110     channels = aalloc( Channels );
     110    channels = anew( Channels );
    111111
    112112    // sout | "Processors: " | Processors | " ProdsPerChan: " | Producers | " ConsPerChan: " | Consumers | "Channels: " | Channels | " Channel Size: " | ChannelSize;
     
    139139    while( cons_done_count != Consumers * Channels ) {
    140140        for ( i; Channels ) {
    141             if ( has_waiters( channels[i] ) ){
     141            if ( has_waiting_consumers( channels[i] ) ){
    142142                #ifdef BIG
    143143                bigObject b{0};
     
    150150       
    151151    }
    152 
     152    // for ( i; Channels ) {
     153    //     // sout | get_count( channels[i] );
     154    //     if ( get_count( channels[i] ) < Consumers ){
     155    //         #ifdef BIG
     156    //         bigObject b{0};
     157    //         #endif
     158    //         for ( j; Consumers ) {
     159    //             #ifdef BIG
     160    //             insert( channels[i], b );
     161    //             #else
     162    //             insert( channels[i], 0 );
     163    //             #endif
     164    //         }
     165    //     }
     166    // }
    153167    sout | "cons";
    154168    for ( i; Consumers * Channels ) {
  • tests/concurrent/pthread/.expect/bounded_buffer.x64.txt

    rb110bcc r2ed94a9  
    1 producer total value is 39780
    2 consumer total value is 39780
     1producer total value is 44280
     2consumer total value is 44280
  • tests/concurrent/pthread/.expect/bounded_buffer.x86.txt

    rb110bcc r2ed94a9  
    1 producer total value is 1770
    2 consumer total value is 1770
     1producer total value is 45060
     2consumer total value is 45060
  • tests/concurrent/signal/disjoint.cfa

    rb110bcc r2ed94a9  
    3838
    3939// Use a global struct because the order needs to match with Signaller thread
    40 static struct {
     40struct {
    4141        global_t mut;
    4242        global_data_t data;
  • tests/concurrent/waitfor/parse.cfa

    rb110bcc r2ed94a9  
    1 // 
    2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
     1//----------------------------------------------------------------------------------------
     2//----------------------------------------------------------------------------------------
    33//
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // waitfor.c --
    8 //
    9 // Author           : Peter A. Buhr
    10 // Created On       : Wed Aug 30 17:53:29 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 22:52:18 2023
    13 // Update Count     : 64
    14 //
     4//              DEPRECATED TEST
     5//              DIFFERS BETWEEN DEBUG AND RELEASE
     6//
     7//----------------------------------------------------------------------------------------
     8//----------------------------------------------------------------------------------------
    159
    1610#include <monitor.hfa>
     
    1812monitor M {};
    1913
    20 void notcalled( M & mutex m1, M & mutex m2 ) {
    21         abort();
    22 }
    23 void or( M & mutex m ) {
    24         abort();
    25 }
    26 void timeout( M & mutex m ) {
    27         abort();
     14M a;
     15
     16void f1( M & mutex a );
     17void f2( M & mutex a );
     18void f2( M & mutex a, M & mutex b );
     19void f3( M & mutex a );
     20void f3( M & mutex a, M & mutex b );
     21void f3( M & mutex a, M & mutex b, M & mutex c );
     22
     23void foo() {
     24
     25        //---------------------------------------
     26        waitfor( f1 : a ) {
     27                1;
     28        }
     29
     30        //---------------------------------------
     31        waitfor( f1 : a ) {
     32                2;
     33        }
     34        waitfor( f2 : a ) {
     35                3;
     36        }
     37
     38        //---------------------------------------
     39        when( 1 < 3 ) waitfor( f2 : a, a ) {
     40                4;
     41        }
     42        or timeout( 100 ) {
     43                5;
     44        }
     45
     46        //---------------------------------------
     47        when( 2 < 3 ) waitfor( f3 : a ) {
     48                5;
     49        }
     50        or else {
     51                6;
     52        }
     53
     54        //---------------------------------------
     55        when( 3 < 3 ) waitfor( f3 : a, a ) {
     56                7;
     57        }
     58        or when( 4 < 3 ) timeout( 101 ) {
     59                8;
     60        }
     61        or when( 5 < 3 ) else {
     62                9;
     63        }
     64
     65        //---------------------------------------
     66        when( 6 < 3 ) waitfor( f3 : a, a, a ) {
     67                10;
     68        }
     69        or when( 7 < 3 ) waitfor( f1 : a  ) {
     70                11;
     71        }
     72        or else {
     73                12;
     74        }
     75
     76        //---------------------------------------
     77        when( 8 < 3 ) waitfor( f3 : a, a ) {
     78                13;
     79        }
     80        or waitfor( f1 : a  ) {
     81                14;
     82        }
     83        or when( 9 < 3 ) timeout( 102 ) {
     84                15;
     85        }
     86
     87        //---------------------------------------
     88        when( 10 < 3 ) waitfor( f1 : a ) {
     89                16;
     90        }
     91        or waitfor( f2 : a, a ) {
     92                17;
     93        }
     94        or timeout( 103 ) {
     95                18;
     96        }
     97        or when( 11 < 3 ) else {
     98                19;
     99        }
    28100}
    29101
    30 void fred( M & mutex m, M & mutex or, M & mutex timeout ) {
    31         // test waitfor and when
    32 
    33         waitfor( notcalled : m, m );
    34 
    35         waitfor( notcalled : m, m ) {
    36         }
    37 
    38         waitfor( notcalled : m, m ) {
    39         }
    40 
    41         when( true ) waitfor( notcalled : m, m );
    42 
    43         when( true ) waitfor( notcalled : m, m ) {
    44         }
    45 
    46         waitfor( notcalled : m, m );
    47         or waitfor( notcalled : m, m );
    48 
    49         when( true ) waitfor( notcalled : m, m );
    50         or when( true ) waitfor( notcalled : m, m );
    51 
    52         waitfor( notcalled : m, m ) {
    53         } or waitfor( notcalled : m, m ) {
    54         }
    55 
    56         waitfor( notcalled : m, m ) {
    57         } or waitfor( notcalled : m, m ) {
    58         }
    59 
    60         when( true ) waitfor( notcalled : m, m ) {
    61         } or when( true ) waitfor( notcalled : m, m ) {
    62         }
    63 
    64         waitfor( notcalled : m, m );
    65         or waitfor( notcalled : m, m ) {
    66         }
    67 
    68         when( true ) waitfor( notcalled : m, m );
    69         or when( true ) waitfor( notcalled : m, m ) {
    70         }
    71 
    72         waitfor( notcalled : m, m ) {
    73         } or waitfor( notcalled : m, m );
    74 
    75         when( true ) waitfor( notcalled : m, m ) {
    76         } or when( true ) waitfor( notcalled : m, m );
    77 
    78         // test when, waitfor and else
    79 
    80         waitfor( notcalled : m, m );
    81         or else;
    82 
    83         when( true ) waitfor( notcalled : m, m );
    84         or else;
    85 
    86         when( true ) waitfor( notcalled : m, m );
    87         or else;
    88 
    89         waitfor( notcalled : m, m ) {
    90         } or else {
    91         }
    92 
    93         when( true ) waitfor( notcalled : m, m ) {
    94         } or else {
    95         }
    96 
    97         waitfor( notcalled : m, m );
    98         or else {
    99         }
    100 
    101         when( true ) waitfor( notcalled : m, m );
    102         or else {
    103         }
    104 
    105         when( true ) waitfor( notcalled : m, m );
    106         or else {
    107         }
    108 
    109         waitfor( notcalled : m, m ) {
    110         } or else;
    111 
    112         when( true ) waitfor( notcalled : m, m ) {
    113         } or else;
    114 
    115         waitfor( notcalled : m, m );
    116         or when( true ) else;
    117 
    118         when( true ) waitfor( notcalled : m, m );
    119         or when( true ) else;
    120 
    121         when( true ) waitfor( notcalled : m, m );
    122         or when( true ) else;
    123 
    124         waitfor( notcalled : m, m ) {
    125         } or when( true ) else {
    126         }
    127 
    128         when( true ) waitfor( notcalled : m, m ) {
    129         } or when( true ) else {
    130         }
    131 
    132         waitfor( notcalled : m, m );
    133         or when( true ) else {
    134         }
    135 
    136         when( true ) waitfor( notcalled : m, m );
    137         or when( true ) else {
    138         }
    139 
    140         when( true ) waitfor( notcalled : m, m );
    141         or when( true ) else {
    142         }
    143 
    144         waitfor( notcalled : m, m ) {
    145         } or when( true ) else;
    146 
    147         when( true ) waitfor( notcalled : m, m ) {
    148         } or when( true ) else;
    149 
    150         // test when, waitfor and timeout
    151 
    152         waitfor( notcalled : m, m );
    153         or timeout( 3 );
    154 
    155         waitfor( notcalled : m, m );
    156         or timeout( 3 );
    157 
    158         when( true ) waitfor( notcalled : m, m );
    159         or timeout( 3 );
    160 
    161         waitfor( notcalled : m, m ) {
    162         } or timeout( 3 ) {
    163         }
    164 
    165         when( true ) waitfor( notcalled : m, m ) {
    166         } or timeout( 3 ) {
    167         }
    168 
    169         when( true ) waitfor( notcalled : m, m ) {
    170         } or timeout( 3 ) {
    171         }
    172 
    173         when( true ) waitfor( notcalled : m, m ) {
    174         } or when ( true ) timeout( 3 ) {
    175         }
    176 
    177         when( true ) waitfor( notcalled : m, m ) {
    178         } or when ( true ) timeout( 3 ) {
    179         }
    180 
    181         waitfor( notcalled : m, m );
    182         or timeout( 3 ) {
    183         }
    184 
    185         when( true ) waitfor( notcalled : m, m );
    186         or timeout( 3 ) {
    187         }
    188 
    189         when( true ) waitfor( notcalled : m, m );
    190         or when( true ) timeout( 3 ) {
    191         }
    192 
    193         waitfor( notcalled : m, m ) {
    194         } or timeout( 3 );
    195 
    196         when( true ) waitfor( notcalled : m, m ) {
    197         } or timeout( 3 );
    198 
    199         when( true ) waitfor( notcalled : m, m ) {
    200         } or when( true ) timeout( 3 );
    201 
    202         // test when, waitfor, timeout and else
    203 
    204         waitfor( notcalled : m, m ) {
    205         } or timeout( 3 ) {
    206         } or when( true ) else {}
    207 
    208         when( true ) waitfor( notcalled : m, m ) {
    209         } or timeout( 3 ) {
    210         } or when( true ) else {}
    211 
    212         waitfor( notcalled : m, m ) {
    213         } or timeout( 3 ) {
    214         } or when( true ) else {}
    215 
    216         waitfor( notcalled : m, m ) {
    217         } or when( true ) timeout( 3 ) {
    218         } or when( true ) else {}
    219 
    220         when( true ) waitfor( notcalled : m, m ) {
    221         } or timeout( 3 ) {
    222         } or when( true ) else {}
    223 
    224         waitfor( notcalled : m, m ) {
    225         } or when( true ) timeout( 3 ) {
    226         } or when( true ) else {}
    227 
    228         when( true ) waitfor( notcalled : m, m ) {
    229         } or when( true ) timeout( 3 ) {
    230         } or when( true ) else {}
    231 
    232         // test quasi-keywords "or" and "timeout"
    233 
    234         int or = 0, timeout = 0;
    235         waitfor( timeout : timeout ) timeout += 1; or timeout( timeout );
    236         waitfor( notcalled : or, or ) or += 1; or timeout( or ) 3;
    237         when( or ) waitfor( or : m ) { 4; } or timeout( or ) or += 1;
    238         when( timeout ) waitfor( notcalled : timeout, timeout ) or += 1; or else timeout += 1;
    239         when( or + timeout ) waitfor( or : m ) 4; or when( or ) timeout( or ) 4; or when( or ) else timeout += 1;
    240         when( 3 ) waitfor( or : or ) 3; or when( or ) waitfor( notcalled : or, or ) 4; or else 4;
    241         when( timeout ) waitfor( or : timeout ) 3; or waitfor( notcalled : timeout, or ) 4; or when( or ) timeout( timeout ) 4;
    242         when( 3 ) waitfor( or : timeout ) or += 1;
    243         or waitfor( or : or ) timeout += 1;
    244         or timeout( timeout ) or += 1;
    245         or when( 3 ) else or += 1;
    246 
    247         // test else selection
    248 
    249         if ( or > timeout ) waitfor( or : or ) 3;
    250         else waitfor( timeout : timeout ) 4;
    251 }
    252 
    253 //Dummy main
    254 int main( int argc, char const * argv[] ) {
    255     #pragma GCC warning "Compiled"                      // force non-empty .expect file, NO TABS!!!
    256 }
    257 
    258 // Local Variables: //
    259 // tab-width: 4 //
    260 // compile-command: "cfa waitfor.cfa" //
    261 // End: //
     102int main() {}
  • tests/declarationSpecifier.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Wed Aug 17 08:21:04 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 23 20:53:31 2023
    13 // Update Count     : 8
     12// Last Modified On : Tue Apr 30 18:20:36 2019
     13// Update Count     : 4
    1414//
    1515
     
    2525short int volatile static const x8;
    2626
    27 static const volatile struct { int i; } x10;
    28 static const struct { int i; } volatile x11;
    29 static struct { int i; } const volatile x12;
    30 const static struct { int i; } volatile x13;
    31 struct { int i; } static const volatile x14;
    32 struct { int i; } const static volatile x15;
    33 struct { int i; } const volatile static x16;
     27const volatile struct { int i; } x10;
     28const struct { int i; } volatile x11;
     29struct { int i; } const volatile x12;
     30static const volatile struct { int i; } x13;
     31const static struct { int i; } volatile x14;
     32struct { int i; } static const volatile x15;
     33struct { int i; } const static volatile x16;
     34struct { int i; } const volatile static x17;
    3435
    3536const Int volatile x20;
     
    4243Int volatile static const x27;
    4344
    44 static const volatile struct { Int i; } x29;
    45 static const struct { Int i; } volatile x30;
    46 static struct { Int i; } const volatile x31;
    47 const static struct { Int i; } volatile x32;
    48 struct { Int i; } static const volatile x33;
    49 struct { Int i; } const static volatile x34;
    50 struct { Int i; } const volatile static x35;
     45const volatile struct { Int i; } x29;
     46const struct { Int i; } volatile x30;
     47struct { Int i; } const volatile x31;
     48static const volatile struct { Int i; } x32;
     49const static struct { Int i; } volatile x33;
     50struct { Int i; } static const volatile x34;
     51struct { Int i; } const static volatile x35;
     52struct { Int i; } const volatile static x36;
    5153
    5254_Thread_local int x37;
  • tests/errors/.expect/declaration.txt

    rb110bcc r2ed94a9  
    1 errors/declaration.cfa:16:1 error: duplicate static storage class(es) in declaration of x1: static const volatile short int
     1errors/declaration.cfa:16:1 error: duplicate static in declaration of x1: static const volatile short int
    22
    3 errors/declaration.cfa:17:1 error: conflicting extern & static storage classes in declaration of x2: extern const volatile short int
     3errors/declaration.cfa:17:1 error: conflicting extern & static in declaration of x2: extern const volatile short int
    44
    5 errors/declaration.cfa:18:1 error: conflicting extern & auto storage classes, conflicting extern & static storage classes, conflicting extern & static storage classes, duplicate extern storage class(es) in declaration of x3: extern const volatile short int
     5errors/declaration.cfa:18:1 error: conflicting extern & auto, conflicting extern & static, conflicting extern & static, duplicate extern in declaration of x3: extern const volatile short int
    66
    7 errors/declaration.cfa:19:1 error: duplicate static storage class(es) in declaration of x4: static const volatile instance of const volatile struct __anonymous0
     7errors/declaration.cfa:19:1 error: duplicate static in declaration of x4: static const volatile instance of const volatile struct __anonymous0
    88  with members
    99    i: int
     
    1111
    1212
    13 errors/declaration.cfa:20:1 error: duplicate const qualifier(s), duplicate static storage class(es), duplicate volatile qualifier(s) in declaration of x5: static const volatile instance of const volatile struct __anonymous1
     13errors/declaration.cfa:20:1 error: duplicate const, duplicate static, duplicate volatile in declaration of x5: static const volatile instance of const volatile struct __anonymous1
    1414  with members
    1515    i: int
     
    1717
    1818
    19 errors/declaration.cfa:22:1 error: duplicate static storage class(es) in declaration of x6: static const volatile Int
     19errors/declaration.cfa:22:1 error: duplicate static in declaration of x6: static const volatile Int
    2020
    21 errors/declaration.cfa:24:1 error: duplicate const qualifier(s) in declaration of f01: static inline function
     21errors/declaration.cfa:24:1 error: duplicate const in declaration of f01: static inline function
    2222  with no parameters
    2323  returning const volatile int
    2424
    2525
    26 errors/declaration.cfa:25:1 error: duplicate volatile qualifier(s) in declaration of f02: static inline function
     26errors/declaration.cfa:25:1 error: duplicate volatile in declaration of f02: static inline function
    2727  with no parameters
    2828  returning const volatile int
    2929
    3030
    31 errors/declaration.cfa:26:1 error: duplicate const qualifier(s) in declaration of f03: static inline function
     31errors/declaration.cfa:26:1 error: duplicate const in declaration of f03: static inline function
    3232  with no parameters
    3333  returning const volatile int
    3434
    3535
    36 errors/declaration.cfa:27:1 error: duplicate volatile qualifier(s) in declaration of f04: static inline function
     36errors/declaration.cfa:27:1 error: duplicate volatile in declaration of f04: static inline function
    3737  with no parameters
    3838  returning const volatile int
    3939
    4040
    41 errors/declaration.cfa:28:1 error: duplicate const qualifier(s) in declaration of f05: static inline function
     41errors/declaration.cfa:28:1 error: duplicate const in declaration of f05: static inline function
    4242  with no parameters
    4343  returning const volatile int
    4444
    4545
    46 errors/declaration.cfa:29:1 error: duplicate volatile qualifier(s) in declaration of f06: static inline function
     46errors/declaration.cfa:29:1 error: duplicate volatile in declaration of f06: static inline function
    4747  with no parameters
    4848  returning const volatile int
    4949
    5050
    51 errors/declaration.cfa:30:1 error: duplicate const qualifier(s) in declaration of f07: static inline function
     51errors/declaration.cfa:30:1 error: duplicate const in declaration of f07: static inline function
    5252  with no parameters
    5353  returning const volatile int
    5454
    5555
    56 errors/declaration.cfa:31:1 error: duplicate const volatile qualifier(s) in declaration of f08: static inline function
     56errors/declaration.cfa:31:1 error: duplicate const, duplicate volatile in declaration of f08: static inline function
    5757  with no parameters
    5858  returning const volatile int
    5959
    6060
    61 errors/declaration.cfa:33:1 error: duplicate const volatile qualifier(s) in declaration of f09: static inline function
     61errors/declaration.cfa:33:1 error: duplicate const, duplicate volatile in declaration of f09: static inline function
    6262  with no parameters
    6363  returning const volatile int
    6464
    6565
    66 errors/declaration.cfa:34:1 error: duplicate const qualifier(s), duplicate _Atomic qualifier(s), duplicate _Atomic qualifier(s), duplicate const restrict volatile qualifier(s) in declaration of f09: static inline function
     66errors/declaration.cfa:34:1 error: duplicate const, duplicate _Atomic, duplicate _Atomic, duplicate const, duplicate restrict, duplicate volatile in declaration of f09: static inline function
    6767  with no parameters
    6868  returning const restrict volatile _Atomic int
  • tests/forall.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Wed May  9 08:48:15 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 23 20:29:59 2023
    13 // Update Count     : 91
     12// Last Modified On : Sun Feb  5 07:54:43 2023
     13// Update Count     : 90
    1414//
    1515
     
    195195
    196196forall( T ) struct S { T t; } (int) x, y, z;
    197 static forall( T ) struct { T t; } (int) a, b, c;
     197forall( T ) struct { T t; } (int) a, b, c;
    198198
    199199forall( T ) static forall( S ) {
  • tests/function-operator.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Fri Aug 25 15:21:11 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 25 07:26:10 2023
    13 // Update Count     : 12
     12// Last Modified On : Thu Apr 11 18:27:45 2019
     13// Update Count     : 10
    1414//
    1515
     
    2222
    2323// STL-like Algorithms
    24 forall(T &, U &)
    25 trait Assignable { T ?=?(T &, U); };
    26 forall(T &)
    27 trait Copyable { void ?{}(T &, T); };
    28 forall(T &)
    29 trait Destructable { void ^?{}(T &); };
     24trait Assignable(T &, U &) { T ?=?(T &, U); };
     25trait Copyable(T &) { void ?{}(T &, T); };
     26trait Destructable(T &) { void ^?{}(T &); };
    3027
    3128trait Iterator(iter & | sized(iter) | Copyable(iter) | Destructable(iter), T) {
  • tests/include/includes.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 22 10:16:58 2023
    13 // Update Count     : 811
     12// Last Modified On : Sun May 22 08:27:20 2022
     13// Update Count     : 779
    1414//
    1515
     
    7272#include <gshadow.h>
    7373#include <iconv.h>
    74 //#include <ifaddrs.h>                                                                  // causes warning messages that break the build
     74#include <ifaddrs.h>
    7575#include <inttypes.h>
    7676#include <langinfo.h>
     
    9797#include <ncurses_dll.h>                                                                // may not be installed, comes with ncurses
    9898#endif
    99 //#include <netdb.h>
     99#include <netdb.h>
    100100#include <nl_types.h>
    101101#include <nss.h>
     
    111111#include <pwd.h>
    112112#include <regex.h>
    113 //#include <resolv.h>
     113#include <resolv.h>
    114114#include <re_comp.h>
    115115#include <sched.h>
     
    170170#endif // __CFA__
    171171
    172 int main() {
     172int main( int argc, char const * argv[] ) {
    173173    #pragma GCC warning "Compiled"                                                      // force non-empty .expect file, NO TABS!!!
    174174}
  • tests/io/comp_basic.cfa

    rb110bcc r2ed94a9  
    2626#include <unistd.h>
    2727
    28 static struct {
     28struct {
    2929        barrier & bar;
    3030        int pipe[2];
     31
    3132} globals;
    3233
  • tests/io/comp_fair.cfa

    rb110bcc r2ed94a9  
    2626#include <unistd.h>
    2727
    28 static struct {
     28struct {
    2929        barrier & bar;
    3030        int pipe[2];
     31
    3132} globals;
    3233
  • tests/linking/mangling/header.hfa

    rb110bcc r2ed94a9  
    88extern name_but_a_typedefed_t a_typedefed_global;
    99
    10 // Must be extern C to prevent name mangling.
    11 extern "C" {
    12         extern struct /* anonymous */ {
    13                 int some_int;
    14                 int some_other_int;
    15         } a_global_with_no_type;
    16 }
     10extern struct /* anonymous */ {
     11        int some_int;
     12        int some_other_int;
     13} a_global_with_no_type;
  • tests/linking/mangling/lib.cfa

    rb110bcc r2ed94a9  
    33name_but_a_typedefed_t a_typedefed_global;
    44
    5 // Must be extern C to prevent name mangling.
    6 extern "C" {
    7         // This declaration is necessary to create an instance of a_global_with_no_type.
    8         // typeof is a trick to get a_global_with_no_type's type because its type is anonymous.
    9         // Otherwise C generates conflicting types for a_global_with_no_type in .h and .c
    10         // because C uses name equivalence and the two anonymous types cannot have the same name.
    11         typeof(a_global_with_no_type) a_global_with_no_type;
    12 }
     5struct {
     6        int some_int;
     7        int some_other_int;
     8} a_global_with_no_type;
  • tests/linking/mangling/main.cfa

    rb110bcc r2ed94a9  
    11#include <fstream.hfa>
    22
    3 static struct { int a; } test; // purposefully before the include to force anonymous name numbering
     3struct { int a; } test; //purposefully before the include
    44
    55#include "header.hfa"
     
    1313
    1414        sout | "Done!";
     15
     16        return 0;
    1517}
  • tests/pybin/settings.py

    rb110bcc r2ed94a9  
    126126        global archive
    127127        global install
    128         global invariant
    129128
    130129        global continue_
     
    141140        all_install  = [Install(o)      for o in list(dict.fromkeys(options.install))]
    142141        archive      = os.path.abspath(os.path.join(original_path, options.archive_errors)) if options.archive_errors else None
    143         invariant    = options.invariant
    144142        continue_    = options.continue_
    145143        dry_run      = options.dry_run # must be called before tools.config_hash()
  • tests/quotedKeyword.cfa

    rb110bcc r2ed94a9  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 23 20:31:05 2023
    13 // Update Count     : 26
     12// Last Modified On : Fri Feb  7 19:07:07 2020
     13// Update Count     : 25
    1414//
    1515
    1616#include <fstream.hfa>
    1717
    18 static struct {
     18struct {
    1919        int ``otype;
    2020        int ``struct;
  • tests/sum.cfa

    rb110bcc r2ed94a9  
    1111// Created On       : Wed May 27 17:56:53 2015
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Fri Feb 24 22:52:12 2023
    14 // Update Count     : 347
     13// Last Modified On : Thu Aug  5 21:27:25 2021
     14// Update Count     : 346
    1515//
    1616
     
    1818#include <stdlib.hfa>
    1919
    20 forall( T )
    21 trait sumable {
     20trait sumable( T ) {
    2221        void ?{}( T &, zero_t );                                                        // 0 literal constructor
    2322        void ?{}( T &, one_t );                                                         // 1 literal constructor
  • tests/test.py

    rb110bcc r2ed94a9  
    114114        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
    115115        parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
    116         parser.add_argument('--invariant', help='Tell the compiler to check invariants while running.', action='store_true')
    117116        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180)
    118117        parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
     
    173172        test.prepare()
    174173
    175         # extra flags for cfa to pass through make.
    176         cfa_flags = 'CFAFLAGS=--invariant' if settings.invariant else None
    177 
    178174        # ----------
    179175        # MAKE
     
    181177        # build, skipping to next test on error
    182178        with Timed() as comp_dur:
    183                 make_ret, _, _ = make(test.target(), flags=cfa_flags, output_file=subprocess.DEVNULL, error=out_file, error_file=err_file)
     179                make_ret, _, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
    184180
    185181        # ----------
Note: See TracChangeset for help on using the changeset viewer.