Changeset b110bcc


Ignore:
Timestamp:
Apr 21, 2023, 5:36:12 PM (2 years ago)
Author:
JiadaL <j82liang@…>
Branches:
ADT, master
Children:
28f8f15, 6e4c44d
Parents:
2ed94a9 (diff), 699a97d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
227 added
5 deleted
179 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/Promote

    r2ed94a9 rb110bcc  
    3636                dir (BuildDir) {
    3737                    sh 'rm -rf *'
    38                         sshagent (credentials: ['github_key_jun1']) {
     38                        sshagent (credentials: ['git_key_mar27']) {
    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: ['github_key_jun1']) {
     71                        sshagent (credentials: ['git_key_mar27']) {
    7272                                sh "git push origin master"
    7373                        }
  • doc/LaTeXmacros/common.sty

    r2ed94a9 rb110bcc  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sat Apr  2 17:35:23 2022
    14 %% Update Count     : 570
     13%% Last Modified On : Tue Apr  4 12:03:19 2023
     14%% Update Count     : 585
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    3030\setlist[itemize,1]{label=\textbullet}% local
    3131%\renewcommand{\labelitemi}{{\raisebox{0.25ex}{\footnotesize$\bullet$}}}
    32 \setlist[enumerate]{listparindent=\parindent}% global
     32\setlist[enumerate]{topsep=0.5ex,parsep=0.25ex,itemsep=0.25ex,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}{\Large$^\sharp$}\xspace} % C# symbolic name
     51\newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name
    5252
    5353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    5454
    55 \usepackage{pslatex}                                                                    % reduce size of san serif font
     55\usepackage[scaled=0.85]{helvet}                                                % descent Helvetica font and scale to times size
     56\usepackage[T1]{fontenc}
    5657\usepackage{relsize}                                                                    % must be after change to small or selects old size
    5758\usepackage{rotating}
     
    195196\newcommand{\viz}{\VIZ\CheckPeriod}
    196197
     198\newcommand{\VS}{\abbrevFont{vs}}
     199\newcommand{\vs}{\VS\CheckPeriod}
     200
    197201\newenvironment{cquote}{%
    198202        \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
     
    244248\renewcommand{\reftextpagerange}[2]{\unskip, pp.~\pageref{#1}--\pageref{#2}}
    245249\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}}
    246251\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}}
    247253
    248254\let\Oldthebibliography\thebibliography
     
    260266\newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
    261267\newcommand{\LstStringStyle}[1]{{\lst@basicstyle{\lst@stringstyle{#1}}}}
     268\newcommand{\LstNumberStyle}[1]{{\lst@basicstyle{\lst@numberstyle{#1}}}}
    262269
    263270\newlength{\gcolumnposn}                                % temporary hack because lstlisting does not handle tabs correctly
     
    280287columns=fullflexible,
    281288basicstyle=\linespread{0.9}\sf,                 % reduce line spacing and use sanserif font
    282 stringstyle=\tt,                                                % use typewriter font
     289stringstyle=\small\tt,                                  % use typewriter font
    283290tabsize=5,                                                              % N space tabbing
    284291xleftmargin=\parindentlnth,                             % indent code to paragraph indentation
  • doc/LaTeXmacros/common.tex

    r2ed94a9 rb110bcc  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Tue Apr 26 16:02:48 2022
    14 %% Update Count     : 558
     13%% Last Modified On : Tue Apr  4 12:03:18 2023
     14%% Update Count     : 567
    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}{\Large$^\sharp$}\xspace} % C# symbolic name
     51\newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name
    5252
    5353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    5454
    55 \usepackage{pslatex}                                                                    % reduce size of san serif font
     55\usepackage[scaled=0.85]{helvet}                                                % descent Helvetica font and scale to times size
     56\usepackage[T1]{fontenc}
    5657\usepackage{relsize}                                                                    % must be after change to small or selects old size
    5758\usepackage{rotating}
     
    196197\newcommand{\viz}{\VIZ\CheckPeriod}
    197198
     199\newcommand{\VS}{\abbrevFont{vs}}
     200\newcommand{\vs}{\VS\CheckPeriod}
    198201\makeatother
    199202
     
    266269\newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
    267270\newcommand{\LstStringStyle}[1]{{\lst@basicstyle{\lst@stringstyle{#1}}}}
     271\newcommand{\LstNumberStyle}[1]{{\lst@basicstyle{\lst@numberstyle{#1}}}}
    268272
    269273\newlength{\gcolumnposn}                                % temporary hack because lstlisting does not handle tabs correctly
     
    287291columns=fullflexible,
    288292basicstyle=\linespread{0.9}\sf,                 % reduce line spacing and use sanserif font
    289 stringstyle=\tt,                                                % use typewriter font
     293stringstyle=\small\tt,                                  % use typewriter font
    290294tabsize=5,                                                              % N space tabbing
    291295xleftmargin=\parindentlnth,                             % indent code to paragraph indentation
  • doc/bibliography/pl.bib

    r2ed94a9 rb110bcc  
    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     booktitle   = {Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation},
     149    organization= {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,
    198208}
    199209
     
    245255}
    246256
     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
    247291@article{dim:ada,
    248292    keywords    = {Dimensional Analysis, Ada},
     
    256300    number      = 2,
    257301    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},
    258317}
    259318
     
    377436    year        = 2016,
    378437    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,
    379447}
    380448
     
    548616}
    549617
     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
    550644@article{Sinha00,
    551645    author      = {Saurabh Sinha and Mary Jean Harrold},
     
    562656    author      = {Martin P. Robillard and Gail C. Murphy},
    563657    title       = {Analyzing Exception Flow in {J}ava Programs},
    564     booktitle   = {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly
     658    organization= {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly
    565659                   with the 7th ACM SIGSOFT International Symposium on Foundations of Software Engineering},
    566660    year        = 1999,
     
    604698    author      = {Henry Qin and Qian Li and Jacqueline Speiser and Peter Kraft and John Ousterhout},
    605699    title       = {Arachne: Core-Aware Thread Management},
    606     booktitle   = {13th {USENIX} Symp. on Oper. Sys. Design and Impl. ({OSDI} 18)},
     700    organization= {13th {USENIX} Symp. on Oper. Sys. Design and Impl. ({OSDI} 18)},
    607701    year        = {2018},
    608702    address     = {Carlsbad, CA},
     
    661755    author      = {Jaewoong Chung and Luke Yen and Stephan Diestelhorst and Martin Pohlack and Michael Hohmuth and David Christie and Dan Grossman},
    662756    title       = {ASF: AMD64 Extension for Lock-Free Data Structures and Transactional Memory},
    663     booktitle   = {Proceedings of the 2010 43rd Annual IEEE/ACM International Symposium on Microarchitecture},
     757    organization= {Proceedings of the 2010 43rd Annual IEEE/ACM International Symposium on Microarchitecture},
    664758    series      = {MICRO '43},
    665759    year        = 2010,
     
    682776}
    683777
     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
    684787@inproceedings{Krischer08,
    685788    keywords    = {exception handling, asynchronous, blocked tasks},
     
    687790    author      = {Roy Krischer and Peter A. Buhr},
    688791    title       = {Asynchronous Exception Propagation in Blocked Tasks},
    689     booktitle   = {4th International Workshop on Exception Handling (WEH.08)},
     792    organization= {4th International Workshop on Exception Handling (WEH.08)},
    690793    optorganization= {16th International Symposium on the Foundations of Software Engineering (FSE 16)},
    691794    address     = {Atlanta, U.S.A},
     
    696799
    697800@article{Joung00,
     801    keywords    = {group mutual exclusion, congenial talking philosophers, resource allocation, shared-memory algorithms},
    698802    author      = {Joung, Yuh-Jzer},
    699803    title       = {Asynchronous group mutual exclusion},
     
    759863    publisher   = {ACM},
    760864    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,
    761874}
    762875
     
    9161029}
    9171030
     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
    9181044% C
    9191045
     
    9881114    year        = 2015,
    9891115    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},
    9901130}
    9911131
     
    11721312@techreport{Prokopec11,
    11731313    keywords    = {ctrie, concurrent map},
    1174     contributer = {a3moss@uwaterloo.ca},
     1314    contributer = {a3moss@uwaterloo.ca},
    11751315    title       = {Cache-aware lock-free concurrent hash tries},
    11761316    author      = {Prokopec, Aleksandar and Bagwell, Phil and Odersky, Martin},
     
    14961636    author      = {Emery D. Berger and Benjamin G. Zorn and Kathryn S. McKinley},
    14971637    title       = {Composing High-Performance Memory Allocators},
    1498     booktitle   = {{SIGPLAN} Conference on Programming Language Design and Implementation},
     1638    organization= {{SIGPLAN} Conference on Programming Language Design and Implementation},
    14991639    pages       = {114-124},
    15001640    year        = 2001,
     
    19962136    address     = {Eindhoven, Neth.},
    19972137    year        = 1965,
    1998     note        = {Reprinted in \cite{Genuys68} pp. 43--112.}
     2138    optnote     = {Reprinted in \cite{Genuys68} pp. 43--112.},
     2139    note        = {\url{https://pure.tue.nl/ws/files/4279816/344354178746665.pdf}},
    19992140}
    20002141
     
    20032144    author      = {Adya, Atul and Howell, Jon and Theimer, Marvin and Bolosky, William J. and Douceur, John R.},
    20042145    title       = {Cooperative Task Management Without Manual Stack Management},
    2005     booktitle   = {Proc. of the General Track USENIX Tech. Conf.},
     2146    organization= {Proc. of the General Track USENIX Tech. Conf.},
    20062147    series      = {ATEC '02},
    20072148    year        = {2002},
     
    21112252    year        = 2016,
    21122253    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},
    21132265}
    21142266
     
    23702522    editor      = {R. E. A. Mason},
    23712523    organization= {IFIP},
    2372     publisher = {North-Holland},
    2373     summary = {
     2524    publisher   = {North-Holland},
     2525    summary     = {
    23742526        Packages group related declarations or subprograms, and encapsulate
    23752527        data types.  Separate interfaces and bodies promotes information
     
    25982750    address     = {Waterview Corporate Center, 20 Waterview Boulevard, Parsippany, NJ 07054},
    25992751    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},
    26002767}
    26012768
     
    26312798    year        = 2003,
    26322799    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},
    26332822}
    26342823
     
    27342923}
    27352924
     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
    27362938@techreport{Habermann80,
    27372939    keywords    = {Ada, threads},
     
    28083010    title       = {Encapsulation and Inheritance in Object-Oriented Programming Languages},
    28093011    journal     = sigplan,
    2810     volume      = {21},    number = {11},
     3012    volume      = {21},
     3013    number      = {11},
    28113014    pages       = {38-45},
    2812     month       = nov, year = 1986,
     3015    month       = nov,
     3016    year        = 1986,
    28133017    comment     = {
    28143018        Client, child interfaces should be distinct.  Child interface
     
    28663070}
    28673071
     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
    28683085@manual{EPT,
    28693086    keywords    = {concurrency, light-weight threads},
     
    29033120    publisher   = {North Oxford Academic},
    29043121    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},
    29053132}
    29063133
     
    36143841    author      = {Robert Griesemer and Rob Pike and Ken Thompson},
    36153842    title       = {{Go} Programming Language},
     3843    address     = {Mountain View, CA, USA},
    36163844    organization= {Google},
    36173845    year        = 2009,
     
    37253953@article{Michael04a,
    37263954    keywords    = {Lock-free, synchronization, concurrent programming, memory management, multiprogramming, dynamic data structures},
     3955    contributer = {pabuhr@plg},
    37273956    author      = {Maged M. Michael},
    37283957    title       = {Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects},
     
    37353964    publisher   = {IEEE Press},
    37363965    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},
    37373980}
    37383981
     
    39174160    year        = {1994},
    39184161    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},
    39194174}
    39204175
     
    46954950    contributer = {pabuhr@plg},
    46964951    author      = {Lua},
    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,
     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,
    47004956}
    47014957
     
    52775533        Programming Language},
    52785534    year        = 1980,
    5279     month       = dec, pages = {139-145},
     5535    month       = dec,
     5536    pages       = {139-145},
    52805537    note        = {SIGPLAN Notices, v. 15, n. 11},
    52815538    abstract    = {
     
    53985655    year        = 2005,
    53995656    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},
    54005669    publisher   = {ACM},
    54015670    address     = {New York, NY, USA},
     
    56465915}
    56475916
     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
    56485926@inproceedings{Krebbers14,
    56495927    keywords    = {c formalization},
     
    58836161}
    58846162
     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
    58856174@incollection{Stroustrup96,
    58866175    keywords    = {concurrency, C++},
     
    59176206    journal     = ieeese,
    59186207    year        = 1984,
    5919     month       = sep, volume = "SE-10", number = 5, pages = {528-543},
     6208    month       = sep,
     6209    volume      = "SE-10",
     6210    number      = 5,
     6211    pages       = {528-543},
    59206212    abstract    = {
    59216213        Parameterized programming is a powerful technique for the reliable
     
    59496241    booktitle   = {USENIX {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Conference},
    59506242    organization= {USENIX Association},
    5951     year        = 1988, pages = {1-18}
     6243    year        = 1988,
     6244    pages       = {1-18},
    59526245}
    59536246
     
    60376330}
    60386331
     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
    60396357@article{Anderson90,
    60406358    keywords    = {spin locks, back off, performance},
     
    60486366    number      = 1,
    60496367    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},
    60506382}
    60516383
     
    67607092}
    67617093
    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}
     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},
    67947105}
    67957106
     
    69277238    journal     = sigplan,
    69287239    year        = 1991,
    6929     month       = oct, volume = 26, number = 10, pages = {29-43},
     7240    month       = oct,
     7241    volume      = 26,
     7242    number      = 10,
     7243    pages       = {29-43},
    69307244    abstract    = {
    69317245        {\tt lcc} is a new retargetable compiler for ANSI C.  Versions for
     
    70177331    publisher   = {ACM},
    70187332    address     = {New York, NY, USA},
    7019     booktitle   = {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
     7333    organization= {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
    70207334    pages       = {67-80},
    70217335    numpages    = {14},
     
    70497363}
    70507364
     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
    70517378@article{Anderson92,
    70527379    keywords    = {light-weight tasks},
     
    70627389}
    70637390
     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
    70647432@manual{SELF,
    70657433    keywords    = {programming language, obect-oriented, polymorphism},
     
    70837451    publisher   = {Springer},
    70847452    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,
    70857462}
    70867463
     
    71507527    publisher   = {Morgan \& Claypool},
    71517528    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}
    71527538}
    71537539
     
    78338219}
    78348220
     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
    78358232@article{Boehm05,
    78368233    keywords    = {concurrency, C++},
     
    80608457}
    80618458
     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
    80628468@article{concatenation,
    80638469    keywords    = {record concatenation, isa},
     
    81248530    author      = {Paul R. Wilson},
    81258531    title       = {Uniprocessor Garbage Collection Techniques},
    8126     booktitle   = {Proceedings of the International Workshop on Memory Management},
     8532    organization= {Proceedings of the International Workshop on Memory Management},
    81278533    location    = {St. Malo, France},
    81288534    publisher   = {Springer},
     
    81378543    author      = {Carl Hewitt and Peter Bishop and Richard Steiger},
    81388544    title       = {A Universal Modular {ACTOR} Formalism for Artificial Intelligence},
    8139     booktitle   = {Proceedings of the 3rd International Joint Conference on Artificial Intelligence},
     8545    organization= {Proceedings of the 3rd International Joint Conference on Artificial Intelligence},
    81408546    address     = {Standford, California, U.S.A.},
    81418547    pages       = {235-245},
     8548    location    = {Stanford, USA},
     8549    series      = {IJCAI'73},
    81428550    month       = aug,
    81438551    year        = 1973,
     
    81718579@article{Karsten20,
    81728580    author      = {Karsten, Martin and Barghi, Saman},
    8173     title       = {{User-level Threading: Have Your Cake and Eat It Too}},
     8581    title       = {User-level Threading: Have Your Cake and Eat It Too},
    81748582    year        = {2020},
    81758583    issue_date  = {March 2020},
     
    81968604}
    81978605
     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
    81988618@article{delegation,
    81998619    keywords    = {delegation, inheritance, actors},
     
    83458765    year        = 2003,
    83468766    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},
    83478794}
    83488795
  • doc/theses/mike_brooks_MMath/Makefile

    r2ed94a9 rb110bcc  
    88PicSRC = ${notdir ${wildcard ${Pictures}/*.png}}
    99DemoSRC = ${notdir ${wildcard ${Programs}/*-demo.cfa}}
    10 PgmSRC = ${notdir ${wildcard ${Programs}/*.cfa}}
     10PgmSRC = ${notdir ${wildcard ${Programs}/*}}
     11RunPgmSRC = ${notdir ${wildcard ${Programs}/*.run.*}}
    1112BibSRC = ${wildcard *.bib}
    1213
     
    1415BibLIB = .:../../bibliography                   # common citation repository
    1516
    16 MAKEFLAGS = --no-print-directory # --silent
     17#MAKEFLAGS = --no-print-directory # --silent
    1718VPATH = ${Build} ${Pictures} ${Programs} # extra search path for file names used in document
    1819
     
    2021BASE = ${basename ${DOCUMENT}}                  # remove suffix
    2122
     23DemoTex = ${DemoSRC:%.cfa=${Build}/%.tex}
     24RunPgmExe = ${addprefix ${Build}/,${basename ${basename ${RunPgmSRC}}}}
     25RunPgmOut = ${RunPgmExe:%=%.out}
     26
    2227# Commands
    2328
    2429LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && pdflatex -halt-on-error -output-directory=${Build}
    2530BibTeX = BIBINPUTS=${BibLIB} && export BIBINPUTS && bibtex
    26 CFA = cfa
     31CFA = cfa -O0 -g
     32CC  = gcc -O0 -g
     33CXX = g++-11 --std=c++20 -O0 -g
    2734
    2835# Rules and Recipes
    2936
    30 .PHONY : all clean                              # not file names
     37.PHONY : all fragments_ran clean                        # not file names
     38.PRECIOUS : ${Build}/% ${Build}/%-demo      # don't delete intermediates
    3139.ONESHELL :
    3240
    33 all : ${DOCUMENT}
     41all : fragments_ran ${DOCUMENT}
     42
     43fragments_ran : $(RunPgmOut)
    3444
    3545clean :
     
    3848# File Dependencies
    3949
    40 %.pdf : ${TeXSRC} ${DemoSRC:%.cfa=%.tex} ${PicSRC} ${PgmSRC} ${BibSRC} Makefile | ${Build}
     50%.pdf : ${TeXSRC} ${DemoTex} ${PicSRC} ${PgmSRC} ${BibSRC} Makefile | ${Build}
    4151        ${LaTeX} ${BASE}
    4252        ${BibTeX} ${Build}/${BASE}
     
    5262
    5363%-demo.tex: %-demo | ${Build}
    54         ${Build}/$< > ${Build}/$@
     64        $< > $@
    5565
    56 %-demo: %-demo.cfa
    57         ${CFA} $< -o ${Build}/$@
     66${Build}/%-demo: ${Programs}/%-demo.cfa | ${Build}
     67        ${CFA} $< -o $@
    5868
     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

    r2ed94a9 rb110bcc  
    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

    r2ed94a9 rb110bcc  
    6060% For hyperlinked PDF, suitable for viewing on a computer, use this:
    6161\documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
     62\usepackage{times}
    6263\usepackage[T1]{fontenc}        % Latin-1 => 256-bit characters, => | not dash, <> not Spanish question marks
    6364
     
    8788\usepackage{comment} % Removes large sections of the document.
    8889\usepackage{tabularx}
    89 \usepackage{subfigure}
     90\usepackage[labelformat=simple,aboveskip=0pt,farskip=0pt,font=normalsize]{subfig}
     91\renewcommand\thesubfigure{(\alph{subfigure})}
    9092
    9193\usepackage{algorithm}
     
    115117    citecolor=blue,        % color of links to bibliography
    116118    filecolor=magenta,      % color of file links
    117     urlcolor=blue           % color of external links
     119    urlcolor=blue,           % color of external links
     120    breaklinks=true
    118121}
    119122\ifthenelse{\boolean{PrintVersion}}{   % for improved print quality, change some hyperref options
     
    129132% although it's supposed to be in both the TeX Live and MikTeX distributions. There are also documentation and
    130133% installation instructions there.
     134
     135% Customizing tabularx
     136\newcolumntype{Y}{>{\centering\arraybackslash}X}
    131137
    132138% Setting up the page margins...
     
    175181\CFAStyle                                               % CFA code-style
    176182\lstset{language=CFA}                                   % default language
    177 \lstset{basicstyle=\linespread{0.9}\tt}                 % CFA typewriter font
     183\lstset{basicstyle=\linespread{0.9}\sf}                 % CFA typewriter font
    178184\lstset{inputpath={programs}}
    179185\newcommand{\PAB}[1]{{\color{red}PAB: #1}}
     186
     187\newcommand{\uCpp}{$\mu$\CC}
    180188
    181189%======================================================================
     
    201209%----------------------------------------------------------------------
    202210\begin{sloppypar}
    203 
    204211\input{intro}
    205212\input{background}
     213\input{list}
    206214\input{array}
    207215\input{string}
  • driver/cfa.cc

    r2ed94a9 rb110bcc  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 14 21:55:12 2021
    13 // Update Count     : 467
     12// Last Modified On : Mon Apr 10 21:16:00 2023
     13// Update Count     : 476
    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.
    4650        if ( putenv( (char *)( *new string( string( __CFA_FLAGPREFIX__ + to_string( flags++ ) + "__=" ) + arg ) ).c_str() ) ) {
    4751                cerr << argv[0] << " error, cannot set environment variable." << endl;
     
    198202                                } // if
    199203                        } else if ( arg == "-CFA" ) {
    200                                 CFA_flag = true;                                                // strip the -CFA flag
     204                                CFA_flag = true;                                                // strip -CFA flag
    201205                                link = false;
    202206                                args[nargs++] = "-fsyntax-only";                // stop after stage 2
    203207                        } else if ( arg == "-debug" ) {
    204                                 debug = true;                                                   // strip the debug flag
     208                                debug = true;                                                   // strip debug flag
    205209                        } else if ( arg == "-nodebug" ) {
    206                                 debug = false;                                                  // strip the nodebug flag
     210                                debug = false;                                                  // strip nodebug flag
    207211                        } else if ( arg == "-quiet" ) {
    208                                 quiet = true;                                                   // strip the quiet flag
     212                                quiet = true;                                                   // strip quiet flag
    209213                        } else if ( arg == "-noquiet" ) {
    210                                 quiet = false;                                                  // strip the noquiet flag
     214                                quiet = false;                                                  // strip noquiet flag
     215                        } else if ( arg == "-invariant" ) {
     216                                Putenv( argv, "-" + arg );
     217                        } else if ( arg == "--invariant" ) {
     218                                Putenv( argv, arg );
    211219                        } else if ( arg == "-no-include-stdhdr" ) {
    212                                 noincstd_flag = true;                                   // strip the no-include-stdhdr flag
     220                                noincstd_flag = true;                                   // strip no-include-stdhdr flag
    213221                        } else if ( arg == "-nolib" ) {
    214                                 nolib = true;                                                   // strip the nolib flag
     222                                nolib = true;                                                   // strip nolib flag
    215223                        } else if ( arg == "-help" ) {
    216                                 help = true;                                                    // strip the help flag
     224                                help = true;                                                    // strip help flag
    217225                        } else if ( arg == "-nohelp" ) {
    218                                 help = false;                                                   // strip the nohelp flag
     226                                help = false;                                                   // strip nohelp flag
    219227                        } else if ( arg == "-cfalib") {
    220228                                compiling_libs = true;
     
    274282                                } // if
    275283                        } else if ( prefix( arg, "-B" ) ) {
    276                                 bprefix = arg.substr(2);                                // strip the -B flag
     284                                bprefix = arg.substr(2);                                // strip -B flag
    277285                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    278286                                args[nargs++] = argv[i];                                // pass flag along
     
    444452
    445453        args[nargs++] = "-fexceptions";                                         // add exception flags (unconditionally)
     454        args[nargs++] = "-D_GNU_SOURCE";                                        // force gnu libraries
    446455
    447456        // add flags based on the type of compile
  • libcfa/src/Makefile.am

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

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

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Fri Jan 14 07:18:11 2022
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Dec 22 20:54:22 2022
    13 // Update Count     : 178
     12// Last Modified On : Mon Mar 20 21:45:24 2023
     13// Update Count     : 186
    1414//
    1515
     
    2828        #define XOSHIRO256PP
    2929        //#define KISS_64
     30    // #define SPLITMIX_64
    3031
    3132        // 32-bit generators
    3233        //#define XORSHIFT_6_21_7
    3334        #define XOSHIRO128PP
     35    // #define SPLITMIX_32
    3436#else                                                                                                   // 32-bit architecture
    3537        // 64-bit generators
    3638        //#define XORSHIFT_13_7_17
    3739        #define XOSHIRO256PP
     40    // #define SPLITMIX_64
    3841
    3942        // 32-bit generators
    4043        //#define XORSHIFT_6_21_7
    4144        #define XOSHIRO128PP
     45    // #define SPLITMIX_32
    4246#endif // __x86_64__
    4347
    4448// 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.
    4749
    4850#ifdef XOSHIRO256PP
    4951#define PRNG_NAME_64 xoshiro256pp
    5052#define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t)
    51 typedef struct PRNG_STATE_64_T { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T;
     53typedef struct { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T;
    5254#endif // XOSHIRO256PP
    5355
     
    5557#define PRNG_NAME_32 xoshiro128pp
    5658#define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t)
    57 typedef struct PRNG_STATE_32_T { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T;
     59typedef struct { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T;
    5860#endif // XOSHIRO128PP
    5961
     
    8385#endif // XORSHIFT_12_25_27
    8486
     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
    8597#ifdef KISS_64
    8698#define PRNG_NAME_64 kiss_64
    8799#define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t)
    88 typedef struct PRNG_STATE_64_T { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;
     100typedef struct { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;
    89101#endif // KISS_^64
    90102
     
    92104#define PRNG_NAME_32 xorwow
    93105#define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t)
    94 typedef struct PRNG_STATE_32_T { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;
     106typedef struct { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;
    95107#endif // XOSHIRO128PP
    96108
     
    119131#ifdef __cforall                                                                                // don't include in C code (invoke.h)
    120132
     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.
     138static 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
     146static 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
     156static 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
     164static 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//--------------------------------------------------
     171static 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
     177static 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//--------------------------------------------------
     183static 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
     194static 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
    121199// https://prng.di.unimi.it/xoshiro256starstar.c
    122200//
     
    130208
    131209#ifndef XOSHIRO256PP
    132 typedef struct xoshiro256pp_t { uint64_t s0, s1, s2, s3; } xoshiro256pp_t;
     210typedef struct { uint64_t s0, s1, s2, s3; } xoshiro256pp_t;
    133211#endif // ! XOSHIRO256PP
    134212
     
    151229
    152230static inline void xoshiro256pp_set_seed( xoshiro256pp_t & state, uint64_t seed ) {
    153         state = (xoshiro256pp_t){ seed, seed, seed, seed };
    154         xoshiro256pp( state );
     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 };
    155237} // xoshiro256pp_set_seed
    156238
     
    165247
    166248#ifndef XOSHIRO128PP
    167 typedef struct xoshiro128pp_t { uint32_t s0, s1, s2, s3; } xoshiro128pp_t;
     249typedef struct { uint32_t s0, s1, s2, s3; } xoshiro128pp_t;
    168250#endif // ! XOSHIRO128PP
    169251
     
    186268
    187269static inline void xoshiro128pp_set_seed( xoshiro128pp_t & state, uint32_t seed ) {
    188         state = (xoshiro128pp_t){ seed, seed, seed, seed };
    189         xoshiro128pp( state );                                                          // prime
     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 };
    190276} // 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__
    223277
    224278//--------------------------------------------------
     
    232286
    233287static inline void xorshift_13_7_17_set_seed( uint64_t & state, uint64_t seed ) {
    234         state = seed;
    235         xorshift_13_7_17( state );                                                      // prime
     288        state = splitmix64( seed );                                                     // prime
    236289} // xorshift_13_7_17_set_seed
    237290
     
    250303
    251304static inline void xorshift_6_21_7_set_seed( uint32_t & state, uint32_t seed ) {
    252         state = seed;
    253         xorshift_6_21_7( state );                                                       // prime
     305    state = splitmix32( seed );                                                 // prime
    254306} // xorshift_6_21_7_set_seed
    255307
     
    265317
    266318static inline void xorshift_12_25_27_set_seed( uint64_t & state, uint64_t seed ) {
    267         state = seed;
    268         xorshift_12_25_27( state );                                                     // prime
     319        state = splitmix64( seed );                                                     // prime
    269320} // xorshift_12_25_27_set_seed
    270321
     
    272323// The state must be seeded with a nonzero value.
    273324#ifndef KISS_64
    274 typedef struct kiss_64_t { uint64_t z, w, jsr, jcong; } kiss_64_t;
     325typedef struct { uint64_t z, w, jsr, jcong; } kiss_64_t;
    275326#endif // ! KISS_64
    276327
     
    287338
    288339static inline void kiss_64_set_seed( kiss_64_t & rs, uint64_t seed ) with(rs) {
    289         z = 1; w = 1; jsr = 4; jcong = seed;
    290         kiss_64( rs );                                                                          // prime
     340        z = 1; w = 1; jsr = 4; jcong = splitmix64( seed );      // prime
    291341} // kiss_64_set_seed
    292342
     
    294344// The state array must be initialized to non-zero in the first four words.
    295345#ifndef XORWOW
    296 typedef struct xorwow_t { uint32_t a, b, c, d, counter; } xorwow_t;
     346typedef struct { uint32_t a, b, c, d, counter; } xorwow_t;
    297347#endif // ! XORWOW
    298348
     
    316366
    317367static inline void xorwow_set_seed( xorwow_t & rs, uint32_t seed ) {
    318         rs = (xorwow_t){ seed, seed, seed, seed, 0 };
    319         xorwow( rs );                                                                           // prime
     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 };
    320374} // xorwow_set_seed
    321375
     
    323377// Used in __tls_rand_fwd
    324378#define M  (1_l64u << 48_l64u)
    325 #define A  (25214903917_l64u)
    326 #define AI (18446708753438544741_l64u)
     379#define A  (25_214_903_917_l64u)
     380#define AI (18_446_708_753_438_544_741_l64u)
    327381#define C  (11_l64u)
    328382#define D  (16_l64u)
  • libcfa/src/concurrency/actor.hfa

    r2ed94a9 rb110bcc  
    33#include <locks.hfa>
    44#include <limits.hfa>
    5 #include <list.hfa>
    65#include <kernel.hfa>
     6#include <iofwd.hfa>
     7#include <virtual_dtor.hfa>
    78
    89#ifdef __CFA_DEBUG__
     
    2021// Define the default number of executor request-queues (mailboxes) written to by actors and serviced by the
    2122// actor-executor threads. Must be greater than 0.
    22 #define __DEFAULT_EXECUTOR_RQUEUES__ 2
     23#define __DEFAULT_EXECUTOR_RQUEUES__ 4
    2324
    2425// Define if executor is created in a separate cluster
    2526#define __DEFAULT_EXECUTOR_SEPCLUS__ false
    2627
    27 // when you flip this make sure to recompile compiler and flip the appropriate flag there too in Actors.cpp
    28 #define __ALLOC 0
     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
    2938
    3039// forward decls
    3140struct actor;
    3241struct message;
     42struct executor;
    3343
    3444enum Allocation { Nodelete, Delete, Destroy, Finished }; // allocation status
     
    4050    __receive_fn fn;
    4151    bool stop;
    42     inline dlink(request);
    4352};
    44 P9_EMBEDDED( request, dlink(request) )
    4553
    4654static inline void ?{}( request & this ) { this.stop = true; } // default ctor makes a sentinel
     
    5866}
    5967
    60 // hybrid data structure. Copies until buffer is full and then allocates for intrusive list
     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)
    6170struct copy_queue {
    62     dlist( request ) list;
    63     #if ! __ALLOC
    6471    request * buffer;
    65     size_t count, buffer_size, index;
    66     #endif
     72    size_t count, buffer_size, index, utilized, last_size;
    6773};
    6874static inline void ?{}( copy_queue & this ) {}
    6975static inline void ?{}( copy_queue & this, size_t buf_size ) with(this) {
    70     list{};
    71     #if ! __ALLOC
    7276    buffer_size = buf_size;
    7377    buffer = aalloc( buffer_size );
    7478    count = 0;
     79    utilized = 0;
    7580    index = 0;
    76     #endif
    77 }
    78 static inline void ^?{}( copy_queue & this ) with(this) {
    79     #if ! __ALLOC
    80     adelete(buffer);
    81     #endif
    82 }
     81    last_size = 0;
     82}
     83static inline void ^?{}( copy_queue & this ) with(this) { adelete(buffer); }
    8384
    8485static inline void insert( copy_queue & this, request & elem ) with(this) {
    85     #if ! __ALLOC
    86     if ( count < buffer_size ) { // fast path ( no alloc )
    87         buffer[count]{ elem };
    88         count++;
    89         return;
    90     }
    91     request * new_elem = alloc();
    92     (*new_elem){ elem };
    93     insert_last( list, *new_elem );
    94     #else
    95     insert_last( list, elem );
    96     #endif
     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 );
     91    }
     92    memcpy( &buffer[count], &elem, sizeof(request) );
     93    count++;
    9794}
    9895
    9996// once you start removing you need to remove all elements
    100 // it is not supported to call insert() before the list is fully empty
    101 // should_delete is an output param
    102 static inline request & remove( copy_queue & this, bool & should_delete ) with(this) {
    103     #if ! __ALLOC
     97// it is not supported to call insert() before the array is fully empty
     98static inline request & remove( copy_queue & this ) with(this) {
    10499    if ( count > 0 ) {
    105100        count--;
    106         should_delete = false;
    107101        size_t old_idx = index;
    108102        index = count == 0 ? 0 : index + 1;
    109103        return buffer[old_idx];
    110104    }
    111     #endif
    112     should_delete = true;
    113     return try_pop_front( list );
    114 }
    115 
    116 static 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 
    124 static size_t __buffer_size = 10; // C_TODO: rework this to be passed from executor through ctors (no need for global)
     105    request * ret = 0p;
     106    return *0p;
     107}
     108
     109// try to reclaim some memory if less than half of buffer is utilized
     110static 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
     117static inline bool isEmpty( copy_queue & this ) with(this) { return count == 0; }
     118
    125119struct work_queue {
    126120    __spinlock_t mutex_lock;
    127     copy_queue owned_queue;
    128     copy_queue * c_queue; // C_TODO: try putting this on the stack with ptr juggling
    129 
     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
    130128}; // work_queue
    131 static 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 ); }
     129static 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
     141static inline void ^?{}( work_queue & this ) with(this) { delete( owned_queue ); }
    138142
    139143static inline void insert( work_queue & this, request & elem ) with(this) {
     
    145149static inline void transfer( work_queue & this, copy_queue ** transfer_to ) with(this) {
    146150    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
    147167    // swap copy queue ptrs
    148168    copy_queue * temp = *transfer_to;
     
    152172} // transfer
    153173
     174// needed since some info needs to persist past worker lifetimes
     175struct 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};
     183static 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
    154200thread worker {
    155     copy_queue owned_queue;
    156     work_queue * request_queues;
     201    work_queue ** request_queues;
    157202    copy_queue * current_queue;
    158         request & req;
     203    executor * executor_;
    159204    unsigned int start, range;
     205    int id;
    160206};
    161207
    162 static inline void ?{}( worker & this, cluster & clu, work_queue * request_queues, unsigned int start, unsigned int range ) {
     208#ifdef ACTOR_STATS
     209// aggregate counters for statistics
     210size_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
     213static 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 ) {
    163215    ((thread &)this){ clu };
    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 
     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
     224static bool no_steal = false;
    174225struct executor {
    175226    cluster * cluster;                                                      // if workers execute on separate cluster
    176227        processor ** processors;                                            // array of virtual processors adding parallelism for workers
    177         work_queue * request_queues;                                // master list of work request queues
    178         worker ** workers;                                                              // array of workers executing work requests
     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
    179233        unsigned int nprocessors, nworkers, nrqueues;   // number of processors/threads/request queues
    180234        bool seperate_clus;                                                             // use same or separate cluster for executor
    181235}; // executor
    182236
     237// #ifdef ACTOR_STATS
     238// __spinlock_t out_lock;
     239// #endif
     240static 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
    183268static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus, size_t buf_size ) with(this) {
    184269    if ( nrqueues < nworkers ) abort( "nrqueues needs to be >= nworkers\n" );
    185     __buffer_size = buf_size;
    186270    this.nprocessors = nprocessors;
    187271    this.nworkers = nworkers;
     
    189273    this.seperate_clus = seperate_clus;
    190274
     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
    191284    if ( seperate_clus ) {
    192285        cluster = alloc();
     
    195288
    196289    request_queues = aalloc( nrqueues );
    197     for ( i; nrqueues )
    198         request_queues[i]{};
     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    }
    199295   
    200296    processors = aalloc( nprocessors );
     
    202298        (*(processors[i] = alloc())){ *cluster };
    203299
    204     workers = alloc( nworkers );
     300    local_queues = aalloc( nworkers );
     301    workers = aalloc( nworkers );
     302    w_infos = aalloc( nworkers );
    205303    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
    206310    for ( unsigned int i = 0, start = 0, range; i < nworkers; i += 1, start += range ) {
    207311        range = reqPerWorker + ( i < extras ? 1 : 0 );
    208         (*(workers[i] = alloc())){ *cluster, request_queues, start, range };
     312        (*(workers[i] = alloc())){ *cluster, worker_req_queues, &local_queues[i], &this, start, range, i };
    209313    } // for
    210314}
    211 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus ) { this{ nprocessors, nworkers, nrqueues, seperate_clus, __buffer_size }; }
     315static 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__ }; }
    212316static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues ) { this{ nprocessors, nworkers, nrqueues, __DEFAULT_EXECUTOR_SEPCLUS__ }; }
    213317static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers ) { this{ nprocessors, nworkers, __DEFAULT_EXECUTOR_RQUEUES__ }; }
     
    216320
    217321static 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
    218328    request sentinels[nworkers];
    219     unsigned int reqPerWorker = nrqueues / nworkers;
    220     for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker ) {
     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 );
    221332        insert( request_queues[step], sentinels[i] );           // force eventually termination
    222333    } // for
     334    #endif
    223335
    224336    for ( i; nworkers )
     
    229341    } // for
    230342
     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
    231352    adelete( workers );
     353    adelete( w_infos );
     354    adelete( local_queues );
    232355    adelete( request_queues );
     356    adelete( worker_req_queues );
    233357    adelete( processors );
    234358    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       
    235371}
    236372
    237373// this is a static field of executor but have to forward decl for get_next_ticket
    238 static unsigned int __next_ticket = 0;
    239 
    240 static inline unsigned int get_next_ticket( executor & this ) with(this) {
    241     return __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues;
     374static size_t __next_ticket = 0;
     375
     376static 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
    242386} // tickets
    243387
    244 // C_TODO: update globals in this file to be static fields once the project is done
     388// TODO: update globals in this file to be static fields once the static fields project is done
    245389static executor * __actor_executor_ = 0p;
    246 static bool __actor_executor_passed = false;        // was an executor passed to start_actor_system
    247 static unsigned long int __num_actors_;                         // number of actor objects in system
     390static bool __actor_executor_passed = false;            // was an executor passed to start_actor_system
     391static size_t __num_actors_ = 0;                                        // number of actor objects in system
    248392static struct thread$ * __actor_executor_thd = 0p;              // used to wake executor after actors finish
    249393struct actor {
    250     unsigned long int ticket;           // executor-queue handle to provide FIFO message execution
    251     Allocation allocation_;                     // allocation action
     394    size_t ticket;                                          // executor-queue handle
     395    Allocation allocation_;                                         // allocation action
     396    inline virtual_dtor;
    252397};
    253398
    254 static inline void ?{}( actor & this ) {
     399static inline void ?{}( actor & this ) with(this) {
    255400    // Once an actor is allocated it must be sent a message or the actor system cannot stop. Hence, its receive
    256401    // member must be called to end it
    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 }
    262 static inline void ^?{}( actor & this ) {}
     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}
    263410
    264411static inline void check_actor( actor & this ) {
     
    276423        }
    277424
    278         if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_SEQ_CST ) == 0 ) ) { // all actors have terminated
     425        if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_RELAXED ) == 0 ) ) { // all actors have terminated
    279426            unpark( __actor_executor_thd );
    280427        }
     
    284431struct message {
    285432    Allocation allocation_;                     // allocation action
     433    inline virtual_dtor;
    286434};
    287435
    288 static inline void ?{}( message & this ) { this.allocation_ = Nodelete; }
    289 static inline void ?{}( message & this, Allocation allocation ) { this.allocation_ = allocation; }
    290 static inline void ^?{}( message & this ) {}
     436static inline void ?{}( message & this ) {
     437    this.allocation_ = Nodelete;
     438}
     439static 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}
     443static 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}
    291446
    292447static inline void check_message( message & this ) {
    293448    switch ( this.allocation_ ) {                                               // analyze message status
    294         case Nodelete: break;
     449        case Nodelete: CFA_DEBUG(this.allocation_ = Finished); break;
    295450        case Delete: delete( &this ); break;
    296451        case Destroy: ^?{}(this); break;
     
    298453    } // switch
    299454}
     455static inline void set_allocation( message & this, Allocation state ) {
     456    this.allocation_ = state;
     457}
    300458
    301459static inline void deliver_request( request & this ) {
    302     Allocation actor_allocation = this.fn( *this.receiver, *this.msg );
    303     this.receiver->allocation_ = actor_allocation;
     460    this.receiver->allocation_ = this.fn( *this.receiver, *this.msg );
     461    check_message( *this.msg );
    304462    check_actor( *this.receiver );
    305     check_message( *this.msg );
     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
     467static 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
     491static 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
     537static 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
    306557}
    307558
    308559void main( worker & this ) with(this) {
    309     bool should_delete;
     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
    310575    Exit:
    311576    for ( unsigned int i = 0;; i = (i + 1) % range ) { // cycle through set of request buffers
    312         // C_TODO: potentially check queue count instead of immediately trying to transfer
    313         transfer( request_queues[i + start], &current_queue );
     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
    314609        while ( ! isEmpty( *current_queue ) ) {
    315             &req = &remove( *current_queue, should_delete );
    316             if ( !&req ) continue; // possibly add some work stealing/idle sleep here
     610            #ifdef ACTOR_STATS
     611            executor_->w_infos[id].processed++;
     612            #endif
     613            &req = &remove( *current_queue );
     614            if ( !&req ) continue;
    317615            if ( req.stop ) break Exit;
    318616            deliver_request( req );
    319 
    320             if ( should_delete ) delete( &req );
    321         } // while
     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 );
    322625    } // for
    323626}
     
    328631
    329632static inline void send( actor & this, request & req ) {
     633    verifyf( this.ticket != (unsigned long int)MAX, "Attempted to send message to deleted/dead actor\n" );
    330634    send( *__actor_executor_, req, this.ticket );
    331635}
    332636
     637static 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
    333649static inline void start_actor_system( size_t num_thds ) {
     650    __reset_stats();
    334651    __actor_executor_thd = active_thread();
    335652    __actor_executor_ = alloc();
     
    337654}
    338655
    339 static inline void start_actor_system() { start_actor_system( active_cluster()->procs.total ); }
     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 ); }
     660static inline void start_actor_system() { start_actor_system( 1 ); }
    340661
    341662static inline void start_actor_system( executor & this ) {
     663    __reset_stats();
    342664    __actor_executor_thd = active_thread();
    343665    __actor_executor_ = &this;
     
    354676    __actor_executor_passed = false;
    355677}
     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
     681message __base_msg_finished @= { .allocation_ : Finished };
     682struct __DeleteMsg { inline message; } DeleteMsg = __base_msg_finished;
     683struct __DestroyMsg { inline message; } DestroyMsg = __base_msg_finished;
     684struct __FinishedMsg { inline message; } FinishedMsg = __base_msg_finished;
     685
     686Allocation receive( actor & this, __DeleteMsg & msg ) { return Delete; }
     687Allocation receive( actor & this, __DestroyMsg & msg ) { return Destroy; }
     688Allocation receive( actor & this, __FinishedMsg & msg ) { return Finished; }
     689
  • libcfa/src/concurrency/channel.hfa

    r2ed94a9 rb110bcc  
     1#pragma once
     2
    13#include <locks.hfa>
    2 
    3 struct no_reacq_lock {
    4     inline exp_backoff_then_block_lock;
     4#include <list.hfa>
     5#include <mutex_stmt.hfa>
     6
     7// link field used for threads waiting on channel
     8struct 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;
    517};
    6 
    7 // have to override these by hand to get around plan 9 inheritance bug where resolver can't find the appropriate routine to call
    8 static inline void   ?{}( no_reacq_lock & this ) { ((exp_backoff_then_block_lock &)this){}; }
    9 static inline bool   try_lock(no_reacq_lock & this) { return try_lock(((exp_backoff_then_block_lock &)this)); }
    10 static inline void   lock(no_reacq_lock & this) { lock(((exp_backoff_then_block_lock &)this)); }
    11 static inline void   unlock(no_reacq_lock & this) { unlock(((exp_backoff_then_block_lock &)this)); }
    12 static inline void   on_notify(no_reacq_lock & this, struct thread$ * t ) { on_notify(((exp_backoff_then_block_lock &)this), t); }
    13 static 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
    15 static inline void   on_wakeup( no_reacq_lock & this, size_t recursion ) {}
     18P9_EMBEDDED( wait_link, dlink(wait_link) )
     19
     20static 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
     26static 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
     33static 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
     42exception 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};
     52vtable(channel_closed) channel_closed_vt;
     53
     54// #define CHAN_STATS // define this to get channel stats printed in dtor
    1655
    1756forall( T ) {
    18 struct channel {
    19     size_t size;
    20     size_t front, back, count;
     57
     58struct __attribute__((aligned(128))) channel {
     59    size_t size, front, back, count;
    2160    T * buffer;
    22     fast_cond_var( no_reacq_lock ) prods, cons;
    23     no_reacq_lock mutex_lock;
     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
    2467};
    2568
     
    2770    size = _size;
    2871    front = back = count = 0;
    29     buffer = anew( size );
     72    buffer = aalloc( size );
    3073    prods{};
    3174    cons{};
    3275    mutex_lock{};
     76    closed = false;
     77    #ifdef CHAN_STATS
     78    blocks = 0;
     79    operations = 0;
     80    #endif
    3381}
    3482
    3583static inline void ?{}( channel(T) &c ){ ((channel(T) &)c){ 0 }; }
    36 static inline void ^?{}( channel(T) &c ) with(c) { delete( buffer ); }
     84static 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}
    3791static inline size_t get_count( channel(T) & chan ) with(chan) { return count; }
    3892static inline size_t get_size( channel(T) & chan ) with(chan) { return size; }
    39 static inline bool has_waiters( channel(T) & chan ) with(chan) { return !empty( cons ) || !empty( prods ); }
    40 static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !empty( cons ); }
    41 static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !empty( prods ); }
    42 
    43 static inline void insert_( channel(T) & chan, T elem ) with(chan) {
     93static inline bool has_waiters( channel(T) & chan ) with(chan) { return !cons`isEmpty || !prods`isEmpty; }
     94static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !cons`isEmpty; }
     95static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !prods`isEmpty; }
     96
     97// closes the channel and notifies all blocked threads
     98static 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
     114static inline void is_closed( channel(T) & chan ) with(chan) { return closed; }
     115
     116static 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
     126static inline void __buf_insert( channel(T) & chan, T & elem ) with(chan) {
    44127    memcpy((void *)&buffer[back], (void *)&elem, sizeof(T));
    45128    count += 1;
     
    48131}
    49132
     133// does the buffer insert or hands elem directly to consumer if one is waiting
     134static 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
     142static 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
     155static inline bool try_insert( channel(T) & chan, T elem ) { return __internal_try_insert( chan, elem ); }
     156
     157// handles closed case of insert routine
     158static 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}
    50163
    51164static inline void insert( channel(T) & chan, T elem ) with(chan) {
    52     lock( mutex_lock );
     165    // check for close before acquire mx
     166    if ( unlikely(closed) ) {
     167        __closed_insert( chan, elem );
     168        return;
     169    }
     170
     171    lock( mutex_lock );
     172
     173    #ifdef CHAN_STATS
     174    if ( !closed ) operations++;
     175    #endif
     176
     177    // if closed handle
     178    if ( unlikely(closed) ) {
     179        unlock( mutex_lock );
     180        __closed_insert( chan, elem );
     181        return;
     182    }
    53183
    54184    // 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 );
     185    if ( size == 0 && !cons`isEmpty ) {
     186        memcpy(cons`first.elem, (void *)&elem, sizeof(T));
     187        wake_one( cons );
    58188        unlock( mutex_lock );
    59         return;
     189        return true;
    60190    }
    61191
    62192    // wait if buffer is full, work will be completed by someone else
    63     if ( count == size ) {
    64         wait( prods, mutex_lock, (uintptr_t)&elem );
     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 );
    65201        return;
    66202    } // if
    67203
    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 );
     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 );
    72208   
    73     notify_one( cons );
    74     unlock( mutex_lock );
    75 }
    76 
    77 static inline T remove( channel(T) & chan ) with(chan) {
    78     lock( mutex_lock );
    79     T retval;
    80 
    81     // have to check for the zero size channel case
    82     if ( size == 0 && !empty( prods ) ) {
    83         memcpy((void *)&retval, (void *)front( prods ), sizeof(T));
    84         notify_one( prods );
    85         unlock( mutex_lock );
    86         return retval;
    87     }
    88 
    89     // wait if buffer is empty, work will be completed by someone else
    90     if (count == 0) {
    91         wait( cons, mutex_lock, (uintptr_t)&retval );
    92         return retval;
    93     }
    94 
    95     // Remove from buffer
     209    unlock( mutex_lock );
     210    return;
     211}
     212
     213// handles buffer remove
     214static inline void __buf_remove( channel(T) & chan, T & retval ) with(chan) {
    96215    memcpy((void *)&retval, (void *)&buffer[front], sizeof(T));
    97216    count -= 1;
    98217    front = (front + 1) % size;
    99 
    100     if (count == size - 1 && !empty( prods ) )
    101         insert_( chan, *((T *)front( prods )) );  // do waiting producer work
    102 
    103     notify_one( prods );
    104     unlock( mutex_lock );
     218}
     219
     220// does the buffer remove and potentially does waiting producer work
     221static 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
     230static 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)
     244static inline [T, bool] try_remove( channel(T) & chan ) {
     245    T retval;
     246    return [ retval, __internal_try_remove( chan, retval ) ];
     247}
     248
     249static inline T try_remove( channel(T) & chan, T elem ) {
     250    T retval;
     251    __internal_try_remove( chan, retval );
    105252    return retval;
    106253}
    107254
     255// handles closed case of insert routine
     256static 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
     260}
     261
     262static inline T remove( channel(T) & chan ) with(chan) {
     263    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    }
     279
     280    // 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 );
     284        unlock( mutex_lock );
     285        return retval;
     286    }
     287
     288    // 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 );
     296        return retval;
     297    }
     298
     299    // Remove from buffer
     300    __do_remove( chan, retval );
     301
     302    unlock( mutex_lock );
     303    return retval;
     304}
    108305} // forall( T )
  • libcfa/src/concurrency/clib/cfathread.cfa

    r2ed94a9 rb110bcc  
    1616// #define EPOLL_FOR_SOCKETS
    1717
     18#include <string.h>
     19
    1820#include "fstream.hfa"
    1921#include "locks.hfa"
     
    2325#include "time.hfa"
    2426#include "stdlib.hfa"
    25 
     27#include "iofwd.hfa"
    2628#include "cfathread.h"
    27 
    28 extern "C" {
    29                 #include <string.h>
    30                 #include <errno.h>
    31 }
    3229
    3330extern void ?{}(processor &, const char[], cluster &, thread$ *);
    3431extern "C" {
    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);
     32        extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
    3733}
    3834
     
    472468}
    473469
    474 #include <iofwd.hfa>
    475 
    476470extern "C" {
    477         #include <unistd.h>
    478         #include <sys/types.h>
    479         #include <sys/socket.h>
    480 
    481471        //--------------------
    482472        // IO operations
     
    488478                , protocol);
    489479        }
    490         int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {
     480        int cfathread_bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) {
    491481                return bind(socket, address, address_len);
    492482        }
     
    496486        }
    497487
    498         int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
     488        int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len) {
    499489                #if defined(EPOLL_FOR_SOCKETS)
    500490                        int ret;
     
    513503        }
    514504
    515         int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {
     505        int cfathread_connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) {
    516506                #if defined(EPOLL_FOR_SOCKETS)
    517507                        int ret;
  • libcfa/src/concurrency/clib/cfathread.h

    r2ed94a9 rb110bcc  
    99// Author           : Thierry Delisle
    1010// Created On       : Tue Sep 22 15:31:20 2020
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 13 23:48:40 2023
     13// Update Count     : 7
    1414//
    1515
     16#pragma once
     17
    1618#if defined(__cforall) || defined(__cplusplus)
     19#include <unistd.h>
     20#include <errno.h>
     21#include <sys/socket.h>
     22
    1723extern "C" {
    1824#endif
    19         #include <asm/types.h>
    20         #include <errno.h>
    21         #include <unistd.h>
    22 
    23 
    2425        //--------------------
    2526        // Basic types
     
    7374        } cfathread_mutexattr_t;
    7475        typedef struct cfathread_mutex * cfathread_mutex_t;
    75         int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict attr) __attribute__((nonnull (1)));
     76        int cfathread_mutex_init(cfathread_mutex_t * restrict mut, const cfathread_mutexattr_t * restrict attr) __attribute__((nonnull (1)));
    7677        int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
    7778        int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
     
    9192        //--------------------
    9293        // IO operations
    93         struct sockaddr;
    94         struct msghdr;
    9594        int cfathread_socket(int domain, int type, int protocol);
    96         int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len);
     95        int cfathread_bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len);
    9796        int cfathread_listen(int socket, int backlog);
    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);
     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);
    10099        int cfathread_dup(int fildes);
    101100        int cfathread_close(int fildes);
  • libcfa/src/concurrency/coroutine.cfa

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

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov 29 20:42:21 2022
    13 // Update Count     : 56
    14 //
     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.
    1517
    1618#include "bits/containers.hfa"
  • libcfa/src/concurrency/io.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#if defined(__CFA_DEBUG__)
     
    296295                                // make sure the target hasn't stopped existing since last time
    297296                                HELP: if(target < ctxs_count) {
    298                                         // calculate it's age and how young it could be before we give ip on helping
     297                                        // calculate it's age and how young it could be before we give up on helping
    299298                                        const __readyQ_avg_t cutoff = calc_cutoff(ctsc, ctx->cq.id, ctxs_count, io.data, io.tscs, __shard_factor.io, false);
    300299                                        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

    r2ed94a9 rb110bcc  
    3131Prelude = """#define __cforall_thread__
    3232
     33#include <unistd.h>
     34#include <errno.h>
     35#include <sys/socket.h>
     36#include <time.hfa>
     37
    3338#include "bits/defs.hfa"
    3439#include "kernel.hfa"
     
    4348        #include <assert.h>
    4449        #include <stdint.h>
    45         #include <errno.h>
    4650        #include <linux/io_uring.h>
    47 
    4851        #include "kernel/fwd.hfa"
    4952
     
    8285// I/O Forwards
    8386//=============================================================================================
    84 #include <time.hfa>
    85 
    86 // Some forward declarations
    87 #include <errno.h>
    88 #include <unistd.h>
    8987
    9088extern "C" {
    91         #include <asm/types.h>
    92         #include <sys/socket.h>
    93         #include <sys/syscall.h>
    94 
    9589#if defined(CFA_HAVE_PREADV2)
    9690        struct iovec;
    97         extern ssize_t preadv2 (int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
     91        extern ssize_t preadv2 (int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags);
    9892#endif
    9993#if defined(CFA_HAVE_PWRITEV2)
    10094        struct iovec;
    101         extern ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
     95        extern ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags);
    10296#endif
    10397
     
    114108        struct msghdr;
    115109        struct sockaddr;
    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);
     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);
    122114
    123115        extern int fallocate(int fd, int mode, off_t offset, off_t len);
    124116        extern int posix_fadvise(int fd, off_t offset, off_t len, int advice);
    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);
     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);
    128120        extern int close(int fd);
    129121
    130         extern ssize_t read (int fd, void *buf, size_t count);
     122        extern ssize_t read (int fd, void * buf, size_t count);
    131123
    132124        struct epoll_event;
    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);
     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);
    136128        extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
    137129}
     
    232224calls = [
    233225        # CFA_HAVE_IORING_OP_READV
    234         Call('READV', 'ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)', {
     226        Call('READV', 'ssize_t preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', {
    235227                'fd'  : 'fd',
     228                'addr': '(typeof(sqe->addr))iov',
     229                'len' : 'iovcnt',
    236230                'off' : 'offset',
    237                 'addr': '(uintptr_t)iov',
    238                 'len' : 'iovcnt',
     231                'rw_flags' : 'flags'
    239232        }, define = 'CFA_HAVE_PREADV2'),
    240233        # CFA_HAVE_IORING_OP_WRITEV
    241         Call('WRITEV', 'ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)', {
     234        Call('WRITEV', 'ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', {
    242235                'fd'  : 'fd',
     236                'addr': '(typeof(sqe->addr))iov',
     237                'len' : 'iovcnt',
    243238                'off' : 'offset',
    244                 'addr': '(uintptr_t)iov',
    245                 'len' : 'iovcnt'
     239                'rw_flags' : 'flags'
    246240        }, define = 'CFA_HAVE_PWRITEV2'),
    247241        # CFA_HAVE_IORING_OP_FSYNC
     
    250244        }),
    251245        # CFA_HAVE_IORING_OP_EPOLL_CTL
    252         Call('EPOLL_CTL', 'int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)', {
     246        Call('EPOLL_CTL', 'int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event)', {
    253247                'fd': 'epfd',
     248                'len': 'op',
    254249                'addr': 'fd',
    255                 'len': 'op',
    256                 'off': '(uintptr_t)event'
     250                'off': '(typeof(sqe->off))event'
    257251        }),
    258252        # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
     
    264258        }),
    265259        # CFA_HAVE_IORING_OP_SENDMSG
    266         Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', {
    267                 'fd': 'sockfd',
    268                 'addr': '(uintptr_t)(struct msghdr *)msg',
     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',
    269263                'len': '1',
    270264                'msg_flags': 'flags'
    271265        }),
    272266        # CFA_HAVE_IORING_OP_RECVMSG
    273         Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', {
    274                 'fd': 'sockfd',
    275                 'addr': '(uintptr_t)(struct msghdr *)msg',
     267        Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags)', {
     268                'fd': 'sockfd',
     269                'addr': '(typeof(sqe->addr))(struct msghdr *)msg',
    276270                'len': '1',
    277271                'msg_flags': 'flags'
    278272        }),
    279273        # CFA_HAVE_IORING_OP_SEND
    280         Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', {
    281                 'fd': 'sockfd',
    282                 'addr': '(uintptr_t)buf',
     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',
    283277                'len': 'len',
    284278                'msg_flags': 'flags'
    285279        }),
    286280        # CFA_HAVE_IORING_OP_RECV
    287         Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', {
    288                 'fd': 'sockfd',
    289                 'addr': '(uintptr_t)buf',
     281        Call('RECV', 'ssize_t recv(int sockfd, void * buf, size_t len, int flags)', {
     282                'fd': 'sockfd',
     283                'addr': '(typeof(sqe->addr))buf',
    290284                'len': 'len',
    291285                'msg_flags': 'flags'
    292286        }),
    293287        # CFA_HAVE_IORING_OP_ACCEPT
    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',
     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',
    298292                'accept_flags': 'flags'
    299293        }),
    300294        # CFA_HAVE_IORING_OP_CONNECT
    301         Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {
    302                 'fd': 'sockfd',
    303                 'addr': '(uintptr_t)addr',
     295        Call('CONNECT', 'int connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen)', {
     296                'fd': 'sockfd',
     297                'addr': '(typeof(sqe->addr))&addr',
    304298                'off': 'addrlen'
    305299        }),
     
    307301        Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
    308302                'fd': 'fd',
    309                 'addr': '(uintptr_t)len',
    310303                'len': 'mode',
    311                 'off': 'offset'
     304                'off': 'offset',
     305                'addr': 'len'
    312306        }),
    313307        # CFA_HAVE_IORING_OP_FADVISE
     
    319313        }),
    320314        # CFA_HAVE_IORING_OP_MADVISE
    321         Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', {
    322                 'addr': '(uintptr_t)addr',
     315        Call('MADVISE', 'int madvise(void * addr, size_t length, int advice)', {
     316                'addr': '(typeof(sqe->addr))addr',
    323317                'len': 'length',
    324318                'fadvise_advice': 'advice'
    325319        }),
    326320        # CFA_HAVE_IORING_OP_OPENAT
    327         Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', {
     321        Call('OPENAT', 'int openat(int dirfd, const char * pathname, int flags, mode_t mode)', {
    328322                'fd': 'dirfd',
    329                 'addr': '(uintptr_t)pathname',
    330                 'len': 'mode',
    331                 'open_flags': 'flags;'
     323                'addr': '(typeof(sqe->addr))pathname',
     324                'open_flags': 'flags;',
     325                'len': 'mode'
    332326        }),
    333327        # CFA_HAVE_IORING_OP_OPENAT2
    334         Call('OPENAT2', 'int openat2(int dirfd, const char *pathname, struct open_how * how, size_t size)', {
     328        Call('OPENAT2', 'int openat2(int dirfd, const char * pathname, struct open_how * how, size_t size)', {
    335329                'fd': 'dirfd',
    336                 'addr': 'pathname',
    337                 'len': 'sizeof(*how)',
    338                 'off': '(uintptr_t)how',
     330                'addr': '(typeof(sqe->addr))pathname',
     331                'off': '(typeof(sqe->off))how',
     332                'len': 'sizeof(*how)'
    339333        }, define = 'CFA_HAVE_OPENAT2'),
    340334        # CFA_HAVE_IORING_OP_CLOSE
     
    343337        }),
    344338        # CFA_HAVE_IORING_OP_STATX
    345         Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', {
     339        Call('STATX', 'int statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf)', {
    346340                'fd': 'dirfd',
    347                 'off': '(uintptr_t)statxbuf',
    348                 'addr': 'pathname',
     341                'addr': '(typeof(sqe->addr))pathname',
     342                'statx_flags': 'flags',
    349343                'len': 'mask',
    350                 'statx_flags': 'flags'
     344                'off': '(typeof(sqe->off))statxbuf'
    351345        }, define = 'CFA_HAVE_STATX'),
    352346        # CFA_HAVE_IORING_OP_READ
    353347        Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
    354348                'fd': 'fd',
    355                 'addr': '(uintptr_t)buf',
     349                'addr': '(typeof(sqe->addr))buf',
    356350                'len': 'count'
    357351        }),
     
    359353        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
    360354                'fd': 'fd',
    361                 'addr': '(uintptr_t)buf',
     355                'addr': '(typeof(sqe->addr))buf',
    362356                'len': 'count'
    363357        }),
    364358        # CFA_HAVE_IORING_OP_SPLICE
    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)', {
     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)', {
    366360                'splice_fd_in': 'fd_in',
    367                 'splice_off_in': 'off_in ? (__u64)*off_in : (__u64)-1',
     361                'splice_off_in': 'off_in ? (typeof(sqe->splice_off_in))*off_in : (typeof(sqe->splice_off_in))-1',
    368362                'fd': 'fd_out',
    369                 'off': 'off_out ? (__u64)*off_out : (__u64)-1',
     363                'off': 'off_out ? (typeof(sqe->off))*off_out : (typeof(sqe->off))-1',
    370364                'len': 'len',
    371365                'splice_flags': 'flags'
  • libcfa/src/concurrency/io/setup.cfa

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

    r2ed94a9 rb110bcc  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu Apr 23 17:31:00 2020
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 13 23:54:57 2023
     13// Update Count     : 1
    1414//
    1515
     
    1717
    1818#include <unistd.h>
     19#include <sys/socket.h>
     20
    1921extern "C" {
    2022        #include <asm/types.h>
     
    4850typedef __off64_t off64_t;
    4951
    50 struct cluster;
    51 struct io_context$;
    52 
    53 struct iovec;
    54 struct msghdr;
    55 struct sockaddr;
    56 struct statx;
    5752struct epoll_event;
    58 
    59 struct io_uring_sqe;
    6053
    6154//-----------------------------------------------------------------------
     
    8881// synchronous calls
    8982#if defined(CFA_HAVE_PREADV2)
    90         extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     83        extern ssize_t cfa_preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    9184#endif
    9285#if defined(CFA_HAVE_PWRITEV2)
    93         extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     86        extern ssize_t cfa_pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    9487#endif
    9588extern int cfa_fsync(int fd, __u64 submit_flags);
    96 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
     89extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);
    9790extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
    98 extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
    99 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
    100 extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
    101 extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
    102 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
    103 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
     91extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);
     92extern ssize_t cfa_recvmsg(int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);
     93extern ssize_t cfa_send(int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);
     94extern ssize_t cfa_recv(int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);
     95extern int cfa_accept4(int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags);
     96extern int cfa_connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags);
    10497extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    10598extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
    106 extern int cfa_madvise(void *addr, size_t length, int advice, __u64 submit_flags);
    107 extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
     99extern int cfa_madvise(void * addr, size_t length, int advice, __u64 submit_flags);
     100extern int cfa_openat(int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);
    108101#if defined(CFA_HAVE_OPENAT2)
    109         extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
     102        extern int cfa_openat2(int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags);
    110103#endif
    111104extern int cfa_close(int fd, __u64 submit_flags);
    112105#if defined(CFA_HAVE_STATX)
    113         extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);
     106        extern int cfa_statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf, __u64 submit_flags);
    114107#endif
    115108extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags);
    116109extern ssize_t cfa_write(int fd, void * buf, size_t count, __u64 submit_flags);
    117 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);
     110extern 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);
    118111extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    119112
     
    121114// asynchronous calls
    122115#if defined(CFA_HAVE_PREADV2)
    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);
     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);
    124117#endif
    125118#if defined(CFA_HAVE_PWRITEV2)
    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);
     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);
    127120#endif
    128121extern void async_fsync(io_future_t & future, int fd, __u64 submit_flags);
    129 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
     122extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);
    130123extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
    131 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
    132 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
    133 extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
    134 extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
    135 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
    136 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
     124extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);
     125extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);
     126extern void async_send(io_future_t & future, int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);
     127extern void async_recv(io_future_t & future, int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);
     128extern void async_accept4(io_future_t & future, int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags);
     129extern void async_connect(io_future_t & future, int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags);
    137130extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    138131extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
    139 extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, __u64 submit_flags);
    140 extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
     132extern void async_madvise(io_future_t & future, void * addr, size_t length, int advice, __u64 submit_flags);
     133extern void async_openat(io_future_t & future, int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);
    141134#if defined(CFA_HAVE_OPENAT2)
    142         extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
     135        extern void async_openat2(io_future_t & future, int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags);
    143136#endif
    144137extern void async_close(io_future_t & future, int fd, __u64 submit_flags);
    145138#if defined(CFA_HAVE_STATX)
    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);
     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);
    147140#endif
    148141void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
    149142extern void async_write(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
    150 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);
     143extern 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);
    151144extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    152145
  • libcfa/src/concurrency/kernel.cfa

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

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include "bits/defs.hfa"
     
    6968        return max_cores_l;
    7069}
    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
    9070
    9171//=======================================================================
     
    11191// Lock-Free registering/unregistering of threads
    11292unsigned register_proc_id( void ) with(__scheduler_lock.lock) {
    113         __kernel_rseq_register();
    114 
    11593        bool * handle = (bool *)&kernelTLS().sched_lock;
    11694
     
    162140
    163141        __atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
    164 
    165         __kernel_rseq_unregister();
    166142}
    167143
     
    505481        /* paranoid */ verify( mock_head(this)    == this.l.prev );
    506482}
    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

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon Feb 13 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Aug 12 08:21:33 2020
    13 // Update Count     : 9
     12// Last Modified On : Thu Mar  2 16:04:46 2023
     13// Update Count     : 11
    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
    3931        #include <sched.h>
    40 #endif
    4132}
    4233
     
    110101// Hardware
    111102
    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 
    122103static inline int __kernel_getcpu() {
    123104        /* 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
    131105        return sched_getcpu();
    132 #endif
    133106}
    134107
  • libcfa/src/concurrency/kernel/startup.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    2019
    2120// C Includes
    22 #include <errno.h>                                      // errno
     21#include <errno.h>                                                                              // errno
    2322#include <signal.h>
    24 #include <string.h>                                     // strerror
    25 #include <unistd.h>                                     // sysconf
    26 
     23#include <string.h>                                                                             // strerror
     24#include <unistd.h>
     25#include <limits.h>                                                                             // PTHREAD_STACK_MIN
    2726extern "C" {
    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
     27        #include <sys/eventfd.h>                                                        // eventfd
     28        #include <sys/mman.h>                                                           // mprotect
     29        #include <sys/resource.h>                                                       // getrlimit
    3330}
    3431
     
    3633#include "kernel/private.hfa"
    3734#include "iofwd.hfa"
    38 #include "startup.hfa"                                  // STARTUP_PRIORITY_XXX
     35#include "startup.hfa"                                                                  // STARTUP_PRIORITY_XXX
    3936#include "limits.hfa"
    4037#include "math.hfa"
     
    150147__scheduler_RWLock_t __scheduler_lock @= { 0 };
    151148
    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 
    164149//-----------------------------------------------------------------------------
    165150// Struct to steal stack
  • libcfa/src/concurrency/locks.cfa

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

    r2ed94a9 rb110bcc  
    3232#include <fstream.hfa>
    3333
    34 
    3534// futex headers
    3635#include <linux/futex.h>      /* Definition of FUTEX_* constants */
     
    155154// futex_mutex
    156155
    157 // - No cond var support
    158156// - Kernel thd blocking alternative to the spinlock
    159157// - No ownership (will deadlock on reacq)
     
    185183        int state;
    186184
    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;
     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;
    199195       
    200196        // if not in contended state, set to be in contended state
     
    209205
    210206static inline void unlock(futex_mutex & this) with(this) {
    211         // if uncontended do atomice unlock and then return
    212         if (__atomic_fetch_sub(&val, 1, __ATOMIC_RELEASE) == 1) return; // TODO: try acq/rel
     207        // if uncontended do atomic unlock and then return
     208    if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
    213209       
    214210        // otherwise threads are blocked so we must wake one
    215         __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);
    216211        futex((int *)&val, FUTEX_WAKE, 1);
    217212}
     
    222217// to set recursion count after getting signalled;
    223218static 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
     227struct 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
     235static inline void  ?{}( go_mutex & this ) with(this) { val = 0; }
     236
     237static 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
     241static 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!!!!!
     246static 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
     276static 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
     284static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); }
     285static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;}
     286static inline void on_wakeup( go_mutex & f, size_t recursion ) {}
    224287
    225288//-----------------------------------------------------------------------------
     
    253316static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); }
    254317
    255 
    256318//-----------------------------------------------------------------------------
    257319// Exponential backoff then block lock
     
    272334        this.lock_value = 0;
    273335}
    274 static 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;
     336
     337static inline void  ^?{}( exp_backoff_then_block_lock & this ){}
    277338
    278339static inline bool internal_try_lock(exp_backoff_then_block_lock & this, size_t & compare_val) with(this) {
    279         if (__atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
    280                 return true;
    281         }
    282         return false;
     340        return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
    283341}
    284342
     
    286344
    287345static inline bool try_lock_contention(exp_backoff_then_block_lock & this) with(this) {
    288         if (__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE) == 0) {
    289                 return true;
    290         }
    291         return false;
     346        return !__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE);
    292347}
    293348
    294349static inline bool block(exp_backoff_then_block_lock & this) with(this) {
    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 );
     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 );
    302357        park( );
    303358        return true;
     
    307362        size_t compare_val = 0;
    308363        int spin = 4;
     364
    309365        // linear backoff
    310366        for( ;; ) {
     
    324380static inline void unlock(exp_backoff_then_block_lock & this) with(this) {
    325381    if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return;
    326         lock( spinlock __cfaabi_dbg_ctx2 );
    327         thread$ * t = &try_pop_front( blocked_threads );
    328         unlock( spinlock );
    329         unpark( t );
     382    lock( spinlock __cfaabi_dbg_ctx2 );
     383    thread$ * t = &try_pop_front( blocked_threads );
     384    unlock( spinlock );
     385    unpark( t );
    330386}
    331387
  • libcfa/src/concurrency/monitor.cfa

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

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

    r2ed94a9 rb110bcc  
     1#pragma once
     2
    13#include "bits/algorithm.hfa"
    24#include "bits/defs.hfa"
     
    46//-----------------------------------------------------------------------------
    57// is_lock
    6 trait is_lock(L & | sized(L)) {
     8forall(L & | sized(L))
     9trait is_lock {
    710        // For acquiring a lock
    811        void lock( L & );
     
    2427    // Sort locks based on address
    2528    __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 
    33 static inline void ^?{}( __mutex_stmt_lock_guard & this ) with(this) {
    34     // for ( size_t i = count; i > 0; i-- ) {
    35     //     unlock(*lockarr[i - 1]);
    36     // }
    3729}
    3830
  • libcfa/src/concurrency/preemption.cfa

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

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include <signal.h>
     
    3534struct pthread_values{
    3635        inline Seqable;
    37         void* value;
     36        void * value;
    3837        bool in_use;
    3938};
     
    5150struct pthread_keys {
    5251        bool in_use;
    53         void (*destructor)( void * );
     52        void (* destructor)( void * );
    5453        Sequence(pthread_values) threads;
    5554};
    5655
    57 static void ?{}(pthread_keys& k){
     56static void ?{}(pthread_keys& k) {
    5857        k.threads{};
    5958}
     
    6261static pthread_keys cfa_pthread_keys_storage[PTHREAD_KEYS_MAX] __attribute__((aligned (16)));
    6362
    64 static void init_pthread_storage(){
    65         for (int i = 0; i < PTHREAD_KEYS_MAX; i++){
     63static void init_pthread_storage() {
     64        for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
    6665                cfa_pthread_keys_storage[i]{};
    6766        }
     
    9695
    9796/* condvar helper routines */
    98 static void init(pthread_cond_t* pcond){
     97static void init(pthread_cond_t * pcond) {
    9998        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
    100         cfa2pthr_cond_var_t* _cond = (cfa2pthr_cond_var_t*)pcond;
     99        cfa2pthr_cond_var_t * _cond = (cfa2pthr_cond_var_t *)pcond;
    101100        ?{}(*_cond);
    102101}
    103102
    104 static cfa2pthr_cond_var_t* get(pthread_cond_t* pcond){
     103static cfa2pthr_cond_var_t * get(pthread_cond_t * pcond) {
    105104        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
    106         return (cfa2pthr_cond_var_t*)pcond;
    107 }
    108 
    109 static void destroy(pthread_cond_t* cond){
     105        return (cfa2pthr_cond_var_t *)pcond;
     106}
     107
     108static void destroy(pthread_cond_t * cond) {
    110109        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
    111110        ^?{}(*get(cond));
     
    116115
    117116/* mutex helper routines */
    118 static void mutex_check(pthread_mutex_t* t){
     117static void mutex_check(pthread_mutex_t * t) {
    119118        // Use double check to improve performance.
    120119        // Check is safe on x86; volatile prevents compiler reordering
    121         volatile pthread_mutex_t *const mutex_ = t;
     120        volatile pthread_mutex_t * const mutex_ = t;
    122121
    123122        // SKULLDUGGERY: not a portable way to access the kind field, /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h
     
    136135
    137136
    138 static void init(pthread_mutex_t* plock){
     137static void init(pthread_mutex_t * plock) {
    139138        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
    140         simple_owner_lock* _lock = (simple_owner_lock*)plock;
     139        simple_owner_lock * _lock = (simple_owner_lock *)plock;
    141140        ?{}(*_lock);
    142141}
    143142
    144 static simple_owner_lock* get(pthread_mutex_t* plock){
     143static simple_owner_lock * get(pthread_mutex_t * plock) {
    145144        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
    146         return (simple_owner_lock*)plock;
    147 }
    148 
    149 static void destroy(pthread_mutex_t* plock){
     145        return (simple_owner_lock *)plock;
     146}
     147
     148static void destroy(pthread_mutex_t * plock) {
    150149        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
    151150        ^?{}(*get(plock));
     
    153152
    154153//######################### Attr helpers #########################
    155 struct cfaPthread_attr_t {                                                              // thread attributes
     154typedef struct cfaPthread_attr_t {                                              // thread attributes
    156155                int contentionscope;
    157156                int detachstate;
    158157                size_t stacksize;
    159                 void *stackaddr;
     158                void * stackaddr;
    160159                int policy;
    161160                int inheritsched;
    162161                struct sched_param param;
    163 } typedef cfaPthread_attr_t;
    164 
    165 static const cfaPthread_attr_t default_attrs{
     162} cfaPthread_attr_t;
     163
     164static const cfaPthread_attr_t default_attrs {
    166165        0,
    167166        0,
    168         (size_t)65000,
    169         (void *)NULL,
     167        65_000,
     168        NULL,
    170169        0,
    171170        0,
     
    173172};
    174173
    175 static 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;
     174static 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;
    178177}
    179178
     
    190189
    191190        // pthreads return value
    192         void *joinval;
     191        void * joinval;
    193192
    194193        // pthread attributes
    195194        pthread_attr_t pthread_attr;
    196195
    197         void *(*start_routine)(void *);
    198         void *start_arg;
     196        void *(* start_routine)(void *);
     197        void * start_arg;
    199198
    200199        // thread local data
    201         pthread_values* pthreadData;
     200        pthread_values * pthreadData;
    202201
    203202        // flag used for tryjoin
     
    207206/* thread part routines */
    208207//  cfaPthread entry point
    209 void main(cfaPthread& _thread) with(_thread){
    210         joinval =  start_routine(start_arg);
     208void main(cfaPthread & _thread) with(_thread) {
     209        joinval = start_routine(start_arg);
    211210        isTerminated = true;
    212211}
    213212
    214 static cfaPthread *lookup( pthread_t p ){
    215         static_assert(sizeof(pthread_t) >= sizeof(cfaPthread*),"sizeof(pthread_t) < sizeof(cfaPthread*)");
    216         return (cfaPthread*)p;
    217 }
    218 
    219 static void pthread_deletespecific_( pthread_values* values )  { // see uMachContext::invokeTask
    220         pthread_values* value;
    221         pthread_keys* key;
     213static cfaPthread * lookup( pthread_t p ) {
     214        static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *),"sizeof(pthread_t) < sizeof(cfaPthread *)");
     215        return (cfaPthread *)p;
     216}
     217
     218static void pthread_deletespecific_( pthread_values * values )  { // see uMachContext::invokeTask
     219        pthread_values * value;
     220        pthread_keys * key;
    222221        bool destcalled = true;
    223         if (values != NULL){
     222        if (values != NULL) {
    224223                for ( int attempts = 0; attempts < PTHREAD_DESTRUCTOR_ITERATIONS && destcalled ; attempts += 1 ) {
    225224                        destcalled = false;
    226225                        lock(key_lock);
    227                         for (int i = 0; i < PTHREAD_KEYS_MAX; i++){
     226                        for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
    228227                                // for each valid key
    229                                 if ( values[i].in_use){
     228                                if ( values[i].in_use) {
    230229                                        value = &values[i];
    231230                                        key = &cfa_pthread_keys[i];
     
    234233                                        // if  a  key  value  has  a  non-NULL  destructor pointer,  and  the  thread  has  a  non-NULL  value associated with that key,
    235234                                        // 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.
    236                                         if (value->value != NULL && key->destructor != NULL){
     235                                        if (value->value != NULL && key->destructor != NULL) {
    237236                                                unlock(key_lock);
    238237                                                key->destructor(value->value); // run destructor
     
    249248}
    250249
    251 static void ^?{}(cfaPthread & mutex t){
     250static void ^?{}(cfaPthread & mutex t) {
    252251        // delete pthread local storage
    253252        pthread_values * values = t.pthreadData;
     
    255254}
    256255
    257 static 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*)");
     256static 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 *)");
    259258
    260259        // set up user thread stackSize
     
    278277        //######################### Pthread Attrs #########################
    279278
    280         int pthread_attr_init(pthread_attr_t *attr) libcfa_public __THROW {
    281                 cfaPthread_attr_t* _attr = get(attr);
     279        int pthread_attr_init(pthread_attr_t * attr) libcfa_public __THROW {
     280                cfaPthread_attr_t * _attr = get(attr);
    282281                ?{}(*_attr, default_attrs);
    283282                return 0;
    284283        }
    285         int pthread_attr_destroy(pthread_attr_t *attr) libcfa_public __THROW {
     284        int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW {
    286285                ^?{}(*get(attr));
    287286                return 0;
    288287        }
    289288
    290         int pthread_attr_setscope( pthread_attr_t *attr, int contentionscope ) libcfa_public __THROW {
     289        int pthread_attr_setscope( pthread_attr_t * attr, int contentionscope ) libcfa_public __THROW {
    291290                get( attr )->contentionscope = contentionscope;
    292291                return 0;
    293292        } // pthread_attr_setscope
    294293
    295         int pthread_attr_getscope( const pthread_attr_t *attr, int *contentionscope ) libcfa_public __THROW {
     294        int pthread_attr_getscope( const pthread_attr_t * attr, int * contentionscope ) libcfa_public __THROW {
    296295                *contentionscope = get( attr )->contentionscope;
    297296                return 0;
    298297        } // pthread_attr_getscope
    299298
    300         int pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate ) libcfa_public __THROW {
     299        int pthread_attr_setdetachstate( pthread_attr_t * attr, int detachstate ) libcfa_public __THROW {
    301300                get( attr )->detachstate = detachstate;
    302301                return 0;
    303302        } // pthread_attr_setdetachstate
    304303
    305         int pthread_attr_getdetachstate( const pthread_attr_t *attr, int *detachstate ) libcfa_public __THROW {
     304        int pthread_attr_getdetachstate( const pthread_attr_t * attr, int * detachstate ) libcfa_public __THROW {
    306305                *detachstate = get( attr )->detachstate;
    307306                return 0;
    308307        } // pthread_attr_getdetachstate
    309308
    310         int pthread_attr_setstacksize( pthread_attr_t *attr, size_t stacksize ) libcfa_public __THROW {
     309        int pthread_attr_setstacksize( pthread_attr_t * attr, size_t stacksize ) libcfa_public __THROW {
    311310                get( attr )->stacksize = stacksize;
    312311                return 0;
    313312        } // pthread_attr_setstacksize
    314313
    315         int pthread_attr_getstacksize( const pthread_attr_t *attr, size_t *stacksize ) libcfa_public __THROW {
     314        int pthread_attr_getstacksize( const pthread_attr_t * attr, size_t * stacksize ) libcfa_public __THROW {
    316315                *stacksize = get( attr )->stacksize;
    317316                return 0;
     
    326325        } // pthread_attr_setguardsize
    327326
    328         int pthread_attr_setstackaddr( pthread_attr_t *attr, void *stackaddr ) libcfa_public __THROW {
     327        int pthread_attr_setstackaddr( pthread_attr_t * attr, void * stackaddr ) libcfa_public __THROW {
    329328                get( attr )->stackaddr = stackaddr;
    330329                return 0;
    331330        } // pthread_attr_setstackaddr
    332331
    333         int pthread_attr_getstackaddr( const pthread_attr_t *attr, void **stackaddr ) libcfa_public __THROW {
     332        int pthread_attr_getstackaddr( const pthread_attr_t * attr, void ** stackaddr ) libcfa_public __THROW {
    334333                *stackaddr = get( attr )->stackaddr;
    335334                return 0;
    336335        } // pthread_attr_getstackaddr
    337336
    338         int pthread_attr_setstack( pthread_attr_t *attr, void *stackaddr, size_t stacksize ) libcfa_public __THROW {
     337        int pthread_attr_setstack( pthread_attr_t * attr, void * stackaddr, size_t stacksize ) libcfa_public __THROW {
    339338                get( attr )->stackaddr = stackaddr;
    340339                get( attr )->stacksize = stacksize;
     
    342341        } // pthread_attr_setstack
    343342
    344         int pthread_attr_getstack( const pthread_attr_t *attr, void **stackaddr, size_t *stacksize ) libcfa_public __THROW {
     343        int pthread_attr_getstack( const pthread_attr_t * attr, void ** stackaddr, size_t * stacksize ) libcfa_public __THROW {
    345344                *stackaddr = get( attr )->stackaddr;
    346345                *stacksize = get( attr )->stacksize;
     
    351350        // already running thread threadID. It shall be called on unitialized attr
    352351        // and destroyed with pthread_attr_destroy when no longer needed.
    353         int pthread_getattr_np( pthread_t threadID, pthread_attr_t *attr ) libcfa_public __THROW { // GNU extension
     352        int pthread_getattr_np( pthread_t threadID, pthread_attr_t * attr ) libcfa_public __THROW { // GNU extension
    354353                check_nonnull(attr);
    355354
     
    363362        //######################### Threads #########################
    364363
    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();
     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();
    367366                (*t){_thread, attr, start_routine, arg};
    368367                return 0;
    369368        }
    370369
    371 
    372         int pthread_join(pthread_t _thread, void **value_ptr) libcfa_public __THROW {
     370        int pthread_join(pthread_t _thread, void ** value_ptr) libcfa_public __THROW {
    373371                // if thread is invalid
    374372                if (_thread == NULL) return EINVAL;
     
    376374
    377375                // get user thr pointer
    378                 cfaPthread* p = lookup(_thread);
     376                cfaPthread * p = lookup(_thread);
    379377                try {
    380378                        join(*p);
     
    389387        }
    390388
    391         int pthread_tryjoin_np(pthread_t _thread, void **value_ptr) libcfa_public __THROW {
     389        int pthread_tryjoin_np(pthread_t _thread, void ** value_ptr) libcfa_public __THROW {
    392390                // if thread is invalid
    393391                if (_thread == NULL) return EINVAL;
    394392                if (_thread == pthread_self()) return EDEADLK;
    395393
    396                 cfaPthread* p = lookup(_thread);
     394                cfaPthread * p = lookup(_thread);
    397395
    398396                // thread not finished ?
     
    412410        void pthread_exit(void * status) libcfa_public __THROW {
    413411                pthread_t pid = pthread_self();
    414                 cfaPthread* _thread = (cfaPthread*)pid;
     412                cfaPthread * _thread = (cfaPthread *)pid;
    415413                _thread->joinval = status;  // set return value
    416414                _thread->isTerminated = 1;  // set terminated flag
     
    426424        //######################### Mutex #########################
    427425
    428         int pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t *attr) libcfa_public __THROW {
     426        int pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t * attr) libcfa_public __THROW {
    429427                check_nonnull(_mutex);
    430428                init(_mutex);
     
    435433        int pthread_mutex_destroy(pthread_mutex_t *_mutex) libcfa_public __THROW {
    436434                check_nonnull(_mutex);
    437                 simple_owner_lock* _lock = get(_mutex);
    438                 if (_lock->owner != NULL){
     435                simple_owner_lock * _lock = get(_mutex);
     436                if (_lock->owner != NULL) {
    439437                        return EBUSY;
    440438                }
     
    446444                check_nonnull(_mutex);
    447445                mutex_check(_mutex);
    448                 simple_owner_lock* _lock = get(_mutex);
     446                simple_owner_lock * _lock = get(_mutex);
    449447                lock(*_lock);
    450448                return 0;
     
    453451        int pthread_mutex_unlock(pthread_mutex_t *_mutex) libcfa_public __THROW {
    454452                check_nonnull(_mutex);
    455                 simple_owner_lock* _lock = get(_mutex);
    456                 if (_lock->owner != active_thread()){
     453                simple_owner_lock * _lock = get(_mutex);
     454                if (_lock->owner != active_thread()) {
    457455                        return EPERM;
    458456                } // current thread does not hold the mutex
     
    463461        int pthread_mutex_trylock(pthread_mutex_t *_mutex) libcfa_public __THROW {
    464462                check_nonnull(_mutex);
    465                 simple_owner_lock* _lock = get(_mutex);
    466                 if (_lock->owner != active_thread() && _lock->owner != NULL){
     463                simple_owner_lock * _lock = get(_mutex);
     464                if (_lock->owner != active_thread() && _lock->owner != NULL) {
    467465                        return EBUSY;
    468466                }   // if mutex is owned
     
    474472
    475473        /* conditional variable routines */
    476         int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) libcfa_public __THROW {
     474        int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) libcfa_public __THROW {
    477475                check_nonnull(cond);
    478476                init(cond);
     
    480478        }  //pthread_cond_init
    481479
    482         int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *_mutex) libcfa_public __THROW {
     480        int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t *_mutex) libcfa_public __THROW {
    483481                check_nonnull(_mutex);
    484482                check_nonnull(cond);
     
    494492        } // pthread_cond_timedwait
    495493
    496         int pthread_cond_signal(pthread_cond_t *cond) libcfa_public __THROW {
     494        int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW {
    497495                check_nonnull(cond);
    498496                return notify_one(*get(cond));
    499497        } // pthread_cond_signal
    500498
    501         int pthread_cond_broadcast(pthread_cond_t *cond) libcfa_public __THROW {
     499        int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW {
    502500                check_nonnull(cond);
    503501                return notify_all(*get(cond));
    504502        } // pthread_cond_broadcast
    505503
    506         int pthread_cond_destroy(pthread_cond_t *cond) libcfa_public __THROW {
     504        int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW {
    507505                check_nonnull(cond);
    508506                destroy(cond);
     
    514512        //######################### Local storage #########################
    515513
    516         int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) libcfa_public __THROW {
     514        int pthread_once(pthread_once_t * once_control, void (* init_routine)(void)) libcfa_public __THROW {
    517515                static_assert(sizeof(pthread_once_t) >= sizeof(int),"sizeof(pthread_once_t) < sizeof(int)");
    518516                check_nonnull(once_control);
     
    527525        } // pthread_once
    528526
    529         int pthread_key_create( pthread_key_t *key, void (*destructor)( void * ) ) libcfa_public __THROW {
     527        int pthread_key_create( pthread_key_t * key, void (* destructor)( void * ) ) libcfa_public __THROW {
    530528                lock(key_lock);
    531529                for ( int i = 0; i < PTHREAD_KEYS_MAX; i += 1 ) {
     
    562560        }   // pthread_key_delete
    563561
    564         int pthread_setspecific( pthread_key_t key, const void *value ) libcfa_public __THROW {
     562        int pthread_setspecific( pthread_key_t key, const void * value ) libcfa_public __THROW {
    565563                // get current thread
    566                 cfaPthread* t = lookup(pthread_self());
     564                cfaPthread * t = lookup(pthread_self());
    567565                // if current thread's pthreadData is NULL; initialize it
    568                 pthread_values* values;
    569                 if (t->pthreadData == NULL){
     566                pthread_values * values;
     567                if (t->pthreadData == NULL) {
    570568                        values = anew( PTHREAD_KEYS_MAX);
    571569                        t->pthreadData = values;
    572                         for (int i = 0;i < PTHREAD_KEYS_MAX; i++){
     570                        for ( int i = 0;i < PTHREAD_KEYS_MAX; i++ ) {
    573571                                t->pthreadData[i].in_use = false;
    574572                        }   // for
     
    593591        } //pthread_setspecific
    594592
    595         void* pthread_getspecific(pthread_key_t key) libcfa_public __THROW {
     593        void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW {
    596594                if (key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use) return NULL;
    597595
    598596                // get current thread
    599                 cfaPthread* t = lookup(pthread_self());
     597                cfaPthread * t = lookup(pthread_self());
    600598                if (t->pthreadData == NULL) return NULL;
    601599                lock(key_lock);
    602                 pthread_values &entry = ((pthread_values *)t->pthreadData)[key];
     600                pthread_values & entry = ((pthread_values *)t->pthreadData)[key];
    603601                if ( ! entry.in_use ) {
    604602                        unlock( key_lock );
    605603                        return NULL;
    606604                } // if
    607                 void *value = entry.value;
     605                void * value = entry.value;
    608606                unlock(key_lock);
    609607
     
    875873        //######################### Parallelism #########################
    876874
    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
     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
    892890
    893891        //######################### Cancellation #########################
     
    906904        } // pthread_cancel
    907905
    908         int pthread_setcancelstate( int state, int *oldstate ) libcfa_public __THROW {
     906        int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW {
    909907                abort("pthread_setcancelstate not implemented");
    910908                return 0;
    911909        } // pthread_setcancelstate
    912910
    913         int pthread_setcanceltype( int type, int *oldtype ) libcfa_public __THROW {
     911        int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW {
    914912                abort("pthread_setcanceltype not implemented");
    915913                return 0;
     
    918916
    919917#pragma GCC diagnostic pop
    920 
  • libcfa/src/concurrency/ready_queue.cfa

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

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

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

    r2ed94a9 rb110bcc  
    99
    1010
    11 //
    12 // Single-dim array sruct (with explicit packing and atom)
    13 //
    14 
     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//
    1537forall( [N], S & | sized(S), Timmed &, Tbase & ) {
     38
     39    //
     40    // Single-dim array sruct (with explicit packing and atom)
     41    //
    1642    struct arpk {
    1743        S strides[N];
  • libcfa/src/containers/list.hfa

    r2ed94a9 rb110bcc  
    3232static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; }
    3333
    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 ) \
    36 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \
    37     static inline tytagref(immedBase, Tbase) ?`inner( derived & this ) { \
     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 ) { \
    3862        immedBase & ib = this; \
    3963        Tbase & b = ib`inner; \
  • libcfa/src/containers/vector2.hfa

    r2ed94a9 rb110bcc  
    99// Author           : Michael Brooks
    1010// Created On       : Thu Jun 23 22:00:00 2021
    11 // Last Modified By : Michael Brooks
    12 // Last Modified On : Thu Jun 23 22:00:00 2021
    13 // Update Count     : 1
    14 //
     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
    1517
    1618#include <stdlib.hfa>
  • libcfa/src/interpose.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Wed Mar 29 16:10:31 2017
    1111// Last Modified By : Peter A. Buhr
    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
     12// Last Modified On : Mon Mar 27 21:09:03 2023
     13// Update Count     : 196
     14//
     15
    1716#include <stdio.h>
    18 #include <string.h>                                                                             // strlen
    1917#include <unistd.h>                                                                             // _exit, getpid
    20 #include <signal.h>
    2118extern "C" {
    2219#include <dlfcn.h>                                                                              // dlopen, dlsym
     
    2421}
    2522
    26 #include "bits/debug.hfa"
    2723#include "bits/defs.hfa"
    2824#include "bits/signal.hfa"                                                              // sigHandler_?
     
    4036
    4137typedef void (* generic_fptr_t)(void);
     38
    4239static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) {
    43         const char * error;
    44 
    4540        union { generic_fptr_t fptr; void * ptr; } originalFunc;
    4641
    4742        #if defined( _GNU_SOURCE )
    48                 if ( version ) {
    49                         originalFunc.ptr = dlvsym( library, symbol, version );
    50                 } else {
    51                         originalFunc.ptr = dlsym( library, symbol );
    52                 }
     43        if ( version ) {
     44                originalFunc.ptr = dlvsym( library, symbol, version );
     45        } else {
     46                originalFunc.ptr = dlsym( library, symbol );
     47        } // if
    5348        #else
    54                 originalFunc.ptr = dlsym( library, symbol );
     49        originalFunc.ptr = dlsym( library, symbol );
    5550        #endif // _GNU_SOURCE
    5651
    57         error = dlerror();
    58         if ( error ) abort( "interpose_symbol : internal error, %s\n", error );
    59 
     52        if ( ! originalFunc.ptr ) {                                                     // == nullptr
     53                abort( "interpose_symbol : internal error, %s\n", dlerror() );
     54        } // if
    6055        return originalFunc.fptr;
    6156}
    6257
    6358static 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
     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() );
    7968        } // if
    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
    91         } // if
    92 
    93         return do_interpose_symbol(library, symbol, version);
     69        #endif // RTLD_NEXT
     70
     71        return do_interpose_symbol( library, symbol, version );
    9472}
    9573
     
    12199                preload_libgcc();
    122100
    123 #pragma GCC diagnostic push
    124 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
     101                #pragma GCC diagnostic push
     102                #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
    125103                INTERPOSE_LIBC( abort, version );
    126104                INTERPOSE_LIBC( exit , version );
    127 #pragma GCC diagnostic pop
     105                #pragma GCC diagnostic pop
    128106
    129107                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
    130118
    131119                // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
     
    293281        va_start( args, fmt );
    294282        __abort( false, fmt, args );
    295     // CONTROL NEVER REACHES HERE!
     283        // CONTROL NEVER REACHES HERE!
    296284        va_end( args );
    297285}
    298286
    299287void abort( bool signalAbort, const char fmt[], ... ) {
    300     va_list args;
    301     va_start( args, fmt );
    302     __abort( signalAbort, fmt, args );
    303     // CONTROL NEVER REACHES HERE!
    304     va_end( args );
     288        va_list args;
     289        va_start( args, fmt );
     290        __abort( signalAbort, fmt, args );
     291        // CONTROL NEVER REACHES HERE!
     292        va_end( args );
    305293}
    306294
  • libcfa/src/interpose_thread.cfa

    r2ed94a9 rb110bcc  
    1414//
    1515
    16 #include <stdarg.h>                                                                             // va_start, va_end
    17 #include <stdio.h>
    18 #include <string.h>                                                                             // strlen
     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
    1921#include <signal.h>
    2022#include <pthread.h>
     23#include <signal.h>
    2124extern "C" {
    2225#include <dlfcn.h>                                                                              // dlopen, dlsym
    23 #include <execinfo.h>                                                                   // backtrace, messages
    2426}
    2527
    26 #include "bits/debug.hfa"
    2728#include "bits/defs.hfa"
    28 #include <assert.h>
    2929
    3030//=============================================================================================
     
    3434typedef void (* generic_fptr_t)(void);
    3535
    36 generic_fptr_t interpose_symbol(
     36generic_fptr_t libcfa_public 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 ) libcfa_public {
    41         const char * error;
     40) {
     41        void * library;
    4242
    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
     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() );
    5550        } // if
     51        #endif // RTLD_NEXT
    5652
    57         return do_interpose_symbol(library, symbol, version);
     53        return do_interpose_symbol( library, symbol, version );
    5854}
    5955
     
    8379#pragma GCC diagnostic push
    8480#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
    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 );
     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 );
    9591#pragma GCC diagnostic pop
    9692        }
  • libcfa/src/iostream.cfa

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

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

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

    r2ed94a9 rb110bcc  
    1818#include <math.hfa>
    1919
    20 trait fromint(T) {
     20forall(T)
     21trait fromint {
    2122    void ?{}(T&, int);
    2223};
    23 trait zeroinit(T) {
     24forall(T)
     25trait zeroinit {
    2426    void ?{}(T&, zero_t);
    2527};
    26 trait zero_assign(T) {
     28forall(T)
     29trait zero_assign {
    2730    T ?=?(T&, zero_t);
    2831};
    29 trait subtract(T) {
     32forall(T)
     33trait subtract {
    3034    T ?-?(T, T);
    3135};
    32 trait negate(T) {
     36forall(T)
     37trait negate {
    3338    T -?(T);
    3439};
    35 trait add(T) {
     40forall(T)
     41trait add {
    3642    T ?+?(T, T);
    3743};
    38 trait multiply(T) {
     44forall(T)
     45trait multiply {
    3946    T ?*?(T, T);
    4047};
    41 trait divide(T) {
     48forall(T)
     49trait divide {
    4250    T ?/?(T, T);
    4351};
    44 trait lessthan(T) {
     52forall(T)
     53trait lessthan {
    4554    int ?<?(T, T);
    4655};
    47 trait equality(T) {
     56forall(T)
     57trait equality {
    4858    int ?==?(T, T);
    4959};
    50 trait sqrt(T) {
     60forall(T)
     61trait sqrt {
    5162    T sqrt(T);
    5263};
  • src/AST/Attribute.hpp

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

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

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

    r2ed94a9 rb110bcc  
    2020#include <unordered_map>
    2121
    22 #include "Common/utility.h"
     22#include "Common/Eval.h"       // for eval
    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, bool isVarArgs)
     59        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag 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(static_cast<ArgumentFlag>(isVarArgs));
     63        FunctionType * ftype = new FunctionType( 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, bool isVarArgs)
     83        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag 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) ? VariableArgs : FixedArgs );
     88        FunctionType * type = new FunctionType( isVarArgs );
    8989        for ( auto & param : this->params ) {
    9090                type->params.emplace_back( param->get_type() );
  • src/AST/Decl.hpp

    r2ed94a9 rb110bcc  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:44:00 2022
    13 // Update Count     : 34
     12// Last Modified On : Wed Apr  5 10:42:00 2023
     13// Update Count     : 35
    1414//
    1515
     
    122122};
    123123
     124/// Function variable arguments flag
     125enum ArgumentFlag { FixedArgs, VariableArgs };
     126
    124127/// Object declaration `int foo()`
    125128class FunctionDecl : public DeclWithType {
     
    144147                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    145148                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    146                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     149                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
    147150
    148151        FunctionDecl( const CodeLocation & location, const std::string & name,
     
    150153                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    151154                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    152                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     155                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
    153156
    154157        const Type * get_type() const override;
     
    313316public:
    314317        bool isTyped; // isTyped indicated if the enum has a declaration like:
    315         // enum (type_optional) Name {...} 
     318        // enum (type_optional) Name {...}
    316319        ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    317320        enum class EnumHiding { Visible, Hide } hide;
     
    371374};
    372375
     376/// Assembly declaration: `asm ... ( "..." : ... )`
    373377class AsmDecl : public Decl {
    374378public:
  • src/AST/Expr.hpp

    r2ed94a9 rb110bcc  
    254254};
    255255
     256/// A name qualified by a namespace or type.
    256257class QualifiedNameExpr final : public Expr {
    257258public:
     
    259260        std::string name;
    260261
    261         QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 
     262        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
    262263        : Expr( loc ), type_decl( d ), name( n ) {}
    263264
     
    621622};
    622623
     624/// A name that refers to a generic dimension parameter.
    623625class DimensionExpr final : public Expr {
    624626public:
     
    910912};
    911913
    912 
    913914}
    914915
  • src/AST/Fwd.hpp

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

    r2ed94a9 rb110bcc  
    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

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Sep 22 13:44:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Apr 14 15:09:00 2023
     13// Update Count     : 3
    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.
     41bool isUnnamedBitfield( const ObjectDecl * obj );
     42
    4043}
  • src/AST/ParseNode.hpp

    r2ed94a9 rb110bcc  
    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);
    4244};
    4345
  • src/AST/Pass.impl.hpp

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

    r2ed94a9 rb110bcc  
    1818
    1919#include "Common/Stats/Heap.h"
    20 
    2120namespace ast {
    22 template<typename core_t>
    23 class Pass;
    24 
    25 class TranslationUnit;
    26 
    27 struct PureVisitor;
    28 
    29 template<typename node_t>
    30 node_t * deepCopy( const node_t * localRoot );
    31 
    32 namespace __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;
     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
     27namespace ast::__pass {
     28
     29typedef std::function<void( void * )> cleanup_func_t;
     30typedef 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
     34class bool_ref {
     35public:
     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
     42private:
     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
     57class guard_value {
     58public:
     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
     80private:
     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) {}
    5886        };
    5987
    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;
     88        std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
     89};
     90
     91// Guard structure implementation for whether or not children should be visited
     92class visit_children_guard {
     93public:
     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
     109private:
     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
     117template<typename core_t, typename node_t>
     118struct 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.
     126template< typename node_t >
     127struct 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.
     136template< template<class...> class container_t >
     137struct 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) {}
    94146        };
    95147
    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
     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.
     162template< template<class...> class container_t, typename node_t >
     163struct 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
     174template<bool is_void>
     175struct __assign;
     176
     177template<>
     178struct __assign<true> {
    122179        template<typename core_t, typename node_t>
    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
     180        static inline void result( core_t & core, const node_t * & node ) {
     181                core.previsit( node );
     182        }
     183};
     184
     185template<>
     186struct __assign<false> {
    237187        template<typename core_t, typename node_t>
    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 
     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
     197template<bool is_void>
     198struct __return;
     199
     200template<>
     201struct __return<true> {
    251202        template<typename core_t, typename node_t>
    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
     203        static inline const node_t * result( core_t & core, const node_t * & node ) {
     204                core.postvisit( node );
     205                return node;
     206        }
     207};
     208
     209template<>
     210struct __return<false> {
    255211        template<typename core_t, typename node_t>
    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; } \
     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
     232template<typename core_t, typename node_t>
     233static 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
     246template<typename core_t, typename node_t>
     247static inline auto previsit( core_t &, const node_t *, long ) {}
     248
     249// PostVisit : never mutates the passed pointer but may return a different node
     250template<typename core_t, typename node_t>
     251static 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
     261template<typename core_t, typename node_t>
     262static 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 ) \
     277template< typename core_t > \
     278static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
     279\
     280template< typename core_t > \
     281static inline default_type * name( core_t &, long ) { return nullptr; }
     282
     283// List of fields and their expected types
     284FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
     285FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
     286FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     287FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
     288FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
     289FIELD_PTR( visit_children, __pass::bool_ref )
     290FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
     291FIELD_PTR( visitor, ast::Pass<core_t> * const )
     292
     293// Remove the macro to make sure we don't clash
     294#undef FIELD_PTR
     295
     296template< typename core_t >
     297static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     298        // Stats::Heap::stacktrace_push(core_t::traceId);
     299}
     300
     301template< typename core_t >
     302static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     303        // Stats::Heap::stacktrace_pop();
     304}
     305
     306template< typename core_t >
     307static void beginTrace(core_t &, long) {}
     308
     309template< typename core_t >
     310static 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
     315template< typename core_t >
     316static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
     317
     318template< typename core_t >
     319static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
     320        return core.on_error(decl);
     321}
     322
     323template< typename core_t, typename node_t >
     324static 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
     331template< typename core_t, typename node_t >
     332static 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
     339namespace 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
     359namespace 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        } \
    284384        \
    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
     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
     456namespace 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`
     489namespace 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.
     503namespace 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
  • src/AST/Print.cpp

    r2ed94a9 rb110bcc  
    2929namespace ast {
    3030
    31 template <typename C, typename... T>
    32 constexpr array<C,sizeof...(T)> make_array(T&&... values)
    33 {
    34         return array<C,sizeof...(T)>{
    35                 std::forward<T>(values)...
    36         };
     31namespace {
     32
     33template<typename C, typename... T>
     34constexpr array<C, sizeof...(T)> make_array( T&&... values ) {
     35        return array<C, sizeof...(T)>{ std::forward<T>( values )... };
     36}
     37
     38namespace 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
     52template<typename bits_t, size_t N>
     53void 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        }
    3761}
    3862
     
    80104        static const char* Names[];
    81105
    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 
    119106        void print( const std::vector<ast::Label> & labels ) {
    120107                if ( labels.empty() ) return;
     
    230217                }
    231218
    232                 print( node->storage );
     219                ast::print( os, node->storage );
    233220                os << node->typeString();
    234221
     
    272259
    273260        void preprint( const ast::Type * node ) {
    274                 print( node->qualifiers );
     261                ast::print( os, node->qualifiers );
    275262        }
    276263
     
    278265                print( node->forall );
    279266                print( node->assertions );
    280                 print( node->qualifiers );
     267                ast::print( os, node->qualifiers );
    281268        }
    282269
    283270        void preprint( const ast::BaseInstType * node ) {
    284271                print( node->attributes );
    285                 print( node->qualifiers );
     272                ast::print( os, node->qualifiers );
    286273        }
    287274
     
    294281                }
    295282
    296                 print( node->storage );
     283                ast::print( os, node->storage );
    297284
    298285                if ( node->type ) {
     
    338325                if ( ! short_mode ) printAll( node->attributes );
    339326
    340                 print( node->storage );
    341                 print( node->funcSpec );
    342 
    343 
     327                ast::print( os, node->storage );
     328                ast::print( os, node->funcSpec );
    344329
    345330                if ( node->type && node->isTypeFixed ) {
     
    384369                                --indent;
    385370                        }
     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;
    386379                }
    387380
     
    746739        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    747740                os << "Suspend Statement";
    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;
     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;
    752745                }
    753746                os << endl;
     
    16271620};
    16281621
     1622} // namespace
     1623
    16291624void print( ostream & os, const ast::Node * node, Indenter indent ) {
    16301625        Printer printer { os, indent, false };
     
    16371632}
    16381633
    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
    1642 constexpr array<const char*, 3> Printer::Names::FuncSpecifiers;
    1643 constexpr array<const char*, 6> Printer::Names::StorageClasses;
    1644 constexpr array<const char*, 5> Printer::Names::Qualifiers;
     1634void print( ostream & os, Function::Specs specs ) {
     1635        print( os, specs, Names::FuncSpecifiers );
    16451636}
     1637
     1638void print( ostream & os, Storage::Classes storage ) {
     1639        print( os, storage, Names::StorageClasses );
     1640}
     1641
     1642void print( ostream & os, CV::Qualifiers qualifiers ) {
     1643        print( os, qualifiers, Names::Qualifiers );
     1644}
     1645
     1646} // namespace ast
  • src/AST/Print.hpp

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Wed May  8 13:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 20 14:34:00 2022
    13 // Update Count     : 36
     12// Last Modified On : Wed Apr  5 10:34:00 2023
     13// Update Count     : 37
    1414//
    1515
     
    205205};
    206206
     207// A while loop or a do-while loop:
     208enum WhileDoKind { While, DoWhile };
     209
    207210// While loop: while (...) ... else ... or do ... while (...) else ...;
    208211class WhileDoStmt final : public Stmt {
     
    212215        ptr<Stmt> else_;
    213216        std::vector<ptr<Stmt>> inits;
    214         bool isDoWhile;
     217        WhileDoKind isDoWhile;
    215218
    216219        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
    217                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     220                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    218221                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    219222
    220223        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_,
    221                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     224                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    222225                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    223226
     
    364367  public:
    365368        ptr<CompoundStmt> then;
    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) {}
     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) {}
    370373
    371374        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    394397};
    395398
     399// Clause in a waitfor statement: waitfor (..., ...) ...
    396400class WaitForClause final : public StmtClause {
    397401  public:
     
    454458        MUTATE_FRIEND
    455459};
     460
    456461} // namespace ast
    457462
  • src/AST/SymbolTable.cpp

    r2ed94a9 rb110bcc  
    7070        if ( baseExpr ) {
    7171                if (baseExpr->env) {
    72                         Expr * base = shallowCopy(baseExpr);
     72                        Expr * base = deepCopy(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         addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     262        addIdCommon( 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         addId( decl, OnConflict::error(), nullptr, deleter );
     267        addIdCommon( decl, OnConflict::error(), nullptr, deleter );
    268268}
    269269
     
    677677}
    678678
    679 void SymbolTable::addId(
    680                 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    681                 const Decl * deleter ) {
     679void SymbolTable::addIdCommon(
     680                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
     681                const Expr * baseExpr, const Decl * deleter ) {
    682682        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    683683        if (kind == NUMBER_OF_KINDS) { // not a special decl
    684                 addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
     684                addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
    685685        }
    686686        else {
     
    695695                        assertf(false, "special decl with non-function type");
    696696                }
    697                 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
    698         }
    699 }
    700 
    701 void SymbolTable::addId(
    702                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    703                 const Decl * deleter ) {
     697                addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
     698        }
     699}
     700
     701void SymbolTable::addIdToTable(
     702                const DeclWithType * decl, const std::string & lookupKey,
     703                IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
     704                const Expr * baseExpr, const Decl * deleter ) {
    704705        ++*stats().add_calls;
    705706        const std::string &name = decl->name;
     
    778779void SymbolTable::addMembers(
    779780                const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict 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                         }
     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 );
    798799                }
    799800        }
  • src/AST/SymbolTable.hpp

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

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon May 13 15:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:49:00 2022
    13 // Update Count     : 6
     12// Last Modified On : Thu Apr  6 15:59:00 2023
     13// Update Count     : 7
    1414//
    1515
     
    199199
    200200TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    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 }
     201: Type( q ), types( std::move(ts) ) {}
    220202
    221203bool isUnboundType(const Type * type) {
  • src/AST/Type.hpp

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

    r2ed94a9 rb110bcc  
    213213* `get_statement()` exclusively used for code location, replaced with `CodeLocation` field
    214214
    215 `CaseStmt`
     215`CaseStmt` => `CaseClause`
    216216* `_isDefault` has been removed
    217217  * `isDefault` calculates value from `cond`
     
    227227* `block` -> `body` and `finallyBlock` -> `finally`
    228228
    229 `ThrowStmt` `CatchStmt`
     229`ThrowStmt` and `CatchStmt` => `CatchClause`
    230230* moved `Kind` enums to shared `ast::ExceptionKind` enum
    231231
    232 `FinallyStmt`
     232`FinallyStmt` => `FinallyClause`
    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`
    282283
    283284`TypeInstType`
  • src/CodeGen/CodeGenerator.cc

    r2ed94a9 rb110bcc  
    1717#include <cassert>                   // for assert, assertf
    1818#include <list>                      // for _List_iterator, list, list<>::it...
     19#include <sstream>                   // for stringstream
    1920
    2021#include "AST/Decl.hpp"              // for DeclWithType
    2122#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

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

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

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

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  2 10:59:10 2023
    13 // Update Count     : 36
     12// Last Modified On : Sat Feb 25 12:01:31 2023
     13// Update Count     : 37
    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

    r2ed94a9 rb110bcc  
    2020        Common/CodeLocationTools.hpp \
    2121        Common/CodeLocationTools.cpp \
    22         Common/CompilerError.h \
    23         Common/Debug.h \
    2422        Common/DeclStats.hpp \
    2523        Common/DeclStats.cpp \
    2624        Common/ErrorObjects.h \
    2725        Common/Eval.cc \
     26        Common/Eval.h \
    2827        Common/Examine.cc \
    2928        Common/Examine.h \
     
    3130        Common/Indenter.h \
    3231        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/UnimplementedError.h \
     54        Common/ToString.hpp \
    5555        Common/UniqueName.cc \
    5656        Common/UniqueName.h \
  • src/Common/utility.h

    r2ed94a9 rb110bcc  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // utility.h --
     7// utility.h -- General utilities used across the compiler.
    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 : Mon Apr 25 14:26:00 2022
    13 // Update Count     : 51
     12// Last Modified On : Fri Feb 17 15:25:00 2023
     13// Update Count     : 53
    1414//
    1515
     
    1919#include <cctype>
    2020#include <algorithm>
    21 #include <functional>
    2221#include <iostream>
    23 #include <iterator>
    2422#include <list>
    2523#include <memory>
    26 #include <sstream>
    2724#include <string>
    2825#include <type_traits>
    29 #include <utility>
    3026#include <vector>
    3127#include <cstring>                                                                              // memcmp
     
    4945                return 0;
    5046        } // if
    51 }
    52 
    53 template< typename T, typename U >
    54 struct 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 
    64 template< typename T, typename U >
    65 static inline T * maybeBuild( const U *orig ) {
    66         return maybeBuild_t<T,U>::doit(orig);
    67 }
    68 
    69 template< typename T, typename U >
    70 static inline T * maybeMoveBuild( const U *orig ) {
    71         T* ret = maybeBuild<T>(orig);
    72         delete orig;
    73         return ret;
    7447}
    7548
     
    168141        splice( src, dst );
    169142        dst.swap( src );
    170 }
    171 
    172 template < typename T >
    173 void toString_single( std::ostream & os, const T & value ) {
    174         os << value;
    175 }
    176 
    177 template < typename T, typename... Params >
    178 void toString_single( std::ostream & os, const T & value, const Params & ... params ) {
    179         os << value;
    180         toString_single( os, params ... );
    181 }
    182 
    183 template < typename ... Params >
    184 std::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
    193 template< typename T >
    194 void 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
    206 template< typename T >
    207 void 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 );
    210143}
    211144
     
    236169}
    237170
    238 template< typename... Args >
    239 auto zip(Args&&... args) -> decltype(zipWith(std::forward<Args>(args)..., std::make_pair)) {
    240   return zipWith(std::forward<Args>(args)..., std::make_pair);
    241 }
    242 
    243 template< class InputIterator1, class InputIterator2, class OutputIterator, class BinFunction >
    244 void 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
    250 template< class InputIt, class Distance >
    251 InputIt operator+( InputIt it, Distance n ) {
    252         advance(it, n);
    253         return it;
    254 }
    255 
    256 template< typename T >
    257 void warn_single( const T & arg ) {
    258         std::cerr << arg << std::endl;
    259 }
    260 
    261 template< typename T, typename... Params >
    262 void warn_single(const T & arg, const Params & ... params ) {
    263         std::cerr << arg;
    264         warn_single( params... );
    265 }
    266 
    267 template< typename... Params >
    268 void warn( const Params & ... params ) {
    269         std::cerr << "Warning: ";
    270         warn_single( params... );
    271 }
    272 
    273171// determines if pref is a prefix of str
    274172static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
    275173        if ( pref.size() > str.size() ) return false;
    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 
    285 template< typename ThisType >
    286 class 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 
    300 template< typename ThisType >
    301 std::weak_ptr<ThisType> RefCountSingleton<ThisType>::global_instance;
     174        return pref == str.substr(start, pref.size());
     175}
    302176
    303177// -----------------------------------------------------------------------------
     
    356230        ~ValueGuardPtr() { if( ref ) { swap( *ref, old ); } }
    357231};
    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 
    364 template< typename T >
    365 struct 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 
    376 template< typename T >
    377 reverse_iterate_t< T > reverseIterate( T & ref ) {
    378         return reverse_iterate_t< T >( ref );
    379 }
    380 
    381 template< typename T >
    382 struct 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 
    429 template< typename T >
    430 enumerate_t<T> enumerate( T & ref ) {
    431         return enumerate_t< T >{ ref };
    432 }
    433 
    434 template< typename T >
    435 const enumerate_t< const T > enumerate( const T & ref ) {
    436         return enumerate_t< const T >{ ref };
    437 }
    438 
    439 template< typename OutType, typename Range, typename Functor >
    440 OutType 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 
    458 template<typename... Args>
    459 class 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 
    497 public:
    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):
    508 static 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 
    514 static 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.
    521 template< typename... Args >
    522 group_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.
    528 template< typename... Args >
    529 group_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
    537 template< typename T, typename Func >
    538 struct 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 
    560 template< typename... Args >
    561 lambda_iterate_t<Args...> lazy_map( const Args &... args ) {
    562         return lambda_iterate_t<Args...>( args...);
    563 }
    564232
    565233// -----------------------------------------------------------------------------
     
    583251} // ilog2
    584252
    585 // -----------------------------------------------------------------------------
    586 /// evaluates expr as a long long int. If second is false, expr could not be evaluated
    587 std::pair<long long int, bool> eval(const Expression * expr);
    588 
    589 namespace ast {
    590         class Expr;
    591 }
    592 
    593 std::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.
    599 template<typename Iter, typename Compare>
    600 Iter 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 
    618 template<typename Iter, typename Compare>
    619 inline 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
    624 template<typename Iter>
    625 inline Iter sort_mins( Iter begin, Iter end ) {
    626         return sort_mins( begin, end, std::less<typename std::iterator_traits<Iter>::value_type>{} );
    627 }
    628 
    629253// Local Variables: //
    630254// tab-width: 4 //
  • src/CompilationState.cc

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

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

    r2ed94a9 rb110bcc  
    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         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;
     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        }
    5360        }
    5461
     
    6471    }
    6572
    66     // this collects the valid actor and message struct decl pts
     73    // this collects the derived actor and message struct decl ptrs
    6774    void postvisit( const StructInstType * node ) {
    6875        if ( ! *actorDecl || ! *msgDecl ) return;
    6976        if ( insideStruct && !namedDecl ) {
    70             if ( node->aggr() == *actorDecl ) {
     77            auto actorIter = actorStructDecls.find( node->aggr() );   
     78            if ( actorIter != actorStructDecls.end() ) {
    7179                actorStructDecls.insert( parentDecl );
    72             } else if ( node->aggr() == *msgDecl ) {
     80                return;
     81            }
     82            auto messageIter = messageStructDecls.find( node->aggr() );
     83            if ( messageIter != messageStructDecls.end() ) {
    7384                messageStructDecls.insert( parentDecl );
    7485            }
     
    180191};
    181192
    182 #define __ALLOC 0 // C_TODO: complete swap to no-alloc version
    183 
    184 struct GenReceiveDecls : public ast::WithDeclsToAdd<> {
     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)
     196struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
    185197    unordered_set<const StructDecl *> & actorStructDecls;
    186198    unordered_set<const StructDecl *>  & messageStructDecls;
     
    191203    FwdDeclTable & forwardDecls;
    192204
     205    // generates the operator for actor message sends
    193206        void postvisit( const FunctionDecl * decl ) {
    194207        // return if not of the form receive( param1, param2 ) or if it is a forward decl
     
    209222        auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
    210223        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 
    216224            //////////////////////////////////////////////////////////////////////
    217225            // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
    218226            /*
    219227                static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
    220                     request * new_req = alloc();
     228                    request new_req;
    221229                    Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
    222230                    __receive_fn fn = (__receive_fn)my_work_fn;
    223                     (*new_req){ &receiver, &msg, fn };
    224                     send( receiver, *new_req );
     231                    new_req{ &receiver, &msg, fn };
     232                    send( receiver, new_req );
    225233                    return receiver;
    226234                }
    227             */ // C_TODO: update this with new no alloc version
     235            */
    228236            CompoundStmt * sendBody = new CompoundStmt( decl->location );
    229237
    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
    242238            // Generates: request new_req;
    243239            sendBody->push_back( new DeclStmt(
     
    249245                )
    250246            ));
    251             #endif
    252247           
    253248            // Function type is: Allocation (*)( derived_actor &, derived_msg & )
     
    268263            ));
    269264
    270             // Function type is: Allocation (*)( actor &, messsage & )
     265            // Function type is: Allocation (*)( actor &, message & )
    271266            FunctionType * genericReceive = new FunctionType();
    272267            genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
     
    274269            genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    275270
    276             // Generates: Allocation (*fn)( actor &, messsage & ) = (Allocation (*)( actor &, messsage & ))my_work_fn;
     271            // Generates: Allocation (*fn)( actor &, message & ) = (Allocation (*)( actor &, message & ))my_work_fn;
    277272            // More readable synonymous code:
    278273            //     typedef Allocation (*__receive_fn)(actor &, message &);
     
    290285            ));
    291286
    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
    323287            // Generates: new_req{ &receiver, &msg, fn };
    324288            sendBody->push_back( new ExprStmt(
     
    350314                                )
    351315                        ));
    352             #endif
    353316           
    354317            // Generates: return receiver;
     
    358321            FunctionDecl * sendOperatorFunction = new FunctionDecl(
    359322                decl->location,
    360                 "?|?",
     323                "?<<?",
    361324                {},                     // forall
    362325                {
     
    388351            // forward decls to resolve use before decl problem for '|' routines
    389352            forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
    390             // forwardDecls.push_back( ast::deepCopy( sendOperatorFunction ) );
    391353
    392354            sendOperatorFunction->stmts = sendBody;
     
    396358
    397359  public:
    398     GenReceiveDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     360    GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    399361        const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
    400362        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
     
    402364};
    403365
    404 struct GenFwdDecls : public ast::WithDeclsToAdd<> {
     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
     369struct FwdDeclOperator : public ast::WithDeclsToAdd<> {
    405370    unordered_set<const StructDecl *> & actorStructDecls;
    406371    unordered_set<const StructDecl *>  & messageStructDecls;
    407372    FwdDeclTable & forwardDecls;
    408373
     374    // handles forward declaring the message operator
    409375    void postvisit( const StructDecl * decl ) {
    410376        list<FunctionDecl *> toAddAfter;
     
    433399
    434400  public:
    435     GenFwdDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    436         FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
    437         forwardDecls(forwardDecls) {}
     401    FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     402        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
    438403};
    439404
     
    461426    Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    462427        allocationDecl, actorDecl, msgDecl );
    463        
     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
    464433    // second pass locates all receive() routines that overload the generic receive fn
    465434    // it then generates the appropriate operator '|' send routines for the receive routines
    466     Pass<GenReceiveDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
     435    Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    467436        allocationDecl, actorDecl, msgDecl, forwardDecls );
    468437
    469438    // The third pass forward declares operator '|' send routines
    470     Pass<GenFwdDecls>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
     439    Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
    471440}
    472441
  • src/Concurrency/Actors.hpp

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

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

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

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

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

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

    r2ed94a9 rb110bcc  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Fri Feb 05 12:22:20 2016
    13 // Update Count     : 6
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct  7 17:05:20 2022
     13// Update Count     : 7
    1414//
    1515
     
    1818#include <utility>                      // for pair
    1919
     20#include "AST/Pass.hpp"                 // for Pass
     21#include "AST/Type.hpp"
    2022#include "Common/PassVisitor.h"         // for PassVisitor
    2123#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::iterator
     
    8991                handleForall( pointerType->get_forall() );
    9092        }
     93
     94namespace {
     95
     96struct 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 );
     108private:
     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
     117FindFunctionCore::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
     124void 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
     133void 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
     142ast::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
     154void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) {
     155        GuardScope( typeVars );
     156        //handleForall( type->forall );
     157}
     158
     159} // namespace
     160
     161void 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
     172const 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
    91183} // namespace GenPoly
    92184
  • src/GenPoly/FindFunction.h

    r2ed94a9 rb110bcc  
    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 : Sat Jul 22 09:23:36 2017
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct  7 10:30:00 2022
     13// Update Count     : 3
    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
     33typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & );
     34
     35/// Recursively walks `type`, placing all functions that match `predicate`
     36/// under `typeVars` into `functions`.
     37void 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)`.
     41const ast::Type * findAndReplaceFunction( const ast::Type * type,
     42                std::vector<ast::ptr<ast::FunctionType>> & functions,
     43                const TypeVarMap & typeVars, FindFunctionPred predicate );
     44
    3245} // namespace GenPoly
    3346
  • src/GenPoly/GenPoly.cc

    r2ed94a9 rb110bcc  
    275275        }
    276276
     277const 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
    277285        bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {
    278286//              if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {
     
    319327                return 0;
    320328        }
     329
     330const 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}
    321340
    322341        Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {
     
    796815        }
    797816
     817void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) {
     818        typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) );
     819}
     820
    798821void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
    799         typeVars.insert( *type, ast::TypeData( type->base ) );
     822        typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) );
    800823}
    801824
     
    822845}
    823846
     847void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ) {
     848        for ( auto & typeDecl : decl->type_params ) {
     849                addToTypeVarMap( typeDecl, typeVars );
     850        }
     851}
     852
    824853        void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
    825854                for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {
  • src/GenPoly/GenPoly.h

    r2ed94a9 rb110bcc  
    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 );
    113114
    114115        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    115116        void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
    116117        void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
     118        void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars );
    117119
    118120        /// Prints type variable map
  • src/GenPoly/Lvalue.cc

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

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

    r2ed94a9 rb110bcc  
    3232#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    3333#include "Common/SemanticError.h"      // for SemanticError
     34#include "Common/ToString.hpp"         // for toCString
    3435#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 
    12411235                template< typename... Params >
    12421236                void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
    1243                         // toggle warnings vs. errors here.
    1244                         // warn( params... );
    1245                         error( *this, loc, params... );
     1237                        SemanticErrorException err( loc, toString( params... ) );
     1238                        errors.append( err );
    12461239                }
    12471240
  • src/InitTweak/FixInitNew.cpp

    r2ed94a9 rb110bcc  
    1414#include <utility>                     // for pair
    1515
     16#include "AST/DeclReplacer.hpp"
     17#include "AST/Expr.hpp"
    1618#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"
    1724#include "CodeGen/GenType.h"           // for genPrettyType
    1825#include "CodeGen/OperatorTable.h"
    19 #include "Common/CodeLocationTools.hpp"
    2026#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    2127#include "Common/SemanticError.h"      // for SemanticError
     28#include "Common/ToString.hpp"         // for toCString
    2229#include "Common/UniqueName.h"         // for UniqueName
    23 #include "Common/utility.h"            // for CodeLocation, ValueGuard, toSt...
    2430#include "FixGlobalInit.h"             // for fixGlobalInit
    2531#include "GenInit.h"                   // for genCtorDtor
     
    2834#include "ResolvExpr/Unify.h"          // for typesCompatible
    2935#include "SymTab/Autogen.h"            // for genImplicitCall
     36#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3037#include "SymTab/Indexer.h"            // for Indexer
    3138#include "SymTab/Mangler.h"            // for Mangler
     
    4552#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    4653
    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 
    5554extern bool ctordtorp; // print all debug
    5655extern bool ctorp; // print ctor debug
     
    6362namespace InitTweak {
    6463namespace {
     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
    65102        struct SelfAssignChecker {
    66103                void previsit( const ast::ApplicationExpr * appExpr );
     
    107144        private:
    108145                /// hack to implement WithTypeSubstitution while conforming to mutation safety.
    109                 ast::TypeSubstitution * env;
    110                 bool                    envModified;
     146                ast::TypeSubstitution * env         = nullptr;
     147                bool                    envModified = false;
    111148        };
    112149
     
    121158                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    122159
    123           protected:
     160        protected:
    124161                ObjectSet curVars;
    125162        };
     
    202239
    203240                SemanticErrorException errors;
    204           private:
     241        private:
    205242                template< typename... Params >
    206243                void emit( CodeLocation, const Params &... params );
     
    288325                static UniqueName dtorNamer( "__cleanup_dtor" );
    289326                std::string name = dtorNamer.newName();
    290                 ast::FunctionDecl * dtorFunc = SymTab::genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
     327                ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
    291328                stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
    292329
     
    522559        {
    523560                static UniqueName tempNamer("_tmp_cp");
    524                 assert( env );
    525561                const CodeLocation loc = impCpCtorExpr->location;
    526562                // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )
     
    534570
    535571                // xxx - this originally mutates arg->result in place. is it correct?
     572                assert( env );
    536573                result = env->applyFree( result.get() ).node;
    537574                auto mutResult = result.get_and_mutate();
     
    10801117        void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
    10811118                switch( stmt->kind ) {
    1082                   case ast::BranchStmt::Continue:
    1083                   case ast::BranchStmt::Break:
     1119                case ast::BranchStmt::Continue:
     1120                case ast::BranchStmt::Break:
    10841121                        // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
    10851122                        // always be empty), but it serves as a small sanity check.
    1086                   case ast::BranchStmt::Goto:
     1123                case ast::BranchStmt::Goto:
    10871124                        handleGoto( stmt );
    10881125                        break;
    1089                   default:
     1126                default:
    10901127                        assert( false );
    10911128                } // switch
     
    13031340        }
    13041341
    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 
    13111342        template< typename... Params >
    13121343        void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
    1313                 // toggle warnings vs. errors here.
    1314                 // warn( params... );
    1315                 error( *this, loc, params... );
     1344                SemanticErrorException err( loc, toString( params... ) );
     1345                errors.append( err );
    13161346        }
    13171347
     
    13191349                // xxx - functions returning ast::ptr seems wrong...
    13201350                auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
    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 );
     1351                return res.release();
    13241352        }
    13251353
  • src/InitTweak/GenInit.cc

    r2ed94a9 rb110bcc  
    3131#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
    3232#include "Common/SemanticError.h"      // for SemanticError
     33#include "Common/ToString.hpp"         // for toCString
    3334#include "Common/UniqueName.h"         // for UniqueName
    3435#include "Common/utility.h"            // for ValueGuard, maybeClone
     
    3839#include "ResolvExpr/Resolver.h"
    3940#include "SymTab/Autogen.h"            // for genImplicitCall
     41#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4042#include "SymTab/Mangler.h"            // for Mangler
    4143#include "SynTree/LinkageSpec.h"       // for isOverridable, C
  • src/Parser/DeclarationNode.cc

    r2ed94a9 rb110bcc  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 12:34:05 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug  8 17:07:00 2022
    13 // Update Count     : 1185
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Apr 20 11:46:00 2023
     13// Update Count     : 1393
    1414//
     15
     16#include "DeclarationNode.h"
    1517
    1618#include <cassert>                 // for assert, assertf, strict_dynamic_cast
     
    2123#include <string>                  // for string, operator+, allocator, char...
    2224
     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
    2335#include "Common/SemanticError.h"  // for SemanticError
    2436#include "Common/UniqueName.h"     // for UniqueName
    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::...
     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
    3341#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
    3442#include "TypedefTable.h"          // for TypedefTable
     
    4149
    4250// These must harmonize with the corresponding DeclarationNode enumerations.
    43 const char * DeclarationNode::basicTypeNames[] = { "void", "_Bool", "char", "int", "int128",
    44                                                                                                    "float", "double", "long double", "float80", "float128",
    45                                                                                                    "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames" };
    46 const char * DeclarationNode::complexTypeNames[] = { "_Complex", "NoComplexTypeNames", "_Imaginary" }; // Imaginary unsupported => parse, but make invisible and print error message
    47 const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" };
    48 const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" };
    49 const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" };
     51const 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};
     56const char * DeclarationNode::complexTypeNames[] = {
     57        "_Complex", "NoComplexTypeNames", "_Imaginary"
     58}; // Imaginary unsupported => parse, but make invisible and print error message
     59const char * DeclarationNode::signednessNames[] = {
     60        "signed", "unsigned", "NoSignednessNames"
     61};
     62const char * DeclarationNode::lengthNames[] = {
     63        "short", "long", "long long", "NoLengthNames"
     64};
     65const char * DeclarationNode::builtinTypeNames[] = {
     66        "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames"
     67};
    5068
    5169UniqueName DeclarationNode::anonymous( "__anonymous" );
    5270
    53 extern LinkageSpec::Spec linkage;                                               // defined in parser.yy
     71extern ast::Linkage::Spec linkage;                                              // defined in parser.yy
    5472
    5573DeclarationNode::DeclarationNode() :
     
    5775
    5876//      variable.name = nullptr;
    59         variable.tyClass = TypeDecl::NUMBER_OF_KINDS;
     77        variable.tyClass = ast::TypeDecl::NUMBER_OF_KINDS;
    6078        variable.assertions = nullptr;
    6179        variable.initializer = nullptr;
    6280
    63 //      attr.name = nullptr;
    64         attr.expr = nullptr;
    65         attr.type = nullptr;
    66 
    6781        assert.condition = nullptr;
    6882        assert.message = nullptr;
     
    7084
    7185DeclarationNode::~DeclarationNode() {
    72 //      delete attr.name;
    73         delete attr.expr;
    74         delete attr.type;
    75 
    7686//      delete variable.name;
    7787        delete variable.assertions;
    7888        delete variable.initializer;
    7989
    80 //      delete type;
     90//      delete type;
    8191        delete bitfieldWidth;
    8292
     
    103113        newnode->hasEllipsis = hasEllipsis;
    104114        newnode->linkage = linkage;
    105         newnode->asmName = maybeClone( asmName );
    106         cloneAll( attributes, newnode->attributes );
     115        newnode->asmName = maybeCopy( asmName );
     116        newnode->attributes = attributes;
    107117        newnode->initializer = maybeClone( initializer );
    108118        newnode->extension = extension;
     
    115125        newnode->variable.initializer = maybeClone( variable.initializer );
    116126
    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 
    121127        newnode->assert.condition = maybeClone( assert.condition );
    122         newnode->assert.message = maybeClone( assert.message );
     128        newnode->assert.message = maybeCopy( assert.message );
    123129        return newnode;
    124130} // DeclarationNode::clone
     
    130136        } // if
    131137
    132         if ( linkage != LinkageSpec::Cforall ) {
    133                 os << LinkageSpec::name( linkage ) << " ";
    134         } // if
    135 
    136         storageClasses.print( os );
    137         funcSpecs.print( os );
     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 );
    138144
    139145        if ( type ) {
     
    154160        } // if
    155161
    156         for ( Attribute * attr: reverseIterate( attributes ) ) {
    157                 os << string( indent + 2, ' ' ) << "attr " << attr->name.c_str();
    158         } // for
     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
    159168
    160169        os << endl;
     
    168177}
    169178
    170 DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) {
     179DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) {
    171180        DeclarationNode * newnode = new DeclarationNode;
    172181        newnode->storageClasses = sc;
     
    174183} // DeclarationNode::newStorageClass
    175184
    176 DeclarationNode * DeclarationNode::newFuncSpecifier( Type::FuncSpecifiers fs ) {
     185DeclarationNode * DeclarationNode::newFuncSpecifier( ast::Function::Specs fs ) {
    177186        DeclarationNode * newnode = new DeclarationNode;
    178187        newnode->funcSpecs = fs;
     
    180189} // DeclarationNode::newFuncSpecifier
    181190
    182 DeclarationNode * DeclarationNode::newTypeQualifier( Type::Qualifiers tq ) {
     191DeclarationNode * DeclarationNode::newTypeQualifier( ast::CV::Qualifiers tq ) {
    183192        DeclarationNode * newnode = new DeclarationNode;
    184193        newnode->type = new TypeData();
     
    240249}
    241250
    242 DeclarationNode * DeclarationNode::newAggregate( AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
     251DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
    243252        DeclarationNode * newnode = new DeclarationNode;
    244253        newnode->type = new TypeData( TypeData::Aggregate );
    245254        newnode->type->aggregate.kind = kind;
    246         newnode->type->aggregate.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
     255        newnode->type->aggregate.anon = name == nullptr;
     256        newnode->type->aggregate.name = newnode->type->aggregate.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
    247257        newnode->type->aggregate.actuals = actuals;
    248258        newnode->type->aggregate.fields = fields;
     
    250260        newnode->type->aggregate.tagged = false;
    251261        newnode->type->aggregate.parent = nullptr;
    252         newnode->type->aggregate.anon = name == nullptr;
    253262        return newnode;
    254263} // DeclarationNode::newAggregate
     
    257266        DeclarationNode * newnode = new DeclarationNode;
    258267        newnode->type = new TypeData( TypeData::Enum );
    259         newnode->type->enumeration.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
     268        newnode->type->enumeration.anon = name == nullptr;
     269        newnode->type->enumeration.name = newnode->type->enumeration.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
    260270        newnode->type->enumeration.constants = constants;
    261271        newnode->type->enumeration.body = body;
    262         newnode->type->enumeration.anon = name == nullptr;
    263272        newnode->type->enumeration.typed = typed;
    264273        newnode->type->enumeration.hiding = hiding;
    265         if ( base && base->type)  {
     274        if ( base && base->type )  {
    266275                newnode->type->base = base->type;
    267276        } // if
     
    269278        return newnode;
    270279} // DeclarationNode::newEnum
    271 
    272 
    273280
    274281DeclarationNode * DeclarationNode::newName( const string * name ) {
     
    323330} // DeclarationNode::newFromTypeGen
    324331
    325 DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {
     332DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) {
    326333        DeclarationNode * newnode = newName( name );
    327334        newnode->type = nullptr;
     
    335342        newnode->type = new TypeData( TypeData::Aggregate );
    336343        newnode->type->aggregate.name = name;
    337         newnode->type->aggregate.kind = AggregateDecl::Trait;
     344        newnode->type->aggregate.kind = ast::AggregateDecl::Trait;
    338345        newnode->type->aggregate.params = params;
    339346        newnode->type->aggregate.fields = asserts;
     
    345352        newnode->type = new TypeData( TypeData::AggregateInst );
    346353        newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
    347         newnode->type->aggInst.aggregate->aggregate.kind = AggregateDecl::Trait;
     354        newnode->type->aggInst.aggregate->aggregate.kind = ast::AggregateDecl::Trait;
    348355        newnode->type->aggInst.aggregate->aggregate.name = name;
    349356        newnode->type->aggInst.params = params;
     
    380387        newnode->type->array.dimension = size;
    381388        newnode->type->array.isStatic = isStatic;
    382         if ( newnode->type->array.dimension == nullptr || newnode->type->array.dimension->isExpressionType<ConstantExpr * >() ) {
     389        if ( newnode->type->array.dimension == nullptr || newnode->type->array.dimension->isExpressionType<ast::ConstantExpr *>() ) {
    383390                newnode->type->array.isVarLen = false;
    384391        } else {
     
    450457        DeclarationNode * newnode = new DeclarationNode;
    451458        newnode->type = nullptr;
    452         std::list< Expression * > exprs;
     459        std::vector<ast::ptr<ast::Expr>> exprs;
    453460        buildList( expr, exprs );
    454         newnode->attributes.push_back( new Attribute( *name, exprs ) );
     461        newnode->attributes.push_back(
     462                new ast::Attribute( *name, std::move( exprs ) ) );
    455463        delete name;
    456464        return newnode;
     
    469477}
    470478
    471 DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, Expression * message ) {
     479DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, ast::Expr * message ) {
    472480        DeclarationNode * newnode = new DeclarationNode;
    473481        newnode->assert.condition = condition;
     
    476484}
    477485
    478 
    479 void appendError( string & dst, const string & src ) {
     486static void appendError( string & dst, const string & src ) {
    480487        if ( src.empty() ) return;
    481488        if ( dst.empty() ) { dst = src; return; }
     
    484491
    485492void DeclarationNode::checkQualifiers( const TypeData * src, const TypeData * dst ) {
    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
     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() );
    494502        } // for
    495503} // DeclarationNode::checkQualifiers
    496504
    497505void DeclarationNode::checkSpecifiers( DeclarationNode * src ) {
    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
     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                }
    519537        } // if
    520538
     
    526544        storageClasses |= q->storageClasses;
    527545
    528         for ( Attribute * attr: reverseIterate( q->attributes ) ) {
    529                 attributes.push_front( attr->clone() );
    530         } // for
     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
    531553        return this;
    532554} // DeclarationNode::copySpecifiers
     
    576598
    577599        checkQualifiers( type, q->type );
    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] );
     600        if ( (builtin == Zero || builtin == One) && q->type->qualifiers.any() && error.length() == 0 ) {
     601                SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, builtinTypeNames[builtin] );
    580602        } // if
    581603        addQualifiersToType( q->type, type );
     
    598620        } else {
    599621                switch ( dst->kind ) {
    600                   case TypeData::Unknown:
     622                case TypeData::Unknown:
    601623                        src->qualifiers |= dst->qualifiers;
    602624                        dst = src;
    603625                        src = nullptr;
    604626                        break;
    605                   case TypeData::Basic:
     627                case TypeData::Basic:
    606628                        dst->qualifiers |= src->qualifiers;
    607629                        if ( src->kind != TypeData::Unknown ) {
     
    631653                        } // if
    632654                        break;
    633                   default:
     655                default:
    634656                        switch ( src->kind ) {
    635                           case TypeData::Aggregate:
    636                           case TypeData::Enum:
     657                        case TypeData::Aggregate:
     658                        case TypeData::Enum:
    637659                                dst->base = new TypeData( TypeData::AggregateInst );
    638660                                dst->base->aggInst.aggregate = src;
     
    643665                                src = nullptr;
    644666                                break;
    645                           default:
     667                        default:
    646668                                if ( dst->forall ) {
    647669                                        dst->forall->appendList( src->forall );
     
    714736
    715737DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) {
    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;
     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;
    723745        } // if
    724746
    725747        assert( type );
    726748        switch ( type->kind ) {
    727           case TypeData::Symbolic:
     749        case TypeData::Symbolic:
    728750                if ( type->symbolic.assertions ) {
    729751                        type->symbolic.assertions->appendList( assertions );
     
    732754                } // if
    733755                break;
    734           default:
     756        default:
    735757                assert( false );
    736758        } // switch
     
    796818DeclarationNode * DeclarationNode::copyAttribute( DeclarationNode * a ) {
    797819        if ( a ) {
    798                 for ( Attribute *attr: reverseIterate( a->attributes ) ) {
    799                         attributes.push_front( attr );
    800                 } // for
     820                spliceBegin( attributes, a->attributes );
    801821                a->attributes.clear();
    802822        } // if
     
    831851                if ( type ) {
    832852                        switch ( type->kind ) {
    833                           case TypeData::Aggregate:
    834                           case TypeData::Enum:
     853                        case TypeData::Aggregate:
     854                        case TypeData::Enum:
    835855                                p->type->base = new TypeData( TypeData::AggregateInst );
    836856                                p->type->base->aggInst.aggregate = type;
     
    841861                                break;
    842862
    843                           default:
     863                        default:
    844864                                p->type->base = type;
    845865                        } // switch
     
    863883
    864884DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
    865   if ( ! a ) return this;
     885        if ( ! a ) return this;
    866886        assert( a->type->kind == TypeData::Array );
    867887        TypeData * lastArray = findLast( a->type );
    868888        if ( type ) {
    869889                switch ( type->kind ) {
    870                   case TypeData::Aggregate:
    871                   case TypeData::Enum:
     890                case TypeData::Aggregate:
     891                case TypeData::Enum:
    872892                        lastArray->base = new TypeData( TypeData::AggregateInst );
    873893                        lastArray->base->aggInst.aggregate = type;
     
    877897                        lastArray->base->qualifiers |= type->qualifiers;
    878898                        break;
    879                   default:
     899                default:
    880900                        lastArray->base = type;
    881901                } // switch
     
    919939
    920940DeclarationNode * DeclarationNode::addTypeInitializer( DeclarationNode * init ) {
    921         assertf( variable.tyClass != TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
     941        assertf( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
    922942        variable.initializer = init;
    923943        return this;
     
    9831003}
    9841004
    985 void buildList( const DeclarationNode * firstNode, std::list< Declaration * > & outputList ) {
     1005// If a typedef wraps an anonymous declaration, name the inner declaration
     1006// so it has a consistent name across translation units.
     1007static 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.
     1051static 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.
     1076static 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
     1087void buildList( DeclarationNode * firstNode,
     1088                std::vector<ast::ptr<ast::Decl>> & outputList ) {
    9861089        SemanticErrorException errors;
    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() ) ) {
     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 ) ) {
    9901093                try {
    991                         bool extracted = false;
    992                         bool anon = false;
     1094                        bool extracted_named = false;
     1095                        ast::UnionDecl * unionDecl = nullptr;
     1096
    9931097                        if ( DeclarationNode * extr = cur->extractAggregate() ) {
    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;
     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;
    10001106
    10011107                                        // need to remember the cases where a declaration contains an anonymous aggregate definition
    1002                                         extracted = true;
    10031108                                        assert( extr->type );
    10041109                                        if ( extr->type->kind == TypeData::Aggregate ) {
    1005                                                 anon = extr->type->aggregate.anon;
     1110                                                // typedef struct { int A } B is the only case?
     1111                                                extracted_named = !extr->type->aggregate.anon;
    10061112                                        } else if ( extr->type->kind == TypeData::Enum ) {
    1007                                                 // xxx - is it useful to have an implicit anonymous enum member?
    1008                                                 anon = extr->type->enumeration.anon;
     1113                                                // typedef enum { A } B is the only case?
     1114                                                extracted_named = !extr->type->enumeration.anon;
     1115                                        } else {
     1116                                                extracted_named = true;
    10091117                                        }
    10101118                                } // if
     
    10121120                        } // if
    10131121
    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;
     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                                        }
    10381142                                } // if
     1143                                *out++ = decl;
    10391144                        } // if
    1040                 } catch( SemanticErrorException & e ) {
     1145                } catch ( SemanticErrorException & e ) {
    10411146                        errors.append( e );
    10421147                } // try
     
    10491154
    10501155// currently only builds assertions, function parameters, and return values
    1051 void buildList( const DeclarationNode * firstNode, std::list< DeclarationWithType * > & outputList ) {
     1156void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
    10521157        SemanticErrorException errors;
    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() ) ) {
     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 ) ) {
    10561161                try {
    1057                         Declaration * decl = cur->build();
    1058                         assert( decl );
    1059                         if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     1162                        ast::Decl * decl = cur->build();
     1163                        assertf( decl, "buildList: build for ast::DeclWithType." );
     1164                        if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    10601165                                dwt->location = cur->location;
    10611166                                *out++ = dwt;
    1062                         } else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) {
     1167                        } else if ( ast::StructDecl * agg = dynamic_cast<ast::StructDecl *>( decl ) ) {
    10631168                                // e.g., int foo(struct S) {}
    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;
     1169                                auto inst = new ast::StructInstType( agg->name );
     1170                                auto obj = new ast::ObjectDecl( cur->location, "", inst );
     1171                                obj->linkage = linkage;
    10671172                                *out++ = obj;
    10681173                                delete agg;
    1069                         } else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) {
     1174                        } else if ( ast::UnionDecl * agg = dynamic_cast<ast::UnionDecl *>( decl ) ) {
    10701175                                // e.g., int foo(union U) {}
    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;
     1176                                auto inst = new ast::UnionInstType( agg->name );
     1177                                auto obj = new ast::ObjectDecl( cur->location,
     1178                                        "", inst, nullptr, ast::Storage::Classes(),
     1179                                        linkage );
    10741180                                *out++ = obj;
    1075                         } else if ( EnumDecl * agg = dynamic_cast< EnumDecl * >( decl ) ) {
     1181                        } else if ( ast::EnumDecl * agg = dynamic_cast<ast::EnumDecl *>( decl ) ) {
    10761182                                // e.g., int foo(enum E) {}
    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;
     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                                );
    10801191                                *out++ = obj;
     1192                        } else {
     1193                                assertf( false, "buildList: Could not convert to ast::DeclWithType." );
    10811194                        } // if
    1082                 } catch( SemanticErrorException & e ) {
     1195                } catch ( SemanticErrorException & e ) {
    10831196                        errors.append( e );
    10841197                } // try
     
    10901203} // buildList
    10911204
    1092 void buildTypeList( const DeclarationNode * firstNode, std::list< Type * > & outputList ) {
     1205void buildTypeList( const DeclarationNode * firstNode,
     1206                std::vector<ast::ptr<ast::Type>> & outputList ) {
    10931207        SemanticErrorException errors;
    1094         std::back_insert_iterator< std::list< Type * > > out( outputList );
    1095         const DeclarationNode * cur = firstNode;
    1096 
    1097         while ( cur ) {
     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 ) ) {
    10981211                try {
    10991212                        * out++ = cur->buildType();
    1100                 } catch( SemanticErrorException & e ) {
     1213                } catch ( SemanticErrorException & e ) {
    11011214                        errors.append( e );
    11021215                } // try
    1103                 cur = dynamic_cast< DeclarationNode * >( cur->get_next() );
    1104         } // while
     1216        } // for
    11051217
    11061218        if ( ! errors.isEmpty() ) {
     
    11091221} // buildTypeList
    11101222
    1111 Declaration * DeclarationNode::build() const {
     1223ast::Decl * DeclarationNode::build() const {
    11121224        if ( ! error.empty() ) SemanticError( this, error + " in declaration of " );
    11131225
    11141226        if ( asmStmt ) {
    1115                 return new AsmDecl( strict_dynamic_cast<AsmStmt *>( asmStmt->build() ) );
     1227                auto stmt = strict_dynamic_cast<ast::AsmStmt *>( asmStmt->build() );
     1228                return new ast::AsmDecl( stmt->location, stmt );
    11161229        } // if
    11171230        if ( directiveStmt ) {
    1118                 return new DirectiveDecl( strict_dynamic_cast<DirectiveStmt *>( directiveStmt->build() ) );
    1119         } // if
    1120 
    1121         if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
     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 ) {
    11221236                // otype is internally converted to dtype + otype parameters
    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." );
     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." );
    11251239                assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
    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() );
     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 );
    11281249                return ret;
    11291250        } // if
     
    11471268                } // if
    11481269                bool isDelete = initializer && initializer->get_isDelete();
    1149                 Declaration * decl = buildDecl( type, name ? *name : string( "" ), storageClasses, maybeBuild< Expression >( bitfieldWidth ), funcSpecs, linkage, asmName, isDelete ? nullptr : maybeBuild< Initializer >(initializer), attributes )->set_extension( extension );
     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 );
    11501281                if ( isDelete ) {
    1151                         DeclarationWithType * dwt = strict_dynamic_cast<DeclarationWithType *>( decl );
     1282                        auto dwt = strict_dynamic_cast<ast::DeclWithType *>( decl );
    11521283                        dwt->isDeleted = true;
    11531284                }
     
    11561287
    11571288        if ( assert.condition ) {
    1158                 return new StaticAssertDecl( maybeBuild< Expression >( assert.condition ), strict_dynamic_cast< ConstantExpr * >( maybeClone( assert.message ) ) );
     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 );
    11591292        }
    11601293
     
    11671300        } // if
    11681301        if ( enumInLine ) {
    1169                 return new InlineMemberDecl( *name, storageClasses, linkage, nullptr );
     1302                return new ast::InlineMemberDecl( location,
     1303                        *name, (ast::Type*)nullptr, storageClasses, linkage );
    11701304        } // if
    11711305        assertf( name, "ObjectDecl must a have name\n" );
    1172         return (new ObjectDecl( *name, storageClasses, linkage, maybeBuild< Expression >( bitfieldWidth ), nullptr, maybeBuild< Initializer >( initializer ) ))->set_asmName( asmName )->set_extension( extension );
    1173 }
    1174 
    1175 Type * DeclarationNode::buildType() const {
     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
     1319ast::Type * DeclarationNode::buildType() const {
    11761320        assert( type );
    11771321
    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 
    11841322        switch ( type->kind ) {
    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
     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;
    11991344                return simpletypes;
    12001345        } // switch
  • src/Parser/ExpressionNode.cc

    r2ed94a9 rb110bcc  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 13:17:07 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug  7 09:18:56 2021
    13 // Update Count     : 1077
    14 //
     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"
    1517
    1618#include <cassert>                 // for assert
     
    2123#include <string>                  // for string, operator+, operator==
    2224
     25#include "AST/Expr.hpp"            // for NameExpr
     26#include "AST/Type.hpp"            // for BaseType, SueInstType
    2327#include "Common/SemanticError.h"  // for SemanticError
    2428#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild, CodeLo...
    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
     29#include "DeclarationNode.h"       // for DeclarationNode
     30#include "InitializerNode.h"       // for InitializerNode
    3131#include "parserutility.h"         // for notZeroExpr
    32 
    33 class Initializer;
    3432
    3533using namespace std;
     
    4846// because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their
    4947// type.
    50 
    51 extern const Type::Qualifiers noQualifiers;                             // no qualifiers on constants
    5248
    5349// static inline bool checkH( char c ) { return c == 'h' || c == 'H'; }
     
    7167        size_t end = str.length() - 1;
    7268        if ( posn == end ) { type = 3; return; }                        // no length after 'l' => long
    73        
     69
    7470        string::size_type next = posn + 1;                                      // advance to length
    7571        if ( str[next] == '3' ) {                                                       // 32
     
    122118                if ( str[i] == '1' ) v |= 1;
    123119                i += 1;
    124           if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
     120                if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
    125121                v <<= 1;
    126122        } // for
    127123} // scanbin
    128124
    129 Expression * build_constantInteger( string & str ) {
    130         static const BasicType::Kind kind[2][6] = {
     125ast::Expr * build_constantInteger(
     126                const CodeLocation & location, string & str ) {
     127        static const ast::BasicType::Kind kind[2][6] = {
    131128                // short (h) must be before char (hh) because shorter type has the longer suffix
    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, },
     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, },
    134131        };
    135132
     
    141138        string str2( "0x0" );
    142139        unsigned long long int v, v2 = 0;                                       // converted integral value
    143         Expression * ret, * ret2;
     140        ast::Expr * ret, * ret2;
    144141
    145142        int type = -1;                                                                          // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
     
    149146        // special constants
    150147        if ( str == "0" ) {
    151                 ret = new ConstantExpr( Constant( (Type *)new ZeroType( noQualifiers ), str, (unsigned long long int)0 ) );
     148                ret = new ast::ConstantExpr( location, new ast::ZeroType(), str, 0 );
    152149                goto CLEANUP;
    153150        } // if
    154151        if ( str == "1" ) {
    155                 ret = new ConstantExpr( Constant( (Type *)new OneType( noQualifiers ), str, (unsigned long long int)1 ) );
     152                ret = new ast::ConstantExpr( location, new ast::OneType(), str, 1 );
    156153                goto CLEANUP;
    157154        } // if
    158 
    159         string::size_type posn;
    160155
    161156        // 'u' can appear before or after length suffix
     
    166161        } else {
    167162                // At least one digit in integer constant, so safe to backup while looking for suffix.
    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: ;
     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
    191190        } // if
    192191
     
    196195        if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target " + str );
    197196#endif // ! __SIZEOF_INT128__
    198        
     197
    199198        if ( str[0] == '0' ) {                                                          // radix character ?
    200199                dec = false;
     
    206205                                unsigned int len = str.length();
    207206                                if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large " + str );
    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: ;
     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
    213213                                sscanf( (char *)str.c_str(), "%llx", &v );
    214214#endif // __SIZEOF_INT128__
     
    301301
    302302        // Constant type is correct for overload resolving.
    303         ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][type] ), str, v ) );
     303        ret = new ast::ConstantExpr( location,
     304                new ast::BasicType( kind[Unsigned][type] ), str, v );
    304305        if ( Unsigned && type < 2 ) {                                           // hh or h, less than int ?
    305306                // int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values.
    306                 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
     307                ret = new ast::CastExpr( location,
     308                        ret,
     309                        new ast::BasicType( kind[Unsigned][type] ),
     310                        ast::ExplicitCast );
    307311        } else if ( ltype != -1 ) {                                                     // explicit length ?
    308312                if ( ltype == 6 ) {                                                             // int128, (int128)constant
    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 ) );
     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                        );
    313325                } else {                                                                                // explicit length, (length_type)constant
    314                         ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false );
     326                        ret = new ast::CastExpr( location,
     327                                ret,
     328                                new ast::TypeInstType( lnthsInt[Unsigned][ltype], ast::TypeDecl::Dtype ),
     329                                ast::ExplicitCast );
    315330                        if ( ltype == 5 ) {                                                     // pointer, intptr( (uintptr_t)constant )
    316                                 ret = build_func( new ExpressionNode( build_varref( new string( "intptr" ) ) ), new ExpressionNode( ret ) );
     331                                ret = build_func( location,
     332                                        new ExpressionNode(
     333                                                build_varref( location, new string( "intptr" ) ) ),
     334                                        new ExpressionNode( ret ) );
    317335                        } // if
    318336                } // if
     
    358376
    359377
    360 Expression * 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 },
     378ast::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 },
    364383        };
    365384
     
    398417
    399418        assert( 0 <= type && type < 12 );
    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 );
     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 );
    403429        } // if
    404430
     
    415441} // sepString
    416442
    417 Expression * build_constantChar( string & str ) {
     443ast::Expr * build_constantChar( const CodeLocation & location, string & str ) {
    418444        string units;                                                                           // units
    419445        sepString( str, units, '\'' );                                          // separate constant from units
    420446
    421         Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::Char ), str, (unsigned long long int)(unsigned char)str[1] ) );
     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] );
    422451        if ( units.length() != 0 ) {
    423                 ret = new UntypedExpr( new NameExpr( units ), { ret } );
     452                ret = new ast::UntypedExpr( location,
     453                        new ast::NameExpr( location, units ),
     454                        { ret } );
    424455        } // if
    425456
     
    428459} // build_constantChar
    429460
    430 Expression * build_constantStr( string & str ) {
     461ast::Expr * build_constantStr(
     462                const CodeLocation & location,
     463                string & str ) {
    431464        assert( str.length() > 0 );
    432465        string units;                                                                           // units
    433466        sepString( str, units, '"' );                                           // separate constant from units
    434467
    435         Type * strtype;
     468        ast::Type * strtype;
    436469        switch ( str[0] ) {                                                                     // str has >= 2 characters, i.e, null string "" => safe to look at subscripts 0/1
    437           case 'u':
     470        case 'u':
    438471                if ( str[1] == '8' ) goto Default;                              // utf-8 characters => array of char
    439472                // lookup type of associated typedef
    440                 strtype = new TypeInstType( Type::Qualifiers( ), "char16_t", false );
     473                strtype = new ast::TypeInstType( "char16_t", ast::TypeDecl::Dtype );
    441474                break;
    442           case 'U':
    443                 strtype = new TypeInstType( Type::Qualifiers( ), "char32_t", false );
     475        case 'U':
     476                strtype = new ast::TypeInstType( "char32_t", ast::TypeDecl::Dtype );
    444477                break;
    445           case 'L':
    446                 strtype = new TypeInstType( Type::Qualifiers( ), "wchar_t", false );
     478        case 'L':
     479                strtype = new ast::TypeInstType( "wchar_t", ast::TypeDecl::Dtype );
    447480                break;
    448           Default:                                                                                      // char default string type
    449           default:
    450                 strtype = new BasicType( Type::Qualifiers( ), BasicType::Char );
     481        Default:                                                                                        // char default string type
     482        default:
     483                strtype = new ast::BasicType( ast::BasicType::Char );
    451484        } // switch
    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 ) );
     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 );
    456492        if ( units.length() != 0 ) {
    457                 ret = new UntypedExpr( new NameExpr( units ), { ret } );
     493                ret = new ast::UntypedExpr( location,
     494                        new ast::NameExpr( location, units ),
     495                        { ret } );
    458496        } // if
    459497
     
    462500} // build_constantStr
    463501
    464 Expression * build_field_name_FLOATING_FRACTIONconstant( const string & str ) {
     502ast::Expr * build_field_name_FLOATING_FRACTIONconstant(
     503                const CodeLocation & location, const string & str ) {
    465504        if ( str.find_first_not_of( "0123456789", 1 ) != string::npos ) SemanticError( yylloc, "invalid tuple index " + str );
    466         Expression * ret = build_constantInteger( *new string( str.substr(1) ) );
     505        ast::Expr * ret = build_constantInteger( location,
     506                *new string( str.substr(1) ) );
    467507        delete &str;
    468508        return ret;
    469509} // build_field_name_FLOATING_FRACTIONconstant
    470510
    471 Expression * build_field_name_FLOATING_DECIMALconstant( const string & str ) {
     511ast::Expr * build_field_name_FLOATING_DECIMALconstant(
     512                const CodeLocation & location, const string & str ) {
    472513        if ( str[str.size() - 1] != '.' ) SemanticError( yylloc, "invalid tuple index " + str );
    473         Expression * ret = build_constantInteger( *new string( str.substr( 0, str.size()-1 ) ) );
     514        ast::Expr * ret = build_constantInteger(
     515                location, *new string( str.substr( 0, str.size()-1 ) ) );
    474516        delete &str;
    475517        return ret;
    476518} // build_field_name_FLOATING_DECIMALconstant
    477519
    478 Expression * build_field_name_FLOATINGconstant( const string & str ) {
     520ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation & location,
     521                const string & str ) {
    479522        // str is of the form A.B -> separate at the . and return member expression
    480523        int a, b;
     
    482525        stringstream ss( str );
    483526        ss >> a >> dot >> b;
    484         UntypedMemberExpr * ret = new UntypedMemberExpr( new ConstantExpr( Constant::from_int( b ) ), new ConstantExpr( Constant::from_int( a ) ) );
     527        auto ret = new ast::UntypedMemberExpr( location,
     528                ast::ConstantExpr::from_int( location, b ),
     529                ast::ConstantExpr::from_int( location, a )
     530        );
    485531        delete &str;
    486532        return ret;
    487533} // build_field_name_FLOATINGconstant
    488534
    489 Expression * 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;
     535ast::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
    499548} // make_field_name_fraction_constants
    500549
    501 Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ) {
    502         return make_field_name_fraction_constants( fieldName, maybeMoveBuild< Expression >( fracts ) );
     550ast::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 ) );
    503554} // build_field_name_fraction_constants
    504555
    505 NameExpr * build_varref( const string * name ) {
    506         NameExpr * expr = new NameExpr( *name );
     556ast::NameExpr * build_varref( const CodeLocation & location,
     557                const string * name ) {
     558        ast::NameExpr * expr = new ast::NameExpr( location, *name );
    507559        delete name;
    508560        return expr;
    509561} // build_varref
    510562
    511 QualifiedNameExpr * 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 );
     563ast::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 );
    518571                        }
    519572                }
    520573        }
    521         return new QualifiedNameExpr( newDecl, name->name );
     574        return new ast::QualifiedNameExpr( location, newDecl, name->name );
    522575}
    523576
    524 QualifiedNameExpr * 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 );
     577ast::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 );
    527581}
    528582
    529 DimensionExpr * build_dimensionref( const string * name ) {
    530         DimensionExpr * expr = new DimensionExpr( *name );
     583ast::DimensionExpr * build_dimensionref( const CodeLocation & location,
     584                const string * name ) {
     585        ast::DimensionExpr * expr = new ast::DimensionExpr( location, *name );
    531586        delete name;
    532587        return expr;
     
    544599}; // OperName
    545600
    546 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) {
    547         Type * targetType = maybeMoveBuildType( decl_node );
    548         if ( dynamic_cast< VoidType * >( targetType ) ) {
     601ast::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 ) ) {
    549606                delete targetType;
    550                 return new CastExpr( maybeMoveBuild< Expression >(expr_node), false );
     607                return new ast::CastExpr( location,
     608                        maybeMoveBuild( expr_node ),
     609                        ast::ExplicitCast );
    551610        } else {
    552                 return new CastExpr( maybeMoveBuild< Expression >(expr_node), targetType, false );
     611                return new ast::CastExpr( location,
     612                        maybeMoveBuild( expr_node ),
     613                        targetType,
     614                        ast::ExplicitCast );
    553615        } // if
    554616} // build_cast
    555617
    556 Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node ) {
    557         return new KeywordCastExpr( maybeMoveBuild< Expression >(expr_node), target );
     618ast::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        );
    558625}
    559626
    560 Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) {
    561         return new VirtualCastExpr( maybeMoveBuild< Expression >( expr_node ), maybeMoveBuildType( decl_node ) );
     627ast::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        );
    562634} // build_virtual_cast
    563635
    564 Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member ) {
    565         return new UntypedMemberExpr( member, maybeMoveBuild< Expression >(expr_node) );
     636ast::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        );
    566643} // build_fieldSel
    567644
    568 Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member ) {
    569         UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) );
     645ast::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        );
    570651        deref->location = expr_node->location;
    571         deref->get_args().push_back( maybeMoveBuild< Expression >(expr_node) );
    572         UntypedMemberExpr * ret = new UntypedMemberExpr( member, deref );
     652        deref->args.push_back( maybeMoveBuild( expr_node ) );
     653        auto ret = new ast::UntypedMemberExpr( location, member, deref );
    573654        return ret;
    574655} // build_pfieldSel
    575656
    576 Expression * build_offsetOf( DeclarationNode * decl_node, NameExpr * member ) {
    577         Expression * ret = new UntypedOffsetofExpr( maybeMoveBuildType( decl_node ), member->get_name() );
     657ast::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 );
    578665        delete member;
    579666        return ret;
    580667} // build_offsetOf
    581668
    582 Expression * 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 );
     669ast::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        );
    584678} // build_and_or
    585679
    586 Expression * 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 );
     680ast::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        );
    590689} // build_unary_val
    591690
    592 Expression * 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 
    598 Expression * 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 );
     691ast::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        );
    603702} // build_binary_val
    604703
    605 Expression * 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 
    612 Expression * 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) );
     704ast::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        );
    614713} // build_cond
    615714
    616 Expression * build_tuple( ExpressionNode * expr_node ) {
    617         list< Expression * > exprs;
     715ast::Expr * build_tuple( const CodeLocation & location,
     716                ExpressionNode * expr_node ) {
     717        std::vector<ast::ptr<ast::Expr>> exprs;
    618718        buildMoveList( expr_node, exprs );
    619         return new UntypedTupleExpr( exprs );;
     719        return new ast::UntypedTupleExpr( location, std::move( exprs ) );
    620720} // build_tuple
    621721
    622 Expression * build_func( ExpressionNode * function, ExpressionNode * expr_node ) {
    623         list< Expression * > args;
     722ast::Expr * build_func( const CodeLocation & location,
     723                ExpressionNode * function,
     724                ExpressionNode * expr_node ) {
     725        std::vector<ast::ptr<ast::Expr>> args;
    624726        buildMoveList( expr_node, args );
    625         return new UntypedExpr( maybeMoveBuild< Expression >(function), args );
     727        return new ast::UntypedExpr( location,
     728                maybeMoveBuild( function ),
     729                std::move( args )
     730        );
    626731} // build_func
    627732
    628 Expression * 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) );
     733ast::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 ) );
    632743        // these types do not have associated type information
    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) );
     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 ) );
    636749                } else {
    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) );
     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 ) );
    642759                } else {
    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) );
     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 ) );
    648769                } else {
    649                         return new CompoundLiteralExpr( new EnumInstType( Type::Qualifiers(), newDeclEnumDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
     770                        return new ast::CompoundLiteralExpr( location,
     771                                new ast::EnumInstType( newDeclEnumDecl->name ),
     772                                maybeMoveBuild( kids ) );
    650773                } // if
    651774        } else {
     
    656779// Local Variables: //
    657780// tab-width: 4 //
    658 // mode: c++ //
    659 // compile-command: "make install" //
    660781// End: //
  • src/Parser/InitializerNode.cc

    r2ed94a9 rb110bcc  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:20:24 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 28 23:27:20 2017
    13 // Update Count     : 26
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr  4 11:18:00 2023
     13// Update Count     : 27
    1414//
     15
     16#include "InitializerNode.h"
    1517
    1618#include <iostream>                // for operator<<, ostream, basic_ostream
     
    1820#include <string>                  // for operator<<, string
    1921
     22#include "AST/Expr.hpp"            // for Expr
     23#include "AST/Init.hpp"            // for Designator, Init, ListInit, Sing...
     24#include "Common/SemanticError.h"  // for SemanticError
     25#include "Common/utility.h"        // for maybeBuild
     26#include "ExpressionNode.h"        // for ExpressionNode
     27#include "DeclarationNode.h"       // for buildList
     28
    2029using namespace std;
    2130
    22 #include "Common/SemanticError.h"  // for SemanticError
    23 #include "Common/utility.h"        // for maybeBuild
    24 #include "ParseNode.h"             // for InitializerNode, ExpressionNode
    25 #include "SynTree/Expression.h"    // for Expression
    26 #include "SynTree/Initializer.h"   // for Initializer, ListInit, SingleInit
     31static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
     32        return maybeConstructed ? ast::MaybeConstruct : ast::NoConstruct;
     33}
    2734
    2835InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des )
     
    3340        if ( kids )
    3441                set_last( nullptr );
    35 } // InitializerNode::InitializerNode
     42} // InitializerNode::InitializerNode
    3643
    3744InitializerNode::InitializerNode( InitializerNode * init, bool aggrp, ExpressionNode * des )
     
    8592} // InitializerNode::printOneLine
    8693
    87 Initializer * InitializerNode::build() const {
     94ast::Init * InitializerNode::build() const {
    8895        assertf( ! isDelete, "Should not build delete stmt InitializerNode" );
    8996        if ( aggregate ) {
    9097                // steal designators from children
    91                 std::list< Designation * > designlist;
     98                std::vector<ast::ptr<ast::Designation>> designlist;
    9299                InitializerNode * child = next_init();
    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 ) );
     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 ) ) );
    97105                } // for
    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
     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                );
    106119        } // if
    107120        return nullptr;
  • src/Parser/ParseNode.h

    r2ed94a9 rb110bcc  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:28:16 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Nov  2 21:27:07 2022
    13 // Update Count     : 939
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Apr  3 17:55:00 2023
     13// Update Count     : 942
    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
    2629#include "Common/CodeLocation.h"   // for CodeLocation
    2730#include "Common/SemanticError.h"  // for SemanticError
    2831#include "Common/UniqueName.h"     // for UniqueName
    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::...
     32#include "Common/utility.h"        // for maybeClone
     33#include "Parser/parserutility.h"  // for maybeBuild, maybeCopy
    3634
    3735class Attribute;
     
    4038class DeclarationWithType;
    4139class Initializer;
     40class InitializerNode;
    4241class ExpressionNode;
    4342struct StatementNode;
     
    8281}; // ParseNode
    8382
    84 //##############################################################################
    85 
    86 class 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 
    121 class 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 
    145 template< typename T >
    146 struct 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 };
    158 
    15983// Must harmonize with OperName.
    16084enum class OperKinds {
     
    17296
    17397struct LabelNode {
    174         std::list< Label > labels;
     98        std::vector<ast::Label> labels;
    17599};
    176100
    177 Expression * build_constantInteger( std::string & str ); // these 4 routines modify the string
    178 Expression * build_constantFloat( std::string & str );
    179 Expression * build_constantChar( std::string & str );
    180 Expression * build_constantStr( std::string & str );
    181 Expression * build_field_name_FLOATING_FRACTIONconstant( const std::string & str );
    182 Expression * build_field_name_FLOATING_DECIMALconstant( const std::string & str );
    183 Expression * build_field_name_FLOATINGconstant( const std::string & str );
    184 Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts );
    185 
    186 NameExpr * build_varref( const std::string * name );
    187 QualifiedNameExpr * build_qualified_expr( const DeclarationNode * decl_node, const NameExpr * name );
    188 QualifiedNameExpr * build_qualified_expr( const EnumDecl * decl, const NameExpr * name );
    189 DimensionExpr * build_dimensionref( const std::string * name );
    190 
    191 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
    192 Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node );
    193 Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
    194 Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member );
    195 Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member );
    196 Expression * build_offsetOf( DeclarationNode * decl_node, NameExpr * member );
    197 Expression * build_and( ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    198 Expression * build_and_or( ExpressionNode * expr_node1, ExpressionNode * expr_node2, bool kind );
    199 Expression * build_unary_val( OperKinds op, ExpressionNode * expr_node );
    200 Expression * build_unary_ptr( OperKinds op, ExpressionNode * expr_node );
    201 Expression * build_binary_val( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    202 Expression * build_binary_ptr( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    203 Expression * build_cond( ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );
    204 Expression * build_tuple( ExpressionNode * expr_node = nullptr );
    205 Expression * build_func( ExpressionNode * function, ExpressionNode * expr_node );
    206 Expression * build_compoundLiteral( DeclarationNode * decl_node, InitializerNode * kids );
    207 
    208 //##############################################################################
    209 
    210 struct TypeData;
    211 
    212 struct 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 
    363 Type * buildType( TypeData * type );
    364 
    365 static inline Type * maybeMoveBuildType( const DeclarationNode * orig ) {
    366         Type * ret = orig ? orig->buildType() : nullptr;
    367         delete orig;
    368         return ret;
    369 }
    370 
    371 //##############################################################################
    372 
    373 struct 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 
    398 Statement * build_expr( ExpressionNode * ctl );
    399 
    400 struct 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 
    408 struct 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 
    419 Expression * build_if_control( CondCtl * ctl, std::list< Statement * > & init );
    420 Statement * build_if( CondCtl * ctl, StatementNode * then, StatementNode * else_ );
    421 Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt );
    422 Statement * build_case( ExpressionNode * ctl );
    423 Statement * build_default();
    424 Statement * build_while( CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    425 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    426 Statement * build_for( ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    427 Statement * build_branch( BranchStmt::Type kind );
    428 Statement * build_branch( std::string * identifier, BranchStmt::Type kind );
    429 Statement * build_computedgoto( ExpressionNode * ctl );
    430 Statement * build_return( ExpressionNode * ctl );
    431 Statement * build_throw( ExpressionNode * ctl );
    432 Statement * build_resume( ExpressionNode * ctl );
    433 Statement * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
    434 Statement * build_try( StatementNode * try_, StatementNode * catch_, StatementNode * finally_ );
    435 Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
    436 Statement * build_finally( StatementNode * stmt );
    437 Statement * build_compound( StatementNode * first );
    438 StatementNode * maybe_build_compound( StatementNode * first );
    439 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    440 Statement * build_directive( std::string * directive );
    441 SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
    442 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
    443 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
    444 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when );
    445 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when, StatementNode * else_stmt, ExpressionNode * else_when );
    446 Statement * build_with( ExpressionNode * exprs, StatementNode * stmt );
    447 Statement * build_mutex( ExpressionNode * exprs, StatementNode * stmt );
    448 
    449 //##############################################################################
    450 
    451 template< typename SynTreeType, typename NodeType, template< typename, typename...> class Container, typename... Args >
    452 void 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
    481 void buildList( const DeclarationNode * firstNode, std::list< Declaration * > & outputList );
    482 void buildList( const DeclarationNode * firstNode, std::list< DeclarationWithType * > & outputList );
    483 void buildTypeList( const DeclarationNode * firstNode, std::list< Type * > & outputList );
    484 
    485 template< typename SynTreeType, typename NodeType >
    486 void buildMoveList( const NodeType * firstNode, std::list< SynTreeType * > & outputList ) {
    487         buildList( firstNode, outputList );
    488         delete firstNode;
    489 }
    490 
    491 // in ParseNode.cc
    492101std::ostream & operator<<( std::ostream & out, const ParseNode * node );
    493102
  • src/Parser/ParserTypes.h

    r2ed94a9 rb110bcc  
    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

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon Dec 19 11:00:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Dec 22 10:18:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Mon Mar  6  9:42:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    2020#include "CodeTools/TrackLoc.h"             // for fillLocations
    2121#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    22 #include "Parser/ParseNode.h"               // for DeclarationNode, buildList
     22#include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
    2323#include "Parser/TypedefTable.h"            // for TypedefTable
    2424
    2525// Variables global to the parsing code.
    26 LinkageSpec::Spec linkage = LinkageSpec::Cforall;
     26ast::Linkage::Spec linkage = ast::Linkage::Cforall;
    2727TypedefTable typedefTable;
    2828DeclarationNode * parseTree = nullptr;
    2929
    30 void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit ) {
     30void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit ) {
    3131        extern int yyparse( void );
    3232        extern FILE * yyin;
     
    4646
    4747ast::TranslationUnit buildUnit(void) {
    48         std::list<Declaration *> translationUnit;
    49         buildList( parseTree, translationUnit );
    50 
     48        std::vector<ast::ptr<ast::Decl>> decls;
     49        buildList( parseTree, decls );
    5150        delete parseTree;
    5251        parseTree = nullptr;
    5352
    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 );
     53        ast::TranslationUnit transUnit;
     54        for ( auto decl : decls ) {
     55                transUnit.decls.emplace_back( std::move( decl ) );
     56        }
    6057        return transUnit;
    6158}
  • src/Parser/RunParser.hpp

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon Dec 19 10:42:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Dec 22 10:23:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Thr Feb 16 10:08:00 2023
     13// Update Count     : 2
    1414//
    1515
     
    1818#include <iosfwd>                           // for ostream
    1919
    20 #include "SynTree/LinkageSpec.h"            // for Spec
     20#include "AST/LinkageSpec.hpp"              // 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, LinkageSpec::Spec linkage, bool alwaysExit = false );
     31void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit = false );
    3232
    3333/// Drain the internal accumulator of parsed code and build a translation
  • src/Parser/StatementNode.cc

    r2ed94a9 rb110bcc  
    1010// Author           : Rodolfo G. Esteves
    1111// Created On       : Sat May 16 14:59:41 2015
    12 // Last Modified By : Peter A. Buhr
    13 // Last Modified On : Wed Feb  2 20:29:30 2022
    14 // Update Count     : 425
     12// Last Modified By : Andrew Beach
     13// Last Modified On : Tue Apr 11 10:16:00 2023
     14// Update Count     : 428
    1515//
    1616
     17#include "StatementNode.h"
     18
    1719#include <cassert>                 // for assert, strict_dynamic_cast, assertf
    18 #include <list>                    // for list
    1920#include <memory>                  // for unique_ptr
    2021#include <string>                  // for string
    2122
     23#include "AST/Label.hpp"           // for Label
     24#include "AST/Stmt.hpp"            // for Stmt, AsmStmt, BranchStmt, CaseCla...
    2225#include "Common/SemanticError.h"  // for SemanticError
    2326#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
    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
     27#include "DeclarationNode.h"       // for DeclarationNode
     28#include "ExpressionNode.h"        // for ExpressionNode
    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.
     36static 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
     43static 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}
    3549
    3650StatementNode::StatementNode( DeclarationNode * decl ) {
     
    3852        DeclarationNode * agg = decl->extractAggregate();
    3953        if ( agg ) {
    40                 StatementNode * nextStmt = new StatementNode( new DeclStmt( maybeBuild< Declaration >( decl ) ) );
     54                StatementNode * nextStmt = new StatementNode(
     55                        new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
    4156                set_next( nextStmt );
    4257                if ( decl->get_next() ) {
     
    5166                agg = decl;
    5267        } // if
    53         stmt.reset( new DeclStmt( maybeMoveBuild< Declaration >(agg) ) );
     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 ) ) );
    5471} // StatementNode::StatementNode
    5572
    56 StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
    57         StatementNode * prev = this;
     73StatementNode * 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
     86ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
     87        ClauseNode * prev = this;
    5888        // find end of list and maintain previous pointer
    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()) );
     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() ) );
    6292                prev = curr;
    6393        } // for
     94        ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
    6495        // convert from StatementNode list to Statement list
    65         StatementNode * node = dynamic_cast< StatementNode * >(prev);
    66         list< Statement * > stmts;
     96        std::vector<ast::ptr<ast::Stmt>> stmts;
    6797        buildMoveList( stmt, stmts );
    6898        // splice any new Statements to end of current Statements
    69         CaseStmt * caseStmt = dynamic_cast< CaseStmt * >(node->stmt.get());
    70         caseStmt->get_statements().splice( caseStmt->get_statements().end(), stmts );
     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();
    71104        return this;
    72 } // StatementNode::append_last_case
    73 
    74 Statement * build_expr( ExpressionNode * ctl ) {
    75         Expression * e = maybeMoveBuild< Expression >( ctl );
    76 
    77         if ( e ) return new ExprStmt( e );
    78         else return new NullStmt();
     105} // ClauseNode::append_last_case
     106
     107ast::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        }
    79113} // build_expr
    80114
    81 Expression * build_if_control( CondCtl * ctl, list< Statement * > & init ) {
    82         if ( ctl->init != 0 ) {
    83                 buildMoveList( ctl->init, init );
     115static 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 );
    84120        } // if
    85121
    86         Expression * cond = nullptr;
     122        ast::Expr * cond = nullptr;
    87123        if ( ctl->condition ) {
    88124                // compare the provided condition against 0
    89                 cond = notZeroExpr( maybeMoveBuild< Expression >(ctl->condition) );
     125                cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
    90126        } else {
    91                 for ( Statement * stmt : init ) {
     127                for ( ast::ptr<ast::Stmt> & stmt : inits ) {
    92128                        // build the && of all of the declared variables compared against 0
    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;
     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;
    97133                }
    98134        }
     
    101137} // build_if_control
    102138
    103 Statement * 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 );
     139ast::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        );
    121149} // build_if
    122150
    123 Statement * 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 ) );
     151ast::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;
    132167                        } // if
    133168                } // for
    134169        } // if
    135170        // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
    136         return new SwitchStmt( maybeMoveBuild< Expression >(ctl), aststmt );
     171        return new ast::SwitchStmt( location,
     172                maybeMoveBuild( ctl ), std::move( aststmt ) );
    137173} // build_switch
    138174
    139 Statement * build_case( ExpressionNode * ctl ) {
    140         return new CaseStmt( maybeMoveBuild< Expression >(ctl), {} ); // stmt starts empty and then added to
     175ast::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, {} );
    141179} // build_case
    142180
    143 Statement * build_default() {
    144         return new CaseStmt( nullptr, {}, true );                       // stmt starts empty and then added to
     181ast::CaseClause * build_default( const CodeLocation & location ) {
     182        // stmt starts empty and then added to
     183        return new ast::CaseClause( location, nullptr, {} );
    145184} // build_default
    146185
    147 Statement * 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 );
     186ast::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        );
    159197} // build_while
    160198
    161 Statement * 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 
     199ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
    169200        // do-while cannot have declarations in the contitional, so init is always empty
    170         return new WhileDoStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), aststmt.front(), astelse.front(), {}, true );
     201        return new ast::WhileDoStmt( location,
     202                notZeroExpr( maybeMoveBuild( ctl ) ),
     203                buildMoveSingle( stmt ),
     204                buildMoveOptional( else_ ),
     205                {},
     206                ast::DoWhile
     207        );
    171208} // build_do_while
    172209
    173 Statement * build_for( ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
    174         list< Statement * > astinit;                                            // maybe empty
     210ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
     211        std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
    175212        buildMoveList( forctl->init, astinit );
    176213
    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);
     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 );
    182219        delete forctl;
    183220
    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() );
     221        return new ast::ForStmt( location,
     222                std::move( astinit ),
     223                astcond,
     224                astincr,
     225                buildMoveSingle( stmt ),
     226                buildMoveOptional( else_ )
     227        );
    192228} // build_for
    193229
    194 Statement * build_branch( BranchStmt::Type kind ) {
    195         Statement * ret = new BranchStmt( "", kind );
    196         return ret;
     230ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
     231        return new ast::BranchStmt( location,
     232                kind,
     233                ast::Label( location )
     234        );
    197235} // build_branch
    198236
    199 Statement * build_branch( string * identifier, BranchStmt::Type kind ) {
    200         Statement * ret = new BranchStmt( * identifier, kind );
     237ast::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        );
    201242        delete identifier;                                                                      // allocated by lexer
    202243        return ret;
    203244} // build_branch
    204245
    205 Statement * build_computedgoto( ExpressionNode * ctl ) {
    206         return new BranchStmt( maybeMoveBuild< Expression >(ctl), BranchStmt::Goto );
     246ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
     247        ast::Expr * expr = maybeMoveBuild( ctl );
     248        return new ast::BranchStmt( expr->location, expr );
    207249} // build_computedgoto
    208250
    209 Statement * build_return( ExpressionNode * ctl ) {
    210         list< Expression * > exps;
     251ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
     252        std::vector<ast::ptr<ast::Expr>> exps;
    211253        buildMoveList( ctl, exps );
    212         return new ReturnStmt( exps.size() > 0 ? exps.back() : nullptr );
     254        return new ast::ReturnStmt( location,
     255                exps.size() > 0 ? exps.back().release() : nullptr
     256        );
    213257} // build_return
    214258
    215 Statement * build_throw( ExpressionNode * ctl ) {
    216         list< Expression * > exps;
     259static ast::Stmt * build_throw_stmt(
     260                const CodeLocation & location,
     261                ExpressionNode * ctl,
     262                ast::ExceptionKind kind ) {
     263        std::vector<ast::ptr<ast::Expr>> exps;
    217264        buildMoveList( ctl, exps );
    218265        assertf( exps.size() < 2, "CFA internal error: leaking memory" );
    219         return new ThrowStmt( ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr );
     266        return new ast::ThrowStmt( location,
     267                kind,
     268                !exps.empty() ? exps.back().release() : nullptr,
     269                (ast::Expr *)nullptr
     270        );
     271}
     272
     273ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
     274        return build_throw_stmt( loc, ctl, ast::Terminate );
    220275} // build_throw
    221276
    222 Statement * 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 );
     277ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
     278        return build_throw_stmt( loc, ctl, ast::Resume );
    227279} // build_resume
    228280
    229 Statement * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
     281ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
    230282        (void)ctl;
    231283        (void)target;
     
    233285} // build_resume_at
    234286
    235 Statement * 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 );
     287ast::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() );
     294        }
     295        return new ast::TryStmt( location,
     296                tryBlock,
     297                std::move( aststmt ),
     298                finallyBlock
     299        );
    241300} // build_try
    242301
    243 Statement * 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() );
     302ast::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        );
    248309} // build_catch
    249310
    250 Statement * 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() ) );
     311ast::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        );
    255317} // build_finally
    256318
    257 SuspendStmt * 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() );
    267         }
    268 
    269         return node;
    270 }
    271 
    272 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
    273         auto node = new WaitForStmt();
    274 
    275         WaitForStmt::Target target;
    276         target.function = maybeBuild<Expression>( targetExpr );
     319ast::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
     328ast::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 ) );
    277333
    278334        ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
    279335        targetExpr->set_next( nullptr );
    280         buildMoveList< Expression >( next, target.arguments );
     336        buildMoveList( next, clause->target_args );
    281337
    282338        delete targetExpr;
    283339
    284         node->clauses.push_back( WaitForStmt::Clause{
    285                 target,
    286                 maybeMoveBuild<Statement >( stmt ),
    287                 notZeroExpr( maybeMoveBuild<Expression>( when ) )
    288         });
    289 
    290         return node;
     340        existing->clauses.insert( existing->clauses.begin(), clause );
     341
     342        return existing;
    291343} // build_waitfor
    292344
    293 WaitForStmt * 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 
    312 WaitForStmt * 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;
     345ast::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
     353ast::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;
    325360} // build_waitfor_timeout
    326361
    327 WaitForStmt * 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 
    340 Statement * build_with( ExpressionNode * exprs, StatementNode * stmt ) {
    341         list< Expression * > e;
     362ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
     363        std::vector<ast::ptr<ast::Expr>> e;
    342364        buildMoveList( exprs, e );
    343         Statement * s = maybeMoveBuild<Statement>( stmt );
    344         return new DeclStmt( new WithStmt( e, s ) );
     365        ast::Stmt * s = maybeMoveBuild( stmt );
     366        return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
    345367} // build_with
    346368
    347 Statement * build_compound( StatementNode * first ) {
    348         CompoundStmt * cs = new CompoundStmt();
    349         buildMoveList( first, cs->get_kids() );
     369ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
     370        auto cs = new ast::CompoundStmt( location );
     371        buildMoveList( first, cs->kids );
    350372        return cs;
    351373} // build_compound
     
    355377// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
    356378// conical form for code generation.
    357 StatementNode * maybe_build_compound( StatementNode * first ) {
     379StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
    358380        // Optimization: if the control-structure statement is a compound statement, do not wrap it.
    359381        // e.g., if (...) {...} do not wrap the existing compound statement.
    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 );
     382        if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
     383                return new StatementNode( build_compound( location, first ) );
    364384        } // if
    365385        return first;
     
    367387
    368388// Question
    369 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    370         list< Expression * > out, in;
    371         list< ConstantExpr * > clob;
     389ast::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;
    372392
    373393        buildMoveList( output, out );
    374394        buildMoveList( input, in );
    375395        buildMoveList( clobber, clob );
    376         return new AsmStmt( voltile, instruction, out, in, clob, gotolabels ? gotolabels->labels : noLabels );
     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        );
    377404} // build_asm
    378405
    379 Statement * build_directive( string * directive ) {
    380         return new DirectiveStmt( *directive );
     406ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
     407        auto stmt = new ast::DirectiveStmt( location, *directive );
     408        delete directive;
     409        return stmt;
    381410} // build_directive
    382411
    383 Statement * build_mutex( ExpressionNode * exprs, StatementNode * stmt ) {
    384         list< Expression * > expList;
     412ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
     413        std::vector<ast::ptr<ast::Expr>> expList;
    385414        buildMoveList( exprs, expList );
    386         Statement * body = maybeMoveBuild<Statement>( stmt );
    387         return new MutexStmt( body, expList );
     415        ast::Stmt * body = maybeMoveBuild( stmt );
     416        return new ast::MutexStmt( location, body, std::move( expList ) );
    388417} // build_mutex
    389418
  • src/Parser/TypeData.cc

    r2ed94a9 rb110bcc  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 15:12:51 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue May 10 22:36:52 2022
    13 // Update Count     : 677
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr  4 13:39:00 2023
     13// Update Count     : 680
    1414//
     15
     16#include "TypeData.h"
    1517
    1618#include <cassert>                 // for assert
    1719#include <ostream>                 // for operator<<, ostream, basic_ostream
    1820
     21#include "AST/Decl.hpp"            // for AggregateDecl, ObjectDecl, TypeDe...
     22#include "AST/Init.hpp"            // for SingleInit, ListInit
     23#include "AST/Print.hpp"           // for print
    1924#include "Common/SemanticError.h"  // for SemanticError
    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"
     25#include "Common/utility.h"        // for splice, spliceBegin
     26#include "Parser/ExpressionNode.h" // for ExpressionNode
     27#include "Parser/StatementNode.h"  // for StatementNode
    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                 // nothing else to initialize
    41                 break;
    42           case Basic:
    43                 // basic = new Basic_t;
    44                 break;
    45           case Array:
    46                 // array = new Array_t;
     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:
    4744                array.dimension = nullptr;
    4845                array.isVarLen = false;
    4946                array.isStatic = false;
    5047                break;
    51           case Function:
    52                 // function = new Function_t;
     48        case Function:
    5349                function.params = nullptr;
    5450                function.idList = nullptr;
     
    5753                function.withExprs = nullptr;
    5854                break;
    59                 // Enum is an Aggregate, so both structures are initialized together.
    60           case Enum:
    61                 // enumeration = new Enumeration_t;
     55        case Enum:
    6256                enumeration.name = nullptr;
    6357                enumeration.constants = nullptr;
     
    6559                enumeration.anon = false;
    6660                break;
    67           case Aggregate:
    68                 // aggregate = new Aggregate_t;
    69                 aggregate.kind = AggregateDecl::NoAggregate;
     61        case Aggregate:
     62                aggregate.kind = ast::AggregateDecl::NoAggregate;
    7063                aggregate.name = nullptr;
    7164                aggregate.params = nullptr;
     
    7770                aggregate.anon = false;
    7871                break;
    79           case AggregateInst:
    80                 // aggInst = new AggInst_t;
     72        case AggregateInst:
    8173                aggInst.aggregate = nullptr;
    8274                aggInst.params = nullptr;
    8375                aggInst.hoistType = false;
    8476                break;
    85           case Symbolic:
    86           case SymbolicInst:
    87                 // symbolic = new Symbolic_t;
     77        case Symbolic:
     78        case SymbolicInst:
    8879                symbolic.name = nullptr;
    8980                symbolic.params = nullptr;
     
    9182                symbolic.assertions = nullptr;
    9283                break;
    93           case Tuple:
    94                 // tuple = new Tuple_t;
     84        case Tuple:
    9585                tuple = nullptr;
    9686                break;
    97           case Typeof:
    98           case Basetypeof:
    99                 // typeexpr = new Typeof_t;
     87        case Typeof:
     88        case Basetypeof:
    10089                typeexpr = nullptr;
    10190                break;
    102           case Vtable:
    103                 break;
    104           case Builtin:
    105                 // builtin = new Builtin_t;
    106                 case Qualified:
     91        case Vtable:
     92        case Builtin:
     93                // No unique data to initialize.
     94                break;
     95        case Qualified:
    10796                qualified.parent = nullptr;
    10897                qualified.child = nullptr;
     
    117106
    118107        switch ( kind ) {
    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:
     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:
    130117                delete array.dimension;
    131                 // delete array;
    132                 break;
    133           case Function:
     118                break;
     119        case Function:
    134120                delete function.params;
    135121                delete function.idList;
     
    137123                delete function.body;
    138124                delete function.withExprs;
    139                 // delete function;
    140                 break;
    141           case Aggregate:
     125                break;
     126        case Aggregate:
    142127                delete aggregate.name;
    143128                delete aggregate.params;
    144129                delete aggregate.actuals;
    145130                delete aggregate.fields;
    146                 // delete aggregate;
    147                 break;
    148           case AggregateInst:
     131                break;
     132        case AggregateInst:
    149133                delete aggInst.aggregate;
    150134                delete aggInst.params;
    151                 // delete aggInst;
    152                 break;
    153           case Enum:
     135                break;
     136        case Enum:
    154137                delete enumeration.name;
    155138                delete enumeration.constants;
    156                 // delete enumeration;
    157                 break;
    158           case Symbolic:
    159           case SymbolicInst:
     139                break;
     140        case Symbolic:
     141        case SymbolicInst:
    160142                delete symbolic.name;
    161143                delete symbolic.params;
    162144                delete symbolic.actuals;
    163145                delete symbolic.assertions;
    164                 // delete symbolic;
    165                 break;
    166           case Tuple:
    167                 // delete tuple->members;
     146                break;
     147        case Tuple:
    168148                delete tuple;
    169149                break;
    170           case Typeof:
    171           case Basetypeof:
    172                 // delete typeexpr->expr;
     150        case Typeof:
     151        case Basetypeof:
    173152                delete typeexpr;
    174153                break;
    175           case Vtable:
    176                 break;
    177           case Builtin:
    178                 // delete builtin;
    179                 break;
    180           case Qualified:
     154        case Vtable:
     155        case Builtin:
     156                // No unique data to deconstruct.
     157                break;
     158        case Qualified:
    181159                delete qualified.parent;
    182160                delete qualified.child;
     161                break;
    183162        } // switch
    184163} // TypeData::~TypeData
     
    192171
    193172        switch ( kind ) {
    194           case Unknown:
    195           case EnumConstant:
    196           case Pointer:
    197           case Reference:
    198           case GlobalScope:
     173        case Unknown:
     174        case EnumConstant:
     175        case Pointer:
     176        case Reference:
     177        case GlobalScope:
    199178                // nothing else to copy
    200179                break;
    201           case Basic:
     180        case Basic:
    202181                newtype->basictype = basictype;
    203182                newtype->complextype = complextype;
     
    205184                newtype->length = length;
    206185                break;
    207           case Array:
     186        case Array:
    208187                newtype->array.dimension = maybeClone( array.dimension );
    209188                newtype->array.isVarLen = array.isVarLen;
    210189                newtype->array.isStatic = array.isStatic;
    211190                break;
    212           case Function:
     191        case Function:
    213192                newtype->function.params = maybeClone( function.params );
    214193                newtype->function.idList = maybeClone( function.idList );
     
    217196                newtype->function.withExprs = maybeClone( function.withExprs );
    218197                break;
    219           case Aggregate:
     198        case Aggregate:
    220199                newtype->aggregate.kind = aggregate.kind;
    221200                newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
     
    228207                newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
    229208                break;
    230           case AggregateInst:
     209        case AggregateInst:
    231210                newtype->aggInst.aggregate = maybeClone( aggInst.aggregate );
    232211                newtype->aggInst.params = maybeClone( aggInst.params );
    233212                newtype->aggInst.hoistType = aggInst.hoistType;
    234213                break;
    235           case Enum:
     214        case Enum:
    236215                newtype->enumeration.name = enumeration.name ? new string( *enumeration.name ) : nullptr;
    237216                newtype->enumeration.constants = maybeClone( enumeration.constants );
     
    239218                newtype->enumeration.anon = enumeration.anon;
    240219                break;
    241           case Symbolic:
    242           case SymbolicInst:
     220        case Symbolic:
     221        case SymbolicInst:
    243222                newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr;
    244223                newtype->symbolic.params = maybeClone( symbolic.params );
     
    247226                newtype->symbolic.isTypedef = symbolic.isTypedef;
    248227                break;
    249           case Tuple:
     228        case Tuple:
    250229                newtype->tuple = maybeClone( tuple );
    251230                break;
    252           case Typeof:
    253           case Basetypeof:
     231        case Typeof:
     232        case Basetypeof:
    254233                newtype->typeexpr = maybeClone( typeexpr );
    255234                break;
    256           case Vtable:
    257                 break;
    258           case Builtin:
     235        case Vtable:
     236                break;
     237        case Builtin:
    259238                assert( builtintype == DeclarationNode::Zero || builtintype == DeclarationNode::One );
    260239                newtype->builtintype = builtintype;
    261240                break;
    262                 case Qualified:
     241        case Qualified:
    263242                newtype->qualified.parent = maybeClone( qualified.parent );
    264243                newtype->qualified.child = maybeClone( qualified.child );
     
    270249
    271250void TypeData::print( ostream &os, int indent ) const {
    272         for ( int i = 0; i < Type::NumTypeQualifier; i += 1 ) {
    273                 if ( qualifiers[i] ) os << Type::QualifiersNames[ i ] << ' ';
    274         } // for
     251        ast::print( os, qualifiers );
    275252
    276253        if ( forall ) {
     
    280257
    281258        switch ( kind ) {
    282           case Basic:
     259        case Basic:
    283260                if ( signedness != DeclarationNode::NoSignedness ) os << DeclarationNode::signednessNames[ signedness ] << " ";
    284261                if ( length != DeclarationNode::NoLength ) os << DeclarationNode::lengthNames[ length ] << " ";
     
    286263                if ( basictype != DeclarationNode::NoBasicType ) os << DeclarationNode::basicTypeNames[ basictype ] << " ";
    287264                break;
    288           case Pointer:
     265        case Pointer:
    289266                os << "pointer ";
    290267                if ( base ) {
     
    293270                } // if
    294271                break;
    295           case Reference:
     272        case Reference:
    296273                os << "reference ";
    297274                if ( base ) {
     
    300277                } // if
    301278                break;
    302           case Array:
     279        case Array:
    303280                if ( array.isStatic ) {
    304281                        os << "static ";
     
    316293                } // if
    317294                break;
    318           case Function:
     295        case Function:
    319296                os << "function" << endl;
    320297                if ( function.params ) {
     
    344321                } // if
    345322                break;
    346           case Aggregate:
    347                 os << AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
     323        case Aggregate:
     324                os << ast::AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
    348325                if ( aggregate.params ) {
    349326                        os << string( indent + 2, ' ' ) << "with type parameters" << endl;
     
    362339                } // if
    363340                break;
    364           case AggregateInst:
     341        case AggregateInst:
    365342                if ( aggInst.aggregate ) {
    366343                        os << "instance of " ;
     
    374351                } // if
    375352                break;
    376           case Enum:
    377                 os << "enumeration ";
     353        case Enum:
     354                os << "enumeration " << *enumeration.name << endl;;
    378355                if ( enumeration.constants ) {
    379356                        os << "with constants" << endl;
     
    388365                } // if
    389366                break;
    390           case EnumConstant:
     367        case EnumConstant:
    391368                os << "enumeration constant ";
    392369                break;
    393           case Symbolic:
     370        case Symbolic:
    394371                if ( symbolic.isTypedef ) {
    395372                        os << "typedef definition ";
     
    411388                } // if
    412389                break;
    413           case SymbolicInst:
     390        case SymbolicInst:
    414391                os << *symbolic.name;
    415392                if ( symbolic.actuals ) {
     
    419396                } // if
    420397                break;
    421           case Tuple:
     398        case Tuple:
    422399                os << "tuple ";
    423400                if ( tuple ) {
     
    426403                } // if
    427404                break;
    428           case Basetypeof:
     405        case Basetypeof:
    429406                os << "base-";
    430407                #if defined(__GNUC__) && __GNUC__ >= 7
     
    432409                #endif
    433410                // FALL THROUGH
    434           case Typeof:
     411        case Typeof:
    435412                os << "type-of expression ";
    436413                if ( typeexpr ) {
     
    438415                } // if
    439416                break;
    440           case Vtable:
     417        case Vtable:
    441418                os << "vtable";
    442419                break;
    443           case Builtin:
     420        case Builtin:
    444421                os << DeclarationNode::builtinTypeNames[builtintype];
    445422                break;
    446           case GlobalScope:
    447                 break;
    448           case Qualified:
     423        case GlobalScope:
     424                break;
     425        case Qualified:
    449426                qualified.parent->print( os );
    450427                os << ".";
    451428                qualified.child->print( os );
    452429                break;
    453           case Unknown:
     430        case Unknown:
    454431                os << "entity of unknown type ";
    455432                break;
    456           default:
     433        default:
    457434                os << "internal error: TypeData::print " << kind << endl;
    458435                assert( false );
     
    462439const std::string * TypeData::leafName() const {
    463440        switch ( kind ) {
    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:
     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:
    478455                assertf(false, "Tried to get leaf name from kind without a name: %d", kind);
    479456                break;
    480           case Aggregate:
     457        case Aggregate:
    481458                return aggregate.name;
    482           case Enum:
     459        case Enum:
    483460                return enumeration.name;
    484           case Symbolic:
    485           case SymbolicInst:
     461        case Symbolic:
     462        case SymbolicInst:
    486463                return symbolic.name;
    487           case Qualified:
     464        case Qualified:
    488465                return qualified.child->leafName();
    489466        } // switch
     
    492469
    493470
    494 template< typename ForallList >
    495 void buildForall( const DeclarationNode * firstNode, ForallList &outputList ) {
    496         buildList( firstNode, outputList );
     471void 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        }
    497483        auto n = firstNode;
    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
     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
     624void 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 );
    525769        } // for
    526770} // buildForall
    527771
    528772
    529 Type * typebuild( const TypeData * td ) {
     773ast::Type * typebuild( const TypeData * td ) {
    530774        assert( td );
    531775        switch ( td->kind ) {
    532           case TypeData::Unknown:
     776        case TypeData::Unknown:
    533777                // fill in implicit int
    534                 return new BasicType( buildQualifiers( td ), BasicType::SignedInt );
    535           case TypeData::Basic:
     778                return new ast::BasicType(
     779                        ast::BasicType::SignedInt,
     780                        buildQualifiers( td )
     781                );
     782        case TypeData::Basic:
    536783                return buildBasicType( td );
    537           case TypeData::Pointer:
     784        case TypeData::Pointer:
    538785                return buildPointer( td );
    539           case TypeData::Array:
     786        case TypeData::Array:
    540787                return buildArray( td );
    541           case TypeData::Reference:
     788        case TypeData::Reference:
    542789                return buildReference( td );
    543           case TypeData::Function:
    544                 return buildFunction( td );
    545           case TypeData::AggregateInst:
     790        case TypeData::Function:
     791                return buildFunctionType( td );
     792        case TypeData::AggregateInst:
    546793                return buildAggInst( td );
    547           case TypeData::EnumConstant:
    548                 return new EnumInstType( buildQualifiers( td ), "" );
    549           case TypeData::SymbolicInst:
     794        case TypeData::EnumConstant:
     795                return new ast::EnumInstType( "", buildQualifiers( td ) );
     796        case TypeData::SymbolicInst:
    550797                return buildSymbolicInst( td );
    551           case TypeData::Tuple:
     798        case TypeData::Tuple:
    552799                return buildTuple( td );
    553           case TypeData::Typeof:
    554           case TypeData::Basetypeof:
     800        case TypeData::Typeof:
     801        case TypeData::Basetypeof:
    555802                return buildTypeof( td );
    556           case TypeData::Vtable:
     803        case TypeData::Vtable:
    557804                return buildVtable( td );
    558           case TypeData::Builtin:
     805        case TypeData::Builtin:
    559806                switch ( td->builtintype ) {
    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 ) );
     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 ) );
    566813                } // switch
    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:
     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:
    574825                assert( false );
    575826        } // switch
     
    583834
    584835        switch ( td->kind ) {
    585           case TypeData::Aggregate:
     836        case TypeData::Aggregate:
    586837                if ( ! toplevel && td->aggregate.body ) {
    587838                        ret = td->clone();
    588839                } // if
    589840                break;
    590           case TypeData::Enum:
     841        case TypeData::Enum:
    591842                if ( ! toplevel && td->enumeration.body ) {
    592843                        ret = td->clone();
    593844                } // if
    594845                break;
    595           case TypeData::AggregateInst:
     846        case TypeData::AggregateInst:
    596847                if ( td->aggInst.aggregate ) {
    597848                        ret = typeextractAggregate( td->aggInst.aggregate, false );
    598849                } // if
    599850                break;
    600           default:
     851        default:
    601852                if ( td->base ) {
    602853                        ret = typeextractAggregate( td->base, false );
     
    607858
    608859
    609 Type::Qualifiers buildQualifiers( const TypeData * td ) {
     860ast::CV::Qualifiers buildQualifiers( const TypeData * td ) {
    610861        return td->qualifiers;
    611862} // buildQualifiers
     
    616867} // genTSError
    617868
    618 Type * buildBasicType( const TypeData * td ) {
    619         BasicType::Kind ret;
     869ast::Type * buildBasicType( const TypeData * td ) {
     870        ast::BasicType::Kind ret;
    620871
    621872        switch ( td->basictype ) {
    622           case DeclarationNode::Void:
     873        case DeclarationNode::Void:
    623874                if ( td->signedness != DeclarationNode::NoSignedness ) {
    624875                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    627878                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
    628879                } // if
    629                 return new VoidType( buildQualifiers( td ) );
    630                 break;
    631 
    632           case DeclarationNode::Bool:
     880                return new ast::VoidType( buildQualifiers( td ) );
     881                break;
     882
     883        case DeclarationNode::Bool:
    633884                if ( td->signedness != DeclarationNode::NoSignedness ) {
    634885                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    638889                } // if
    639890
    640                 ret = BasicType::Bool;
    641                 break;
    642 
    643           case DeclarationNode::Char:
     891                ret = ast::BasicType::Bool;
     892                break;
     893
     894        case DeclarationNode::Char:
    644895                // C11 Standard 6.2.5.15: The three types char, signed char, and unsigned char are collectively called the
    645896                // character types. The implementation shall define char to have the same range, representation, and behavior as
    646897                // either signed char or unsigned char.
    647                 static BasicType::Kind chartype[] = { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::Char };
     898                static ast::BasicType::Kind chartype[] = { ast::BasicType::SignedChar, ast::BasicType::UnsignedChar, ast::BasicType::Char };
    648899
    649900                if ( td->length != DeclarationNode::NoLength ) {
     
    654905                break;
    655906
    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 },
     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 },
    660911                };
    661912
    662           Integral: ;
     913        Integral: ;
    663914                if ( td->signedness == DeclarationNode::NoSignedness ) {
    664915                        const_cast<TypeData *>(td)->signedness = DeclarationNode::Signed;
     
    667918                break;
    668919
    669           case DeclarationNode::Int128:
    670                 ret = td->signedness == DeclarationNode::Unsigned ? BasicType::UnsignedInt128 : BasicType::SignedInt128;
     920        case DeclarationNode::Int128:
     921                ret = td->signedness == DeclarationNode::Unsigned ? ast::BasicType::UnsignedInt128 : ast::BasicType::SignedInt128;
    671922                if ( td->length != DeclarationNode::NoLength ) {
    672923                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
     
    674925                break;
    675926
    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, },
     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, },
    691942                };
    692943
    693           FloatingPoint: ;
     944        FloatingPoint: ;
    694945                if ( td->signedness != DeclarationNode::NoSignedness ) {
    695946                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    715966                break;
    716967
    717           case DeclarationNode::NoBasicType:
     968        case DeclarationNode::NoBasicType:
    718969                // No basic type in declaration => default double for Complex/Imaginary and int type for integral types
    719970                if ( td->complextype == DeclarationNode::Complex || td->complextype == DeclarationNode::Imaginary ) {
     
    724975                const_cast<TypeData *>(td)->basictype = DeclarationNode::Int;
    725976                goto Integral;
    726           default:
    727                 assertf( false, "unknown basic type" );
     977        default:
     978                assertf( false, "unknown basic type" );
    728979                return nullptr;
    729980        } // switch
    730981
    731         BasicType * bt = new BasicType( buildQualifiers( td ), ret );
    732         buildForall( td->forall, bt->get_forall() );
     982        ast::BasicType * bt = new ast::BasicType( ret, buildQualifiers( td ) );
    733983        return bt;
    734984} // buildBasicType
    735985
    736986
    737 PointerType * buildPointer( const TypeData * td ) {
    738         PointerType * pt;
     987ast::PointerType * buildPointer( const TypeData * td ) {
     988        ast::PointerType * pt;
    739989        if ( td->base ) {
    740                 pt = new PointerType( buildQualifiers( td ), typebuild( td->base ) );
     990                pt = new ast::PointerType(
     991                        typebuild( td->base ),
     992                        buildQualifiers( td )
     993                );
    741994        } else {
    742                 pt = new PointerType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
     995                pt = new ast::PointerType(
     996                        new ast::BasicType( ast::BasicType::SignedInt ),
     997                        buildQualifiers( td )
     998                );
    743999        } // if
    744         buildForall( td->forall, pt->get_forall() );
    7451000        return pt;
    7461001} // buildPointer
    7471002
    7481003
    749 ArrayType * buildArray( const TypeData * td ) {
    750         ArrayType * at;
     1004ast::ArrayType * buildArray( const TypeData * td ) {
     1005        ast::ArrayType * at;
    7511006        if ( td->base ) {
    752                 at = new ArrayType( buildQualifiers( td ), typebuild( td->base ), maybeBuild< Expression >( td->array.dimension ),
    753                                                         td->array.isVarLen, td->array.isStatic );
     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                );
    7541014        } else {
    755                 at = new ArrayType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ),
    756                                                         maybeBuild< Expression >( td->array.dimension ), td->array.isVarLen, td->array.isStatic );
     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                );
    7571022        } // if
    758         buildForall( td->forall, at->get_forall() );
    7591023        return at;
    7601024} // buildArray
    7611025
    7621026
    763 ReferenceType * buildReference( const TypeData * td ) {
    764         ReferenceType * rt;
     1027ast::ReferenceType * buildReference( const TypeData * td ) {
     1028        ast::ReferenceType * rt;
    7651029        if ( td->base ) {
    766                 rt = new ReferenceType( buildQualifiers( td ), typebuild( td->base ) );
     1030                rt = new ast::ReferenceType(
     1031                        typebuild( td->base ),
     1032                        buildQualifiers( td )
     1033                );
    7671034        } else {
    768                 rt = new ReferenceType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
     1035                rt = new ast::ReferenceType(
     1036                        new ast::BasicType( ast::BasicType::SignedInt ),
     1037                        buildQualifiers( td )
     1038                );
    7691039        } // if
    770         buildForall( td->forall, rt->get_forall() );
    7711040        return rt;
    7721041} // buildReference
    7731042
    7741043
    775 AggregateDecl * buildAggregate( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
     1044ast::AggregateDecl * buildAggregate( const TypeData * td, std::vector<ast::ptr<ast::Attribute>> attributes, ast::Linkage::Spec linkage ) {
    7761045        assert( td->kind == TypeData::Aggregate );
    777         AggregateDecl * at;
     1046        ast::AggregateDecl * at;
    7781047        switch ( td->aggregate.kind ) {
    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:
     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:
    7971079                assert( false );
    7981080        } // switch
    7991081
    800         buildList( td->aggregate.fields, at->get_members() );
     1082        buildList( td->aggregate.fields, at->members );
    8011083        at->set_body( td->aggregate.body );
    8021084
     
    8051087
    8061088
    807 ReferenceToType * buildComAggInst( const TypeData * type, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
     1089ast::BaseInstType * buildComAggInst(
     1090                const TypeData * type,
     1091                std::vector<ast::ptr<ast::Attribute>> && attributes,
     1092                ast::Linkage::Spec linkage ) {
    8081093        switch ( type->kind ) {
    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:
     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:
    8591160                assert( false );
    8601161        } // switch
     1162        assert( false );
    8611163} // buildAggInst
    8621164
    8631165
    864 ReferenceToType * buildAggInst( const TypeData * td ) {
     1166ast::BaseInstType * buildAggInst( const TypeData * td ) {
    8651167        assert( td->kind == TypeData::AggregateInst );
    8661168
    867         // ReferenceToType * ret = buildComAggInst( td->aggInst.aggregate, std::list< Attribute * >() );
    868         ReferenceToType * ret = nullptr;
     1169        ast::BaseInstType * ret = nullptr;
    8691170        TypeData * type = td->aggInst.aggregate;
    8701171        switch ( type->kind ) {
    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:
     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:
    8941205                assert( false );
    8951206        } // switch
    8961207
    897         ret->set_hoistType( td->aggInst.hoistType );
    898         buildList( td->aggInst.params, ret->get_parameters() );
    899         buildForall( td->forall, ret->get_forall() );
     1208        ret->hoistType = td->aggInst.hoistType;
     1209        buildList( td->aggInst.params, ret->params );
    9001210        return ret;
    9011211} // buildAggInst
    9021212
    9031213
    904 NamedTypeDecl * buildSymbolic( const TypeData * td, std::list< Attribute * > attributes, const string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) {
     1214ast::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 ) {
    9051220        assert( td->kind == TypeData::Symbolic );
    906         NamedTypeDecl * ret;
     1221        ast::NamedTypeDecl * ret;
    9071222        assert( td->base );
    9081223        if ( td->symbolic.isTypedef ) {
    909                 ret = new TypedefDecl( name, td->location, scs, typebuild( td->base ), linkage );
     1224                ret = new ast::TypedefDecl(
     1225                        td->location,
     1226                        name,
     1227                        scs,
     1228                        typebuild( td->base ),
     1229                        linkage
     1230                );
    9101231        } else {
    911                 ret = new TypeDecl( name, scs, typebuild( td->base ), TypeDecl::Dtype, true );
     1232                ret = new ast::TypeDecl(
     1233                        td->location,
     1234                        name,
     1235                        scs,
     1236                        typebuild( td->base ),
     1237                        ast::TypeDecl::Dtype,
     1238                        true
     1239                );
    9121240        } // if
    913         buildList( td->symbolic.assertions, ret->get_assertions() );
    914         ret->base->attributes.splice( ret->base->attributes.end(), attributes );
     1241        buildList( td->symbolic.assertions, ret->assertions );
     1242        splice( ret->base.get_and_mutate()->attributes, attributes );
    9151243        return ret;
    9161244} // buildSymbolic
    9171245
    9181246
    919 EnumDecl * buildEnum( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
     1247ast::EnumDecl * buildEnum(
     1248                const TypeData * td,
     1249                std::vector<ast::ptr<ast::Attribute>> && attributes,
     1250                ast::Linkage::Spec linkage ) {
    9201251        assert( td->kind == TypeData::Enum );
    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;
     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;
    9261264        for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
    9271265                if ( cur->enumInLine ) {
     
    9301268                        SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
    9311269                } else if ( cur->has_enumeratorValue() ) {
    932                         ObjectDecl * member = dynamic_cast< ObjectDecl * >(* members);
    933                         member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_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                        );
    9341277                } else if ( !cur->initializer ) {
    935                         if ( baseType && (!dynamic_cast<BasicType *>(baseType) || !dynamic_cast<BasicType *>(baseType)->isInteger())) {
     1278                        if ( baseType && (!dynamic_cast<ast::BasicType *>(baseType) || !dynamic_cast<ast::BasicType *>(baseType)->isInteger())) {
    9361279                                SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." );
    9371280                        }
     
    9401283                // if
    9411284        } // for
    942         ret->set_body( td->enumeration.body );
     1285        ret->body = td->enumeration.body;
    9431286        return ret;
    9441287} // buildEnum
    9451288
    9461289
    947 TypeInstType * buildSymbolicInst( const TypeData * td ) {
     1290ast::TypeInstType * buildSymbolicInst( const TypeData * td ) {
    9481291        assert( td->kind == TypeData::SymbolicInst );
    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() );
     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 );
    9521298        return ret;
    9531299} // buildSymbolicInst
    9541300
    9551301
    956 TupleType * buildTuple( const TypeData * td ) {
     1302ast::TupleType * buildTuple( const TypeData * td ) {
    9571303        assert( td->kind == TypeData::Tuple );
    958         std::list< Type * > types;
     1304        std::vector<ast::ptr<ast::Type>> types;
    9591305        buildTypeList( td->tuple, types );
    960         TupleType * ret = new TupleType( buildQualifiers( td ), types );
    961         buildForall( td->forall, ret->get_forall() );
     1306        ast::TupleType * ret = new ast::TupleType(
     1307                std::move( types ),
     1308                buildQualifiers( td )
     1309        );
    9621310        return ret;
    9631311} // buildTuple
    9641312
    9651313
    966 TypeofType * buildTypeof( const TypeData * td ) {
     1314ast::TypeofType * buildTypeof( const TypeData * td ) {
    9671315        assert( td->kind == TypeData::Typeof || td->kind == TypeData::Basetypeof );
    9681316        assert( td->typeexpr );
    969         // assert( td->typeexpr->expr );
    970         return new TypeofType{ buildQualifiers( td ), td->typeexpr->build(), td->kind == TypeData::Basetypeof };
     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        );
    9711323} // buildTypeof
    9721324
    9731325
    974 VTableType * buildVtable( const TypeData * td ) {
     1326ast::VTableType * buildVtable( const TypeData * td ) {
    9751327        assert( td->base );
    976         return new VTableType{ buildQualifiers( td ), typebuild( td->base ) };
     1328        return new ast::VTableType(
     1329                typebuild( td->base ),
     1330                buildQualifiers( td )
     1331        );
    9771332} // buildVtable
    9781333
    9791334
    980 Declaration * 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 ) {
     1335ast::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
     1409ast::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 ) {
    9811419        if ( td->kind == TypeData::Function ) {
    9821420                if ( td->function.idList ) {                                    // KR function ?
     
    9841422                } // if
    9851423
    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 );
     1424                return buildFunctionDecl(
     1425                        td, name, scs, funcSpec, linkage,
     1426                        asmName, std::move( attributes ) );
    9921427        } else if ( td->kind == TypeData::Aggregate ) {
    993                 return buildAggregate( td, attributes, linkage );
     1428                return buildAggregate( td, std::move( attributes ), linkage );
    9941429        } else if ( td->kind == TypeData::Enum ) {
    995                 return buildEnum( td, attributes, linkage );
     1430                return buildEnum( td, std::move( attributes ), linkage );
    9961431        } else if ( td->kind == TypeData::Symbolic ) {
    997                 return buildSymbolic( td, attributes, name, scs, linkage );
     1432                return buildSymbolic( td, std::move( attributes ), name, scs, linkage );
    9981433        } else {
    999                 return (new ObjectDecl( name, scs, linkage, bitfieldWidth, typebuild( td ), init, attributes ))->set_asmName( asmName );
     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;
    10001445        } // if
    10011446        return nullptr;
     
    10031448
    10041449
    1005 FunctionType * buildFunction( const TypeData * td ) {
     1450ast::FunctionType * buildFunctionType( const TypeData * td ) {
    10061451        assert( td->kind == TypeData::Function );
    1007         FunctionType * ft = new FunctionType( buildQualifiers( td ), ! td->function.params || td->function.params->hasEllipsis );
    1008         buildList( td->function.params, ft->parameters );
     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 );
    10091458        buildForall( td->forall, ft->forall );
    10101459        if ( td->base ) {
    10111460                switch ( td->base->kind ) {
    1012                   case TypeData::Tuple:
    1013                         buildList( td->base->tuple, ft->returnVals );
     1461                case TypeData::Tuple:
     1462                        buildTypeList( td->base->tuple, ft->returns );
    10141463                        break;
    1015                   default:
    1016                         ft->get_returnVals().push_back( dynamic_cast< DeclarationWithType * >( buildDecl( td->base, "", Type::StorageClasses(), nullptr, Type::FuncSpecifiers(), LinkageSpec::Cforall, nullptr ) ) );
     1464                default:
     1465                        ft->returns.push_back( typebuild( td->base ) );
     1466                        break;
    10171467                } // switch
    10181468        } else {
    1019                 ft->get_returnVals().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
     1469                ft->returns.push_back(
     1470                        new ast::BasicType( ast::BasicType::SignedInt ) );
    10201471        } // if
    10211472        return ft;
    1022 } // buildFunction
     1473} // buildFunctionType
    10231474
    10241475
     
    10511502                                param->type = decl->type;                               // set copy declaration type to parameter type
    10521503                                decl->type = nullptr;                                   // reset declaration type
    1053                                 param->attributes.splice( param->attributes.end(), decl->attributes ); // copy and reset attributes from declaration to parameter
     1504                                // Copy and reset attributes from declaration to parameter:
     1505                                splice( param->attributes, decl->attributes );
    10541506                        } // if
    10551507                } // for
  • src/Parser/TypeData.h

    r2ed94a9 rb110bcc  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 15:18:36 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue May 10 22:18:49 2022
    13 // Update Count     : 203
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Mar  1 10:44:00 2023
     13// Update Count     : 206
    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 "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
     22#include "AST/Type.hpp"                             // for Type
     23#include "DeclarationNode.h"                        // for DeclarationNode
    2624
    2725struct TypeData {
     
    3028
    3129        struct Aggregate_t {
    32                 AggregateDecl::Aggregate kind;
     30                ast::AggregateDecl::Aggregate kind;
    3331                const std::string * name = nullptr;
    3432                DeclarationNode * params = nullptr;
     
    3735                bool body;
    3836                bool anon;
    39 
    4037                bool tagged;
    4138                const std::string * parent = nullptr;
     
    9491        DeclarationNode::BuiltinType builtintype = DeclarationNode::NoBuiltinType;
    9592
    96         Type::Qualifiers qualifiers;
     93        ast::CV::Qualifiers qualifiers;
    9794        DeclarationNode * forall = nullptr;
    9895
     
    115112};
    116113
    117 Type * typebuild( const TypeData * );
     114ast::Type * typebuild( const TypeData * );
    118115TypeData * typeextractAggregate( const TypeData * td, bool toplevel = true );
    119 Type::Qualifiers buildQualifiers( const TypeData * td );
    120 Type * buildBasicType( const TypeData * );
    121 PointerType * buildPointer( const TypeData * );
    122 ArrayType * buildArray( const TypeData * );
    123 ReferenceType * buildReference( const TypeData * );
    124 AggregateDecl * buildAggregate( const TypeData *, std::list< Attribute * > );
    125 ReferenceToType * buildComAggInst( const TypeData *, std::list< Attribute * > attributes, LinkageSpec::Spec linkage );
    126 ReferenceToType * buildAggInst( const TypeData * );
    127 TypeDecl * buildVariable( const TypeData * );
    128 EnumDecl * buildEnum( const TypeData *, std::list< Attribute * >, LinkageSpec::Spec );
    129 TypeInstType * buildSymbolicInst( const TypeData * );
    130 TupleType * buildTuple( const TypeData * );
    131 TypeofType * buildTypeof( const TypeData * );
    132 VTableType * buildVtable( const TypeData * );
    133 Declaration * 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 * >() );
    135 FunctionType * buildFunction( const TypeData * );
    136 Declaration * addEnumBase( Declaration *, const TypeData * );
     116ast::CV::Qualifiers buildQualifiers( const TypeData * td );
     117ast::Type * buildBasicType( const TypeData * );
     118ast::PointerType * buildPointer( const TypeData * );
     119ast::ArrayType * buildArray( const TypeData * );
     120ast::ReferenceType * buildReference( const TypeData * );
     121ast::AggregateDecl * buildAggregate( const TypeData *, std::vector<ast::ptr<ast::Attribute>> );
     122ast::BaseInstType * buildComAggInst( const TypeData *, std::vector<ast::ptr<ast::Attribute>> && attributes, ast::Linkage::Spec linkage );
     123ast::BaseInstType * buildAggInst( const TypeData * );
     124ast::TypeDecl * buildVariable( const TypeData * );
     125ast::EnumDecl * buildEnum( const TypeData *, std::vector<ast::ptr<ast::Attribute>> &&, ast::Linkage::Spec );
     126ast::TypeInstType * buildSymbolicInst( const TypeData * );
     127ast::TupleType * buildTuple( const TypeData * );
     128ast::TypeofType * buildTypeof( const TypeData * );
     129ast::VTableType * buildVtable( const TypeData * );
     130ast::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>>() );
     134ast::FunctionType * buildFunctionType( const TypeData * );
     135ast::Decl * addEnumBase( Declaration *, const TypeData * );
    137136void buildKRFunction( const TypeData::Function_t & function );
    138137
  • src/Parser/TypedefTable.cc

    r2ed94a9 rb110bcc  
    1616
    1717#include "TypedefTable.h"
    18 #include <cassert>                                                                              // for assert
    19 #include <iostream>
     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
    2029using namespace std;
    2130
    2231#if 0
    2332#define debugPrint( code ) code
     33
     34static 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
    2445#else
    2546#define debugPrint( code )
    2647#endif
    27 
    28 using namespace std;                                                                    // string, iostream
    29 
    30 debugPrint(
    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 );
    4348
    4449TypedefTable::~TypedefTable() {
     
    7883                typedefTable.addToEnclosingScope( name, kind, "MTD" );
    7984        } // if
     85} // TypedefTable::makeTypedef
     86
     87void TypedefTable::makeTypedef( const string & name ) {
     88        return makeTypedef( name, TYPEDEFname );
    8089} // TypedefTable::makeTypedef
    8190
  • src/Parser/TypedefTable.h

    r2ed94a9 rb110bcc  
    1919
    2020#include "Common/ScopedMap.h"                                                   // for ScopedMap
    21 #include "ParserTypes.h"
    22 #include "parser.hh"                                                                    // for IDENTIFIER, TYPEDEFname, TYPEGENname
    2321
    2422class TypedefTable {
    2523        struct Note { size_t level; bool forall; };
    2624        typedef ScopedMap< std::string, int, Note > KindTable;
    27         KindTable kindTable;   
     25        KindTable kindTable;
    2826        unsigned int level = 0;
    2927  public:
     
    3331        bool existsCurr( const std::string & identifier ) const;
    3432        int isKind( const std::string & identifier ) const;
    35         void makeTypedef( const std::string & name, int kind = TYPEDEFname );
     33        void makeTypedef( const std::string & name, int kind );
     34        void makeTypedef( const std::string & name );
    3635        void addToScope( const std::string & identifier, int kind, const char * );
    3736        void addToEnclosingScope( const std::string & identifier, int kind, const char * );
  • src/Parser/lex.ll

    r2ed94a9 rb110bcc  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Mon Jan 30 19:03:34 2023
    13  * Update Count     : 767
     12 * Last Modified On : Sat Mar 25 08:09:03 2023
     13 * Update Count     : 768
    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
    4649#include "ParseNode.h"
     50#include "ParserTypes.h"                                // for Token
     51#include "StatementNode.h"                              // for CondCtl, ForCtrl
    4752#include "TypedefTable.h"
     53// This (generated) header must come late as it is missing includes.
     54#include "parser.hh"                                    // generated info
    4855
    4956string * build_postfix_name( string * name );
     
    214221__alignof               { KEYWORD_RETURN(ALIGNOF); }                    // GCC
    215222__alignof__             { KEYWORD_RETURN(ALIGNOF); }                    // GCC
     223and                             { QKEYWORD_RETURN(WAND); }                              // CFA
    216224asm                             { KEYWORD_RETURN(ASM); }
    217225__asm                   { KEYWORD_RETURN(ASM); }                                // GCC
  • src/Parser/module.mk

    r2ed94a9 rb110bcc  
    2121SRC += \
    2222       Parser/DeclarationNode.cc \
     23       Parser/DeclarationNode.h \
    2324       Parser/ExpressionNode.cc \
     25       Parser/ExpressionNode.h \
    2426       Parser/InitializerNode.cc \
     27       Parser/InitializerNode.h \
    2528       Parser/lex.ll \
    2629       Parser/ParseNode.cc \
     
    3336       Parser/RunParser.hpp \
    3437       Parser/StatementNode.cc \
     38       Parser/StatementNode.h \
    3539       Parser/TypeData.cc \
    3640       Parser/TypeData.h \
  • src/Parser/parser.yy

    r2ed94a9 rb110bcc  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Sep  1 20:22:55 2001
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  2 21:36:16 2023
    13 // Update Count     : 5865
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr  4 14:02:00 2023
     13// Update Count     : 6329
    1414//
    1515
     
    4444
    4545#include <cstdio>
     46#include <sstream>
    4647#include <stack>
    4748using namespace std;
    4849
    49 #include "SynTree/Declaration.h"
    50 #include "ParseNode.h"
     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_...
    5156#include "TypedefTable.h"
    5257#include "TypeData.h"
    53 #include "SynTree/LinkageSpec.h"
    5458#include "Common/SemanticError.h"                                               // error_str
    5559#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
    5660
    57 #include "SynTree/Attribute.h"     // for Attribute
     61#include "SynTree/Attribute.h"                                                  // for Attribute
    5862
    5963// lex uses __null in a boolean context, it's fine.
     
    6367
    6468extern DeclarationNode * parseTree;
    65 extern LinkageSpec::Spec linkage;
     69extern ast::Linkage::Spec linkage;
    6670extern TypedefTable typedefTable;
    6771
    68 stack<LinkageSpec::Spec> linkageStack;
     72stack<ast::Linkage::Spec> linkageStack;
    6973
    7074bool appendStr( string & to, string & from ) {
     
    199203} // fieldDecl
    200204
    201 #define NEW_ZERO new ExpressionNode( build_constantInteger( *new string( "0" ) ) )
    202 #define NEW_ONE  new ExpressionNode( build_constantInteger( *new string( "1" ) ) )
     205#define NEW_ZERO new ExpressionNode( build_constantInteger( yylloc, *new string( "0" ) ) )
     206#define NEW_ONE  new ExpressionNode( build_constantInteger( yylloc, *new string( "1" ) ) )
    203207#define UPDOWN( compop, left, right ) (compop == OperKinds::LThan || compop == OperKinds::LEThan ? left : right)
    204208#define MISSING_ANON_FIELD "Missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body."
     
    206210#define MISSING_HIGH "Missing high value for down-to range so index is uninitialized."
    207211
    208 ForCtrl * forCtrl( DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
     212static 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
     232ForCtrl * forCtrl( const CodeLocation & location, DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    209233        if ( index->initializer ) {
    210234                SemanticError( yylloc, "Direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." );
     
    213237                SemanticError( yylloc, "Multiple loop indexes disallowed in for-loop declaration." );
    214238        } // if
    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 );
     239        DeclarationNode * initDecl = index->addInitializer( new InitializerNode( start ) );
     240        return makeForCtrl( location, initDecl, compop, comp, inc );
    220241} // forCtrl
    221242
    222 ForCtrl * 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 ) ) );
     243ForCtrl * 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 ) ) );
    226247        } // if
    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 );
     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 );
    234253} // forCtrl
    235254
    236 ForCtrl * 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 );
     255ForCtrl * 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 );
    242261                } else {
    243262                        SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
     
    281300%union {
    282301        Token tok;
    283         ParseNode * pn;
    284         ExpressionNode * en;
     302        ExpressionNode * expr;
    285303        DeclarationNode * decl;
    286         AggregateDecl::Aggregate aggKey;
    287         TypeDecl::Kind tclass;
    288         StatementNode * sn;
    289         WaitForStmt * wfs;
    290         Expression * constant;
     304        ast::AggregateDecl::Aggregate aggKey;
     305        ast::TypeDecl::Kind tclass;
     306        StatementNode * stmt;
     307        ClauseNode * clause;
     308        ast::WaitForStmt * wfs;
    291309        CondCtl * ifctl;
    292         ForCtrl * fctl;
    293         OperKinds compop;
    294         LabelNode * label;
    295         InitializerNode * in;
    296         OperKinds op;
     310        ForCtrl * forctl;
     311        LabelNode * labels;
     312        InitializerNode * init;
     313        OperKinds oper;
    297314        std::string * str;
    298         bool flag;
    299         EnumHiding hide;
    300         CatchStmt::Kind catch_kind;
    301         GenericExpr * genexpr;
     315        bool is_volatile;
     316        EnumHiding enum_hiding;
     317        ast::ExceptionKind except_kind;
     318        ast::GenericExpr * genexpr;
    302319}
    303320
    304 //************************* TERMINAL TOKENS ********************************
     321// ************************ TERMINAL TOKENS ********************************
    305322
    306323// keywords
     
    337354
    338355// names and constants: lexer differentiates between identifier and typedef names
    339 %token<tok> IDENTIFIER          QUOTED_IDENTIFIER       TYPEDIMname             TYPEDEFname             TYPEGENname
    340 %token<tok> TIMEOUT                     WOR                                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
     356%token<tok> IDENTIFIER          TYPEDIMname             TYPEDEFname             TYPEGENname
     357%token<tok> TIMEOUT                     WAND    WOR                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
    341358%token<tok> INTEGERconstant     CHARACTERconstant       STRINGliteral
    342359%token<tok> DIRECTIVE
     
    364381%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    365382%type<tok> quasi_keyword
    366 %type<constant> string_literal
     383%type<expr> string_literal
    367384%type<str> string_literal_list
    368385
    369 %type<hide> hide_opt                                    visible_hide_opt
     386%type<enum_hiding> hide_opt                                     visible_hide_opt
    370387
    371388// expressions
    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
     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
    383400%type<ifctl> conditional_declaration
    384 %type<fctl> for_control_expression              for_control_expression_list
    385 %type<compop> upupeq updown updowneq downupdowneq
    386 %type<en> subrange
     401%type<forctl> for_control_expression            for_control_expression_list
     402%type<oper> upupeq updown updowneq downupdowneq
     403%type<expr> subrange
    387404%type<decl> asm_name_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
     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
    393410%type<genexpr> generic_association              generic_assoc_list
    394411
    395412// statements
    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
     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
    412430
    413431// declarations
     
    421439%type<decl> assertion assertion_list assertion_list_opt
    422440
    423 %type<en> bit_subrange_size_opt bit_subrange_size
     441%type<expr> bit_subrange_size_opt bit_subrange_size
    424442
    425443%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    434452
    435453%type<decl> enumerator_list enum_type enum_type_nobody
    436 %type<in> enumerator_value_opt
     454%type<init> enumerator_value_opt
    437455
    438456%type<decl> external_definition external_definition_list external_definition_list_opt
     
    441459
    442460%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
    443 %type<en> field field_name_list field_name fraction_constants_opt
     461%type<expr> field field_name_list field_name fraction_constants_opt
    444462
    445463%type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
     
    482500%type<decl> typedef_name typedef_declaration typedef_expression
    483501
    484 %type<decl> variable_type_redeclarator type_ptr type_array type_function
     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
    485504
    486505%type<decl> type_parameter_redeclarator type_parameter_ptr type_parameter_array type_parameter_function
     
    489508%type<decl> type_parameter type_parameter_list type_initializer_opt
    490509
    491 %type<en> type_parameters_opt type_list array_type_list
     510%type<expr> type_parameters_opt type_list array_type_list
    492511
    493512%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     
    500519
    501520// initializers
    502 %type<in>  initializer initializer_list_opt initializer_opt
     521%type<init>  initializer initializer_list_opt initializer_opt
    503522
    504523// designators
    505 %type<en>  designator designator_list designation
     524%type<expr>  designator designator_list designation
    506525
    507526
     
    512531// Similar issues exit with the waitfor statement.
    513532
    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.
     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.
    516535%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
    517539%precedence WOR                 // token precedence for start of WOR in WAITFOR statement
    518540%precedence TIMEOUT             // token precedence for start of TIMEOUT in WAITFOR statement
     
    592614constant:
    593615                // ENUMERATIONconstant is not included here; it is treated as a variable with type "enumeration constant".
    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 ) ); }
     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 ) ); }
    599621        ;
    600622
    601623quasi_keyword:                                                                                  // CFA
    602624        TIMEOUT
     625        | WAND
    603626        | WOR
    604627        | CATCH
     
    621644
    622645string_literal:
    623         string_literal_list                                                     { $$ = build_constantStr( *$1 ); }
     646        string_literal_list                                                     { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); }
    624647        ;
    625648
     
    638661primary_expression:
    639662        IDENTIFIER                                                                                      // typedef name cannot be used as a variable name
    640                 { $$ = new ExpressionNode( build_varref( $1 ) ); }
     663                { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
    641664        | quasi_keyword
    642                 { $$ = new ExpressionNode( build_varref( $1 ) ); }
     665                { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
    643666        | TYPEDIMname                                                                           // CFA, generic length argument
    644667                // { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( DeclarationNode::newFromTypedef( $1 ) ) ) ); }
    645668                // { $$ = new ExpressionNode( build_varref( $1 ) ); }
    646                 { $$ = new ExpressionNode( build_dimensionref( $1 ) ); }
     669                { $$ = new ExpressionNode( build_dimensionref( yylloc, $1 ) ); }
    647670        | tuple
    648671        | '(' comma_expression ')'
    649672                { $$ = $2; }
    650673        | '(' compound_statement ')'                                            // GCC, lambda expression
    651                 { $$ = new ExpressionNode( new StmtExpr( dynamic_cast<CompoundStmt *>(maybeMoveBuild<Statement>($2) ) ) ); }
     674                { $$ = new ExpressionNode( new ast::StmtExpr( yylloc, dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( $2 ) ) ) ); }
    652675        | type_name '.' identifier                                                      // CFA, nested type
    653                 { $$ = new ExpressionNode( build_qualified_expr( $1, build_varref( $3 ) ) ); }
     676                { $$ = new ExpressionNode( build_qualified_expr( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
    654677        | type_name '.' '[' field_name_list ']'                         // CFA, nested type / tuple field selector
    655678                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
     
    657680                {
    658681                        // add the missing control expression to the GenericExpr and return it
    659                         $5->control = maybeMoveBuild<Expression>( $3 );
     682                        $5->control = maybeMoveBuild( $3 );
    660683                        $$ = new ExpressionNode( $5 );
    661684                }
     
    683706                {
    684707                        // steal the association node from the singleton and delete the wrapper
    685                         $1->associations.splice($1->associations.end(), $3->associations);
     708                        assert( 1 == $3->associations.size() );
     709                        $1->associations.push_back( $3->associations.front() );
    686710                        delete $3;
    687711                        $$ = $1;
     
    693717                {
    694718                        // create a GenericExpr wrapper with one association pair
    695                         $$ = new GenericExpr( nullptr, { { maybeMoveBuildType($1), maybeMoveBuild<Expression>( $3 ) } } );
     719                        $$ = new ast::GenericExpr( yylloc, nullptr, { { maybeMoveBuildType( $1 ), maybeMoveBuild( $3 ) } } );
    696720                }
    697721        | DEFAULT ':' assignment_expression
    698                 { $$ = new GenericExpr( nullptr, { { maybeMoveBuild<Expression>( $3 ) } } ); }
     722                { $$ = new ast::GenericExpr( yylloc, nullptr, { { maybeMoveBuild( $3 ) } } ); }
    699723        ;
    700724
     
    705729                // Switching to this behaviour may help check if a C compatibilty case uses comma-exprs in subscripts.
    706730                // Current: Commas in subscripts make tuples.
    707                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
     731                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
    708732        | postfix_expression '[' assignment_expression ']'
    709733                // CFA, comma_expression disallowed in this context because it results in a common user error: subscripting a
     
    711735                // little advantage to this feature and many disadvantages. It is possible to write x[(i,j)] in CFA, which is
    712736                // equivalent to the old x[i,j].
    713                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
     737                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    714738        | constant '[' assignment_expression ']'                        // 3[a], 'a'[a], 3.5[a]
    715                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
     739                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    716740        | string_literal '[' assignment_expression ']'          // "abc"[3], 3["abc"]
    717                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }
     741                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    718742        | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
    719743                {
    720744                        Token fn;
    721745                        fn.str = new std::string( "?{}" );                      // location undefined - use location of '{'?
    722                         $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
     746                        $$ = new ExpressionNode( new ast::ConstructorExpr( yylloc, build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
    723747                }
    724748        | postfix_expression '(' argument_expression_list_opt ')'
    725                 { $$ = new ExpressionNode( build_func( $1, $3 ) ); }
     749                { $$ = new ExpressionNode( build_func( yylloc, $1, $3 ) ); }
    726750        | VA_ARG '(' primary_expression ',' declaration_specifier_nobody abstract_parameter_declarator_opt ')'
    727751                // { SemanticError( yylloc, "va_arg is currently unimplemented." ); $$ = nullptr; }
    728                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( new string( "__builtin_va_arg") ) ),
     752                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, new string( "__builtin_va_arg") ) ),
    729753                                                                                           (ExpressionNode *)($3->set_last( (ExpressionNode *)($6 ? $6->addType( $5 ) : $5) )) ) ); }
    730754        | postfix_expression '`' identifier                                     // CFA, postfix call
    731                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
     755                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    732756        | constant '`' identifier                                                       // CFA, postfix call
    733                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
     757                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    734758        | string_literal '`' identifier                                         // CFA, postfix call
    735                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
     759                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    736760        | postfix_expression '.' identifier
    737                 { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
     761                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
    738762        | postfix_expression '.' INTEGERconstant                        // CFA, tuple index
    739                 { $$ = new ExpressionNode( build_fieldSel( $1, build_constantInteger( *$3 ) ) ); }
     763                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_constantInteger( yylloc, *$3 ) ) ); }
    740764        | postfix_expression FLOATING_FRACTIONconstant          // CFA, tuple index
    741                 { $$ = new ExpressionNode( build_fieldSel( $1, build_field_name_FLOATING_FRACTIONconstant( *$2 ) ) ); }
     765                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_field_name_FLOATING_FRACTIONconstant( yylloc, *$2 ) ) ); }
    742766        | postfix_expression '.' '[' field_name_list ']'        // CFA, tuple field selector
    743                 { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
     767                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    744768        | postfix_expression '.' aggregate_control
    745                 { $$ = new ExpressionNode( build_keyword_cast( $3, $1 ) ); }
     769                { $$ = new ExpressionNode( build_keyword_cast( yylloc, $3, $1 ) ); }
    746770        | postfix_expression ARROW identifier
    747                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
     771                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
    748772        | postfix_expression ARROW INTEGERconstant                      // CFA, tuple index
    749                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_constantInteger( *$3 ) ) ); }
     773                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_constantInteger( yylloc, *$3 ) ) ); }
    750774        | postfix_expression ARROW '[' field_name_list ']'      // CFA, tuple field selector
    751                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
     775                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    752776        | postfix_expression ICR
    753                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, $1 ) ); }
     777                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::IncrPost, $1 ) ); }
    754778        | postfix_expression DECR
    755                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::DecrPost, $1 ) ); }
     779                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::DecrPost, $1 ) ); }
    756780        | '(' type_no_function ')' '{' initializer_list_opt comma_opt '}' // C99, compound-literal
    757                 { $$ = new ExpressionNode( build_compoundLiteral( $2, new InitializerNode( $5, true ) ) ); }
     781                { $$ = new ExpressionNode( build_compoundLiteral( yylloc, $2, new InitializerNode( $5, true ) ) ); }
    758782        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    759                 { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
     783                { $$ = new ExpressionNode( build_compoundLiteral( yylloc, $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    760784        | '^' primary_expression '{' argument_expression_list_opt '}' // CFA, destructor call
    761785                {
    762786                        Token fn;
    763787                        fn.str = new string( "^?{}" );                          // location undefined
    764                         $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) );
     788                        $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) );
    765789                }
    766790        ;
     
    781805        '@'                                                                                                     // CFA, default parameter
    782806                { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; }
    783                 // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
     807                // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
    784808        | assignment_expression
    785809        ;
     
    793817        field_name
    794818        | FLOATING_DECIMALconstant field
    795                 { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), maybeMoveBuild<Expression>( $2 ) ) ); }
     819                { $$ = new ExpressionNode( build_fieldSel( yylloc, new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( yylloc, *$1 ) ), maybeMoveBuild( $2 ) ) ); }
    796820        | FLOATING_DECIMALconstant '[' field_name_list ']'
    797                 { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), build_tuple( $3 ) ) ); }
     821                { $$ = new ExpressionNode( build_fieldSel( yylloc, new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( yylloc, *$1 ) ), build_tuple( yylloc, $3 ) ) ); }
    798822        | field_name '.' field
    799                 { $$ = new ExpressionNode( build_fieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
     823                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); }
    800824        | field_name '.' '[' field_name_list ']'
    801                 { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
     825                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    802826        | field_name ARROW field
    803                 { $$ = new ExpressionNode( build_pfieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
     827                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); }
    804828        | field_name ARROW '[' field_name_list ']'
    805                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
     829                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    806830        ;
    807831
    808832field_name:
    809833        INTEGERconstant fraction_constants_opt
    810                 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_constantInteger( *$1 ), $2 ) ); }
     834                { $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_constantInteger( yylloc, *$1 ), $2 ) ); }
    811835        | FLOATINGconstant fraction_constants_opt
    812                 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); }
     836                { $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_field_name_FLOATINGconstant( yylloc, *$1 ), $2 ) ); }
    813837        | identifier_at fraction_constants_opt                          // CFA, allow anonymous fields
    814838                {
    815                         $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) );
     839                        $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_varref( yylloc, $1 ), $2 ) );
    816840                }
    817841        ;
     
    822846        | fraction_constants_opt FLOATING_FRACTIONconstant
    823847                {
    824                         Expression * constant = build_field_name_FLOATING_FRACTIONconstant( *$2 );
    825                         $$ = $1 != nullptr ? new ExpressionNode( build_fieldSel( $1, constant ) ) : new ExpressionNode( constant );
     848                        ast::Expr * constant = build_field_name_FLOATING_FRACTIONconstant( yylloc, *$2 );
     849                        $$ = $1 != nullptr ? new ExpressionNode( build_fieldSel( yylloc, $1, constant ) ) : new ExpressionNode( constant );
    826850                }
    827851        ;
     
    833857        | constant
    834858        | string_literal
    835                 { $$ = new ExpressionNode( $1 ); }
     859                { $$ = $1; }
    836860        | EXTENSION cast_expression                                                     // GCC
    837861                { $$ = $2->set_extension( true ); }
     
    842866                {
    843867                        switch ( $1 ) {
    844                           case OperKinds::AddressOf:
    845                                 $$ = new ExpressionNode( new AddressExpr( maybeMoveBuild<Expression>( $2 ) ) );
     868                        case OperKinds::AddressOf:
     869                                $$ = new ExpressionNode( new ast::AddressExpr( maybeMoveBuild( $2 ) ) );
    846870                                break;
    847                           case OperKinds::PointTo:
    848                                 $$ = new ExpressionNode( build_unary_val( $1, $2 ) );
     871                        case OperKinds::PointTo:
     872                                $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) );
    849873                                break;
    850                           case OperKinds::And:
    851                                 $$ = new ExpressionNode( new AddressExpr( new AddressExpr( maybeMoveBuild<Expression>( $2 ) ) ) );
     874                        case OperKinds::And:
     875                                $$ = new ExpressionNode( new ast::AddressExpr( new ast::AddressExpr( maybeMoveBuild( $2 ) ) ) );
    852876                                break;
    853                           default:
     877                        default:
    854878                                assert( false );
    855879                        }
    856880                }
    857881        | unary_operator cast_expression
    858                 { $$ = new ExpressionNode( build_unary_val( $1, $2 ) ); }
     882                { $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) ); }
    859883        | ICR unary_expression
    860                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::Incr, $2 ) ); }
     884                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Incr, $2 ) ); }
    861885        | DECR unary_expression
    862                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::Decr, $2 ) ); }
     886                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Decr, $2 ) ); }
    863887        | SIZEOF unary_expression
    864                 { $$ = new ExpressionNode( new SizeofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }
     888                { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuild( $2 ) ) ); }
    865889        | SIZEOF '(' type_no_function ')'
    866                 { $$ = new ExpressionNode( new SizeofExpr( maybeMoveBuildType( $3 ) ) ); }
     890                { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
    867891        | ALIGNOF unary_expression                                                      // GCC, variable alignment
    868                 { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }
     892                { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuild( $2 ) ) ); }
    869893        | ALIGNOF '(' type_no_function ')'                                      // GCC, type alignment
    870                 { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuildType( $3 ) ) ); }
     894                { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
    871895        | OFFSETOF '(' type_no_function ',' identifier ')'
    872                 { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); }
     896                { $$ = new ExpressionNode( build_offsetOf( yylloc, $3, build_varref( yylloc, $5 ) ) ); }
    873897        | TYPEID '(' type_no_function ')'
    874898                {
     
    895919        unary_expression
    896920        | '(' type_no_function ')' cast_expression
    897                 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
     921                { $$ = new ExpressionNode( build_cast( yylloc, $2, $4 ) ); }
    898922        | '(' aggregate_control '&' ')' cast_expression         // CFA
    899                 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
     923                { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); }
    900924        | '(' aggregate_control '*' ')' cast_expression         // CFA
    901                 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
     925                { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); }
    902926        | '(' VIRTUAL ')' cast_expression                                       // CFA
    903                 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild<Expression>( $4 ), maybeMoveBuildType( nullptr ) ) ); }
     927                { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $4 ), maybeMoveBuildType( nullptr ) ) ); }
    904928        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    905                 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild<Expression>( $5 ), maybeMoveBuildType( $3 ) ) ); }
     929                { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); }
    906930        | '(' RETURN type_no_function ')' cast_expression       // CFA
    907931                { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }
     
    911935                { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; }
    912936//      | '(' type_no_function ')' tuple
    913 //              { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
     937//              { $$ = new ast::ExpressionNode( build_cast( yylloc, $2, $4 ) ); }
    914938        ;
    915939
     
    929953        cast_expression
    930954        | exponential_expression '\\' cast_expression
    931                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Exp, $1, $3 ) ); }
     955                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Exp, $1, $3 ) ); }
    932956        ;
    933957
     
    935959        exponential_expression
    936960        | multiplicative_expression '*' exponential_expression
    937                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Mul, $1, $3 ) ); }
     961                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Mul, $1, $3 ) ); }
    938962        | multiplicative_expression '/' exponential_expression
    939                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Div, $1, $3 ) ); }
     963                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Div, $1, $3 ) ); }
    940964        | multiplicative_expression '%' exponential_expression
    941                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Mod, $1, $3 ) ); }
     965                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Mod, $1, $3 ) ); }
    942966        ;
    943967
     
    945969        multiplicative_expression
    946970        | additive_expression '+' multiplicative_expression
    947                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Plus, $1, $3 ) ); }
     971                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Plus, $1, $3 ) ); }
    948972        | additive_expression '-' multiplicative_expression
    949                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Minus, $1, $3 ) ); }
     973                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Minus, $1, $3 ) ); }
    950974        ;
    951975
     
    953977        additive_expression
    954978        | shift_expression LS additive_expression
    955                 { $$ = new ExpressionNode( build_binary_val( OperKinds::LShift, $1, $3 ) ); }
     979                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LShift, $1, $3 ) ); }
    956980        | shift_expression RS additive_expression
    957                 { $$ = new ExpressionNode( build_binary_val( OperKinds::RShift, $1, $3 ) ); }
     981                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::RShift, $1, $3 ) ); }
    958982        ;
    959983
     
    961985        shift_expression
    962986        | relational_expression '<' shift_expression
    963                 { $$ = new ExpressionNode( build_binary_val( OperKinds::LThan, $1, $3 ) ); }
     987                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LThan, $1, $3 ) ); }
    964988        | relational_expression '>' shift_expression
    965                 { $$ = new ExpressionNode( build_binary_val( OperKinds::GThan, $1, $3 ) ); }
     989                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::GThan, $1, $3 ) ); }
    966990        | relational_expression LE shift_expression
    967                 { $$ = new ExpressionNode( build_binary_val( OperKinds::LEThan, $1, $3 ) ); }
     991                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LEThan, $1, $3 ) ); }
    968992        | relational_expression GE shift_expression
    969                 { $$ = new ExpressionNode( build_binary_val( OperKinds::GEThan, $1, $3 ) ); }
     993                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::GEThan, $1, $3 ) ); }
    970994        ;
    971995
     
    973997        relational_expression
    974998        | equality_expression EQ relational_expression
    975                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Eq, $1, $3 ) ); }
     999                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Eq, $1, $3 ) ); }
    9761000        | equality_expression NE relational_expression
    977                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Neq, $1, $3 ) ); }
     1001                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Neq, $1, $3 ) ); }
    9781002        ;
    9791003
     
    9811005        equality_expression
    9821006        | AND_expression '&' equality_expression
    983                 { $$ = new ExpressionNode( build_binary_val( OperKinds::BitAnd, $1, $3 ) ); }
     1007                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::BitAnd, $1, $3 ) ); }
    9841008        ;
    9851009
     
    9871011        AND_expression
    9881012        | exclusive_OR_expression '^' AND_expression
    989                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Xor, $1, $3 ) ); }
     1013                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Xor, $1, $3 ) ); }
    9901014        ;
    9911015
     
    9931017        exclusive_OR_expression
    9941018        | inclusive_OR_expression '|' exclusive_OR_expression
    995                 { $$ = new ExpressionNode( build_binary_val( OperKinds::BitOr, $1, $3 ) ); }
     1019                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::BitOr, $1, $3 ) ); }
    9961020        ;
    9971021
     
    9991023        inclusive_OR_expression
    10001024        | logical_AND_expression ANDAND inclusive_OR_expression
    1001                 { $$ = new ExpressionNode( build_and_or( $1, $3, true ) ); }
     1025                { $$ = new ExpressionNode( build_and_or( yylloc, $1, $3, ast::AndExpr ) ); }
    10021026        ;
    10031027
     
    10051029        logical_AND_expression
    10061030        | logical_OR_expression OROR logical_AND_expression
    1007                 { $$ = new ExpressionNode( build_and_or( $1, $3, false ) ); }
     1031                { $$ = new ExpressionNode( build_and_or( yylloc, $1, $3, ast::OrExpr ) ); }
    10081032        ;
    10091033
     
    10111035        logical_OR_expression
    10121036        | logical_OR_expression '?' comma_expression ':' conditional_expression
    1013                 { $$ = new ExpressionNode( build_cond( $1, $3, $5 ) ); }
     1037                { $$ = new ExpressionNode( build_cond( yylloc, $1, $3, $5 ) ); }
    10141038                // FIX ME: computes $1 twice
    10151039        | logical_OR_expression '?' /* empty */ ':' conditional_expression // GCC, omitted first operand
    1016                 { $$ = new ExpressionNode( build_cond( $1, $1, $4 ) ); }
     1040                { $$ = new ExpressionNode( build_cond( yylloc, $1, $1, $4 ) ); }
    10171041        ;
    10181042
     
    10291053//                              SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr;
    10301054//                      } else {
    1031                                 $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) );
     1055                                $$ = new ExpressionNode( build_binary_val( yylloc, $2, $1, $3 ) );
    10321056//                      } // if
    10331057                }
     
    10741098//              { $$ = new ExpressionNode( build_tuple( $3 ) ); }
    10751099        '[' ',' tuple_expression_list ']'
    1076                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
     1100                { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
    10771101        | '[' push assignment_expression pop ',' tuple_expression_list ']'
    1078                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $6 ) ) )); }
     1102                { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $6 ) ) )); }
    10791103        ;
    10801104
     
    10921116        assignment_expression
    10931117        | comma_expression ',' assignment_expression
    1094                 { $$ = new ExpressionNode( new CommaExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
     1118                { $$ = new ExpressionNode( new ast::CommaExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    10951119        ;
    10961120
     
    11131137        | mutex_statement
    11141138        | waitfor_statement
     1139        | waituntil_statement
    11151140        | exception_statement
    11161141        | enable_disable_statement
     
    11181143        | asm_statement
    11191144        | DIRECTIVE
    1120                 { $$ = new StatementNode( build_directive( $1 ) ); }
     1145                { $$ = new StatementNode( build_directive( yylloc, $1 ) ); }
    11211146        ;
    11221147
     
    11241149                // labels cannot be identifiers 0 or 1
    11251150        identifier_or_type_name ':' attribute_list_opt statement
    1126                 { $$ = $4->add_label( $1, $3 ); }
     1151                { $$ = $4->add_label( yylloc, $1, $3 ); }
    11271152        | identifier_or_type_name ':' attribute_list_opt error // syntax error
    11281153                {
     
    11361161compound_statement:
    11371162        '{' '}'
    1138                 { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); }
     1163                { $$ = new StatementNode( build_compound( yylloc, (StatementNode *)0 ) ); }
    11391164        | '{' push
    11401165          local_label_declaration_opt                                           // GCC, local labels appear at start of block
    11411166          statement_decl_list                                                           // C99, intermix declarations and statements
    11421167          pop '}'
    1143                 { $$ = new StatementNode( build_compound( $4 ) ); }
     1168                { $$ = new StatementNode( build_compound( yylloc, $4 ) ); }
    11441169        ;
    11451170
     
    11721197expression_statement:
    11731198        comma_expression_opt ';'
    1174                 { $$ = new StatementNode( build_expr( $1 ) ); }
    1175         | MUTEX '(' ')' comma_expression ';'
    1176                 { $$ = new StatementNode( build_mutex( nullptr, new StatementNode( build_expr( $4 ) ) ) ); }
     1199                { $$ = new StatementNode( build_expr( yylloc, $1 ) ); }
    11771200        ;
    11781201
     
    11831206                { $$ = $2; }
    11841207        | SWITCH '(' comma_expression ')' case_clause
    1185                 { $$ = new StatementNode( build_switch( true, $3, $5 ) ); }
     1208                { $$ = new StatementNode( build_switch( yylloc, true, $3, $5 ) ); }
    11861209        | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA
    11871210                {
    1188                         StatementNode *sw = new StatementNode( build_switch( true, $3, $8 ) );
     1211                        StatementNode *sw = new StatementNode( build_switch( yylloc, true, $3, $8 ) );
    11891212                        // The semantics of the declaration list is changed to include associated initialization, which is performed
    11901213                        // *before* the transfer to the appropriate case clause by hoisting the declarations into a compound
     
    11921215                        // therefore, are removed from the grammar even though C allows it. The change also applies to choose
    11931216                        // statement.
    1194                         $$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     1217                        $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
    11951218                }
    11961219        | SWITCH '(' comma_expression ')' '{' error '}'         // CFA, syntax error
    11971220                { SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; }
    11981221        | CHOOSE '(' comma_expression ')' case_clause           // CFA
    1199                 { $$ = new StatementNode( build_switch( false, $3, $5 ) ); }
     1222                { $$ = new StatementNode( build_switch( yylloc, false, $3, $5 ) ); }
    12001223        | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA
    12011224                {
    1202                         StatementNode *sw = new StatementNode( build_switch( false, $3, $8 ) );
    1203                         $$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     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;
    12041227                }
    12051228        | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, syntax error
     
    12101233        IF '(' conditional_declaration ')' statement            %prec THEN
    12111234                // explicitly deal with the shift/reduce conflict on if/else
    1212                 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); }
     1235                { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), nullptr ) ); }
    12131236        | IF '(' conditional_declaration ')' statement ELSE statement
    1214                 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
     1237                { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), maybe_build_compound( yylloc, $7 ) ) ); }
    12151238        ;
    12161239
     
    12241247        | declaration comma_expression                                          // semi-colon separated
    12251248                { $$ = new CondCtl( $1, $2 ); }
    1226         ;
     1249        ;
    12271250
    12281251// CASE and DEFAULT clauses are only allowed in the SWITCH statement, precluding Duff's device. In addition, a case
     
    12321255        constant_expression                                                     { $$ = $1; }
    12331256        | constant_expression ELLIPSIS constant_expression      // GCC, subrange
    1234                 { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
     1257                { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    12351258        | subrange                                                                                      // CFA, subrange
    12361259        ;
    12371260
    12381261case_value_list:                                                                                // CFA
    1239         case_value                                                                      { $$ = new StatementNode( build_case( $1 ) ); }
     1262        case_value                                                                      { $$ = new ClauseNode( build_case( yylloc, $1 ) ); }
    12401263                // convert case list, e.g., "case 1, 3, 5:" into "case 1: case 3: case 5"
    1241         | case_value_list ',' case_value                        { $$ = (StatementNode *)($1->set_last( new StatementNode( build_case( $3 ) ) ) ); }
     1264        | case_value_list ',' case_value                        { $$ = $1->set_last( new ClauseNode( build_case( yylloc, $3 ) ) ); }
    12421265        ;
    12431266
     
    12481271        | CASE case_value_list error                                            // syntax error
    12491272                { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
    1250         | DEFAULT ':'                                                           { $$ = new StatementNode( build_default() ); }
     1273        | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
    12511274                // A semantic check is required to ensure only one default clause per switch/choose statement.
    12521275        | DEFAULT error                                                                         //  syntax error
     
    12561279case_label_list:                                                                                // CFA
    12571280        case_label
    1258         | case_label_list case_label                            { $$ = (StatementNode *)( $1->set_last( $2 )); }
     1281        | case_label_list case_label                            { $$ = $1->set_last( $2 ); }
    12591282        ;
    12601283
    12611284case_clause:                                                                                    // CFA
    1262         case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); }
     1285        case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( yylloc, $2 ) ); }
    12631286        ;
    12641287
     
    12711294switch_clause_list:                                                                             // CFA
    12721295        case_label_list statement_list_nodecl
    1273                 { $$ = $1->append_last_case( new StatementNode( build_compound( $2 ) ) ); }
     1296                { $$ = $1->append_last_case( new StatementNode( build_compound( yylloc, $2 ) ) ); }
    12741297        | switch_clause_list case_label_list statement_list_nodecl
    1275                 { $$ = (StatementNode *)( $1->set_last( $2->append_last_case( new StatementNode( build_compound( $3 ) ) ) ) ); }
     1298                { $$ = $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ); }
    12761299        ;
    12771300
    12781301iteration_statement:
    12791302        WHILE '(' ')' statement                                                         %prec THEN // CFA => while ( 1 )
    1280                 { $$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) ); }
     1303                { $$ = new StatementNode( build_while( yylloc, new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( yylloc, $4 ) ) ); }
    12811304        | WHILE '(' ')' statement ELSE statement                        // CFA
    12821305                {
    1283                         $$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) );
    1284                         SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
     1306                        $$ = new StatementNode( build_while( yylloc, new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( yylloc, $4 ) ) );
     1307                        SemanticWarning( yylloc, Warning::SuperfluousElse );
    12851308                }
    12861309        | WHILE '(' conditional_declaration ')' statement       %prec THEN
    1287                 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
     1310                { $$ = new StatementNode( build_while( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
    12881311        | WHILE '(' conditional_declaration ')' statement ELSE statement // CFA
    1289                 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ), $7 ) ); }
     1312                { $$ = new StatementNode( build_while( yylloc, $3, maybe_build_compound( yylloc, $5 ), $7 ) ); }
    12901313        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    1291                 { $$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) ); }
     1314                { $$ = new StatementNode( build_do_while( yylloc, NEW_ONE, maybe_build_compound( yylloc, $2 ) ) ); }
    12921315        | DO statement WHILE '(' ')' ELSE statement                     // CFA
    12931316                {
    1294                         $$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) );
    1295                         SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
     1317                        $$ = new StatementNode( build_do_while( yylloc, NEW_ONE, maybe_build_compound( yylloc, $2 ) ) );
     1318                        SemanticWarning( yylloc, Warning::SuperfluousElse );
    12961319                }
    12971320        | DO statement WHILE '(' comma_expression ')' ';'
    1298                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
     1321                { $$ = new StatementNode( build_do_while( yylloc, $5, maybe_build_compound( yylloc, $2 ) ) ); }
    12991322        | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
    1300                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); }
     1323                { $$ = new StatementNode( build_do_while( yylloc, $5, maybe_build_compound( yylloc, $2 ), $8 ) ); }
    13011324        | FOR '(' ')' statement                                                         %prec THEN // CFA => for ( ;; )
    1302                 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
     1325                { $$ = new StatementNode( build_for( yylloc, new ForCtrl( nullptr, nullptr, nullptr ), maybe_build_compound( yylloc, $4 ) ) ); }
    13031326        | FOR '(' ')' statement ELSE statement                          // CFA
    13041327                {
    1305                         $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
    1306                         SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
     1328                        $$ = new StatementNode( build_for( yylloc, new ForCtrl( nullptr, nullptr, nullptr ), maybe_build_compound( yylloc, $4 ) ) );
     1329                        SemanticWarning( yylloc, Warning::SuperfluousElse );
    13071330                }
    13081331        | FOR '(' for_control_expression_list ')' statement     %prec THEN
    1309                 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
     1332                { $$ = new StatementNode( build_for( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
    13101333        | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA
    1311                 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ), $7 ) ); }
     1334                { $$ = new StatementNode( build_for( yylloc, $3, maybe_build_compound( yylloc, $5 ), $7 ) ); }
    13121335        ;
    13131336
     
    13231346                        if ( $1->condition ) {
    13241347                                if ( $3->condition ) {
    1325                                         $1->condition->expr.reset( new LogicalExpr( $1->condition->expr.release(), $3->condition->expr.release(), true ) );
     1348                                        $1->condition->expr.reset( new ast::LogicalExpr( yylloc, $1->condition->expr.release(), $3->condition->expr.release(), ast::AndExpr ) );
    13261349                                } // if
    13271350                        } else $1->condition = $3->condition;
    13281351                        if ( $1->change ) {
    13291352                                if ( $3->change ) {
    1330                                         $1->change->expr.reset( new CommaExpr( $1->change->expr.release(), $3->change->expr.release() ) );
     1353                                        $1->change->expr.reset( new ast::CommaExpr( yylloc, $1->change->expr.release(), $3->change->expr.release() ) );
    13311354                                } // if
    13321355                        } else $1->change = $3->change;
     
    13371360for_control_expression:
    13381361        ';' comma_expression_opt ';' comma_expression_opt
    1339                 { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); }
     1362                { $$ = new ForCtrl( nullptr, $2, $4 ); }
    13401363        | comma_expression ';' comma_expression_opt ';' comma_expression_opt
    1341                 { $$ = new ForCtrl( $1, $3, $5 ); }
     1364                {
     1365                        StatementNode * init = $1 ? new StatementNode( new ast::ExprStmt( yylloc, maybeMoveBuild( $1 ) ) ) : nullptr;
     1366                        $$ = new ForCtrl( init, $3, $5 );
     1367                }
    13421368        | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';'
    1343                 { $$ = new ForCtrl( $1, $2, $4 ); }
     1369                { $$ = new ForCtrl( new StatementNode( $1 ), $2, $4 ); }
    13441370
    13451371        | '@' ';' comma_expression                                                      // CFA, empty loop-index
    1346                 { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, nullptr ); }
     1372                { $$ = new ForCtrl( nullptr, $3, nullptr ); }
    13471373        | '@' ';' comma_expression ';' comma_expression         // CFA, empty loop-index
    1348                 { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, $5 ); }
     1374                { $$ = new ForCtrl( nullptr, $3, $5 ); }
    13491375
    13501376        | comma_expression                                                                      // CFA, anonymous loop-index
    1351                 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), NEW_ZERO, OperKinds::LThan, $1->clone(), NEW_ONE ); }
     1377                { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), NEW_ZERO, OperKinds::LThan, $1->clone(), NEW_ONE ); }
    13521378        | downupdowneq comma_expression                                         // CFA, anonymous loop-index
    1353                 { $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $1, NEW_ZERO, $2->clone() ), $1, UPDOWN( $1, $2->clone(), NEW_ZERO ), NEW_ONE ); }
     1379                { $$ = forCtrl( yylloc, $2, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $1, NEW_ZERO, $2->clone() ), $1, UPDOWN( $1, $2->clone(), NEW_ZERO ), NEW_ONE ); }
    13541380
    13551381        | comma_expression updowneq comma_expression            // CFA, anonymous loop-index
    1356                 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), NEW_ONE ); }
     1382                { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), NEW_ONE ); }
    13571383        | '@' updowneq comma_expression                                         // CFA, anonymous loop-index
    13581384                {
    13591385                        if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1360                         else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, NEW_ONE );
     1386                        else $$ = forCtrl( yylloc, $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, NEW_ONE );
    13611387                }
    13621388        | comma_expression updowneq '@'                                         // CFA, anonymous loop-index
     
    13661392                }
    13671393        | comma_expression updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
    1368                 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), $5 ); }
     1394                { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), $5 ); }
    13691395        | '@' updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
    13701396                {
    13711397                        if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1372                         else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, $5 );
     1398                        else $$ = forCtrl( yylloc, $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, $5 );
    13731399                }
    13741400        | comma_expression updowneq '@' '~' comma_expression // CFA, anonymous loop-index
     
    13891415
    13901416        | comma_expression ';' comma_expression                         // CFA
    1391                 { $$ = forCtrl( $3, $1, NEW_ZERO, OperKinds::LThan, $3->clone(), NEW_ONE ); }
     1417                { $$ = forCtrl( yylloc, $3, $1, NEW_ZERO, OperKinds::LThan, $3->clone(), NEW_ONE ); }
    13921418        | comma_expression ';' downupdowneq comma_expression // CFA
    1393                 { $$ = forCtrl( $4, $1, UPDOWN( $3, NEW_ZERO, $4->clone() ), $3, UPDOWN( $3, $4->clone(), NEW_ZERO ), NEW_ONE ); }
     1419                { $$ = forCtrl( yylloc, $4, $1, UPDOWN( $3, NEW_ZERO, $4->clone() ), $3, UPDOWN( $3, $4->clone(), NEW_ZERO ), NEW_ONE ); }
    13941420
    13951421        | comma_expression ';' comma_expression updowneq comma_expression // CFA
    1396                 { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), NEW_ONE ); }
     1422                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), NEW_ONE ); }
    13971423        | comma_expression ';' '@' updowneq comma_expression // CFA
    13981424                {
    13991425                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1400                         else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, NEW_ONE );
     1426                        else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, NEW_ONE );
    14011427                }
    14021428        | comma_expression ';' comma_expression updowneq '@' // CFA
     
    14041430                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14051431                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1406                         else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
     1432                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
    14071433                }
    14081434        | comma_expression ';' '@' updowneq '@'                         // CFA, error
     
    14101436
    14111437        | comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA
    1412                 { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
     1438                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
    14131439        | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, error
    14141440                {
    14151441                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1416                         else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, $7 );
     1442                        else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, $7 );
    14171443                }
    14181444        | comma_expression ';' comma_expression updowneq '@' '~' comma_expression // CFA
     
    14201446                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14211447                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1422                         else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, $7 );
     1448                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, $7 );
    14231449                }
    14241450        | comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA
    1425                 { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
     1451                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
    14261452        | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, error
    14271453                {
    14281454                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1429                         else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, nullptr );
     1455                        else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, nullptr );
    14301456                }
    14311457        | comma_expression ';' comma_expression updowneq '@' '~' '@' // CFA
     
    14331459                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14341460                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1435                         else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, nullptr );
     1461                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, nullptr );
    14361462                }
    14371463        | comma_expression ';' '@' updowneq '@' '~' '@' // CFA
     
    14391465
    14401466        | declaration comma_expression                                          // CFA
    1441                 { $$ = forCtrl( $1, NEW_ZERO, OperKinds::LThan, $2, NEW_ONE ); }
     1467                { $$ = forCtrl( yylloc, $1, NEW_ZERO, OperKinds::LThan, $2, NEW_ONE ); }
    14421468        | declaration downupdowneq comma_expression                     // CFA
    1443                 { $$ = forCtrl( $1, UPDOWN( $2, NEW_ZERO, $3 ), $2, UPDOWN( $2, $3->clone(), NEW_ZERO ), NEW_ONE ); }
     1469                { $$ = forCtrl( yylloc, $1, UPDOWN( $2, NEW_ZERO, $3 ), $2, UPDOWN( $2, $3->clone(), NEW_ZERO ), NEW_ONE ); }
    14441470
    14451471        | declaration comma_expression updowneq comma_expression // CFA
    1446                 { $$ = forCtrl( $1, UPDOWN( $3, $2->clone(), $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), NEW_ONE ); }
     1472                { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2->clone(), $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), NEW_ONE ); }
    14471473        | declaration '@' updowneq comma_expression                     // CFA
    14481474                {
    14491475                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1450                         else $$ = forCtrl( $1, $4, $3, nullptr, NEW_ONE );
     1476                        else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, NEW_ONE );
    14511477                }
    14521478        | declaration comma_expression updowneq '@'                     // CFA
     
    14541480                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14551481                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1456                         else $$ = forCtrl( $1, $2, $3, nullptr, NEW_ONE );
     1482                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, NEW_ONE );
    14571483                }
    14581484
    14591485        | declaration comma_expression updowneq comma_expression '~' comma_expression // CFA
    1460                 { $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), $6 ); }
     1486                { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), $6 ); }
    14611487        | declaration '@' updowneq comma_expression '~' comma_expression // CFA
    14621488                {
    14631489                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1464                         else $$ = forCtrl( $1, $4, $3, nullptr, $6 );
     1490                        else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, $6 );
    14651491                }
    14661492        | declaration comma_expression updowneq '@' '~' comma_expression // CFA
     
    14681494                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14691495                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1470                         else $$ = forCtrl( $1, $2, $3, nullptr, $6 );
     1496                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, $6 );
    14711497                }
    14721498        | declaration comma_expression updowneq comma_expression '~' '@' // CFA
    1473                 { $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), nullptr ); }
     1499                { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), nullptr ); }
    14741500        | declaration '@' updowneq comma_expression '~' '@' // CFA
    14751501                {
    14761502                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1477                         else $$ = forCtrl( $1, $4, $3, nullptr, nullptr );
     1503                        else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, nullptr );
    14781504                }
    14791505        | declaration comma_expression updowneq '@' '~' '@'     // CFA
     
    14811507                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14821508                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1483                         else $$ = forCtrl( $1, $2, $3, nullptr, nullptr );
     1509                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, nullptr );
    14841510                }
    14851511        | declaration '@' updowneq '@' '~' '@'                          // CFA, error
     
    14961522                        SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr;
    14971523                }
    1498         ;
     1524        ;
    14991525
    15001526downupdowneq:
     
    15051531        | ErangeDownEq
    15061532                { $$ = OperKinds::GEThan; }
    1507         ;
     1533        ;
    15081534
    15091535updown:
     
    15121538        | ErangeDown
    15131539                { $$ = OperKinds::GThan; }
    1514         ;
     1540        ;
    15151541
    15161542updowneq:
     
    15201546        | ErangeDownEq
    15211547                { $$ = OperKinds::GEThan; }
    1522         ;
     1548        ;
    15231549
    15241550jump_statement:
    15251551        GOTO identifier_or_type_name ';'
    1526                 { $$ = new StatementNode( build_branch( $2, BranchStmt::Goto ) ); }
     1552                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Goto ) ); }
    15271553        | GOTO '*' comma_expression ';'                                         // GCC, computed goto
    15281554                // The syntax for the GCC computed goto violates normal expression precedence, e.g., goto *i+3; => goto *(i+3);
     
    15311557                // A semantic check is required to ensure fallthru appears only in the body of a choose statement.
    15321558        | fall_through_name ';'                                                         // CFA
    1533                 { $$ = new StatementNode( build_branch( BranchStmt::FallThrough ) ); }
     1559                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThrough ) ); }
    15341560        | fall_through_name identifier_or_type_name ';'         // CFA
    1535                 { $$ = new StatementNode( build_branch( $2, BranchStmt::FallThrough ) ); }
     1561                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::FallThrough ) ); }
    15361562        | fall_through_name DEFAULT ';'                                         // CFA
    1537                 { $$ = new StatementNode( build_branch( BranchStmt::FallThroughDefault ) ); }
     1563                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThroughDefault ) ); }
    15381564        | CONTINUE ';'
    15391565                // A semantic check is required to ensure this statement appears only in the body of an iteration statement.
    1540                 { $$ = new StatementNode( build_branch( BranchStmt::Continue ) ); }
     1566                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::Continue ) ); }
    15411567        | CONTINUE identifier_or_type_name ';'                          // CFA, multi-level continue
    15421568                // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and
    15431569                // the target of the transfer appears only at the start of an iteration statement.
    1544                 { $$ = new StatementNode( build_branch( $2, BranchStmt::Continue ) ); }
     1570                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Continue ) ); }
    15451571        | BREAK ';'
    15461572                // A semantic check is required to ensure this statement appears only in the body of an iteration statement.
    1547                 { $$ = new StatementNode( build_branch( BranchStmt::Break ) ); }
     1573                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::Break ) ); }
    15481574        | BREAK identifier_or_type_name ';'                                     // CFA, multi-level exit
    15491575                // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and
    15501576                // the target of the transfer appears only at the start of an iteration statement.
    1551                 { $$ = new StatementNode( build_branch( $2, BranchStmt::Break ) ); }
     1577                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Break ) ); }
    15521578        | RETURN comma_expression_opt ';'
    1553                 { $$ = new StatementNode( build_return( $2 ) ); }
     1579                { $$ = new StatementNode( build_return( yylloc, $2 ) ); }
    15541580        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    15551581                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    15561582        | SUSPEND ';'
    1557                 { $$ = new StatementNode( build_suspend( nullptr ) ); }
     1583                { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::None ) ); }
    15581584        | SUSPEND compound_statement
    1559                 { $$ = new StatementNode( build_suspend( $2 ) ); }
     1585                { $$ = new StatementNode( build_suspend( yylloc, $2, ast::SuspendStmt::None ) ); }
    15601586        | SUSPEND COROUTINE ';'
    1561                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
     1587                { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Coroutine ) ); }
    15621588        | SUSPEND COROUTINE compound_statement
    1563                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
     1589                { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Coroutine ) ); }
    15641590        | SUSPEND GENERATOR ';'
    1565                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
     1591                { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Generator ) ); }
    15661592        | SUSPEND GENERATOR compound_statement
    1567                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
     1593                { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Generator ) ); }
    15681594        | THROW assignment_expression_opt ';'                           // handles rethrow
    1569                 { $$ = new StatementNode( build_throw( $2 ) ); }
     1595                { $$ = new StatementNode( build_throw( yylloc, $2 ) ); }
    15701596        | THROWRESUME assignment_expression_opt ';'                     // handles reresume
    1571                 { $$ = new StatementNode( build_resume( $2 ) ); }
     1597                { $$ = new StatementNode( build_resume( yylloc, $2 ) ); }
    15721598        | THROWRESUME assignment_expression_opt AT assignment_expression ';' // handles reresume
    15731599                { $$ = new StatementNode( build_resume_at( $2, $4 ) ); }
     
    15811607with_statement:
    15821608        WITH '(' tuple_expression_list ')' statement
    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".
     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".
    15871613mutex_statement:
    1588         MUTEX '(' argument_expression_list ')' statement
    1589                 { $$ = new StatementNode( build_mutex( $3, $5 ) ); }
     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                }
    15901619        ;
    15911620
     
    15981627                { $$ = nullptr; }
    15991628        | when_clause
    1600         ;
    1601 
    1602 waitfor:
    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 )); }
    16091629        ;
    16101630
     
    16171637
    16181638timeout:
    1619         TIMEOUT '(' comma_expression ')'                        { $$ = $3; }
    1620         ;
    1621 
    1622 waitfor_clause:
     1639        TIMEOUT '(' comma_expression ')'                        { $$ = $3; }
     1640        ;
     1641
     1642wor:
     1643        OROR
     1644        | WOR
     1645
     1646waitfor:
     1647        WAITFOR '(' cast_expression ')'
     1648                { $$ = $3; }
     1649        | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
     1650                { $$ = (ExpressionNode *)($3->set_last( $5 )); }
     1651        ;
     1652
     1653wor_waitfor_clause:
    16231654        when_clause_opt waitfor statement                                       %prec THEN
    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 ); }
     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 ) ); }
    16311663        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1632         | when_clause_opt timeout statement WOR ELSE statement // syntax error
     1664        | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
    16331665                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    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 ); }
     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 ) ); }
    16361668        ;
    16371669
    16381670waitfor_statement:
    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 ) ); }
     1671        wor_waitfor_clause                                                                      %prec THEN
     1672                { $$ = new StatementNode( $1 ); }
     1673        ;
     1674
     1675wand:
     1676        ANDAND
     1677        | WAND
     1678        ;
     1679
     1680waituntil:
     1681        WAITUNTIL '(' cast_expression ')'
     1682                { $$ = $3; }
     1683        ;
     1684
     1685waituntil_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
     1692wand_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
     1699wor_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
     1715waituntil_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 ) ); }
    16431719        ;
    16441720
    16451721exception_statement:
    1646         TRY compound_statement handler_clause                                   %prec THEN
    1647                 { $$ = new StatementNode( build_try( $2, $3, nullptr ) ); }
     1722        TRY compound_statement handler_clause                                   %prec THEN
     1723                { $$ = new StatementNode( build_try( yylloc, $2, $3, nullptr ) ); }
    16481724        | TRY compound_statement finally_clause
    1649                 { $$ = new StatementNode( build_try( $2, nullptr, $3 ) ); }
     1725                { $$ = new StatementNode( build_try( yylloc, $2, nullptr, $3 ) ); }
    16501726        | TRY compound_statement handler_clause finally_clause
    1651                 { $$ = new StatementNode( build_try( $2, $3, $4 ) ); }
     1727                { $$ = new StatementNode( build_try( yylloc, $2, $3, $4 ) ); }
    16521728        ;
    16531729
    16541730handler_clause:
    16551731        handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1656                 { $$ = new StatementNode( build_catch( $1, $4, $6, $8 ) ); }
     1732                { $$ = new ClauseNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
    16571733        | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1658                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $5, $7, $9 ) ) ); }
     1734                { $$ = $1->set_last( new ClauseNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
    16591735        ;
    16601736
     
    16661742
    16671743handler_key:
    1668         CATCH                                                                           { $$ = CatchStmt::Terminate; }
    1669         | RECOVER                                                                       { $$ = CatchStmt::Terminate; }
    1670         | CATCHRESUME                                                           { $$ = CatchStmt::Resume; }
    1671         | FIXUP                                                                         { $$ = CatchStmt::Resume; }
     1744        CATCH                                                                           { $$ = ast::Terminate; }
     1745        | RECOVER                                                                       { $$ = ast::Terminate; }
     1746        | CATCHRESUME                                                           { $$ = ast::Resume; }
     1747        | FIXUP                                                                         { $$ = ast::Resume; }
    16721748        ;
    16731749
    16741750finally_clause:
    1675         FINALLY compound_statement                                      { $$ = new StatementNode( build_finally( $2 ) ); }
     1751        FINALLY compound_statement                                      { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); }
    16761752        ;
    16771753
     
    16991775asm_statement:
    17001776        ASM asm_volatile_opt '(' string_literal ')' ';'
    1701                 { $$ = new StatementNode( build_asm( $2, $4, nullptr ) ); }
     1777                { $$ = new StatementNode( build_asm( yylloc, $2, $4, nullptr ) ); }
    17021778        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ')' ';' // remaining GCC
    1703                 { $$ = new StatementNode( build_asm( $2, $4, $6 ) ); }
     1779                { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6 ) ); }
    17041780        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ':' asm_operands_opt ')' ';'
    1705                 { $$ = new StatementNode( build_asm( $2, $4, $6, $8 ) ); }
     1781                { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6, $8 ) ); }
    17061782        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ':' asm_operands_opt ':' asm_clobbers_list_opt ')' ';'
    1707                 { $$ = new StatementNode( build_asm( $2, $4, $6, $8, $10 ) ); }
     1783                { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6, $8, $10 ) ); }
    17081784        | ASM asm_volatile_opt GOTO '(' string_literal ':' ':' asm_operands_opt ':' asm_clobbers_list_opt ':' label_list ')' ';'
    1709                 { $$ = new StatementNode( build_asm( $2, $5, nullptr, $8, $10, $12 ) ); }
     1785                { $$ = new StatementNode( build_asm( yylloc, $2, $5, nullptr, $8, $10, $12 ) ); }
    17101786        ;
    17111787
     
    17311807asm_operand:                                                                                    // GCC
    17321808        string_literal '(' constant_expression ')'
    1733                 { $$ = new ExpressionNode( new AsmExpr( nullptr, $1, maybeMoveBuild<Expression>( $3 ) ) ); }
     1809                { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    17341810        | '[' IDENTIFIER ']' string_literal '(' constant_expression ')'
    1735                 { $$ = new ExpressionNode( new AsmExpr( $2, $4, maybeMoveBuild<Expression>( $6 ) ) ); }
     1811                {
     1812                        $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, maybeMoveBuild( $4 ), maybeMoveBuild( $6 ) ) );
     1813                        delete $2.str;
     1814                }
    17361815        ;
    17371816
     
    17401819                { $$ = nullptr; }                                                               // use default argument
    17411820        | string_literal
    1742                 { $$ = new ExpressionNode( $1 ); }
     1821                { $$ = $1; }
    17431822        | asm_clobbers_list_opt ',' string_literal
    1744                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
     1823                { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); }
    17451824        ;
    17461825
     
    17481827        identifier
    17491828                {
    1750                         $$ = new LabelNode(); $$->labels.push_back( *$1 );
     1829                        $$ = new LabelNode(); $$->labels.emplace_back( yylloc, *$1 );
    17511830                        delete $1;                                                                      // allocated by lexer
    17521831                }
    17531832        | label_list ',' identifier
    17541833                {
    1755                         $$ = $1; $1->labels.push_back( *$3 );
     1834                        $$ = $1; $1->labels.emplace_back( yylloc, *$3 );
    17561835                        delete $3;                                                                      // allocated by lexer
    17571836                }
     
    18041883                {
    18051884                        // printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" );
    1806                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     1885                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    18071886                        //   printf( "\tattr %s\n", attr->name.c_str() );
    18081887                        // } // for
     
    18141893static_assert:
    18151894        STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11
    1816                 { $$ = DeclarationNode::newStaticAssert( $3, $5 ); }
     1895                { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); }
    18171896        | STATICASSERT '(' constant_expression ')' ';'          // CFA
    1818                 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( *new string( "\"\"" ) ) ); }
     1897                { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); }
    18191898
    18201899// C declaration syntax is notoriously confusing and error prone. Cforall provides its own type, variable and function
     
    19392018        TYPEDEF type_specifier declarator
    19402019                {
    1941                         // if type_specifier is an anon aggregate => name
    19422020                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "4" );
    1943                         $$ = $3->addType( $2 )->addTypedef();
     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
    19442024                }
    19452025        | typedef_declaration pop ',' push declarator
     
    19492029                }
    19502030        | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
    1951                 {
    1952                         typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "6" );
    1953                         $$ = $4->addType( $3 )->addQualifiers( $1 )->addTypedef();
    1954                 }
     2031                { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
    19552032        | type_specifier TYPEDEF declarator
    1956                 {
    1957                         typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "7" );
    1958                         $$ = $3->addType( $1 )->addTypedef();
    1959                 }
     2033                { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
    19602034        | type_specifier TYPEDEF type_qualifier_list declarator
    1961                 {
    1962                         typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "8" );
    1963                         $$ = $4->addQualifiers( $1 )->addTypedef()->addType( $1 );
    1964                 }
     2035                { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
    19652036        ;
    19662037
     
    19692040        TYPEDEF identifier '=' assignment_expression
    19702041                {
    1971                         SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     2042                        SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    19722043                }
    19732044        | typedef_expression pop ',' push identifier '=' assignment_expression
    19742045                {
    1975                         SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     2046                        SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    19762047                }
    19772048        ;
     
    19832054        | typedef_expression                                                            // deprecated GCC, naming expression type
    19842055        | 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                }
    19852066        ;
    19862067
     
    19882069                // A semantic check is required to ensure asm_name only appears on declarations with implicit or explicit static
    19892070                // storage-class
    1990         declarator asm_name_opt initializer_opt
     2071        variable_declarator asm_name_opt initializer_opt
    19912072                { $$ = $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
    19922081        | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    19932082                { $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
     2083        ;
     2084
     2085general_function_declarator:
     2086        function_type_redeclarator
     2087        | function_declarator
    19942088        ;
    19952089
     
    20002094        | sue_declaration_specifier invalid_types
    20012095                {
    2002                         SemanticError( yylloc,
    2003                                                   ::toString( "Missing ';' after end of ",
    2004                                                                           $1->type->enumeration.name ? "enum" : AggregateDecl::aggrString( $1->type->aggregate.kind ),
    2005                                                                           " declaration" ) );
     2096                        SemanticError( yylloc, ::toString( "Missing ';' after end of ",
     2097                                $1->type->enumeration.name ? "enum" : ast::AggregateDecl::aggrString( $1->type->aggregate.kind ),
     2098                                " declaration" ) );
    20062099                        $$ = nullptr;
    20072100                }
     
    20282121        basic_type_specifier
    20292122        | 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                 }
    20362123        | type_type_specifier
    20372124        ;
     
    22422329                { $$ = DeclarationNode::newTypeof( $3 ); }
    22432330        | BASETYPEOF '(' type ')'                                                       // CFA: basetypeof( x ) y;
    2244                 { $$ = DeclarationNode::newTypeof( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ), true ); }
     2331                { $$ = DeclarationNode::newTypeof( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ), true ); }
    22452332        | BASETYPEOF '(' comma_expression ')'                           // CFA: basetypeof( a+b ) y;
    22462333                { $$ = DeclarationNode::newTypeof( $3, true ); }
     
    22552342                {
    22562343                        // printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2257                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2344                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    22582345                        //   printf( "\tattr %s\n", attr->name.c_str() );
    22592346                        // } // for
     
    22712358                {
    22722359                        // printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2273                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2360                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    22742361                        //   printf( "\tattr %s\n", attr->name.c_str() );
    22752362                        // } // for
     
    23492436                {
    23502437                        // printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2351                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2438                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    23522439                        //   printf( "\tattr %s\n", attr->name.c_str() );
    23532440                        // } // for
     
    23732460          '{' field_declaration_list_opt '}' type_parameters_opt
    23742461                {
    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
    23802462                        $$ = 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
    23852463                }
    23862464        | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
     
    23912469          '{' field_declaration_list_opt '}' type_parameters_opt
    23922470                {
    2393                         // printf( "AGG3\n" );
    23942471                        DeclarationNode::newFromTypedef( $3 );
    23952472                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    24022479          '{' field_declaration_list_opt '}' type_parameters_opt
    24032480                {
    2404                         // printf( "AGG4\n" );
    24052481                        DeclarationNode::newFromTypeGen( $3, nullptr );
    24062482                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    24292505                        // switched to a TYPEGENname. Link any generic arguments from typegen_name to new generic declaration and
    24302506                        // delete newFromTypeGen.
    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;
     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                        }
    24352515                }
    24362516        ;
     
    24432523aggregate_data:
    24442524        STRUCT vtable_opt
    2445                 { $$ = AggregateDecl::Struct; }
     2525                { $$ = ast::AggregateDecl::Struct; }
    24462526        | UNION
    2447                 { $$ = AggregateDecl::Union; }
     2527                { $$ = ast::AggregateDecl::Union; }
    24482528        | EXCEPTION                                                                                     // CFA
    2449                 { $$ = AggregateDecl::Exception; }
    2450           //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2529                { $$ = ast::AggregateDecl::Exception; }
     2530          //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = ast::AggregateDecl::NoAggregate; }
    24512531        ;
    24522532
    24532533aggregate_control:                                                                              // CFA
    24542534        MONITOR
    2455                 { $$ = AggregateDecl::Monitor; }
     2535                { $$ = ast::AggregateDecl::Monitor; }
    24562536        | MUTEX STRUCT
    2457                 { $$ = AggregateDecl::Monitor; }
     2537                { $$ = ast::AggregateDecl::Monitor; }
    24582538        | GENERATOR
    2459                 { $$ = AggregateDecl::Generator; }
     2539                { $$ = ast::AggregateDecl::Generator; }
    24602540        | MUTEX GENERATOR
    2461                 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2541                {
     2542                        SemanticError( yylloc, "monitor generator is currently unimplemented." );
     2543                        $$ = ast::AggregateDecl::NoAggregate;
     2544                }
    24622545        | COROUTINE
    2463                 { $$ = AggregateDecl::Coroutine; }
     2546                { $$ = ast::AggregateDecl::Coroutine; }
    24642547        | MUTEX COROUTINE
    2465                 { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2548                {
     2549                        SemanticError( yylloc, "monitor coroutine is currently unimplemented." );
     2550                        $$ = ast::AggregateDecl::NoAggregate;
     2551                }
    24662552        | THREAD
    2467                 { $$ = AggregateDecl::Thread; }
     2553                { $$ = ast::AggregateDecl::Thread; }
    24682554        | MUTEX THREAD
    2469                 { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2555                {
     2556                        SemanticError( yylloc, "monitor thread is currently unimplemented." );
     2557                        $$ = ast::AggregateDecl::NoAggregate;
     2558                }
    24702559        ;
    24712560
     
    24832572                        $$ = fieldDecl( $1, $2 );
    24842573                        // printf( "type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2485                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2574                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    24862575                        //   printf( "\tattr %s\n", attr->name.c_str() );
    24872576                        // } // for
     
    24902579                { $$ = fieldDecl( $2, $3 ); distExt( $$ ); }
    24912580        | STATIC type_specifier field_declaring_list_opt ';' // CFA
    2492                 { SemanticError( yylloc, "STATIC aggregate field qualifier currently unimplemented." ); $$ = nullptr; }
     2581                { SemanticError( yylloc, "STATIC aggregate field qualifier currently unimplemented." ); $$ = nullptr; }
    24932582        | INLINE type_specifier field_abstract_list_opt ';'     // CFA
    24942583                {
     
    25012590                }
    25022591        | INLINE aggregate_control ';'                                          // CFA
    2503                 { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
     2592                { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
    25042593        | typedef_declaration ';'                                                       // CFA
    25052594        | cfa_field_declaring_list ';'                                          // CFA, new style field declaration
     
    25272616                { $$ = $1->addBitfield( $2 ); }
    25282617        | 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
    25292621                // A semantic check is required to ensure bit_subrange only appears on integral types.
    25302622                { $$ = $1->addBitfield( $2 ); }
     
    25812673                { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); }
    25822674        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
    2583                 {
    2584                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 )
     2675                {
     2676                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() )
    25852677                        { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    25862678
     
    25892681        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    25902682                {
    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." ); }
     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." ); }
    25922684                        typedefTable.makeTypedef( *$6 );
    25932685                }
     
    27572849type_no_function:                                                                               // sizeof, alignof, cast (constructor)
    27582850        cfa_abstract_declarator_tuple                                           // CFA
    2759         | type_specifier
     2851        | type_specifier                                                                        // cannot be type_specifier_nobody, e.g., (struct S {}){} is a thing
    27602852        | type_specifier abstract_declarator
    27612853                { $$ = $2->addType( $1 ); }
     
    28022894        designator_list ':'                                                                     // C99, CFA uses ":" instead of "="
    28032895        | identifier_at ':'                                                                     // GCC, field name
    2804                 { $$ = new ExpressionNode( build_varref( $1 ) ); }
     2896                { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
    28052897        ;
    28062898
     
    28142906designator:
    28152907        '.' identifier_at                                                                       // C99, field name
    2816                 { $$ = new ExpressionNode( build_varref( $2 ) ); }
     2908                { $$ = new ExpressionNode( build_varref( yylloc, $2 ) ); }
    28172909        | '[' push assignment_expression pop ']'                        // C99, single array element
    28182910                // assignment_expression used instead of constant_expression because of shift/reduce conflicts with tuple.
     
    28212913                { $$ = $3; }
    28222914        | '[' push constant_expression ELLIPSIS constant_expression pop ']' // GCC, multiple array elements
    2823                 { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $3 ), maybeMoveBuild<Expression>( $5 ) ) ); }
     2915                { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $3 ), maybeMoveBuild( $5 ) ) ); }
    28242916        | '.' '[' push field_name_list pop ']'                          // CFA, tuple field selector
    28252917                { $$ = $4; }
     
    28612953                {
    28622954                        typedefTable.addToScope( *$2, TYPEDEFname, "9" );
    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 ..." ); }
     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 ..." ); }
    28662958                }
    28672959          type_initializer_opt assertion_list_opt
     
    28742966                {
    28752967                        typedefTable.addToScope( *$2, TYPEDIMname, "9" );
    2876                         $$ = DeclarationNode::newTypeParam( TypeDecl::Dimension, $2 );
     2968                        $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dimension, $2 );
    28772969                }
    28782970        // | type_specifier identifier_parameter_declarator
    28792971        | assertion_list
    2880                 { $$ = DeclarationNode::newTypeParam( TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
     2972                { $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
    28812973        ;
    28822974
    28832975new_type_class:                                                                                 // CFA
    28842976        // empty
    2885                 { $$ = TypeDecl::Otype; }
     2977                { $$ = ast::TypeDecl::Otype; }
    28862978        | '&'
    2887                 { $$ = TypeDecl::Dtype; }
     2979                { $$ = ast::TypeDecl::Dtype; }
    28882980        | '*'
    2889                 { $$ = TypeDecl::DStype; }                                              // dtype + sized
     2981                { $$ = ast::TypeDecl::DStype; }                                         // dtype + sized
    28902982        // | '(' '*' ')'
    2891         //      { $$ = TypeDecl::Ftype; }
     2983        //      { $$ = ast::TypeDecl::Ftype; }
    28922984        | ELLIPSIS
    2893                 { $$ = TypeDecl::Ttype; }
     2985                { $$ = ast::TypeDecl::Ttype; }
    28942986        ;
    28952987
    28962988type_class:                                                                                             // CFA
    28972989        OTYPE
    2898                 { $$ = TypeDecl::Otype; }
     2990                { $$ = ast::TypeDecl::Otype; }
    28992991        | DTYPE
    2900                 { $$ = TypeDecl::Dtype; }
     2992                { $$ = ast::TypeDecl::Dtype; }
    29012993        | FTYPE
    2902                 { $$ = TypeDecl::Ftype; }
     2994                { $$ = ast::TypeDecl::Ftype; }
    29032995        | TTYPE
    2904                 { $$ = TypeDecl::Ttype; }
     2996                { $$ = ast::TypeDecl::Ttype; }
    29052997        ;
    29062998
     
    29283020type_list:                                                                                              // CFA
    29293021        type
    2930                 { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
     3022                { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
    29313023        | assignment_expression
    29323024        | type_list ',' type
    2933                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
     3025                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
    29343026        | type_list ',' assignment_expression
    29353027                { $$ = (ExpressionNode *)( $1->set_last( $3 )); }
     
    29683060        TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' '}'
    29693061                {
    2970                         SemanticWarning( yylloc, Warning::DeprecTraitSyntax, "" );
     3062                        SemanticWarning( yylloc, Warning::DeprecTraitSyntax );
    29713063                        $$ = DeclarationNode::newTrait( $2, $4, nullptr );
    29723064                }
     
    29753067        | TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' push trait_declaration_list pop '}'
    29763068                {
    2977                         SemanticWarning( yylloc, Warning::DeprecTraitSyntax, "" );
     3069                        SemanticWarning( yylloc, Warning::DeprecTraitSyntax );
    29783070                        $$ = DeclarationNode::newTrait( $2, $4, $8 );
    29793071                }
     
    30383130external_definition:
    30393131        DIRECTIVE
    3040                 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); }
     3132                { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( yylloc, $1 ) ) ); }
    30413133        | 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                }
    30423146        | IDENTIFIER IDENTIFIER
    30433147                { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; }
     
    30593163                }
    30603164        | ASM '(' string_literal ')' ';'                                        // GCC, global assembler statement
    3061                 { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, nullptr ) ) ); }
     3165                { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( yylloc, false, $3, nullptr ) ) ); }
    30623166        | EXTERN STRINGliteral
    30633167                {
    30643168                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    3065                         linkage = LinkageSpec::update( yylloc, linkage, $2 );
     3169                        linkage = ast::Linkage::update( yylloc, linkage, $2 );
    30663170                }
    30673171          up external_definition down
     
    30743178                {
    30753179                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    3076                         linkage = LinkageSpec::update( yylloc, linkage, $2 );
     3180                        linkage = ast::Linkage::update( yylloc, linkage, $2 );
    30773181                }
    30783182          '{' up external_definition_list_opt down '}'
     
    30853189        | type_qualifier_list
    30863190                {
    3087                         if ( $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3191                        if ( $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    30883192                        if ( $1->type->forall ) forall = true;          // remember generic type
    30893193                }
     
    30913195                {
    30923196                        distQual( $5, $1 );
    3093                         forall = false;
     3197                        forall = false;
    30943198                        $$ = $5;
    30953199                }
    30963200        | declaration_qualifier_list
    30973201                {
    3098                         if ( $1->type && $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3202                        if ( $1->type && $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    30993203                        if ( $1->type && $1->type->forall ) forall = true; // remember generic type
    31003204                }
     
    31023206                {
    31033207                        distQual( $5, $1 );
    3104                         forall = false;
     3208                        forall = false;
    31053209                        $$ = $5;
    31063210                }
    31073211        | declaration_qualifier_list type_qualifier_list
    31083212                {
    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." ); }
     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." ); }
    31103214                        if ( ($1->type && $1->type->forall) || ($2->type && $2->type->forall) ) forall = true; // remember generic type
    31113215                }
     
    31133217                {
    31143218                        distQual( $6, $1->addQualifiers( $2 ) );
    3115                         forall = false;
     3219                        forall = false;
    31163220                        $$ = $6;
    31173221                }
     
    31573261                        $$ = $2->addFunctionBody( $4, $3 )->addType( $1 );
    31583262                }
    3159         | declaration_specifier variable_type_redeclarator with_clause_opt compound_statement
     3263        | declaration_specifier function_type_redeclarator with_clause_opt compound_statement
    31603264                {
    31613265                        rebindForall( $1, $2 );
     
    31933297        | variable_type_redeclarator
    31943298        | function_declarator
     3299        | function_type_redeclarator
    31953300        ;
    31963301
    31973302subrange:
    31983303        constant_expression '~' constant_expression                     // CFA, integer subrange
    3199                 { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
     3304                { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    32003305        ;
    32013306
     
    32063311                {
    32073312                        DeclarationNode * name = new DeclarationNode();
    3208                         name->asmName = $3;
     3313                        name->asmName = maybeMoveBuild( $3 );
    32093314                        $$ = name->addQualifiers( $5 );
    32103315                }
     
    33193424        | '(' attribute_list variable_ptr ')' array_dimension
    33203425                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3321         | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
     3426        | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
    33223427                { $$ = $2->addArray( $4 ); }
    33233428        | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis
     
    34433548        ;
    34443549
    3445 // This pattern parses a declaration for a variable or function prototype that redefines a type name, e.g.:
     3550// This pattern parses a declaration for a variable that redefines a type name, e.g.:
    34463551//
    34473552//              typedef int foo;
     
    34493554//                 int foo; // redefine typedef name in new scope
    34503555//              }
    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.
    34543556
    34553557paren_type:
     
    34663568        paren_type attribute_list_opt
    34673569                { $$ = $1->addQualifiers( $2 ); }
    3468         | type_ptr
    3469         | type_array attribute_list_opt
     3570        | variable_type_ptr
     3571        | variable_type_array attribute_list_opt
    34703572                { $$ = $1->addQualifiers( $2 ); }
    3471         | type_function attribute_list_opt
     3573        | variable_type_function attribute_list_opt
    34723574                { $$ = $1->addQualifiers( $2 ); }
    34733575        ;
    34743576
    3475 type_ptr:
     3577variable_type_ptr:
    34763578        ptrref_operator variable_type_redeclarator
    34773579                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    34783580        | ptrref_operator type_qualifier_list variable_type_redeclarator
    34793581                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3480         | '(' type_ptr ')' attribute_list_opt                           // redundant parenthesis
     3582        | '(' variable_type_ptr ')' attribute_list_opt          // redundant parenthesis
    34813583                { $$ = $2->addQualifiers( $4 ); }
    3482         | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis
     3584        | '(' attribute_list variable_type_ptr ')' attribute_list_opt // redundant parenthesis
    34833585                { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
    34843586        ;
    34853587
    3486 type_array:
     3588variable_type_array:
    34873589        paren_type array_dimension
    34883590                { $$ = $1->addArray( $2 ); }
    3489         | '(' type_ptr ')' array_dimension
     3591        | '(' variable_type_ptr ')' array_dimension
    34903592                { $$ = $2->addArray( $4 ); }
    3491         | '(' attribute_list type_ptr ')' array_dimension
     3593        | '(' attribute_list variable_type_ptr ')' array_dimension
    34923594                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3493         | '(' type_array ')' multi_array_dimension                      // redundant parenthesis
     3595        | '(' variable_type_array ')' multi_array_dimension     // redundant parenthesis
    34943596                { $$ = $2->addArray( $4 ); }
    3495         | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis
     3597        | '(' attribute_list variable_type_array ')' multi_array_dimension // redundant parenthesis
    34963598                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3497         | '(' type_array ')'                                                            // redundant parenthesis
     3599        | '(' variable_type_array ')'                                           // redundant parenthesis
    34983600                { $$ = $2; }
    3499         | '(' attribute_list type_array ')'                                     // redundant parenthesis
     3601        | '(' attribute_list variable_type_array ')'            // redundant parenthesis
    35003602                { $$ = $3->addQualifiers( $2 ); }
    35013603        ;
    35023604
    3503 type_function:
     3605variable_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
     3620function_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
     3628function_type_no_ptr:
    35043629        paren_type '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    35053630                { $$ = $1->addParamList( $4 ); }
    3506         | '(' type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3631        | '(' function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
    35073632                { $$ = $2->addParamList( $6 ); }
    3508         | '(' attribute_list type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3633        | '(' attribute_list function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
    35093634                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    3510         | '(' type_function ')'                                                         // redundant parenthesis
     3635        | '(' function_type_no_ptr ')'                                          // redundant parenthesis
    35113636                { $$ = $2; }
    3512         | '(' attribute_list type_function ')'                          // redundant parenthesis
     3637        | '(' attribute_list function_type_no_ptr ')'           // redundant parenthesis
     3638                { $$ = $3->addQualifiers( $2 ); }
     3639        ;
     3640
     3641function_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
     3652function_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
    35133664                { $$ = $3->addQualifiers( $2 ); }
    35143665        ;
     
    36803831array_type_list:
    36813832        basic_type_name
    3682                 { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
     3833                { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
    36833834        | type_name
    3684                 { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
     3835                { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
    36853836        | assignment_expression upupeq assignment_expression
    36863837        | array_type_list ',' basic_type_name
    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 ) ) ) )); }
     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 ) ) ) )); }
    36903841        | array_type_list ',' assignment_expression upupeq assignment_expression
    36913842        ;
     
    36963847        | ErangeUpEq
    36973848                { $$ = OperKinds::LEThan; }
    3698         ;
     3849        ;
    36993850
    37003851multi_array_dimension:
  • src/Parser/parserutility.cc

    r2ed94a9 rb110bcc  
    1010// Created On       : Sat May 16 15:30:39 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tus Jul 18 10:12:00 2017
    13 // Update Count     : 8
     12// Last Modified On : Wed Mar  1 10:42:00 2023
     13// Update Count     : 9
    1414//
    1515
     
    1919#include <string>                // for string
    2020
    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...
     21#include "AST/Expr.hpp"          // for UntypedExpr, CastExpr, ConstantExpr
     22#include "AST/Type.hpp"          // for BasicType, ZeroType, BasicType::Kind...
    2423
    2524// rewrite
     
    2827//    if ( (int)(x != 0) ) ...
    2928
    30 Expression *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 ) );
     29ast::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        );
    3644}
    3745
  • src/Parser/parserutility.h

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

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

    r2ed94a9 rb110bcc  
    5555namespace ResolvExpr {
    5656
     57/// Unique identifier for matching expression resolutions to their requesting expression
     58UniqueId globalResnSlot = 0;
     59
     60namespace {
     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
     1701bool 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
     1810void 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
     1917std::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
    571935const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
    581936        if ( expr->result.as< ast::ReferenceType >() ) {
     
    641942        return expr;
    651943}
    66 
    67 /// Unique identifier for matching expression resolutions to their requesting expression
    68 UniqueId globalResnSlot = 0;
    691944
    701945Cost computeConversionCost(
     
    931968}
    941969
    95 namespace {
    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 
    1674 bool 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 
    1783 void 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 
    1890 std::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 
    19081970} // namespace ResolvExpr
    19091971
  • src/ResolvExpr/CurrentObject.cc

    r2ed94a9 rb110bcc  
    99// Author           : Rob Schluntz
    1010// Created On       : Tue Jun 13 15:28:32 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul  1 09:16:01 2022
    13 // Update Count     : 15
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Apr 10  9:40:00 2023
     13// Update Count     : 18
    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
    3031#include "Common/Indenter.h"           // for Indenter, operator<<
    3132#include "Common/SemanticError.h"      // for SemanticError
     
    592593
    593594namespace 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
    594634        /// create a new MemberIterator that traverses a type correctly
    595635        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
     
    631671        };
    632672
    633         /// Iterates array types
    634         class ArrayIterator final : public MemberIterator {
     673        /// Iterates over an indexed type:
     674        class IndexIterator : public MemberIterator {
     675        protected:
    635676                CodeLocation location;
    636                 const ArrayType * array = nullptr;
    637                 const Type * base = nullptr;
    638677                size_t index = 0;
    639678                size_t size = 0;
    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                 }
     679                std::unique_ptr<MemberIterator> memberIter;
     680        public:
     681                IndexIterator( const CodeLocation & loc, size_t size ) :
     682                        location( loc ), size( size )
     683                {}
    659684
    660685                void setPosition( const Expr * expr ) {
     
    665690                        auto arg = eval( expr );
    666691                        index = arg.first;
    667                         return;
    668692
    669693                        // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    683707
    684708                void setPosition(
    685                         std::deque< ptr< Expr > >::const_iterator begin,
    686                         std::deque< ptr< Expr > >::const_iterator end
     709                        std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
     710                        std::deque<ast::ptr<ast::Expr>>::const_iterator end
    687711                ) override {
    688712                        if ( begin == end ) return;
     
    695719
    696720                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                }
    697746
    698747                ArrayIterator & bigStep() override {
     
    833882
    834883                const Type * getNext() final {
    835                         return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr;
     884                        bool hasMember = memberIter && *memberIter;
     885                        return hasMember ? memberIter->getType() : nullptr;
    836886                }
    837887
     
    897947        };
    898948
    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);
     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() ) );
    908963                }
    909964
    910965                TupleIterator & bigStep() override {
    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                         }
     966                        ++index;
     967                        memberIter.reset( index < size ?
     968                                createMemberIterator( location, typeAtIndex() ) : nullptr );
    919969                        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 {};
    9201004                }
    9211005        };
  • src/ResolvExpr/CurrentObject.h

    r2ed94a9 rb110bcc  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jun  8 11:07:25 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:48 2017
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Apr  6 16:14:00 2023
     13// Update Count     : 4
    1414//
    1515
     
    6565
    6666        /// Iterates members of a type by initializer
    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         };
     67        class MemberIterator;
    10468
    10569        /// Builds initializer lists in resolution
  • src/ResolvExpr/ExplodedArg.hpp

    r2ed94a9 rb110bcc  
    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

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

    r2ed94a9 rb110bcc  
    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
    4042#include "Common/PassVisitor.h"          // for PassVisitor
    4143#include "Common/SemanticError.h"        // for SemanticError
    4244#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    43 #include "Common/utility.h"              // for ValueGuard, group_iterate
     45#include "Common/ToString.hpp"           // for toCString
    4446#include "InitTweak/GenInit.h"
    4547#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
  • src/ResolvExpr/Resolver.h

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Thu Mar 03 15:45:56 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 27 14:39:06 2018
    13 // Update Count     : 63
     12// Last Modified On : Fri Apr 14 15:03:00 2023
     13// Update Count     : 64
    1414//
    1515
     
    211211        }
    212212
    213         bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
    214                 return obj && obj->name.empty() && obj->bitfieldWidth;
    215         }
    216 
    217213        /// inserts a forward declaration for functionDecl into declsToAdd
    218214        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
     
    234230        }
    235231
    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 
    247232        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    248233        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    256241                ftype->parameters.push_back( dstParam );
    257242                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);
    266243        }
    267244
  • src/SymTab/Autogen.h

    r2ed94a9 rb110bcc  
    99// Author           : Rob Schluntz
    1010// Created On       : Sun May 17 21:53:34 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 16:38:06 2019
    13 // Update Count     : 16
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Apr 14 15:06:00 2023
     13// Update Count     : 17
    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 );
    4847
    4948        /// generate the type of an assignment function for paramType.
     
    5554        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
    5655
    57         ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
    58 
    5956        /// generate the type of a copy constructor for paramType.
    6057        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     
    6764        template< typename OutputIterator >
    6865        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 );
    7566
    7667        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
     
    121112
    122113                *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 };
    180114
    181115                srcParam.clearArrayIndices();
     
    248182        }
    249183
    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 
    320184        template< typename OutputIterator >
    321185        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
     
    325189                } else {
    326190                        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 );
    344191                }
    345192        }
     
    379226        }
    380227
    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         }
    414228} // namespace SymTab
    415229
  • src/SymTab/FixFunction.cc

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

    r2ed94a9 rb110bcc  
    2424#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
    2525#include "Common/PassVisitor.h"
     26#include "Common/ToString.hpp"           // for toCString
    2627#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

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

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

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

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

    r2ed94a9 rb110bcc  
    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
    8995        if ( statements ) {
    9096                os << indent << "... with body" << endl << indent+1;
  • src/SynTree/Type.cc

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

    r2ed94a9 rb110bcc  
    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 : Wed Jul 14 15:40:00 2021
    13 // Update Count     : 171
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Feb 19 22:37:10 2023
     13// Update Count     : 176
    1414//
    1515
     
    2323
    2424#include "BaseSyntaxNode.h"  // for BaseSyntaxNode
    25 #include "Common/utility.h"  // for operator+
     25#include "Common/Iterate.hpp"// 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 { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
     187        virtual AggregateDecl * getAggr() const;
    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

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

    r2ed94a9 rb110bcc  
    1616#include "Validate/FixQualifiedTypes.hpp"
    1717
     18#include "AST/LinkageSpec.hpp"             // for Linkage
    1819#include "AST/Pass.hpp"
    1920#include "AST/TranslationUnit.hpp"
     21#include "Common/ToString.hpp"             // for toString
     22#include "SymTab/Mangler.h"                // for Mangler
    2023#include "Validate/NoIdSymbolTable.hpp"
    21 #include "SymTab/Mangler.h"            // for Mangler
    22 #include "AST/LinkageSpec.hpp"                     // for Linkage
    2324
    2425namespace Validate {
  • src/Validate/ForallPointerDecay.cpp

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

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

    r2ed94a9 rb110bcc  
    1616#include "Validate/HoistStruct.hpp"
    1717
     18#include <sstream>
     19
    1820#include "AST/Pass.hpp"
    1921#include "AST/TranslationUnit.hpp"
    20 #include "Common/utility.h"
    2122
    2223namespace Validate {
  • src/Virtual/module.mk

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

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

    r2ed94a9 rb110bcc  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Oct  5 12:06:00 2022
    13 // Update Count     : 679
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 21:12:17 2023
     13// Update Count     : 682
    1414//
    1515
     
    3232
    3333#include "AST/Convert.hpp"
     34#include "AST/Util.hpp"                     // for checkInvariants
    3435#include "CompilationState.h"
    3536#include "../config.h"                      // for CFA_LIBDIR
     
    4041#include "CodeTools/TrackLoc.h"             // for fillLocations
    4142#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
    4746#include "Common/utility.h"                 // for deleteAll, filter, printAll
    4847#include "Concurrency/Actors.hpp"           // for implementActors
     
    8483#include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign
    8584#include "Virtual/ExpandCasts.h"            // for expandCasts
     85#include "Virtual/VirtualDtor.hpp"           // for implementVirtDtors
    8686
    8787static void NewPass( const char * const name ) {
     
    102102}
    103103
    104 #define PASS( name, pass )                  \
     104// Helpers for checkInvariant:
     105void checkInvariants( std::list< Declaration * > & ) {}
     106using ast::checkInvariants;
     107
     108#define PASS( name, pass, unit, ... )       \
    105109        if ( errorp ) { cerr << name << endl; } \
    106110        NewPass(name);                          \
    107111        Stats::Time::StartBlock(name);          \
    108         pass;                                   \
    109         Stats::Time::StopBlock();
     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        }
    110123
    111124static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
     
    274287                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" );
    275288                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
    276                         parse( gcc_builtins, LinkageSpec::Compiler );
     289                        parse( gcc_builtins, ast::Linkage::Compiler );
    277290
    278291                        // read the extra prelude in, if not generating the cfa library
    279292                        FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" );
    280293                        assertf( extras, "cannot open extras.cf\n" );
    281                         parse( extras, LinkageSpec::BuiltinC );
     294                        parse( extras, ast::Linkage::BuiltinC );
    282295
    283296                        if ( ! libcfap ) {
     
    285298                                FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" );
    286299                                assertf( prelude, "cannot open prelude.cfa\n" );
    287                                 parse( prelude, LinkageSpec::Intrinsic );
     300                                parse( prelude, ast::Linkage::Intrinsic );
    288301
    289302                                // Read to cfa builtins, if not generating the cfa library
    290303                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" );
    291304                                assertf( builtins, "cannot open builtins.cf\n" );
    292                                 parse( builtins, LinkageSpec::BuiltinCFA );
    293                         } // if
    294                 } // if
    295 
    296                 parse( input, libcfap ? LinkageSpec::Intrinsic : LinkageSpec::Cforall, yydebug );
     305                                parse( builtins, ast::Linkage::BuiltinCFA );
     306                        } // if
     307                } // if
     308
     309                parse( input, libcfap ? ast::Linkage::Intrinsic : ast::Linkage::Cforall, yydebug );
    297310
    298311                transUnit = buildUnit();
    299312
    300                 if ( astp ) {
    301                         dump( std::move( transUnit ) );
    302                         return EXIT_SUCCESS;
    303                 } // if
     313                DUMP( astp, std::move( transUnit ) );
    304314
    305315                Stats::Time::StopBlock();
     
    310320                }
    311321
    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 ) );
     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 );
    352354
    353355                if ( symtabp ) {
     
    360362                } // if
    361363
    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 ) );
     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 );
    372371
    373372                if ( libcfap ) {
     
    381380                } // if
    382381
    383                 if ( bresolvep ) {
    384                         dump( std::move( transUnit ) );
    385                         return EXIT_SUCCESS;
    386                 } // if
     382                DUMP( bresolvep, std::move( transUnit ) );
    387383
    388384                if ( resolvprotop ) {
     
    391387                } // if
    392388
    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()));
     389                PASS( "Resolve", ResolvExpr::resolve, transUnit );
     390                DUMP( exprp, std::move( transUnit ) );
     391
     392                PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
    402393
    403394                // fix ObjectDecl - replaces ConstructorInit nodes
    404                 if ( ctorinitp ) {
    405                         dump( std::move( transUnit ) );
    406                         return EXIT_SUCCESS;
    407                 } // if
     395                DUMP( ctorinitp, std::move( transUnit ) );
    408396
    409397                // Currently not working due to unresolved issues with UniqueExpr
    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 ) );
     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 );
    414402
    415403                // Needs to happen before tuple types are expanded.
    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
     404                PASS( "Convert Specializations",  GenPoly::convertSpecializations, transUnit );
     405
     406                PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
     407                DUMP( tuplep, std::move( transUnit ) );
    424408
    425409                // Must come after Translate Tries.
    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 ) );
     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 );
    435416
    436417                translationUnit = convert( std::move( transUnit ) );
    437418
    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 ) );
     419                DUMP( bboxp, translationUnit );
     420                PASS( "Box", GenPoly::box, translationUnit );
     421
     422                PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit );
    445423
    446424                // Code has been lowered to C, now we can start generation.
    447425
    448                 if ( bcodegenp ) {
    449                         dump( translationUnit );
    450                         return EXIT_SUCCESS;
    451                 } // if
     426                DUMP( bcodegenp, translationUnit );
    452427
    453428                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    456431
    457432                CodeTools::fillLocations( translationUnit );
    458                 PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
     433                PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
    459434
    460435                CodeGen::FixMain::fix( translationUnit, *output,
     
    476451                } // if
    477452                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;
    491453                if ( output != &cout ) {
    492454                        delete output;
     
    517479
    518480
    519 static const char optstring[] = ":c:ghlLmNnpdP:S:twW:D:";
     481static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
    520482
    521483enum { PreludeDir = 128 };
     
    524486        { "gdb", no_argument, nullptr, 'g' },
    525487        { "help", no_argument, nullptr, 'h' },
     488        { "invariant", no_argument, nullptr, 'i' },
    526489        { "libcfa", no_argument, nullptr, 'l' },
    527490        { "linemarks", no_argument, nullptr, 'L' },
    528         { "no-main", no_argument, 0, 'm' },
     491        { "no-main", no_argument, nullptr, 'm' },
    529492        { "no-linemarks", no_argument, nullptr, 'N' },
    530493        { "no-prelude", no_argument, nullptr, 'n' },
     
    545508        "wait for gdb to attach",                                                       // -g
    546509        "print translator help message",                                        // -h
     510        "invariant checking during AST passes",                         // -i
    547511        "generate libcfa.c",                                                            // -l
    548512        "generate line marks",                                                          // -L
     
    638602                        usage( argv );                                                          // no return
    639603                        break;
     604                  case 'i':                                                                             // invariant checking
     605                        invariant = true;
     606                        break;
    640607                  case 'l':                                                                             // generate libcfa.c
    641608                        libcfap = true;
  • tests/.expect/PRNG.x64.txt

    r2ed94a9 rb110bcc  
     1
     2CFA xoshiro256pp
    13
    24                    PRNG()     PRNG(5)   PRNG(0,5)
    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
     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
    2325seed 1009
    2426
    2527Sequential
    26 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     28trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    2729
    2830Concurrent
    29 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    30 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    31 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    32 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     31trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     32trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     33trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     34trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    3335
    3436                    prng()     prng(5)   prng(0,5)
    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
     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
    5557seed 1009
    5658
    5759Sequential
    58 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     60trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    5961
    6062Concurrent
    61 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    62 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    63 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    64 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     63trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     64trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     65trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     66trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    6567
    6668                   prng(t)   prng(t,5) prng(t,0,5)
    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
     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
    8789seed 1009
    8890
    8991Sequential
    90 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     92trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    9193
    9294Concurrent
    93 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    94 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    95 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
    96 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%
     95trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     96trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     97trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     98trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
  • tests/.expect/PRNG.x86.txt

    r2ed94a9 rb110bcc  
     1
     2CFA xoshiro128pp
    13
    24                    PRNG()     PRNG(5)   PRNG(0,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
     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
    2325seed 1009
    2426
    2527Sequential
    26 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     28trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    2729
    2830Concurrent
    29 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    30 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    31 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    32 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     31trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     32trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     33trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     34trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    3335
    3436                    prng()     prng(5)   prng(0,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
     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
    5557seed 1009
    5658
    5759Sequential
    58 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     60trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    5961
    6062Concurrent
    61 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    62 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    63 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    64 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     63trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     64trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     65trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     66trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    6567
    6668                   prng(t)   prng(t,5) prng(t,0,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
     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
    8789seed 1009
    8890
    8991Sequential
    90 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     92trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    9193
    9294Concurrent
    93 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    94 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    95 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
    96 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%
     95trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     96trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     97trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     98trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
  • tests/.expect/attributes.arm64.txt

    r2ed94a9 rb110bcc  
    2626    return _X4_retS12__anonymous0_1;
    2727}
    28 __attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
     28__attribute__ ((unused)) static 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)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
     1353signed 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));
    13541354struct Vad {
    13551355    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.x64.txt

    r2ed94a9 rb110bcc  
    2626    return _X4_retS12__anonymous0_1;
    2727}
    28 __attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
     28__attribute__ ((unused)) static 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)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
     1353signed 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));
    13541354struct Vad {
    13551355    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.x86.txt

    r2ed94a9 rb110bcc  
    2626    return _X4_retS12__anonymous0_1;
    2727}
    28 __attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
     28__attribute__ ((unused)) static 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)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
     1353signed 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));
    13541354struct Vad {
    13551355    __attribute__ ((unused)) signed int :4;
  • tests/.expect/declarationSpecifier.arm64.txt

    r2ed94a9 rb110bcc  
    5151
    5252}
    53 volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
     53static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
    5454struct __anonymous1 {
    5555    signed int _X1ii_1;
     
    9696
    9797}
    98 volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
     98static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
    9999struct __anonymous2 {
    100100    signed int _X1ii_1;
     
    141141
    142142}
    143 volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
     143static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
    144144struct __anonymous3 {
    145145    signed int _X1ii_1;
     
    322322}
    323323static volatile const struct __anonymous6 _X3x16KVS12__anonymous6_1;
    324 struct __anonymous7 {
    325     signed int _X1ii_1;
    326 };
    327 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    328 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    329 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    330 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);
    331 static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1);
    332 static 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 }
    338 static 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 }
    344 static 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 }
    350 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){
    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 }
    362 static 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 }
    368 static volatile const struct __anonymous7 _X3x17KVS12__anonymous7_1;
    369324volatile const signed short int _X3x20KVs_1;
    370325static volatile const signed short int _X3x21KVs_1;
     
    375330static volatile const signed short int _X3x26KVs_1;
    376331static volatile const signed short int _X3x27KVs_1;
     332struct __anonymous7 {
     333    signed short int _X1is_1;
     334};
     335static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     336static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     337static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     338static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     339static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1);
     340static 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}
     346static 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}
     352static 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}
     358static 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}
     370static 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}
     376static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1;
    377377struct __anonymous8 {
    378378    signed short int _X1is_1;
     
    419419
    420420}
    421 volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;
     421static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1;
    422422struct __anonymous9 {
    423423    signed short int _X1is_1;
     
    464464
    465465}
    466 volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;
     466static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1;
    467467struct __anonymous10 {
    468468    signed short int _X1is_1;
     
    509509
    510510}
    511 volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;
     511static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1;
    512512struct __anonymous11 {
    513513    signed short int _X1is_1;
     
    554554
    555555}
    556 static volatile const struct __anonymous11 _X3x32KVS13__anonymous11_1;
     556static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1;
    557557struct __anonymous12 {
    558558    signed short int _X1is_1;
     
    599599
    600600}
    601 static volatile const struct __anonymous12 _X3x33KVS13__anonymous12_1;
     601static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1;
    602602struct __anonymous13 {
    603603    signed short int _X1is_1;
     
    644644
    645645}
    646 static volatile const struct __anonymous13 _X3x34KVS13__anonymous13_1;
    647 struct __anonymous14 {
    648     signed short int _X1is_1;
    649 };
    650 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    651 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    652 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    653 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);
    654 static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1);
    655 static 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 }
    661 static 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 }
    667 static 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 }
    673 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){
    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 }
    685 static 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 }
    691 static volatile const struct __anonymous14 _X3x35KVS13__anonymous14_1;
    692 struct __anonymous15 {
    693     signed short int _X1is_1;
    694 };
    695 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    696 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    697 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    698 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);
    699 static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1);
    700 static 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 }
    706 static 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 }
    712 static 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 }
    718 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){
    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 }
    730 static 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 }
    736 static volatile const struct __anonymous15 _X3x36KVS13__anonymous15_1;
     646static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1;
    737647_Thread_local signed int _X3x37i_1;
    738648__thread signed int _X3x38i_1;
     
    753663static inline volatile const signed short int _X3f27Fs___1();
    754664static inline volatile const signed short int _X3f28Fs___1();
     665struct __anonymous14 {
     666    signed int _X1ii_1;
     667};
     668static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     669static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     670static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     671static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     672static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1);
     673static 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}
     679static 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}
     685static 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}
     691static 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}
     703static 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}
     709static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1();
     710struct __anonymous15 {
     711    signed int _X1ii_1;
     712};
     713static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     714static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     715static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     716static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     717static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1);
     718static 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}
     724static 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}
     730static 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}
     736static 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}
     748static 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}
     754static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1();
    755755struct __anonymous16 {
    756756    signed int _X1ii_1;
     
    797797
    798798}
    799 static inline volatile const struct __anonymous16 _X3f31FS13__anonymous16___1();
     799static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1();
    800800struct __anonymous17 {
    801801    signed int _X1ii_1;
     
    842842
    843843}
    844 static inline volatile const struct __anonymous17 _X3f32FS13__anonymous17___1();
     844static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1();
    845845struct __anonymous18 {
    846846    signed int _X1ii_1;
     
    887887
    888888}
    889 static inline volatile const struct __anonymous18 _X3f33FS13__anonymous18___1();
     889static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1();
    890890struct __anonymous19 {
    891891    signed int _X1ii_1;
     
    932932
    933933}
    934 static inline volatile const struct __anonymous19 _X3f34FS13__anonymous19___1();
     934static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1();
    935935struct __anonymous20 {
    936936    signed int _X1ii_1;
     
    977977
    978978}
    979 static inline volatile const struct __anonymous20 _X3f35FS13__anonymous20___1();
     979static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1();
    980980struct __anonymous21 {
    981981    signed int _X1ii_1;
     
    10221022
    10231023}
    1024 static inline volatile const struct __anonymous21 _X3f36FS13__anonymous21___1();
    1025 struct __anonymous22 {
    1026     signed int _X1ii_1;
    1027 };
    1028 static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
    1029 static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
    1030 static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
    1031 static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
    1032 static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1);
    1033 static 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 }
    1039 static 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 }
    1045 static 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 }
    1051 static 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 }
    1063 static 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 }
    1069 static inline volatile const struct __anonymous22 _X3f37FS13__anonymous22___1();
    1070 struct __anonymous23 {
    1071     signed int _X1ii_1;
    1072 };
    1073 static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
    1074 static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
    1075 static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
    1076 static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
    1077 static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1);
    1078 static 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 }
    1084 static 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 }
    1090 static 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 }
    1096 static 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 }
    1108 static 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 }
    1114 static inline volatile const struct __anonymous23 _X3f38FS13__anonymous23___1();
     1024static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1();
    11151025static inline volatile const signed short int _X3f41Fs___1();
    11161026static inline volatile const signed short int _X3f42Fs___1();
  • tests/.expect/declarationSpecifier.x64.txt

    r2ed94a9 rb110bcc  
    5151
    5252}
    53 volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
     53static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
    5454struct __anonymous1 {
    5555    signed int _X1ii_1;
     
    9696
    9797}
    98 volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
     98static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
    9999struct __anonymous2 {
    100100    signed int _X1ii_1;
     
    141141
    142142}
    143 volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
     143static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
    144144struct __anonymous3 {
    145145    signed int _X1ii_1;
     
    322322}
    323323static volatile const struct __anonymous6 _X3x16KVS12__anonymous6_1;
    324 struct __anonymous7 {
    325     signed int _X1ii_1;
    326 };
    327 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    328 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    329 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    330 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);
    331 static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1);
    332 static 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 }
    338 static 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 }
    344 static 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 }
    350 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){
    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 }
    362 static 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 }
    368 static volatile const struct __anonymous7 _X3x17KVS12__anonymous7_1;
    369324volatile const signed short int _X3x20KVs_1;
    370325static volatile const signed short int _X3x21KVs_1;
     
    375330static volatile const signed short int _X3x26KVs_1;
    376331static volatile const signed short int _X3x27KVs_1;
     332struct __anonymous7 {
     333    signed short int _X1is_1;
     334};
     335static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     336static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     337static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     338static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     339static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1);
     340static 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}
     346static 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}
     352static 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}
     358static 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}
     370static 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}
     376static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1;
    377377struct __anonymous8 {
    378378    signed short int _X1is_1;
     
    419419
    420420}
    421 volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;
     421static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1;
    422422struct __anonymous9 {
    423423    signed short int _X1is_1;
     
    464464
    465465}
    466 volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;
     466static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1;
    467467struct __anonymous10 {
    468468    signed short int _X1is_1;
     
    509509
    510510}
    511 volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;
     511static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1;
    512512struct __anonymous11 {
    513513    signed short int _X1is_1;
     
    554554
    555555}
    556 static volatile const struct __anonymous11 _X3x32KVS13__anonymous11_1;
     556static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1;
    557557struct __anonymous12 {
    558558    signed short int _X1is_1;
     
    599599
    600600}
    601 static volatile const struct __anonymous12 _X3x33KVS13__anonymous12_1;
     601static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1;
    602602struct __anonymous13 {
    603603    signed short int _X1is_1;
     
    644644
    645645}
    646 static volatile const struct __anonymous13 _X3x34KVS13__anonymous13_1;
    647 struct __anonymous14 {
    648     signed short int _X1is_1;
    649 };
    650 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    651 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    652 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    653 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);
    654 static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1);
    655 static 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 }
    661 static 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 }
    667 static 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 }
    673 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){
    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 }
    685 static 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 }
    691 static volatile const struct __anonymous14 _X3x35KVS13__anonymous14_1;
    692 struct __anonymous15 {
    693     signed short int _X1is_1;
    694 };
    695 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    696 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    697 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    698 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);
    699 static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1);
    700 static 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 }
    706 static 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 }
    712 static 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 }
    718 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){
    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 }
    730 static 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 }
    736 static volatile const struct __anonymous15 _X3x36KVS13__anonymous15_1;
     646static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1;
    737647_Thread_local signed int _X3x37i_1;
    738648__thread signed int _X3x38i_1;
     
    753663static inline volatile const signed short int _X3f27Fs___1();
    754664static inline volatile const signed short int _X3f28Fs___1();
     665struct __anonymous14 {
     666    signed int _X1ii_1;
     667};
     668static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     669static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     670static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     671static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     672static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1);
     673static 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}
     679static 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}
     685static 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}
     691static 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}
     703static 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}
     709static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1();
     710struct __anonymous15 {
     711    signed int _X1ii_1;
     712};
     713static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     714static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     715static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     716static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     717static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1);
     718static 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}
     724static 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}
     730static 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}
     736static 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}
     748static 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}
     754static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1();
    755755struct __anonymous16 {
    756756    signed int _X1ii_1;
     
    797797
    798798}
    799 static inline volatile const struct __anonymous16 _X3f31FS13__anonymous16___1();
     799static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1();
    800800struct __anonymous17 {
    801801    signed int _X1ii_1;
     
    842842
    843843}
    844 static inline volatile const struct __anonymous17 _X3f32FS13__anonymous17___1();
     844static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1();
    845845struct __anonymous18 {
    846846    signed int _X1ii_1;
     
    887887
    888888}
    889 static inline volatile const struct __anonymous18 _X3f33FS13__anonymous18___1();
     889static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1();
    890890struct __anonymous19 {
    891891    signed int _X1ii_1;
     
    932932
    933933}
    934 static inline volatile const struct __anonymous19 _X3f34FS13__anonymous19___1();
     934static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1();
    935935struct __anonymous20 {
    936936    signed int _X1ii_1;
     
    977977
    978978}
    979 static inline volatile const struct __anonymous20 _X3f35FS13__anonymous20___1();
     979static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1();
    980980struct __anonymous21 {
    981981    signed int _X1ii_1;
     
    10221022
    10231023}
    1024 static inline volatile const struct __anonymous21 _X3f36FS13__anonymous21___1();
    1025 struct __anonymous22 {
    1026     signed int _X1ii_1;
    1027 };
    1028 static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
    1029 static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
    1030 static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
    1031 static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
    1032 static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1);
    1033 static 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 }
    1039 static 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 }
    1045 static 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 }
    1051 static 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 }
    1063 static 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 }
    1069 static inline volatile const struct __anonymous22 _X3f37FS13__anonymous22___1();
    1070 struct __anonymous23 {
    1071     signed int _X1ii_1;
    1072 };
    1073 static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
    1074 static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
    1075 static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
    1076 static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
    1077 static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1);
    1078 static 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 }
    1084 static 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 }
    1090 static 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 }
    1096 static 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 }
    1108 static 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 }
    1114 static inline volatile const struct __anonymous23 _X3f38FS13__anonymous23___1();
     1024static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1();
    11151025static inline volatile const signed short int _X3f41Fs___1();
    11161026static inline volatile const signed short int _X3f42Fs___1();
  • tests/.expect/declarationSpecifier.x86.txt

    r2ed94a9 rb110bcc  
    5151
    5252}
    53 volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
     53static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;
    5454struct __anonymous1 {
    5555    signed int _X1ii_1;
     
    9696
    9797}
    98 volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
     98static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;
    9999struct __anonymous2 {
    100100    signed int _X1ii_1;
     
    141141
    142142}
    143 volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
     143static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;
    144144struct __anonymous3 {
    145145    signed int _X1ii_1;
     
    322322}
    323323static volatile const struct __anonymous6 _X3x16KVS12__anonymous6_1;
    324 struct __anonymous7 {
    325     signed int _X1ii_1;
    326 };
    327 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    328 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
    329 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
    330 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);
    331 static inline void _X12_constructorFv_S12__anonymous7i_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed int _X1ii_1);
    332 static 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 }
    338 static 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 }
    344 static 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 }
    350 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){
    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 }
    362 static 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 }
    368 static volatile const struct __anonymous7 _X3x17KVS12__anonymous7_1;
    369324volatile const signed short int _X3x20KVs_1;
    370325static volatile const signed short int _X3x21KVs_1;
     
    375330static volatile const signed short int _X3x26KVs_1;
    376331static volatile const signed short int _X3x27KVs_1;
     332struct __anonymous7 {
     333    signed short int _X1is_1;
     334};
     335static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     336static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     337static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1);
     338static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1);
     339static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1);
     340static 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}
     346static 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}
     352static 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}
     358static 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}
     370static 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}
     376static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1;
    377377struct __anonymous8 {
    378378    signed short int _X1is_1;
     
    419419
    420420}
    421 volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;
     421static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1;
    422422struct __anonymous9 {
    423423    signed short int _X1is_1;
     
    464464
    465465}
    466 volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;
     466static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1;
    467467struct __anonymous10 {
    468468    signed short int _X1is_1;
     
    509509
    510510}
    511 volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;
     511static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1;
    512512struct __anonymous11 {
    513513    signed short int _X1is_1;
     
    554554
    555555}
    556 static volatile const struct __anonymous11 _X3x32KVS13__anonymous11_1;
     556static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1;
    557557struct __anonymous12 {
    558558    signed short int _X1is_1;
     
    599599
    600600}
    601 static volatile const struct __anonymous12 _X3x33KVS13__anonymous12_1;
     601static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1;
    602602struct __anonymous13 {
    603603    signed short int _X1is_1;
     
    644644
    645645}
    646 static volatile const struct __anonymous13 _X3x34KVS13__anonymous13_1;
    647 struct __anonymous14 {
    648     signed short int _X1is_1;
    649 };
    650 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    651 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
    652 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
    653 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);
    654 static inline void _X12_constructorFv_S13__anonymous14s_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed short int _X1is_1);
    655 static 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 }
    661 static 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 }
    667 static 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 }
    673 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){
    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 }
    685 static 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 }
    691 static volatile const struct __anonymous14 _X3x35KVS13__anonymous14_1;
    692 struct __anonymous15 {
    693     signed short int _X1is_1;
    694 };
    695 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    696 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
    697 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
    698 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);
    699 static inline void _X12_constructorFv_S13__anonymous15s_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed short int _X1is_1);
    700 static 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 }
    706 static 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 }
    712 static 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 }
    718 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){
    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 }
    730 static 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 }
    736 static volatile const struct __anonymous15 _X3x36KVS13__anonymous15_1;
     646static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1;
    737647_Thread_local signed int _X3x37i_1;
    738648__thread signed int _X3x38i_1;
     
    753663static inline volatile const signed short int _X3f27Fs___1();
    754664static inline volatile const signed short int _X3f28Fs___1();
     665struct __anonymous14 {
     666    signed int _X1ii_1;
     667};
     668static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     669static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     670static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1);
     671static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1);
     672static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1);
     673static 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}
     679static 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}
     685static 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}
     691static 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}
     703static 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}
     709static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1();
     710struct __anonymous15 {
     711    signed int _X1ii_1;
     712};
     713static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     714static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     715static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1);
     716static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1);
     717static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1);
     718static 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}
     724static 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}
     730static 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}
     736static 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}
     748static 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}
     754static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1();
    755755struct __anonymous16 {
    756756    signed int _X1ii_1;
     
    797797
    798798}
    799 static inline volatile const struct __anonymous16 _X3f31FS13__anonymous16___1();
     799static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1();
    800800struct __anonymous17 {
    801801    signed int _X1ii_1;
     
    842842
    843843}
    844 static inline volatile const struct __anonymous17 _X3f32FS13__anonymous17___1();
     844static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1();
    845845struct __anonymous18 {
    846846    signed int _X1ii_1;
     
    887887
    888888}
    889 static inline volatile const struct __anonymous18 _X3f33FS13__anonymous18___1();
     889static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1();
    890890struct __anonymous19 {
    891891    signed int _X1ii_1;
     
    932932
    933933}
    934 static inline volatile const struct __anonymous19 _X3f34FS13__anonymous19___1();
     934static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1();
    935935struct __anonymous20 {
    936936    signed int _X1ii_1;
     
    977977
    978978}
    979 static inline volatile const struct __anonymous20 _X3f35FS13__anonymous20___1();
     979static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1();
    980980struct __anonymous21 {
    981981    signed int _X1ii_1;
     
    10221022
    10231023}
    1024 static inline volatile const struct __anonymous21 _X3f36FS13__anonymous21___1();
    1025 struct __anonymous22 {
    1026     signed int _X1ii_1;
    1027 };
    1028 static inline void _X12_constructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
    1029 static inline void _X12_constructorFv_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
    1030 static inline void _X11_destructorFv_S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1);
    1031 static inline struct __anonymous22 _X16_operator_assignFS13__anonymous22_S13__anonymous22S13__anonymous22_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, struct __anonymous22 _X4_srcS13__anonymous22_1);
    1032 static inline void _X12_constructorFv_S13__anonymous22i_autogen___1(struct __anonymous22 *_X4_dstS13__anonymous22_1, signed int _X1ii_1);
    1033 static 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 }
    1039 static 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 }
    1045 static 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 }
    1051 static 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 }
    1063 static 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 }
    1069 static inline volatile const struct __anonymous22 _X3f37FS13__anonymous22___1();
    1070 struct __anonymous23 {
    1071     signed int _X1ii_1;
    1072 };
    1073 static inline void _X12_constructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
    1074 static inline void _X12_constructorFv_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
    1075 static inline void _X11_destructorFv_S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1);
    1076 static inline struct __anonymous23 _X16_operator_assignFS13__anonymous23_S13__anonymous23S13__anonymous23_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, struct __anonymous23 _X4_srcS13__anonymous23_1);
    1077 static inline void _X12_constructorFv_S13__anonymous23i_autogen___1(struct __anonymous23 *_X4_dstS13__anonymous23_1, signed int _X1ii_1);
    1078 static 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 }
    1084 static 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 }
    1090 static 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 }
    1096 static 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 }
    1108 static 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 }
    1114 static inline volatile const struct __anonymous23 _X3f38FS13__anonymous23___1();
     1024static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1();
    11151025static inline volatile const signed short int _X3f41Fs___1();
    11161026static inline volatile const signed short int _X3f42Fs___1();
  • tests/.expect/nested_function.x64.txt

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

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

    r2ed94a9 rb110bcc  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Fri Feb  3 23:06:44 2023
    14 ## Update Count     : 94
     13## Last Modified On : Mon Apr 10 23:24:02 2023
     14## Update Count     : 96
    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
     186        init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment concurrent/waitfor/parse
    187187$(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    188188        $(CFACOMPILE_SYNTAX)
  • tests/PRNG.cfa

    r2ed94a9 rb110bcc  
    88// Created On       : Wed Dec 29 09:38:12 2021
    99// Last Modified By : Peter A. Buhr
    10 // Last Modified On : Wed Dec 21 20:39:59 2022
    11 // Update Count     : 406
     10// Last Modified On : Sat Apr 15 16:44:31 2023
     11// Update Count     : 419
    1212//
    1313
     
    1515#include <stdlib.hfa>                                                                   // PRNG
    1616#include <clock.hfa>
    17 #include <thread.hfa>
    1817#include <limits.hfa>                                                                   // MAX
    1918#include <math.hfa>                                                                             // sqrt
    2019#include <malloc.h>                                                                             // malloc_stats
    2120#include <locale.h>                                                                             // setlocale
     21#include <thread.hfa>
    2222#include <mutex_stmt.hfa>
    2323
    24 #ifdef __x86_64__                                                                               // 64-bit architecture
     24#define xstr(s) str(s)
     25#define str(s) #s
     26
     27#if defined( __x86_64__ ) || defined( __aarch64__ )             // 64-bit architecture
    2528#define PRNG PRNG64
    2629#else                                                                                                   // 32-bit architecture
    2730#define PRNG PRNG32
    2831#endif // __x86_64__
     32
     33//#define TIME
    2934
    3035#ifdef TIME                                                                                             // use -O2 -nodebug
     
    3843#endif // TIME
    3944
    40 void avgstd( unsigned int buckets[] ) {
    41         unsigned int min = MAX, max = 0;
     45static void avgstd( size_t trials, size_t buckets[] ) {
     46        size_t min = MAX, max = 0;
    4247        double sum = 0.0, diff;
    4348        for ( i; BUCKETS ) {
     
    5459        } // for
    5560        double std = sqrt( sum / BUCKETS );
    56         mutex( sout ) sout | "trials"  | TRIALS | "buckets" | BUCKETS
     61        mutex( sout ) sout | "trials"  | trials | "buckets" | BUCKETS
    5762                | "min" | min | "max" | max
    5863                | "avg" | wd(0,1, avg) | "std" | wd(0,1, std) | "rstd" | wd(0,1, (avg == 0 ? 0.0 : std / avg * 100)) | "%";
     
    6469thread T1 {};
    6570void main( T1 & ) {
    66         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    67         for ( TRIALS / 100 ) {
     71        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     72        for ( TRIALS / 50 ) {
    6873                buckets[rand() % BUCKETS] += 1;                                 // concurrent
    6974        } // for
    70         avgstd( buckets );
     75        avgstd( TRIALS / 50, buckets );
    7176        free( buckets );
    7277} // main
     
    7681        PRNG prng;
    7782        if ( seed != 0 ) set_seed( prng, seed );
    78         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     83        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    7984        for ( TRIALS ) {
    8085                buckets[prng( prng ) % BUCKETS] += 1;                   // concurrent
    8186        } // for
    82         avgstd( buckets );
     87        avgstd( TRIALS, buckets );
    8388        free( buckets );
    8489} // main
     
    8691thread T3 {};
    8792void main( T3 & th ) {
    88         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    89         for ( TRIALS ) {
     93        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     94        for ( TRIALS / 5 ) {
    9095                buckets[prng() % BUCKETS] += 1;                                 // concurrent
    9196        } // for
    92         avgstd( buckets );
     97        avgstd( TRIALS / 5, buckets );
    9398        free( buckets );
    9499} // main
     
    96101thread T4 {};
    97102void main( T4 & th ) {
    98         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     103        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    99104        for ( TRIALS ) {
    100                 buckets[prng( th ) % BUCKETS] += 1;     // concurrent
    101         } // for
    102         avgstd( buckets );
     105                buckets[prng( th ) % BUCKETS] += 1;                             // concurrent
     106        } // for
     107        avgstd( TRIALS, buckets );
    103108        free( buckets );
    104109} // main
     
    108113static void dummy( thread$ & th ) __attribute__(( noinline ));
    109114static void dummy( thread$ & th ) {
    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 ) {
     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 ) {
    112117                buckets[prng( th ) % BUCKETS] += 1;                             // sequential
    113118        } // for
    114         avgstd( buckets );
     119        avgstd( TRIALS, buckets );
    115120        free( buckets );
    116121} // dummy
     
    126131        enum { TASKS = 4 };
    127132        Time start;
     133
    128134#ifdef TIME                                                                                             // too slow for test and generates non-repeatable results
    129135#if 1
    130         unsigned int rseed;
     136        sout | "glib rand" | nl | nl;
     137
     138        size_t rseed;
    131139        if ( seed != 0 ) rseed = seed;
    132140        else rseed = rdtscl();
     
    134142
    135143        sout | sepDisable;
    136         sout | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
     144        sout | nl | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
    137145        for ( 20 ) {
    138146                sout | wd(26, rand()) | nonl;
     
    146154        STARTTIME;
    147155        {
    148                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    149                 for ( i; TRIALS / 10 ) {
     156                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     157                for ( i; TRIALS / 5 ) {
    150158                        buckets[rand() % BUCKETS] += 1;                         // sequential
    151159                } // for
    152                 avgstd( buckets );
     160                avgstd( TRIALS / 5, buckets );
    153161                free( buckets );
    154162        }
    155         ENDTIME( " x 10 " );
     163        ENDTIME( " x 5 " );
    156164
    157165        sout | nl | "Concurrent";
     
    163171                } // wait for threads to complete
    164172        }
    165         ENDTIME( " x 100 " );
     173        ENDTIME( " x 50 " );
    166174#endif // 0
    167175#endif // TIME
     176
     177        sout | nl | "CFA " xstr(PRNG_NAME);
     178
    168179#if 1
    169180        PRNG prng;
     
    184195        STARTTIME;
    185196        {
    186                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
     197                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
    187198                for ( TRIALS ) {
    188199                        buckets[prng( prng ) % BUCKETS] += 1;           // sequential
    189200                } // for
    190                 avgstd( buckets );
     201                avgstd( TRIALS, buckets );
    191202                free( buckets );
    192203        }
     
    219230        STARTTIME;
    220231        {
    221                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    222                 for ( TRIALS ) {
     232                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     233                for ( TRIALS / 5 ) {
    223234                        buckets[prng() % BUCKETS] += 1;
    224235                } // for
    225                 avgstd( buckets );
     236                avgstd( TRIALS / 5, buckets );
    226237                free( buckets );
    227238        }
    228         ENDTIME();
     239        ENDTIME( " x 5 " );
    229240
    230241        sout | nl | "Concurrent";
     
    236247                } // wait for threads to complete
    237248        }
    238         ENDTIME();
     249        ENDTIME( " x 5 " );
    239250#endif // 0
    240251#if 1
  • tests/attributes.cfa

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

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

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

    r2ed94a9 rb110bcc  
    77int Times = 1000000;                                                            // default values
    88
    9 struct derived_actor {
    10     inline actor;
    11 };
    12 void ?{}( derived_actor & this ) { ((actor &)this){}; }
    13 
     9struct derived_actor { inline actor; };
    1410struct derived_msg {
    1511    inline message;
     
    2319void ?{}( derived_msg & this ) { ((derived_msg &)this){ 0 }; }
    2420
    25 
    2621Allocation receive( derived_actor & receiver, derived_msg & msg ) {
    2722    if ( msg.cnt >= Times ) {
     
    3328    derived_actor * d_actor = alloc();
    3429    (*d_actor){};
    35     *d_actor | *d_msg;
     30    *d_actor << *d_msg;
    3631    return Delete;
    3732}
     
    6358    derived_actor * d_actor = alloc();
    6459    (*d_actor){};
    65     *d_actor | *d_msg;
     60    *d_actor << *d_msg;
    6661
    6762    printf("stopping\n");
  • tests/concurrent/actors/executor.cfa

    r2ed94a9 rb110bcc  
    1515};
    1616void ?{}( d_actor & this ) with(this) {
    17     ((actor &)this){};
    1817    id = ids++;
    1918    gstart = (&this + (id / Set * Set - id)); // remember group-start array-element
     
    2423
    2524struct d_msg { inline message; } shared_msg;
    26 void ?{}( d_msg & this ) { ((message &) this){ Nodelete }; }
    2725
    2826Allocation receive( d_actor & this, d_msg & msg ) with( this ) {
     
    3028    if ( recs % Batch == 0 ) {
    3129        for ( i; Batch ) {
    32             gstart[sends % Set] | shared_msg;
     30            gstart[sends % Set] << shared_msg;
    3331            sends += 1;
    3432        }
     
    8583        } // switch
    8684
    87    
    8885    executor e{ Processors, Processors, Processors == 1 ? 1 : Processors * 512, true };
    8986
     
    9794
    9895        for ( i; Actors ) {
    99                 actors[i] | shared_msg;
     96                actors[i] << shared_msg;
    10097        } // for
    10198
  • tests/concurrent/actors/matrix.cfa

    r2ed94a9 rb110bcc  
    77unsigned int xr = 500, xc = 500, yc = 500, Processors = 1; // default values
    88
    9 struct derived_actor {
    10     inline actor;
    11 };
    12 void ?{}( derived_actor & this ) { ((actor &)this){}; }
     9struct derived_actor { inline actor; };
    1310
    1411struct derived_msg {
     
    2118void ?{}( derived_msg & this ) {}
    2219void ?{}( derived_msg & this, int * Z, int * X, int ** Y ) {
    23     ((message &) this){ Finished };
     20    ((message &) this){ Nodelete };
    2421    this.Z = Z;
    2522    this.X = X;
     
    108105
    109106        for ( unsigned int r = 0; r < xr; r += 1 ) {
    110                 actors[r] | messages[r];
     107                actors[r] << messages[r];
    111108        } // for
    112109
  • tests/concurrent/actors/pingpong.cfa

    r2ed94a9 rb110bcc  
    66#include <actor.hfa>
    77
    8 struct ping {
    9     inline actor;
    10 };
    11 static inline void ?{}( ping & this ) { ((actor &)this){}; }
    12 
    13 struct pong {
    14     inline actor;
    15 };
    16 static inline void ?{}( pong & this ) { ((actor &)this){}; }
     8struct ping { inline actor; };
     9struct pong { inline actor; };
    1710
    1811struct p_msg {
     
    3225    Allocation retval = Nodelete;
    3326    if ( msg.count == times ) retval = Finished;
    34     *po | msg;
     27    *po << msg;
    3528    return retval;
    3629}
     
    4235    Allocation retval = Nodelete;
    4336    if ( msg.count == times ) retval = Finished;
    44     *pi | msg;
     37    *pi << msg;
    4538    return retval;
    4639}
     
    6053    pi = &pi_actor;
    6154    p_msg m;
    62     pi_actor | m;
     55    pi_actor << m;
    6356    stop_actor_system();
    6457
  • tests/concurrent/actors/static.cfa

    r2ed94a9 rb110bcc  
    77int Times = 1000000;                                                            // default values
    88
    9 struct derived_actor {
    10     inline actor;
    11 };
    12 void ?{}( derived_actor & this ) { ((actor &)this){}; }
    13 
     9struct derived_actor { inline actor; };
    1410struct derived_msg {
    1511    inline message;
     
    2319void ?{}( derived_msg & this ) { ((derived_msg &)this){ 0 }; }
    2420
    25 
    2621Allocation receive( derived_actor & receiver, derived_msg & msg ) {
    2722    if ( msg.cnt >= Times ) {
     
    3025    }
    3126    msg.cnt++;
    32     receiver | msg;
     27    receiver << msg;
    3328    return Nodelete;
    3429}
     
    6055    derived_actor actor;
    6156
    62     actor | msg;
     57    actor << msg;
    6358
    6459    printf("stopping\n");
  • tests/concurrent/actors/types.cfa

    r2ed94a9 rb110bcc  
    1818    int num;
    1919};
    20 static inline void ?{}( d_msg & this ) { ((message &)this){}; }
    2120
    2221// this isn't a valid receive routine since int is not a message type
     
    3635    inline actor;
    3736};
    38 static inline void ?{}( derived_actor2 & this ) { ((actor &)this){}; }
    3937
    4038Allocation receive( derived_actor2 & receiver, d_msg & msg ) {
     
    4341}
    4442
    45 struct derived_actor3 {
    46     inline actor;
    47 };
    48 static inline void ?{}( derived_actor3 & this ) { ((actor &)this){}; }
    49 
     43struct derived_actor3 { inline actor; };
     44struct derived_actor4 { inline derived_actor3; };
    5045struct d_msg2 {
    5146    inline message;
    5247    int num;
    5348};
    54 static inline void ?{}( d_msg2 & this ) { ((message &)this){}; }
    5549
    5650Allocation receive( derived_actor3 & receiver, d_msg & msg ) {
     
    7872    b.num = 1;
    7973    c.num = 2;
    80     a | b | c;
     74    a << b << c;
    8175    stop_actor_system();
    8276
     
    8680    d_msg d_ac2_msg;
    8781    d_ac2_msg.num = 3;
    88     d_ac2_0 | d_ac2_msg;
    89     d_ac2_1 | d_ac2_msg;
     82    d_ac2_0 << d_ac2_msg;
     83    d_ac2_1 << d_ac2_msg;
    9084    stop_actor_system();
    9185
     
    9993        d_msg d_ac23_msg;
    10094        d_ac23_msg.num = 4;
    101         d_ac3_0 | d_ac23_msg;
    102         d_ac2_2 | d_ac23_msg;
     95        d_ac3_0 << d_ac23_msg;
     96        d_ac2_2 << d_ac23_msg;
    10397        stop_actor_system();
    10498    } // RAII to clean up executor
     
    113107        b1.num = -1;
    114108        c2.num = 5;
    115         a3 | b1 | c2;
     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;
    116123        stop_actor_system();
    117124    } // RAII to clean up executor
  • tests/concurrent/channels/parallel_harness.hfa

    r2ed94a9 rb110bcc  
    100100
    101101int test( size_t Processors, size_t Channels, size_t Producers, size_t Consumers, size_t ChannelSize ) {
    102     size_t Clusters = 1;
     102    size_t Clusters = Processors;
    103103    // create a cluster
    104104    cluster clus[Clusters];
     
    108108    }
    109109
    110     channels = anew( Channels );
     110    channels = aalloc( 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_waiting_consumers( channels[i] ) ){
     141            if ( has_waiters( channels[i] ) ){
    142142                #ifdef BIG
    143143                bigObject b{0};
     
    150150       
    151151    }
    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     // }
     152
    167153    sout | "cons";
    168154    for ( i; Consumers * Channels ) {
  • tests/concurrent/pthread/.expect/bounded_buffer.x64.txt

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

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

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

    r2ed94a9 rb110bcc  
    1 //----------------------------------------------------------------------------------------
    2 //----------------------------------------------------------------------------------------
     1// 
     2// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    4 //              DEPRECATED TEST
    5 //              DIFFERS BETWEEN DEBUG AND RELEASE
    6 //
    7 //----------------------------------------------------------------------------------------
    8 //----------------------------------------------------------------------------------------
     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//
    915
    1016#include <monitor.hfa>
     
    1218monitor M {};
    1319
    14 M a;
    15 
    16 void f1( M & mutex a );
    17 void f2( M & mutex a );
    18 void f2( M & mutex a, M & mutex b );
    19 void f3( M & mutex a );
    20 void f3( M & mutex a, M & mutex b );
    21 void f3( M & mutex a, M & mutex b, M & mutex c );
    22 
    23 void 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         }
     20void notcalled( M & mutex m1, M & mutex m2 ) {
     21        abort();
     22}
     23void or( M & mutex m ) {
     24        abort();
     25}
     26void timeout( M & mutex m ) {
     27        abort();
     28}
     29
     30void 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 );
    5098        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         }
     99        }
     100
     101        when( true ) waitfor( notcalled : m, m );
    72102        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         }
    100 }
    101 
    102 int main() {}
     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
     254int 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: //
  • tests/declarationSpecifier.cfa

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

    r2ed94a9 rb110bcc  
    1 errors/declaration.cfa:16:1 error: duplicate static in declaration of x1: static const volatile short int
     1errors/declaration.cfa:16:1 error: duplicate static storage class(es) in declaration of x1: static const volatile short int
    22
    3 errors/declaration.cfa:17:1 error: conflicting extern & static in declaration of x2: extern const volatile short int
     3errors/declaration.cfa:17:1 error: conflicting extern & static storage classes in declaration of x2: extern const volatile short int
    44
    5 errors/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
     5errors/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
    66
    7 errors/declaration.cfa:19:1 error: duplicate static in declaration of x4: static const volatile instance of const volatile struct __anonymous0
     7errors/declaration.cfa:19:1 error: duplicate static storage class(es) 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, duplicate static, duplicate volatile in declaration of x5: static const volatile instance of const volatile struct __anonymous1
     13errors/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
    1414  with members
    1515    i: int
     
    1717
    1818
    19 errors/declaration.cfa:22:1 error: duplicate static in declaration of x6: static const volatile Int
     19errors/declaration.cfa:22:1 error: duplicate static storage class(es) in declaration of x6: static const volatile Int
    2020
    21 errors/declaration.cfa:24:1 error: duplicate const in declaration of f01: static inline function
     21errors/declaration.cfa:24:1 error: duplicate const qualifier(s) 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 in declaration of f02: static inline function
     26errors/declaration.cfa:25:1 error: duplicate volatile qualifier(s) 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 in declaration of f03: static inline function
     31errors/declaration.cfa:26:1 error: duplicate const qualifier(s) 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 in declaration of f04: static inline function
     36errors/declaration.cfa:27:1 error: duplicate volatile qualifier(s) 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 in declaration of f05: static inline function
     41errors/declaration.cfa:28:1 error: duplicate const qualifier(s) 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 in declaration of f06: static inline function
     46errors/declaration.cfa:29:1 error: duplicate volatile qualifier(s) 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 in declaration of f07: static inline function
     51errors/declaration.cfa:30:1 error: duplicate const qualifier(s) 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, duplicate volatile in declaration of f08: static inline function
     56errors/declaration.cfa:31:1 error: duplicate const volatile qualifier(s) 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, duplicate volatile in declaration of f09: static inline function
     61errors/declaration.cfa:33:1 error: duplicate const volatile qualifier(s) 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, duplicate _Atomic, duplicate _Atomic, duplicate const, duplicate restrict, duplicate volatile in declaration of f09: static inline function
     66errors/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
    6767  with no parameters
    6868  returning const restrict volatile _Atomic int
  • tests/forall.cfa

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

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

    r2ed94a9 rb110bcc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun May 22 08:27:20 2022
    13 // Update Count     : 779
     12// Last Modified On : Wed Feb 22 10:16:58 2023
     13// Update Count     : 811
    1414//
    1515
     
    7272#include <gshadow.h>
    7373#include <iconv.h>
    74 #include <ifaddrs.h>
     74//#include <ifaddrs.h>                                                                  // causes warning messages that break the build
    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( int argc, char const * argv[] ) {
     172int main() {
    173173    #pragma GCC warning "Compiled"                                                      // force non-empty .expect file, NO TABS!!!
    174174}
  • tests/io/comp_basic.cfa

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

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

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

    r2ed94a9 rb110bcc  
    33name_but_a_typedefed_t a_typedefed_global;
    44
    5 struct {
    6         int some_int;
    7         int some_other_int;
    8 } a_global_with_no_type;
     5// Must be extern C to prevent name mangling.
     6extern "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}
  • tests/linking/mangling/main.cfa

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

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

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

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

    r2ed94a9 rb110bcc  
    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')
    116117        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180)
    117118        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)
     
    172173        test.prepare()
    173174
     175        # extra flags for cfa to pass through make.
     176        cfa_flags = 'CFAFLAGS=--invariant' if settings.invariant else None
     177
    174178        # ----------
    175179        # MAKE
     
    177181        # build, skipping to next test on error
    178182        with Timed() as comp_dur:
    179                 make_ret, _, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
     183                make_ret, _, _ = make(test.target(), flags=cfa_flags, output_file=subprocess.DEVNULL, error=out_file, error_file=err_file)
    180184
    181185        # ----------
Note: See TracChangeset for help on using the changeset viewer.