Changeset b110bcc
- Timestamp:
- Apr 21, 2023, 5:36:12 PM (2 years ago)
- 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. - Files:
-
- 227 added
- 5 deleted
- 179 edited
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/Promote
r2ed94a9 rb110bcc 36 36 dir (BuildDir) { 37 37 sh 'rm -rf *' 38 sshagent (credentials: ['git hub_key_jun1']) {38 sshagent (credentials: ['git_key_mar27']) { 39 39 sh "git clone --bare ${RemoteRepo} repo" 40 40 } … … 69 69 sh "git status" 70 70 sh "git diff-index --quiet HEAD || git commit -m 'Push from build machine: ${name}'" 71 sshagent (credentials: ['git hub_key_jun1']) {71 sshagent (credentials: ['git_key_mar27']) { 72 72 sh "git push origin master" 73 73 } -
doc/LaTeXmacros/common.sty
r2ed94a9 rb110bcc 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sat Apr 2 17:35:23 202214 %% Update Count : 5 7013 %% Last Modified On : Tue Apr 4 12:03:19 2023 14 %% Update Count : 585 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 30 30 \setlist[itemize,1]{label=\textbullet}% local 31 31 %\renewcommand{\labelitemi}{{\raisebox{0.25ex}{\footnotesize$\bullet$}}} 32 \setlist[enumerate]{ listparindent=\parindent}% global32 \setlist[enumerate]{topsep=0.5ex,parsep=0.25ex,itemsep=0.25ex,listparindent=\parindent}% global 33 33 \setlist[enumerate,2]{leftmargin=\parindent,labelsep=*,align=parleft,label=\alph*.}% local 34 34 \setlist[description]{topsep=0.5ex,itemsep=0pt,listparindent=\parindent,leftmargin=\parindent,labelsep=1.5ex} … … 49 49 \newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace} % C++17 symbolic name 50 50 \newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace} % C++20 symbolic name 51 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\ Large$^\sharp$}\xspace} % C# symbolic name51 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name 52 52 53 53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 54 54 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} 56 57 \usepackage{relsize} % must be after change to small or selects old size 57 58 \usepackage{rotating} … … 195 196 \newcommand{\viz}{\VIZ\CheckPeriod} 196 197 198 \newcommand{\VS}{\abbrevFont{vs}} 199 \newcommand{\vs}{\VS\CheckPeriod} 200 197 201 \newenvironment{cquote}{% 198 202 \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}% … … 244 248 \renewcommand{\reftextpagerange}[2]{\unskip, pp.~\pageref{#1}--\pageref{#2}} 245 249 \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}} 246 251 \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}} 247 253 248 254 \let\Oldthebibliography\thebibliography … … 260 266 \newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}} 261 267 \newcommand{\LstStringStyle}[1]{{\lst@basicstyle{\lst@stringstyle{#1}}}} 268 \newcommand{\LstNumberStyle}[1]{{\lst@basicstyle{\lst@numberstyle{#1}}}} 262 269 263 270 \newlength{\gcolumnposn} % temporary hack because lstlisting does not handle tabs correctly … … 280 287 columns=fullflexible, 281 288 basicstyle=\linespread{0.9}\sf, % reduce line spacing and use sanserif font 282 stringstyle=\ tt,% use typewriter font289 stringstyle=\small\tt, % use typewriter font 283 290 tabsize=5, % N space tabbing 284 291 xleftmargin=\parindentlnth, % indent code to paragraph indentation -
doc/LaTeXmacros/common.tex
r2ed94a9 rb110bcc 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Tue Apr 26 16:02:48 202214 %% Update Count : 5 5813 %% Last Modified On : Tue Apr 4 12:03:18 2023 14 %% Update Count : 567 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 49 49 \newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace} % C++17 symbolic name 50 50 \newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace} % C++20 symbolic name 51 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\ Large$^\sharp$}\xspace} % C# symbolic name51 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name 52 52 53 53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 54 54 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} 56 57 \usepackage{relsize} % must be after change to small or selects old size 57 58 \usepackage{rotating} … … 196 197 \newcommand{\viz}{\VIZ\CheckPeriod} 197 198 199 \newcommand{\VS}{\abbrevFont{vs}} 200 \newcommand{\vs}{\VS\CheckPeriod} 198 201 \makeatother 199 202 … … 266 269 \newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}} 267 270 \newcommand{\LstStringStyle}[1]{{\lst@basicstyle{\lst@stringstyle{#1}}}} 271 \newcommand{\LstNumberStyle}[1]{{\lst@basicstyle{\lst@numberstyle{#1}}}} 268 272 269 273 \newlength{\gcolumnposn} % temporary hack because lstlisting does not handle tabs correctly … … 287 291 columns=fullflexible, 288 292 basicstyle=\linespread{0.9}\sf, % reduce line spacing and use sanserif font 289 stringstyle=\ tt,% use typewriter font293 stringstyle=\small\tt, % use typewriter font 290 294 tabsize=5, % N space tabbing 291 295 xleftmargin=\parindentlnth, % indent code to paragraph indentation -
doc/bibliography/pl.bib
r2ed94a9 rb110bcc 147 147 author = {Zhang, Yizhou and Salvaneschi, Guido and Beightol, Quinn and Liskov, Barbara and Myers, Andrew C.}, 148 148 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}, 150 150 series = {PLDI'16}, 151 151 year = {2016}, … … 196 196 }, 197 197 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, 198 208 } 199 209 … … 245 255 } 246 256 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 247 291 @article{dim:ada, 248 292 keywords = {Dimensional Analysis, Ada}, … … 256 300 number = 2, 257 301 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}, 258 317 } 259 318 … … 377 436 year = 2016, 378 437 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, 379 447 } 380 448 … … 548 616 } 549 617 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 550 644 @article{Sinha00, 551 645 author = {Saurabh Sinha and Mary Jean Harrold}, … … 562 656 author = {Martin P. Robillard and Gail C. Murphy}, 563 657 title = {Analyzing Exception Flow in {J}ava Programs}, 564 booktitle= {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly658 organization= {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly 565 659 with the 7th ACM SIGSOFT International Symposium on Foundations of Software Engineering}, 566 660 year = 1999, … … 604 698 author = {Henry Qin and Qian Li and Jacqueline Speiser and Peter Kraft and John Ousterhout}, 605 699 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)}, 607 701 year = {2018}, 608 702 address = {Carlsbad, CA}, … … 661 755 author = {Jaewoong Chung and Luke Yen and Stephan Diestelhorst and Martin Pohlack and Michael Hohmuth and David Christie and Dan Grossman}, 662 756 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}, 664 758 series = {MICRO '43}, 665 759 year = 2010, … … 682 776 } 683 777 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 684 787 @inproceedings{Krischer08, 685 788 keywords = {exception handling, asynchronous, blocked tasks}, … … 687 790 author = {Roy Krischer and Peter A. Buhr}, 688 791 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)}, 690 793 optorganization= {16th International Symposium on the Foundations of Software Engineering (FSE 16)}, 691 794 address = {Atlanta, U.S.A}, … … 696 799 697 800 @article{Joung00, 801 keywords = {group mutual exclusion, congenial talking philosophers, resource allocation, shared-memory algorithms}, 698 802 author = {Joung, Yuh-Jzer}, 699 803 title = {Asynchronous group mutual exclusion}, … … 759 863 publisher = {ACM}, 760 864 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, 761 874 } 762 875 … … 916 1029 } 917 1030 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 918 1044 % C 919 1045 … … 988 1114 year = 2015, 989 1115 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}, 990 1130 } 991 1131 … … 1172 1312 @techreport{Prokopec11, 1173 1313 keywords = {ctrie, concurrent map}, 1174 contributer 1314 contributer = {a3moss@uwaterloo.ca}, 1175 1315 title = {Cache-aware lock-free concurrent hash tries}, 1176 1316 author = {Prokopec, Aleksandar and Bagwell, Phil and Odersky, Martin}, … … 1496 1636 author = {Emery D. Berger and Benjamin G. Zorn and Kathryn S. McKinley}, 1497 1637 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}, 1499 1639 pages = {114-124}, 1500 1640 year = 2001, … … 1996 2136 address = {Eindhoven, Neth.}, 1997 2137 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}}, 1999 2140 } 2000 2141 … … 2003 2144 author = {Adya, Atul and Howell, Jon and Theimer, Marvin and Bolosky, William J. and Douceur, John R.}, 2004 2145 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.}, 2006 2147 series = {ATEC '02}, 2007 2148 year = {2002}, … … 2111 2252 year = 2016, 2112 2253 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}, 2113 2265 } 2114 2266 … … 2370 2522 editor = {R. E. A. Mason}, 2371 2523 organization= {IFIP}, 2372 publisher 2373 summary 2524 publisher = {North-Holland}, 2525 summary = { 2374 2526 Packages group related declarations or subprograms, and encapsulate 2375 2527 data types. Separate interfaces and bodies promotes information … … 2598 2750 address = {Waterview Corporate Center, 20 Waterview Boulevard, Parsippany, NJ 07054}, 2599 2751 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}, 2600 2767 } 2601 2768 … … 2631 2798 year = 2003, 2632 2799 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}, 2633 2822 } 2634 2823 … … 2734 2923 } 2735 2924 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 2736 2938 @techreport{Habermann80, 2737 2939 keywords = {Ada, threads}, … … 2808 3010 title = {Encapsulation and Inheritance in Object-Oriented Programming Languages}, 2809 3011 journal = sigplan, 2810 volume = {21}, number = {11}, 3012 volume = {21}, 3013 number = {11}, 2811 3014 pages = {38-45}, 2812 month = nov, year = 1986, 3015 month = nov, 3016 year = 1986, 2813 3017 comment = { 2814 3018 Client, child interfaces should be distinct. Child interface … … 2866 3070 } 2867 3071 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 2868 3085 @manual{EPT, 2869 3086 keywords = {concurrency, light-weight threads}, … … 2903 3120 publisher = {North Oxford Academic}, 2904 3121 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}, 2905 3132 } 2906 3133 … … 3614 3841 author = {Robert Griesemer and Rob Pike and Ken Thompson}, 3615 3842 title = {{Go} Programming Language}, 3843 address = {Mountain View, CA, USA}, 3616 3844 organization= {Google}, 3617 3845 year = 2009, … … 3725 3953 @article{Michael04a, 3726 3954 keywords = {Lock-free, synchronization, concurrent programming, memory management, multiprogramming, dynamic data structures}, 3955 contributer = {pabuhr@plg}, 3727 3956 author = {Maged M. Michael}, 3728 3957 title = {Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects}, … … 3735 3964 publisher = {IEEE Press}, 3736 3965 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}, 3737 3980 } 3738 3981 … … 3917 4160 year = {1994}, 3918 4161 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}, 3919 4174 } 3920 4175 … … 4695 4950 contributer = {pabuhr@plg}, 4696 4951 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, 4700 4956 } 4701 4957 … … 5277 5533 Programming Language}, 5278 5534 year = 1980, 5279 month = dec, pages = {139-145}, 5535 month = dec, 5536 pages = {139-145}, 5280 5537 note = {SIGPLAN Notices, v. 15, n. 11}, 5281 5538 abstract = { … … 5398 5655 year = 2005, 5399 5656 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}, 5400 5669 publisher = {ACM}, 5401 5670 address = {New York, NY, USA}, … … 5646 5915 } 5647 5916 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 5648 5926 @inproceedings{Krebbers14, 5649 5927 keywords = {c formalization}, … … 5883 6161 } 5884 6162 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 5885 6174 @incollection{Stroustrup96, 5886 6175 keywords = {concurrency, C++}, … … 5917 6206 journal = ieeese, 5918 6207 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}, 5920 6212 abstract = { 5921 6213 Parameterized programming is a powerful technique for the reliable … … 5949 6241 booktitle = {USENIX {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Conference}, 5950 6242 organization= {USENIX Association}, 5951 year = 1988, pages = {1-18} 6243 year = 1988, 6244 pages = {1-18}, 5952 6245 } 5953 6246 … … 6037 6330 } 6038 6331 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 6039 6357 @article{Anderson90, 6040 6358 keywords = {spin locks, back off, performance}, … … 6048 6366 number = 1, 6049 6367 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}, 6050 6382 } 6051 6383 … … 6760 7092 } 6761 7093 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}, 6794 7105 } 6795 7106 … … 6927 7238 journal = sigplan, 6928 7239 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}, 6930 7244 abstract = { 6931 7245 {\tt lcc} is a new retargetable compiler for ANSI C. Versions for … … 7017 7331 publisher = {ACM}, 7018 7332 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}, 7020 7334 pages = {67-80}, 7021 7335 numpages = {14}, … … 7049 7363 } 7050 7364 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 7051 7378 @article{Anderson92, 7052 7379 keywords = {light-weight tasks}, … … 7062 7389 } 7063 7390 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 7064 7432 @manual{SELF, 7065 7433 keywords = {programming language, obect-oriented, polymorphism}, … … 7083 7451 publisher = {Springer}, 7084 7452 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, 7085 7462 } 7086 7463 … … 7150 7527 publisher = {Morgan \& Claypool}, 7151 7528 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} 7152 7538 } 7153 7539 … … 7833 8219 } 7834 8220 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 7835 8232 @article{Boehm05, 7836 8233 keywords = {concurrency, C++}, … … 8060 8457 } 8061 8458 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 8062 8468 @article{concatenation, 8063 8469 keywords = {record concatenation, isa}, … … 8124 8530 author = {Paul R. Wilson}, 8125 8531 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}, 8127 8533 location = {St. Malo, France}, 8128 8534 publisher = {Springer}, … … 8137 8543 author = {Carl Hewitt and Peter Bishop and Richard Steiger}, 8138 8544 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}, 8140 8546 address = {Standford, California, U.S.A.}, 8141 8547 pages = {235-245}, 8548 location = {Stanford, USA}, 8549 series = {IJCAI'73}, 8142 8550 month = aug, 8143 8551 year = 1973, … … 8171 8579 @article{Karsten20, 8172 8580 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}, 8174 8582 year = {2020}, 8175 8583 issue_date = {March 2020}, … … 8196 8604 } 8197 8605 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 8198 8618 @article{delegation, 8199 8619 keywords = {delegation, inheritance, actors}, … … 8345 8765 year = 2003, 8346 8766 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}, 8347 8794 } 8348 8795 -
doc/theses/mike_brooks_MMath/Makefile
r2ed94a9 rb110bcc 8 8 PicSRC = ${notdir ${wildcard ${Pictures}/*.png}} 9 9 DemoSRC = ${notdir ${wildcard ${Programs}/*-demo.cfa}} 10 PgmSRC = ${notdir ${wildcard ${Programs}/*.cfa}} 10 PgmSRC = ${notdir ${wildcard ${Programs}/*}} 11 RunPgmSRC = ${notdir ${wildcard ${Programs}/*.run.*}} 11 12 BibSRC = ${wildcard *.bib} 12 13 … … 14 15 BibLIB = .:../../bibliography # common citation repository 15 16 16 MAKEFLAGS = --no-print-directory # --silent17 #MAKEFLAGS = --no-print-directory # --silent 17 18 VPATH = ${Build} ${Pictures} ${Programs} # extra search path for file names used in document 18 19 … … 20 21 BASE = ${basename ${DOCUMENT}} # remove suffix 21 22 23 DemoTex = ${DemoSRC:%.cfa=${Build}/%.tex} 24 RunPgmExe = ${addprefix ${Build}/,${basename ${basename ${RunPgmSRC}}}} 25 RunPgmOut = ${RunPgmExe:%=%.out} 26 22 27 # Commands 23 28 24 29 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && pdflatex -halt-on-error -output-directory=${Build} 25 30 BibTeX = BIBINPUTS=${BibLIB} && export BIBINPUTS && bibtex 26 CFA = cfa 31 CFA = cfa -O0 -g 32 CC = gcc -O0 -g 33 CXX = g++-11 --std=c++20 -O0 -g 27 34 28 35 # Rules and Recipes 29 36 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 31 39 .ONESHELL : 32 40 33 all : ${DOCUMENT} 41 all : fragments_ran ${DOCUMENT} 42 43 fragments_ran : $(RunPgmOut) 34 44 35 45 clean : … … 38 48 # File Dependencies 39 49 40 %.pdf : ${TeXSRC} ${Demo SRC:%.cfa=%.tex} ${PicSRC} ${PgmSRC} ${BibSRC} Makefile | ${Build}50 %.pdf : ${TeXSRC} ${DemoTex} ${PicSRC} ${PgmSRC} ${BibSRC} Makefile | ${Build} 41 51 ${LaTeX} ${BASE} 42 52 ${BibTeX} ${Build}/${BASE} … … 52 62 53 63 %-demo.tex: %-demo | ${Build} 54 $ {Build}/$< > ${Build}/$@64 $< > $@ 55 65 56 %-demo: %-demo.cfa 57 ${CFA} $< -o $ {Build}/$@66 ${Build}/%-demo: ${Programs}/%-demo.cfa | ${Build} 67 ${CFA} $< -o $@ 58 68 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 65 65 bibsource = {dblp computer science bibliography, https://dblp.org} 66 66 } 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 60 60 % For hyperlinked PDF, suitable for viewing on a computer, use this: 61 61 \documentclass[letterpaper,12pt,titlepage,oneside,final]{book} 62 \usepackage{times} 62 63 \usepackage[T1]{fontenc} % Latin-1 => 256-bit characters, => | not dash, <> not Spanish question marks 63 64 … … 87 88 \usepackage{comment} % Removes large sections of the document. 88 89 \usepackage{tabularx} 89 \usepackage{subfigure} 90 \usepackage[labelformat=simple,aboveskip=0pt,farskip=0pt,font=normalsize]{subfig} 91 \renewcommand\thesubfigure{(\alph{subfigure})} 90 92 91 93 \usepackage{algorithm} … … 115 117 citecolor=blue, % color of links to bibliography 116 118 filecolor=magenta, % color of file links 117 urlcolor=blue % color of external links 119 urlcolor=blue, % color of external links 120 breaklinks=true 118 121 } 119 122 \ifthenelse{\boolean{PrintVersion}}{ % for improved print quality, change some hyperref options … … 129 132 % although it's supposed to be in both the TeX Live and MikTeX distributions. There are also documentation and 130 133 % installation instructions there. 134 135 % Customizing tabularx 136 \newcolumntype{Y}{>{\centering\arraybackslash}X} 131 137 132 138 % Setting up the page margins... … … 175 181 \CFAStyle % CFA code-style 176 182 \lstset{language=CFA} % default language 177 \lstset{basicstyle=\linespread{0.9}\ tt} % CFA typewriter font183 \lstset{basicstyle=\linespread{0.9}\sf} % CFA typewriter font 178 184 \lstset{inputpath={programs}} 179 185 \newcommand{\PAB}[1]{{\color{red}PAB: #1}} 186 187 \newcommand{\uCpp}{$\mu$\CC} 180 188 181 189 %====================================================================== … … 201 209 %---------------------------------------------------------------------- 202 210 \begin{sloppypar} 203 204 211 \input{intro} 205 212 \input{background} 213 \input{list} 206 214 \input{array} 207 215 \input{string} -
driver/cfa.cc
r2ed94a9 rb110bcc 10 10 // Created On : Tue Aug 20 13:44:49 2002 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jul 14 21:55:12 202113 // Update Count : 4 6712 // Last Modified On : Mon Apr 10 21:16:00 2023 13 // Update Count : 476 14 14 // 15 15 … … 44 44 static int flags = 0; 45 45 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. 46 50 if ( putenv( (char *)( *new string( string( __CFA_FLAGPREFIX__ + to_string( flags++ ) + "__=" ) + arg ) ).c_str() ) ) { 47 51 cerr << argv[0] << " error, cannot set environment variable." << endl; … … 198 202 } // if 199 203 } else if ( arg == "-CFA" ) { 200 CFA_flag = true; // strip the-CFA flag204 CFA_flag = true; // strip -CFA flag 201 205 link = false; 202 206 args[nargs++] = "-fsyntax-only"; // stop after stage 2 203 207 } else if ( arg == "-debug" ) { 204 debug = true; // strip thedebug flag208 debug = true; // strip debug flag 205 209 } else if ( arg == "-nodebug" ) { 206 debug = false; // strip thenodebug flag210 debug = false; // strip nodebug flag 207 211 } else if ( arg == "-quiet" ) { 208 quiet = true; // strip thequiet flag212 quiet = true; // strip quiet flag 209 213 } 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 ); 211 219 } else if ( arg == "-no-include-stdhdr" ) { 212 noincstd_flag = true; // strip theno-include-stdhdr flag220 noincstd_flag = true; // strip no-include-stdhdr flag 213 221 } else if ( arg == "-nolib" ) { 214 nolib = true; // strip thenolib flag222 nolib = true; // strip nolib flag 215 223 } else if ( arg == "-help" ) { 216 help = true; // strip thehelp flag224 help = true; // strip help flag 217 225 } else if ( arg == "-nohelp" ) { 218 help = false; // strip thenohelp flag226 help = false; // strip nohelp flag 219 227 } else if ( arg == "-cfalib") { 220 228 compiling_libs = true; … … 274 282 } // if 275 283 } else if ( prefix( arg, "-B" ) ) { 276 bprefix = arg.substr(2); // strip the-B flag284 bprefix = arg.substr(2); // strip -B flag 277 285 } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) { 278 286 args[nargs++] = argv[i]; // pass flag along … … 444 452 445 453 args[nargs++] = "-fexceptions"; // add exception flags (unconditionally) 454 args[nargs++] = "-D_GNU_SOURCE"; // force gnu libraries 446 455 447 456 // add flags based on the type of compile -
libcfa/src/Makefile.am
r2ed94a9 rb110bcc 48 48 math.hfa \ 49 49 time_t.hfa \ 50 virtual_dtor.hfa \ 50 51 bits/algorithm.hfa \ 51 52 bits/align.hfa \ -
libcfa/src/algorithms/range_iterator.hfa
r2ed94a9 rb110bcc 9 9 // Author : Thierry Delisle 10 10 // 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 14 14 // 15 16 #pragma once 15 17 16 18 generator RangeIter { -
libcfa/src/bitmanip.hfa
r2ed94a9 rb110bcc 11 11 // Created On : Sat Mar 14 18:12:27 2020 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Sat Oct 8 08:28:15 202214 // Update Count : 14 213 // Last Modified On : Mon Jan 9 09:02:43 2023 14 // Update Count : 144 15 15 // 16 16 17 17 #pragma once 18 19 #include "bits/debug.hfa" // verify 18 20 19 21 // Reference: Bit Twiddling Hacks: http://graphics.stanford.edu/%7Eseander/bithacks.html#CountBitsSetNaive -
libcfa/src/bits/random.hfa
r2ed94a9 rb110bcc 10 10 // Created On : Fri Jan 14 07:18:11 2022 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Dec 22 20:54:22 202213 // Update Count : 1 7812 // Last Modified On : Mon Mar 20 21:45:24 2023 13 // Update Count : 186 14 14 // 15 15 … … 28 28 #define XOSHIRO256PP 29 29 //#define KISS_64 30 // #define SPLITMIX_64 30 31 31 32 // 32-bit generators 32 33 //#define XORSHIFT_6_21_7 33 34 #define XOSHIRO128PP 35 // #define SPLITMIX_32 34 36 #else // 32-bit architecture 35 37 // 64-bit generators 36 38 //#define XORSHIFT_13_7_17 37 39 #define XOSHIRO256PP 40 // #define SPLITMIX_64 38 41 39 42 // 32-bit generators 40 43 //#define XORSHIFT_6_21_7 41 44 #define XOSHIRO128PP 45 // #define SPLITMIX_32 42 46 #endif // __x86_64__ 43 47 44 48 // 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.47 49 48 50 #ifdef XOSHIRO256PP 49 51 #define PRNG_NAME_64 xoshiro256pp 50 52 #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;53 typedef struct { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T; 52 54 #endif // XOSHIRO256PP 53 55 … … 55 57 #define PRNG_NAME_32 xoshiro128pp 56 58 #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;59 typedef struct { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T; 58 60 #endif // XOSHIRO128PP 59 61 … … 83 85 #endif // XORSHIFT_12_25_27 84 86 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 85 97 #ifdef KISS_64 86 98 #define PRNG_NAME_64 kiss_64 87 99 #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;100 typedef struct { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T; 89 101 #endif // KISS_^64 90 102 … … 92 104 #define PRNG_NAME_32 xorwow 93 105 #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;106 typedef struct { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T; 95 107 #endif // XOSHIRO128PP 96 108 … … 119 131 #ifdef __cforall // don't include in C code (invoke.h) 120 132 133 // https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64 134 // 135 // Splitmix64 is not recommended for demanding random number requirements, but is often used to calculate initial states 136 // for other more complex pseudo-random number generators (see https://prng.di.unimi.it). 137 // Also https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64. 138 static inline uint64_t splitmix64( uint64_t & state ) { 139 state += 0x9e3779b97f4a7c15; 140 uint64_t z = state; 141 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; 142 z = (z ^ (z >> 27)) * 0x94d049bb133111eb; 143 return z ^ (z >> 31); 144 } // splitmix64 145 146 static inline void splitmix64_set_seed( uint64_t & state , uint64_t seed ) { 147 state = seed; 148 splitmix64( state ); // prime 149 } // splitmix64_set_seed 150 151 // https://github.com/bryc/code/blob/master/jshash/PRNGs.md#splitmix32 152 // 153 // Splitmix32 is not recommended for demanding random number requirements, but is often used to calculate initial states 154 // for other more complex pseudo-random number generators (see https://prng.di.unimi.it). 155 156 static inline uint32_t splitmix32( uint32_t & state ) { 157 state += 0x9e3779b9; 158 uint64_t z = state; 159 z = (z ^ (z >> 15)) * 0x85ebca6b; 160 z = (z ^ (z >> 13)) * 0xc2b2ae35; 161 return z ^ (z >> 16); 162 } // splitmix32 163 164 static inline void splitmix32_set_seed( uint32_t & state, uint64_t seed ) { 165 state = seed; 166 splitmix32( state ); // prime 167 } // splitmix32_set_seed 168 169 #ifdef __SIZEOF_INT128__ 170 //-------------------------------------------------- 171 static inline uint64_t lehmer64( __uint128_t & state ) { 172 __uint128_t ret = state; 173 state *= 0x_da94_2042_e4dd_58b5; 174 return ret >> 64; 175 } // lehmer64 176 177 static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) { 178 // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed. 179 state = splitmix64( seed ); // prime 180 } // lehmer64_set_seed 181 182 //-------------------------------------------------- 183 static inline uint64_t wyhash64( uint64_t & state ) { 184 uint64_t ret = state; 185 state += 0x_60be_e2be_e120_fc15; 186 __uint128_t tmp; 187 tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d; 188 uint64_t m1 = (tmp >> 64) ^ tmp; 189 tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9; 190 uint64_t m2 = (tmp >> 64) ^ tmp; 191 return m2; 192 } // wyhash64 193 194 static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) { 195 state = splitmix64( seed ); // prime 196 } // wyhash64_set_seed 197 #endif // __SIZEOF_INT128__ 198 121 199 // https://prng.di.unimi.it/xoshiro256starstar.c 122 200 // … … 130 208 131 209 #ifndef XOSHIRO256PP 132 typedef struct xoshiro256pp_t{ uint64_t s0, s1, s2, s3; } xoshiro256pp_t;210 typedef struct { uint64_t s0, s1, s2, s3; } xoshiro256pp_t; 133 211 #endif // ! XOSHIRO256PP 134 212 … … 151 229 152 230 static 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 }; 155 237 } // xoshiro256pp_set_seed 156 238 … … 165 247 166 248 #ifndef XOSHIRO128PP 167 typedef struct xoshiro128pp_t{ uint32_t s0, s1, s2, s3; } xoshiro128pp_t;249 typedef struct { uint32_t s0, s1, s2, s3; } xoshiro128pp_t; 168 250 #endif // ! XOSHIRO128PP 169 251 … … 186 268 187 269 static 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 }; 190 276 } // 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 } // lehmer64199 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 ); // prime204 } // lehmer64_set_seed205 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 } // wyhash64217 218 static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {219 state = seed;220 wyhash64( state ); // prime221 } // wyhash64_set_seed222 #endif // __SIZEOF_INT128__223 277 224 278 //-------------------------------------------------- … … 232 286 233 287 static 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 236 289 } // xorshift_13_7_17_set_seed 237 290 … … 250 303 251 304 static 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 254 306 } // xorshift_6_21_7_set_seed 255 307 … … 265 317 266 318 static 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 269 320 } // xorshift_12_25_27_set_seed 270 321 … … 272 323 // The state must be seeded with a nonzero value. 273 324 #ifndef KISS_64 274 typedef struct kiss_64_t{ uint64_t z, w, jsr, jcong; } kiss_64_t;325 typedef struct { uint64_t z, w, jsr, jcong; } kiss_64_t; 275 326 #endif // ! KISS_64 276 327 … … 287 338 288 339 static 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 291 341 } // kiss_64_set_seed 292 342 … … 294 344 // The state array must be initialized to non-zero in the first four words. 295 345 #ifndef XORWOW 296 typedef struct xorwow_t{ uint32_t a, b, c, d, counter; } xorwow_t;346 typedef struct { uint32_t a, b, c, d, counter; } xorwow_t; 297 347 #endif // ! XORWOW 298 348 … … 316 366 317 367 static 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 }; 320 374 } // xorwow_set_seed 321 375 … … 323 377 // Used in __tls_rand_fwd 324 378 #define M (1_l64u << 48_l64u) 325 #define A (25 214903917_l64u)326 #define AI (18 446708753438544741_l64u)379 #define A (25_214_903_917_l64u) 380 #define AI (18_446_708_753_438_544_741_l64u) 327 381 #define C (11_l64u) 328 382 #define D (16_l64u) -
libcfa/src/concurrency/actor.hfa
r2ed94a9 rb110bcc 3 3 #include <locks.hfa> 4 4 #include <limits.hfa> 5 #include <list.hfa>6 5 #include <kernel.hfa> 6 #include <iofwd.hfa> 7 #include <virtual_dtor.hfa> 7 8 8 9 #ifdef __CFA_DEBUG__ … … 20 21 // Define the default number of executor request-queues (mailboxes) written to by actors and serviced by the 21 22 // actor-executor threads. Must be greater than 0. 22 #define __DEFAULT_EXECUTOR_RQUEUES__ 223 #define __DEFAULT_EXECUTOR_RQUEUES__ 4 23 24 24 25 // Define if executor is created in a separate cluster 25 26 #define __DEFAULT_EXECUTOR_SEPCLUS__ false 26 27 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 29 38 30 39 // forward decls 31 40 struct actor; 32 41 struct message; 42 struct executor; 33 43 34 44 enum Allocation { Nodelete, Delete, Destroy, Finished }; // allocation status … … 40 50 __receive_fn fn; 41 51 bool stop; 42 inline dlink(request);43 52 }; 44 P9_EMBEDDED( request, dlink(request) )45 53 46 54 static inline void ?{}( request & this ) { this.stop = true; } // default ctor makes a sentinel … … 58 66 } 59 67 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) 61 70 struct copy_queue { 62 dlist( request ) list;63 #if ! __ALLOC64 71 request * buffer; 65 size_t count, buffer_size, index; 66 #endif 72 size_t count, buffer_size, index, utilized, last_size; 67 73 }; 68 74 static inline void ?{}( copy_queue & this ) {} 69 75 static inline void ?{}( copy_queue & this, size_t buf_size ) with(this) { 70 list{};71 #if ! __ALLOC72 76 buffer_size = buf_size; 73 77 buffer = aalloc( buffer_size ); 74 78 count = 0; 79 utilized = 0; 75 80 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 } 83 static inline void ^?{}( copy_queue & this ) with(this) { adelete(buffer); } 83 84 84 85 static 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++; 97 94 } 98 95 99 96 // 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 98 static inline request & remove( copy_queue & this ) with(this) { 104 99 if ( count > 0 ) { 105 100 count--; 106 should_delete = false;107 101 size_t old_idx = index; 108 102 index = count == 0 ? 0 : index + 1; 109 103 return buffer[old_idx]; 110 104 } 111 #endif112 should_delete = true;113 return try_pop_front( list ); 114 } 115 116 static inline bool isEmpty( copy_queue & this ) with(this) {117 #if ! __ALLOC118 return count == 0 && list`isEmpty;119 #else120 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 110 static inline void reclaim( copy_queue & this ) with(this) { 111 if ( utilized >= last_size || buffer_size <= 4 ) { utilized = 0; return; } 112 utilized = 0; 113 buffer_size--; 114 buffer = realloc( buffer, sizeof( request ) * buffer_size ); // try to reclaim some memory 115 } 116 117 static inline bool isEmpty( copy_queue & this ) with(this) { return count == 0; } 118 125 119 struct work_queue { 126 120 __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 130 128 }; // 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 ); } 129 static inline void ?{}( work_queue & this, size_t buf_size, unsigned int i ) with(this) { 130 owned_queue = alloc(); // allocated separately to avoid false sharing 131 (*owned_queue){ buf_size }; 132 c_queue = owned_queue; 133 being_processed = false; 134 #ifdef ACTOR_STATS 135 id = i; 136 missed = 0; 137 #endif 138 } 139 140 // clean up copy_queue owned by this work_queue 141 static inline void ^?{}( work_queue & this ) with(this) { delete( owned_queue ); } 138 142 139 143 static inline void insert( work_queue & this, request & elem ) with(this) { … … 145 149 static inline void transfer( work_queue & this, copy_queue ** transfer_to ) with(this) { 146 150 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 147 167 // swap copy queue ptrs 148 168 copy_queue * temp = *transfer_to; … … 152 172 } // transfer 153 173 174 // needed since some info needs to persist past worker lifetimes 175 struct worker_info { 176 volatile unsigned long long stamp; 177 #ifdef ACTOR_STATS 178 size_t stolen_from, try_steal, stolen, failed_swaps, msgs_stolen; 179 unsigned long long processed; 180 size_t gulps; 181 #endif 182 }; 183 static inline void ?{}( worker_info & this ) { 184 #ifdef ACTOR_STATS 185 this.stolen_from = 0; 186 this.try_steal = 0; // attempts to steal 187 this.stolen = 0; // successful steals 188 this.processed = 0; // requests processed 189 this.gulps = 0; // number of gulps 190 this.failed_swaps = 0; // steal swap failures 191 this.msgs_stolen = 0; // number of messages stolen 192 #endif 193 this.stamp = rdtscl(); 194 } 195 196 // #ifdef ACTOR_STATS 197 // unsigned int * stolen_arr; 198 // unsigned int * replaced_queue; 199 // #endif 154 200 thread worker { 155 copy_queue owned_queue; 156 work_queue * request_queues; 201 work_queue ** request_queues; 157 202 copy_queue * current_queue; 158 request & req;203 executor * executor_; 159 204 unsigned int start, range; 205 int id; 160 206 }; 161 207 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 210 size_t __total_tries = 0, __total_stolen = 0, __total_workers, __all_gulps = 0, 211 __total_failed_swaps = 0, __all_processed = 0, __num_actors_stats = 0, __all_msgs_stolen = 0; 212 #endif 213 static inline void ?{}( worker & this, cluster & clu, work_queue ** request_queues, copy_queue * current_queue, executor * executor_, 214 unsigned int start, unsigned int range, int id ) { 163 215 ((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 224 static bool no_steal = false; 174 225 struct executor { 175 226 cluster * cluster; // if workers execute on separate cluster 176 227 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 179 233 unsigned int nprocessors, nworkers, nrqueues; // number of processors/threads/request queues 180 234 bool seperate_clus; // use same or separate cluster for executor 181 235 }; // executor 182 236 237 // #ifdef ACTOR_STATS 238 // __spinlock_t out_lock; 239 // #endif 240 static inline void ^?{}( worker & mutex this ) with(this) { 241 #ifdef ACTOR_STATS 242 __atomic_add_fetch(&__all_gulps, executor_->w_infos[id].gulps,__ATOMIC_SEQ_CST); 243 __atomic_add_fetch(&__all_processed, executor_->w_infos[id].processed,__ATOMIC_SEQ_CST); 244 __atomic_add_fetch(&__all_msgs_stolen, executor_->w_infos[id].msgs_stolen,__ATOMIC_SEQ_CST); 245 __atomic_add_fetch(&__total_tries, executor_->w_infos[id].try_steal, __ATOMIC_SEQ_CST); 246 __atomic_add_fetch(&__total_stolen, executor_->w_infos[id].stolen, __ATOMIC_SEQ_CST); 247 __atomic_add_fetch(&__total_failed_swaps, executor_->w_infos[id].failed_swaps, __ATOMIC_SEQ_CST); 248 249 // per worker steal stats (uncomment alongside the lock above this routine to print) 250 // lock( out_lock __cfaabi_dbg_ctx2 ); 251 // printf("Worker id: %d, processed: %llu messages, attempted %lu, stole: %lu, stolen from: %lu\n", id, processed, try_steal, stolen, __atomic_add_fetch(&executor_->w_infos[id].stolen_from, 0, __ATOMIC_SEQ_CST) ); 252 // int count = 0; 253 // int count2 = 0; 254 // for ( i; range ) { 255 // if ( replaced_queue[start + i] > 0 ){ 256 // count++; 257 // // printf("%d: %u, ",i, replaced_queue[i]); 258 // } 259 // if (__atomic_add_fetch(&stolen_arr[start + i],0,__ATOMIC_SEQ_CST) > 0) 260 // count2++; 261 // } 262 // printf("swapped with: %d of %u indices\n", count, executor_->nrqueues / executor_->nworkers ); 263 // printf("%d of %u indices were stolen\n", count2, executor_->nrqueues / executor_->nworkers ); 264 // unlock( out_lock ); 265 #endif 266 } 267 183 268 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus, size_t buf_size ) with(this) { 184 269 if ( nrqueues < nworkers ) abort( "nrqueues needs to be >= nworkers\n" ); 185 __buffer_size = buf_size;186 270 this.nprocessors = nprocessors; 187 271 this.nworkers = nworkers; … … 189 273 this.seperate_clus = seperate_clus; 190 274 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 191 284 if ( seperate_clus ) { 192 285 cluster = alloc(); … … 195 288 196 289 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 } 199 295 200 296 processors = aalloc( nprocessors ); … … 202 298 (*(processors[i] = alloc())){ *cluster }; 203 299 204 workers = alloc( nworkers ); 300 local_queues = aalloc( nworkers ); 301 workers = aalloc( nworkers ); 302 w_infos = aalloc( nworkers ); 205 303 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 206 310 for ( unsigned int i = 0, start = 0, range; i < nworkers; i += 1, start += range ) { 207 311 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 }; 209 313 } // for 210 314 } 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}; }315 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus ) { this{ nprocessors, nworkers, nrqueues, seperate_clus, __DEFAULT_EXECUTOR_BUFSIZE__ }; } 212 316 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues ) { this{ nprocessors, nworkers, nrqueues, __DEFAULT_EXECUTOR_SEPCLUS__ }; } 213 317 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers ) { this{ nprocessors, nworkers, __DEFAULT_EXECUTOR_RQUEUES__ }; } … … 216 320 217 321 static 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 218 328 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 ); 221 332 insert( request_queues[step], sentinels[i] ); // force eventually termination 222 333 } // for 334 #endif 223 335 224 336 for ( i; nworkers ) … … 229 341 } // for 230 342 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 231 352 adelete( workers ); 353 adelete( w_infos ); 354 adelete( local_queues ); 232 355 adelete( request_queues ); 356 adelete( worker_req_queues ); 233 357 adelete( processors ); 234 358 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 235 371 } 236 372 237 373 // 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; 374 static size_t __next_ticket = 0; 375 376 static inline size_t __get_next_ticket( executor & this ) with(this) { 377 #ifdef __CFA_DEBUG__ 378 size_t temp = __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues; 379 380 // reserve MAX for dead actors 381 if ( unlikely( temp == MAX ) ) temp = __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues; 382 return temp; 383 #else 384 return __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_RELAXED) % nrqueues; 385 #endif 242 386 } // tickets 243 387 244 // C_TODO: update globals in this file to be static fields once theproject is done388 // TODO: update globals in this file to be static fields once the static fields project is done 245 389 static executor * __actor_executor_ = 0p; 246 static bool __actor_executor_passed = false; // was an executor passed to start_actor_system247 static unsigned long int __num_actors_;// number of actor objects in system390 static bool __actor_executor_passed = false; // was an executor passed to start_actor_system 391 static size_t __num_actors_ = 0; // number of actor objects in system 248 392 static struct thread$ * __actor_executor_thd = 0p; // used to wake executor after actors finish 249 393 struct 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; 252 397 }; 253 398 254 static inline void ?{}( actor & this ) {399 static inline void ?{}( actor & this ) with(this) { 255 400 // Once an actor is allocated it must be sent a message or the actor system cannot stop. Hence, its receive 256 401 // 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 } 263 410 264 411 static inline void check_actor( actor & this ) { … … 276 423 } 277 424 278 if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_ SEQ_CST) == 0 ) ) { // all actors have terminated425 if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_RELAXED ) == 0 ) ) { // all actors have terminated 279 426 unpark( __actor_executor_thd ); 280 427 } … … 284 431 struct message { 285 432 Allocation allocation_; // allocation action 433 inline virtual_dtor; 286 434 }; 287 435 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 ) {} 436 static inline void ?{}( message & this ) { 437 this.allocation_ = Nodelete; 438 } 439 static inline void ?{}( message & this, Allocation allocation ) { 440 memcpy( &this.allocation_, &allocation, sizeof(allocation) ); // optimization to elide ctor 441 verifyf( this.allocation_ != Finished, "The Finished Allocation status is not supported for message types.\n"); 442 } 443 static inline void ^?{}( message & this ) with(this) { 444 CFA_DEBUG( if ( allocation_ == Nodelete ) printf("A message at location %p was allocated but never sent.\n", &this); ) 445 } 291 446 292 447 static inline void check_message( message & this ) { 293 448 switch ( this.allocation_ ) { // analyze message status 294 case Nodelete: break;449 case Nodelete: CFA_DEBUG(this.allocation_ = Finished); break; 295 450 case Delete: delete( &this ); break; 296 451 case Destroy: ^?{}(this); break; … … 298 453 } // switch 299 454 } 455 static inline void set_allocation( message & this, Allocation state ) { 456 this.allocation_ = state; 457 } 300 458 301 459 static 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 ); 304 462 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 467 static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) { 468 work_queue * my_queue = request_queues[my_idx]; 469 work_queue * other_queue = request_queues[victim_idx]; 470 471 // if either queue is 0p then they are in the process of being stolen 472 if ( other_queue == 0p ) return 0p; 473 474 // try to set our queue ptr to be 0p. If it fails someone moved our queue so return false 475 if ( !__atomic_compare_exchange_n( &request_queues[my_idx], &my_queue, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) 476 return 0p; 477 478 // try to set other queue ptr to be our queue ptr. If it fails someone moved the other queue so fix up then return false 479 if ( !__atomic_compare_exchange_n( &request_queues[victim_idx], &other_queue, my_queue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) { 480 /* paranoid */ verify( request_queues[my_idx] == 0p ); 481 request_queues[my_idx] = my_queue; // reset my queue ptr back to appropriate val 482 return 0p; 483 } 484 485 // we have successfully swapped and since our queue is 0p no one will touch it so write back new queue ptr non atomically 486 request_queues[my_idx] = other_queue; // last write does not need to be atomic 487 return other_queue; 488 } 489 490 // once a worker to steal from has been chosen, choose queue to steal from 491 static inline void choose_queue( worker & this, unsigned int victim_id, unsigned int swap_idx ) with(this) { 492 // have to calculate victim start and range since victim may be deleted before us in shutdown 493 const unsigned int queues_per_worker = executor_->nrqueues / executor_->nworkers; 494 const unsigned int extras = executor_->nrqueues % executor_->nworkers; 495 unsigned int vic_start, vic_range; 496 if ( extras > victim_id ) { 497 vic_range = queues_per_worker + 1; 498 vic_start = vic_range * victim_id; 499 } else { 500 vic_start = extras + victim_id * queues_per_worker; 501 vic_range = queues_per_worker; 502 } 503 unsigned int start_idx = prng( vic_range ); 504 505 unsigned int tries = 0; 506 work_queue * curr_steal_queue; 507 508 for ( unsigned int i = start_idx; tries < vic_range; i = (i + 1) % vic_range ) { 509 tries++; 510 curr_steal_queue = request_queues[ i + vic_start ]; 511 // avoid empty queues and queues that are being operated on 512 if ( curr_steal_queue == 0p || curr_steal_queue->being_processed || isEmpty( *curr_steal_queue->c_queue ) ) 513 continue; 514 515 #ifdef ACTOR_STATS 516 curr_steal_queue = try_swap_queues( this, i + vic_start, swap_idx ); 517 if ( curr_steal_queue ) { 518 executor_->w_infos[id].msgs_stolen += curr_steal_queue->c_queue->count; 519 executor_->w_infos[id].stolen++; 520 // __atomic_add_fetch(&executor_->w_infos[victim_id].stolen_from, 1, __ATOMIC_RELAXED); 521 // replaced_queue[swap_idx]++; 522 // __atomic_add_fetch(&stolen_arr[ i + vic_start ], 1, __ATOMIC_RELAXED); 523 } else { 524 executor_->w_infos[id].failed_swaps++; 525 } 526 #else 527 curr_steal_queue = try_swap_queues( this, i + vic_start, swap_idx ); 528 #endif // ACTOR_STATS 529 530 return; 531 } 532 533 return; 534 } 535 536 // choose a worker to steal from 537 static inline void steal_work( worker & this, unsigned int swap_idx ) with(this) { 538 #if RAND 539 unsigned int victim = prng( executor_->nworkers ); 540 if ( victim == id ) victim = ( victim + 1 ) % executor_->nworkers; 541 choose_queue( this, victim, swap_idx ); 542 #elif SEARCH 543 unsigned long long min = MAX; // smaller timestamp means longer since service 544 int min_id = 0; // use ints not uints to avoid integer underflow without hacky math 545 int n_workers = executor_->nworkers; 546 unsigned long long curr_stamp; 547 int scount = 1; 548 for ( int i = (id + 1) % n_workers; scount < n_workers; i = (i + 1) % n_workers, scount++ ) { 549 curr_stamp = executor_->w_infos[i].stamp; 550 if ( curr_stamp < min ) { 551 min = curr_stamp; 552 min_id = i; 553 } 554 } 555 choose_queue( this, min_id, swap_idx ); 556 #endif 306 557 } 307 558 308 559 void 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 310 575 Exit: 311 576 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], ¤t_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, ¤t_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 314 609 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; 317 615 if ( req.stop ) break Exit; 318 616 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 ); 322 625 } // for 323 626 } … … 328 631 329 632 static inline void send( actor & this, request & req ) { 633 verifyf( this.ticket != (unsigned long int)MAX, "Attempted to send message to deleted/dead actor\n" ); 330 634 send( *__actor_executor_, req, this.ticket ); 331 635 } 332 636 637 static inline void __reset_stats() { 638 #ifdef ACTOR_STATS 639 __total_tries = 0; 640 __total_stolen = 0; 641 __all_gulps = 0; 642 __total_failed_swaps = 0; 643 __all_processed = 0; 644 __num_actors_stats = 0; 645 __all_msgs_stolen = 0; 646 #endif 647 } 648 333 649 static inline void start_actor_system( size_t num_thds ) { 650 __reset_stats(); 334 651 __actor_executor_thd = active_thread(); 335 652 __actor_executor_ = alloc(); … … 337 654 } 338 655 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 ); } 660 static inline void start_actor_system() { start_actor_system( 1 ); } 340 661 341 662 static inline void start_actor_system( executor & this ) { 663 __reset_stats(); 342 664 __actor_executor_thd = active_thread(); 343 665 __actor_executor_ = &this; … … 354 676 __actor_executor_passed = false; 355 677 } 678 679 // Default messages to send to any actor to change status 680 // assigned at creation to __base_msg_finished to avoid unused message warning 681 message __base_msg_finished @= { .allocation_ : Finished }; 682 struct __DeleteMsg { inline message; } DeleteMsg = __base_msg_finished; 683 struct __DestroyMsg { inline message; } DestroyMsg = __base_msg_finished; 684 struct __FinishedMsg { inline message; } FinishedMsg = __base_msg_finished; 685 686 Allocation receive( actor & this, __DeleteMsg & msg ) { return Delete; } 687 Allocation receive( actor & this, __DestroyMsg & msg ) { return Destroy; } 688 Allocation receive( actor & this, __FinishedMsg & msg ) { return Finished; } 689 -
libcfa/src/concurrency/channel.hfa
r2ed94a9 rb110bcc 1 #pragma once 2 1 3 #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 8 struct wait_link { 9 // used to put wait_link on a dl queue 10 inline dlink(wait_link); 11 12 // waiting thread 13 struct thread$ * t; 14 15 // shadow field 16 void * elem; 5 17 }; 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 ) {} 18 P9_EMBEDDED( wait_link, dlink(wait_link) ) 19 20 static inline void ?{}( wait_link & this, thread$ * t, void * elem ) { 21 this.t = t; 22 this.elem = elem; 23 } 24 25 // wake one thread from the list 26 static inline void wake_one( dlist( wait_link ) & queue ) { 27 wait_link & popped = try_pop_front( queue ); 28 unpark( popped.t ); 29 } 30 31 // returns true if woken due to shutdown 32 // blocks thread on list and releases passed lock 33 static inline bool block( dlist( wait_link ) & queue, void * elem_ptr, go_mutex & lock ) { 34 wait_link w{ active_thread(), elem_ptr }; 35 insert_last( queue, w ); 36 unlock( lock ); 37 park(); 38 return w.elem == 0p; 39 } 40 41 // void * used for some fields since exceptions don't work with parametric polymorphism currently 42 exception channel_closed { 43 // on failed insert elem is a ptr to the element attempting to be inserted 44 // on failed remove elem ptr is 0p 45 // on resumption of a failed insert this elem will be inserted 46 // so a user may modify it in the resumption handler 47 void * elem; 48 49 // pointer to chan that is closed 50 void * closed_chan; 51 }; 52 vtable(channel_closed) channel_closed_vt; 53 54 // #define CHAN_STATS // define this to get channel stats printed in dtor 16 55 17 56 forall( T ) { 18 struct channel { 19 size_t size; 20 size_t front, back, count;57 58 struct __attribute__((aligned(128))) channel { 59 size_t size, front, back, count; 21 60 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 24 67 }; 25 68 … … 27 70 size = _size; 28 71 front = back = count = 0; 29 buffer = a new( size );72 buffer = aalloc( size ); 30 73 prods{}; 31 74 cons{}; 32 75 mutex_lock{}; 76 closed = false; 77 #ifdef CHAN_STATS 78 blocks = 0; 79 operations = 0; 80 #endif 33 81 } 34 82 35 83 static inline void ?{}( channel(T) &c ){ ((channel(T) &)c){ 0 }; } 36 static inline void ^?{}( channel(T) &c ) with(c) { delete( buffer ); } 84 static inline void ^?{}( channel(T) &c ) with(c) { 85 #ifdef CHAN_STATS 86 printf("Channel %p Blocks: %lu, Operations: %lu, %.2f%% of ops blocked\n", &c, blocks, operations, ((double)blocks)/operations * 100); 87 #endif 88 verifyf( cons`isEmpty && prods`isEmpty, "Attempted to delete channel with waiting threads (Deadlock).\n" ); 89 delete( buffer ); 90 } 37 91 static inline size_t get_count( channel(T) & chan ) with(chan) { return count; } 38 92 static 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) { 93 static inline bool has_waiters( channel(T) & chan ) with(chan) { return !cons`isEmpty || !prods`isEmpty; } 94 static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !cons`isEmpty; } 95 static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !prods`isEmpty; } 96 97 // closes the channel and notifies all blocked threads 98 static inline void close( channel(T) & chan ) with(chan) { 99 lock( mutex_lock ); 100 closed = true; 101 102 // flush waiting consumers and producers 103 while ( has_waiting_consumers( chan ) ) { 104 cons`first.elem = 0p; 105 wake_one( cons ); 106 } 107 while ( has_waiting_producers( chan ) ) { 108 prods`first.elem = 0p; 109 wake_one( prods ); 110 } 111 unlock(mutex_lock); 112 } 113 114 static inline void is_closed( channel(T) & chan ) with(chan) { return closed; } 115 116 static inline void flush( channel(T) & chan, T elem ) with(chan) { 117 lock( mutex_lock ); 118 while ( count == 0 && !cons`isEmpty ) { 119 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work 120 wake_one( cons ); 121 } 122 unlock( mutex_lock ); 123 } 124 125 // handles buffer insert 126 static inline void __buf_insert( channel(T) & chan, T & elem ) with(chan) { 44 127 memcpy((void *)&buffer[back], (void *)&elem, sizeof(T)); 45 128 count += 1; … … 48 131 } 49 132 133 // does the buffer insert or hands elem directly to consumer if one is waiting 134 static inline void __do_insert( channel(T) & chan, T & elem ) with(chan) { 135 if ( count == 0 && !cons`isEmpty ) { 136 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work 137 wake_one( cons ); 138 } else __buf_insert( chan, elem ); 139 } 140 141 // needed to avoid an extra copy in closed case 142 static inline bool __internal_try_insert( channel(T) & chan, T & elem ) with(chan) { 143 lock( mutex_lock ); 144 #ifdef CHAN_STATS 145 operations++; 146 #endif 147 if ( count == size ) { unlock( mutex_lock ); return false; } 148 __do_insert( chan, elem ); 149 unlock( mutex_lock ); 150 return true; 151 } 152 153 // attempts a nonblocking insert 154 // returns true if insert was successful, false otherwise 155 static inline bool try_insert( channel(T) & chan, T elem ) { return __internal_try_insert( chan, elem ); } 156 157 // handles closed case of insert routine 158 static inline void __closed_insert( channel(T) & chan, T & elem ) with(chan) { 159 channel_closed except{&channel_closed_vt, &elem, &chan }; 160 throwResume except; // throw closed resumption 161 if ( !__internal_try_insert( chan, elem ) ) throw except; // if try to insert fails (would block), throw termination 162 } 50 163 51 164 static 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 } 53 183 54 184 // 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 ); 58 188 unlock( mutex_lock ); 59 return ;189 return true; 60 190 } 61 191 62 192 // 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 ); 65 201 return; 66 202 } // if 67 203 68 if ( count == 0 && ! empty( cons ) )69 // do waiting consumer work70 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 ); 72 208 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 214 static inline void __buf_remove( channel(T) & chan, T & retval ) with(chan) { 96 215 memcpy((void *)&retval, (void *)&buffer[front], sizeof(T)); 97 216 count -= 1; 98 217 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 221 static inline void __do_remove( channel(T) & chan, T & retval ) with(chan) { 222 __buf_remove( chan, retval ); 223 if (count == size - 1 && !prods`isEmpty ) { 224 __buf_insert( chan, *(T *)prods`first.elem ); // do waiting producer work 225 wake_one( prods ); 226 } 227 } 228 229 // needed to avoid an extra copy in closed case and single return val case 230 static inline bool __internal_try_remove( channel(T) & chan, T & retval ) with(chan) { 231 lock( mutex_lock ); 232 #ifdef CHAN_STATS 233 operations++; 234 #endif 235 if ( count == 0 ) { unlock( mutex_lock ); return false; } 236 __do_remove( chan, retval ); 237 unlock( mutex_lock ); 238 return true; 239 } 240 241 // attempts a nonblocking remove 242 // returns [T, true] if insert was successful 243 // returns [T, false] if insert was successful (T uninit) 244 static inline [T, bool] try_remove( channel(T) & chan ) { 245 T retval; 246 return [ retval, __internal_try_remove( chan, retval ) ]; 247 } 248 249 static inline T try_remove( channel(T) & chan, T elem ) { 250 T retval; 251 __internal_try_remove( chan, retval ); 105 252 return retval; 106 253 } 107 254 255 // handles closed case of insert routine 256 static inline void __closed_remove( channel(T) & chan, T & retval ) with(chan) { 257 channel_closed except{&channel_closed_vt, 0p, &chan }; 258 throwResume except; // throw resumption 259 if ( !__internal_try_remove( chan, retval ) ) throw except; // if try to remove fails (would block), throw termination 260 } 261 262 static 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 } 108 305 } // forall( T ) -
libcfa/src/concurrency/clib/cfathread.cfa
r2ed94a9 rb110bcc 16 16 // #define EPOLL_FOR_SOCKETS 17 17 18 #include <string.h> 19 18 20 #include "fstream.hfa" 19 21 #include "locks.hfa" … … 23 25 #include "time.hfa" 24 26 #include "stdlib.hfa" 25 27 #include "iofwd.hfa" 26 28 #include "cfathread.h" 27 28 extern "C" {29 #include <string.h>30 #include <errno.h>31 }32 29 33 30 extern void ?{}(processor &, const char[], cluster &, thread$ *); 34 31 extern "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); 37 33 } 38 34 … … 472 468 } 473 469 474 #include <iofwd.hfa>475 476 470 extern "C" { 477 #include <unistd.h>478 #include <sys/types.h>479 #include <sys/socket.h>480 481 471 //-------------------- 482 472 // IO operations … … 488 478 , protocol); 489 479 } 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) { 491 481 return bind(socket, address, address_len); 492 482 } … … 496 486 } 497 487 498 int cfathread_accept(int socket, struct sockaddr *restrictaddress, socklen_t *restrict address_len) {488 int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len) { 499 489 #if defined(EPOLL_FOR_SOCKETS) 500 490 int ret; … … 513 503 } 514 504 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) { 516 506 #if defined(EPOLL_FOR_SOCKETS) 517 507 int ret; -
libcfa/src/concurrency/clib/cfathread.h
r2ed94a9 rb110bcc 9 9 // Author : Thierry Delisle 10 10 // 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 14 14 // 15 15 16 #pragma once 17 16 18 #if defined(__cforall) || defined(__cplusplus) 19 #include <unistd.h> 20 #include <errno.h> 21 #include <sys/socket.h> 22 17 23 extern "C" { 18 24 #endif 19 #include <asm/types.h>20 #include <errno.h>21 #include <unistd.h>22 23 24 25 //-------------------- 25 26 // Basic types … … 73 74 } cfathread_mutexattr_t; 74 75 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))); 76 77 int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1))); 77 78 int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1))); … … 91 92 //-------------------- 92 93 // IO operations 93 struct sockaddr;94 struct msghdr;95 94 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); 97 96 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); 100 99 int cfathread_dup(int fildes); 101 100 int cfathread_close(int fildes); -
libcfa/src/concurrency/coroutine.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Dec 15 12:06:04 202013 // Update Count : 2 312 // Last Modified On : Thu Feb 16 15:34:46 2023 13 // Update Count : 24 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "coroutine.hfa" -
libcfa/src/concurrency/future.hfa
r2ed94a9 rb110bcc 14 14 // 15 15 16 //#pragma once16 #pragma once 17 17 18 18 #include "bits/locks.hfa" -
libcfa/src/concurrency/invoke.h
r2ed94a9 rb110bcc 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // 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. 15 17 16 18 #include "bits/containers.hfa" -
libcfa/src/concurrency/io.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #if defined(__CFA_DEBUG__) … … 296 295 // make sure the target hasn't stopped existing since last time 297 296 HELP: if(target < ctxs_count) { 298 // calculate it's age and how young it could be before we give ip on helping297 // calculate it's age and how young it could be before we give up on helping 299 298 const __readyQ_avg_t cutoff = calc_cutoff(ctsc, ctx->cq.id, ctxs_count, io.data, io.tscs, __shard_factor.io, false); 300 299 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 31 31 Prelude = """#define __cforall_thread__ 32 32 33 #include <unistd.h> 34 #include <errno.h> 35 #include <sys/socket.h> 36 #include <time.hfa> 37 33 38 #include "bits/defs.hfa" 34 39 #include "kernel.hfa" … … 43 48 #include <assert.h> 44 49 #include <stdint.h> 45 #include <errno.h>46 50 #include <linux/io_uring.h> 47 48 51 #include "kernel/fwd.hfa" 49 52 … … 82 85 // I/O Forwards 83 86 //============================================================================================= 84 #include <time.hfa>85 86 // Some forward declarations87 #include <errno.h>88 #include <unistd.h>89 87 90 88 extern "C" { 91 #include <asm/types.h>92 #include <sys/socket.h>93 #include <sys/syscall.h>94 95 89 #if defined(CFA_HAVE_PREADV2) 96 90 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); 98 92 #endif 99 93 #if defined(CFA_HAVE_PWRITEV2) 100 94 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); 102 96 #endif 103 97 … … 114 108 struct msghdr; 115 109 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); 122 114 123 115 extern int fallocate(int fd, int mode, off_t offset, off_t len); 124 116 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); 128 120 extern int close(int fd); 129 121 130 extern ssize_t read (int fd, void * buf, size_t count);122 extern ssize_t read (int fd, void * buf, size_t count); 131 123 132 124 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); 136 128 extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags); 137 129 } … … 232 224 calls = [ 233 225 # 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)', { 235 227 'fd' : 'fd', 228 'addr': '(typeof(sqe->addr))iov', 229 'len' : 'iovcnt', 236 230 'off' : 'offset', 237 'addr': '(uintptr_t)iov', 238 'len' : 'iovcnt', 231 'rw_flags' : 'flags' 239 232 }, define = 'CFA_HAVE_PREADV2'), 240 233 # 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)', { 242 235 'fd' : 'fd', 236 'addr': '(typeof(sqe->addr))iov', 237 'len' : 'iovcnt', 243 238 'off' : 'offset', 244 'addr': '(uintptr_t)iov', 245 'len' : 'iovcnt' 239 'rw_flags' : 'flags' 246 240 }, define = 'CFA_HAVE_PWRITEV2'), 247 241 # CFA_HAVE_IORING_OP_FSYNC … … 250 244 }), 251 245 # 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)', { 253 247 'fd': 'epfd', 248 'len': 'op', 254 249 'addr': 'fd', 255 'len': 'op', 256 'off': '(uintptr_t)event' 250 'off': '(typeof(sqe->off))event' 257 251 }), 258 252 # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE … … 264 258 }), 265 259 # 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', 269 263 'len': '1', 270 264 'msg_flags': 'flags' 271 265 }), 272 266 # 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', 276 270 'len': '1', 277 271 'msg_flags': 'flags' 278 272 }), 279 273 # 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', 283 277 'len': 'len', 284 278 'msg_flags': 'flags' 285 279 }), 286 280 # 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', 290 284 'len': 'len', 291 285 'msg_flags': 'flags' 292 286 }), 293 287 # 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', 298 292 'accept_flags': 'flags' 299 293 }), 300 294 # 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', 304 298 'off': 'addrlen' 305 299 }), … … 307 301 Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', { 308 302 'fd': 'fd', 309 'addr': '(uintptr_t)len',310 303 'len': 'mode', 311 'off': 'offset' 304 'off': 'offset', 305 'addr': 'len' 312 306 }), 313 307 # CFA_HAVE_IORING_OP_FADVISE … … 319 313 }), 320 314 # 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', 323 317 'len': 'length', 324 318 'fadvise_advice': 'advice' 325 319 }), 326 320 # 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)', { 328 322 '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' 332 326 }), 333 327 # 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)', { 335 329 '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)' 339 333 }, define = 'CFA_HAVE_OPENAT2'), 340 334 # CFA_HAVE_IORING_OP_CLOSE … … 343 337 }), 344 338 # 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)', { 346 340 'fd': 'dirfd', 347 ' off': '(uintptr_t)statxbuf',348 ' addr': 'pathname',341 'addr': '(typeof(sqe->addr))pathname', 342 'statx_flags': 'flags', 349 343 'len': 'mask', 350 ' statx_flags': 'flags'344 'off': '(typeof(sqe->off))statxbuf' 351 345 }, define = 'CFA_HAVE_STATX'), 352 346 # CFA_HAVE_IORING_OP_READ 353 347 Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', { 354 348 'fd': 'fd', 355 'addr': '( uintptr_t)buf',349 'addr': '(typeof(sqe->addr))buf', 356 350 'len': 'count' 357 351 }), … … 359 353 Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', { 360 354 'fd': 'fd', 361 'addr': '( uintptr_t)buf',355 'addr': '(typeof(sqe->addr))buf', 362 356 'len': 'count' 363 357 }), 364 358 # 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)', { 366 360 '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', 368 362 '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', 370 364 'len': 'len', 371 365 'splice_flags': 'flags' -
libcfa/src/concurrency/io/setup.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #if defined(__CFA_DEBUG__) -
libcfa/src/concurrency/iofwd.hfa
r2ed94a9 rb110bcc 9 9 // Author : Thierry Delisle 10 10 // 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 14 14 // 15 15 … … 17 17 18 18 #include <unistd.h> 19 #include <sys/socket.h> 20 19 21 extern "C" { 20 22 #include <asm/types.h> … … 48 50 typedef __off64_t off64_t; 49 51 50 struct cluster;51 struct io_context$;52 53 struct iovec;54 struct msghdr;55 struct sockaddr;56 struct statx;57 52 struct epoll_event; 58 59 struct io_uring_sqe;60 53 61 54 //----------------------------------------------------------------------- … … 88 81 // synchronous calls 89 82 #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); 91 84 #endif 92 85 #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); 94 87 #endif 95 88 extern 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);89 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags); 97 90 extern 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);91 extern ssize_t cfa_sendmsg(int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags); 92 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr * msg, int flags, __u64 submit_flags); 93 extern ssize_t cfa_send(int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags); 94 extern ssize_t cfa_recv(int sockfd, void * buf, size_t len, int flags, __u64 submit_flags); 95 extern int cfa_accept4(int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags); 96 extern int cfa_connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags); 104 97 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags); 105 98 extern 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);99 extern int cfa_madvise(void * addr, size_t length, int advice, __u64 submit_flags); 100 extern int cfa_openat(int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags); 108 101 #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); 110 103 #endif 111 104 extern int cfa_close(int fd, __u64 submit_flags); 112 105 #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); 114 107 #endif 115 108 extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags); 116 109 extern 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);110 extern ssize_t cfa_splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags, __u64 submit_flags); 118 111 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags); 119 112 … … 121 114 // asynchronous calls 122 115 #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); 124 117 #endif 125 118 #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); 127 120 #endif 128 121 extern 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);122 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags); 130 123 extern 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);124 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags); 125 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr * msg, int flags, __u64 submit_flags); 126 extern void async_send(io_future_t & future, int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags); 127 extern void async_recv(io_future_t & future, int sockfd, void * buf, size_t len, int flags, __u64 submit_flags); 128 extern void async_accept4(io_future_t & future, int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags); 129 extern void async_connect(io_future_t & future, int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags); 137 130 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags); 138 131 extern 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);132 extern void async_madvise(io_future_t & future, void * addr, size_t length, int advice, __u64 submit_flags); 133 extern void async_openat(io_future_t & future, int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags); 141 134 #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); 143 136 #endif 144 137 extern void async_close(io_future_t & future, int fd, __u64 submit_flags); 145 138 #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); 147 140 #endif 148 141 void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags); 149 142 extern 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);143 extern void async_splice(io_future_t & future, int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags, __u64 submit_flags); 151 144 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags); 152 145 -
libcfa/src/concurrency/kernel.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 30 18:14:08 202213 // Update Count : 7 612 // Last Modified On : Mon Jan 9 08:42:05 2023 13 // Update Count : 77 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__ -
libcfa/src/concurrency/kernel/cluster.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "bits/defs.hfa" … … 69 68 return max_cores_l; 70 69 } 71 72 #if defined(CFA_HAVE_LINUX_LIBRSEQ)73 // No forward declaration needed74 #define __kernel_rseq_register rseq_register_current_thread75 #define __kernel_rseq_unregister rseq_unregister_current_thread76 #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_register81 #define __kernel_rseq_unregister __kernel_raw_rseq_unregister82 #else83 // No forward declaration needed84 // No initialization needed85 static inline void noop(void) {}86 87 #define __kernel_rseq_register noop88 #define __kernel_rseq_unregister noop89 #endif90 70 91 71 //======================================================================= … … 111 91 // Lock-Free registering/unregistering of threads 112 92 unsigned register_proc_id( void ) with(__scheduler_lock.lock) { 113 __kernel_rseq_register();114 115 93 bool * handle = (bool *)&kernelTLS().sched_lock; 116 94 … … 162 140 163 141 __atomic_store_n(cell, 0p, __ATOMIC_RELEASE); 164 165 __kernel_rseq_unregister();166 142 } 167 143 … … 505 481 /* paranoid */ verify( mock_head(this) == this.l.prev ); 506 482 } 507 508 #if defined(CFA_HAVE_LINUX_LIBRSEQ)509 // No definition needed510 #elif defined(CFA_HAVE_LINUX_RSEQ_H)511 512 #if defined( __x86_64 ) || defined( __i386 )513 #define RSEQ_SIG 0x53053053514 #elif defined( __ARM_ARCH )515 #ifdef __ARMEB__516 #define RSEQ_SIG 0xf3def5e7 /* udf #24035 ; 0x5de3 (ARMv6+) */517 #else518 #define RSEQ_SIG 0xe7f5def3 /* udf #24035 ; 0x5de3 */519 #endif520 #endif521 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 #else561 // No definition needed562 #endif -
libcfa/src/concurrency/kernel/cluster.hfa
r2ed94a9 rb110bcc 146 146 } 147 147 148 static struct {149 constunsigned readyq;150 constunsigned io;148 const static struct { 149 unsigned readyq; 150 unsigned io; 151 151 } __shard_factor = { 2, 1 }; 152 152 -
libcfa/src/concurrency/kernel/private.hfa
r2ed94a9 rb110bcc 10 10 // Created On : Mon Feb 13 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Aug 12 08:21:33 202013 // Update Count : 912 // Last Modified On : Thu Mar 2 16:04:46 2023 13 // Update Count : 11 14 14 // 15 15 … … 29 29 30 30 extern "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 #else36 #ifndef _GNU_SOURCE37 #error kernel/private requires gnu_source38 #endif39 31 #include <sched.h> 40 #endif41 32 } 42 33 … … 110 101 // Hardware 111 102 112 #if defined(CFA_HAVE_LINUX_LIBRSEQ)113 // No data needed114 #elif defined(CFA_HAVE_LINUX_RSEQ_H)115 extern "Cforall" {116 extern __attribute__((aligned(64))) __thread volatile struct rseq __cfaabi_rseq;117 }118 #else119 // No data needed120 #endif121 122 103 static inline int __kernel_getcpu() { 123 104 /* 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 #else131 105 return sched_getcpu(); 132 #endif133 106 } 134 107 -
libcfa/src/concurrency/kernel/startup.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__ 20 19 21 20 // C Includes 22 #include <errno.h> // errno21 #include <errno.h> // errno 23 22 #include <signal.h> 24 #include <string.h> // strerror25 #include <unistd.h> // sysconf26 23 #include <string.h> // strerror 24 #include <unistd.h> 25 #include <limits.h> // PTHREAD_STACK_MIN 27 26 extern "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 33 30 } 34 31 … … 36 33 #include "kernel/private.hfa" 37 34 #include "iofwd.hfa" 38 #include "startup.hfa" // STARTUP_PRIORITY_XXX35 #include "startup.hfa" // STARTUP_PRIORITY_XXX 39 36 #include "limits.hfa" 40 37 #include "math.hfa" … … 150 147 __scheduler_RWLock_t __scheduler_lock @= { 0 }; 151 148 152 #if defined(CFA_HAVE_LINUX_LIBRSEQ)153 // No data needed154 #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 #else161 // No data needed162 #endif163 164 149 //----------------------------------------------------------------------------- 165 150 // Struct to steal stack -
libcfa/src/concurrency/locks.cfa
r2ed94a9 rb110bcc 16 16 17 17 #define __cforall_thread__ 18 #define _GNU_SOURCE19 18 20 19 #include "locks.hfa" -
libcfa/src/concurrency/locks.hfa
r2ed94a9 rb110bcc 32 32 #include <fstream.hfa> 33 33 34 35 34 // futex headers 36 35 #include <linux/futex.h> /* Definition of FUTEX_* constants */ … … 155 154 // futex_mutex 156 155 157 // - No cond var support158 156 // - Kernel thd blocking alternative to the spinlock 159 157 // - No ownership (will deadlock on reacq) … … 185 183 int state; 186 184 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; 199 195 200 196 // if not in contended state, set to be in contended state … … 209 205 210 206 static inline void unlock(futex_mutex & this) with(this) { 211 // if uncontended do atomic eunlock and then return212 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; 213 209 214 210 // otherwise threads are blocked so we must wake one 215 __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);216 211 futex((int *)&val, FUTEX_WAKE, 1); 217 212 } … … 222 217 // to set recursion count after getting signalled; 223 218 static inline void on_wakeup( futex_mutex & f, size_t recursion ) {} 219 220 //----------------------------------------------------------------------------- 221 // go_mutex 222 223 // - Kernel thd blocking alternative to the spinlock 224 // - No ownership (will deadlock on reacq) 225 // - Golang's flavour of mutex 226 // - Impl taken from Golang: src/runtime/lock_futex.go 227 struct go_mutex { 228 // lock state any state other than UNLOCKED is locked 229 // enum LockState { UNLOCKED = 0, LOCKED = 1, SLEEPING = 2 }; 230 231 // stores a lock state 232 int val; 233 }; 234 235 static inline void ?{}( go_mutex & this ) with(this) { val = 0; } 236 237 static inline bool internal_try_lock(go_mutex & this, int & compare_val, int new_val ) with(this) { 238 return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, new_val, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); 239 } 240 241 static inline int internal_exchange(go_mutex & this, int swap ) with(this) { 242 return __atomic_exchange_n((int*)&val, swap, __ATOMIC_ACQUIRE); 243 } 244 245 // if this is called recursively IT WILL DEADLOCK!!!!! 246 static inline void lock(go_mutex & this) with(this) { 247 int state, init_state; 248 249 // speculative grab 250 state = internal_exchange(this, 1); 251 if ( !state ) return; // state == 0 252 init_state = state; 253 for (;;) { 254 for( int i = 0; i < 4; i++ ) { 255 while( !val ) { // lock unlocked 256 state = 0; 257 if (internal_try_lock(this, state, init_state)) return; 258 } 259 for (int i = 0; i < 30; i++) Pause(); 260 } 261 262 while( !val ) { // lock unlocked 263 state = 0; 264 if (internal_try_lock(this, state, init_state)) return; 265 } 266 sched_yield(); 267 268 // if not in contended state, set to be in contended state 269 state = internal_exchange(this, 2); 270 if ( !state ) return; // state == 0 271 init_state = 2; 272 futex((int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK 273 } 274 } 275 276 static inline void unlock( go_mutex & this ) with(this) { 277 // if uncontended do atomic unlock and then return 278 if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return; 279 280 // otherwise threads are blocked so we must wake one 281 futex((int *)&val, FUTEX_WAKE, 1); 282 } 283 284 static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); } 285 static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;} 286 static inline void on_wakeup( go_mutex & f, size_t recursion ) {} 224 287 225 288 //----------------------------------------------------------------------------- … … 253 316 static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); } 254 317 255 256 318 //----------------------------------------------------------------------------- 257 319 // Exponential backoff then block lock … … 272 334 this.lock_value = 0; 273 335 } 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 337 static inline void ^?{}( exp_backoff_then_block_lock & this ){} 277 338 278 339 static 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); 283 341 } 284 342 … … 286 344 287 345 static 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); 292 347 } 293 348 294 349 static 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 298 299 300 301 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 ); 302 357 park( ); 303 358 return true; … … 307 362 size_t compare_val = 0; 308 363 int spin = 4; 364 309 365 // linear backoff 310 366 for( ;; ) { … … 324 380 static inline void unlock(exp_backoff_then_block_lock & this) with(this) { 325 381 if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return; 326 327 328 329 382 lock( spinlock __cfaabi_dbg_ctx2 ); 383 thread$ * t = &try_pop_front( blocked_threads ); 384 unlock( spinlock ); 385 unpark( t ); 330 386 } 331 387 -
libcfa/src/concurrency/monitor.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Thd Feb 23 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 4 07:55:14 201913 // Update Count : 1 012 // Last Modified On : Sun Feb 19 17:00:59 2023 13 // Update Count : 12 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "monitor.hfa" -
libcfa/src/concurrency/mutex.cfa
r2ed94a9 rb110bcc 12 12 // Created On : Fri May 25 01:37:11 2018 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Wed Dec 4 09:16:39 201915 // Update Count : 114 // Last Modified On : Sun Feb 19 17:01:36 2023 15 // Update Count : 3 16 16 // 17 17 18 18 #define __cforall_thread__ 19 #define _GNU_SOURCE20 19 21 20 #include "mutex.hfa" -
libcfa/src/concurrency/mutex_stmt.hfa
r2ed94a9 rb110bcc 1 #pragma once 2 1 3 #include "bits/algorithm.hfa" 2 4 #include "bits/defs.hfa" … … 4 6 //----------------------------------------------------------------------------- 5 7 // is_lock 6 trait is_lock(L & | sized(L)) { 8 forall(L & | sized(L)) 9 trait is_lock { 7 10 // For acquiring a lock 8 11 void lock( L & ); … … 24 27 // Sort locks based on address 25 28 __libcfa_small_sort(this.lockarr, count); 26 27 // acquire locks in order28 // 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 // }37 29 } 38 30 -
libcfa/src/concurrency/preemption.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 17 11:18:57 202213 // Update Count : 5912 // Last Modified On : Mon Jan 9 08:42:59 2023 13 // Update Count : 60 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_PREEMPTION__ -
libcfa/src/concurrency/pthread.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include <signal.h> … … 35 34 struct pthread_values{ 36 35 inline Seqable; 37 void * value;36 void * value; 38 37 bool in_use; 39 38 }; … … 51 50 struct pthread_keys { 52 51 bool in_use; 53 void (* destructor)( void * );52 void (* destructor)( void * ); 54 53 Sequence(pthread_values) threads; 55 54 }; 56 55 57 static void ?{}(pthread_keys& k) {56 static void ?{}(pthread_keys& k) { 58 57 k.threads{}; 59 58 } … … 62 61 static pthread_keys cfa_pthread_keys_storage[PTHREAD_KEYS_MAX] __attribute__((aligned (16))); 63 62 64 static void init_pthread_storage() {65 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++){63 static void init_pthread_storage() { 64 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) { 66 65 cfa_pthread_keys_storage[i]{}; 67 66 } … … 96 95 97 96 /* condvar helper routines */ 98 static void init(pthread_cond_t * pcond){97 static void init(pthread_cond_t * pcond) { 99 98 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; 101 100 ?{}(*_cond); 102 101 } 103 102 104 static cfa2pthr_cond_var_t * get(pthread_cond_t* pcond){103 static cfa2pthr_cond_var_t * get(pthread_cond_t * pcond) { 105 104 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 108 static void destroy(pthread_cond_t * cond) { 110 109 static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)"); 111 110 ^?{}(*get(cond)); … … 116 115 117 116 /* mutex helper routines */ 118 static void mutex_check(pthread_mutex_t * t){117 static void mutex_check(pthread_mutex_t * t) { 119 118 // Use double check to improve performance. 120 119 // 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; 122 121 123 122 // SKULLDUGGERY: not a portable way to access the kind field, /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h … … 136 135 137 136 138 static void init(pthread_mutex_t * plock){137 static void init(pthread_mutex_t * plock) { 139 138 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; 141 140 ?{}(*_lock); 142 141 } 143 142 144 static simple_owner_lock * get(pthread_mutex_t* plock){143 static simple_owner_lock * get(pthread_mutex_t * plock) { 145 144 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 148 static void destroy(pthread_mutex_t * plock) { 150 149 static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)"); 151 150 ^?{}(*get(plock)); … … 153 152 154 153 //######################### Attr helpers ######################### 155 struct cfaPthread_attr_t {// thread attributes154 typedef struct cfaPthread_attr_t { // thread attributes 156 155 int contentionscope; 157 156 int detachstate; 158 157 size_t stacksize; 159 void * stackaddr;158 void * stackaddr; 160 159 int policy; 161 160 int inheritsched; 162 161 struct sched_param param; 163 } typedefcfaPthread_attr_t;164 165 static const cfaPthread_attr_t default_attrs {162 } cfaPthread_attr_t; 163 164 static const cfaPthread_attr_t default_attrs { 166 165 0, 167 166 0, 168 (size_t)65000,169 (void *)NULL,167 65_000, 168 NULL, 170 169 0, 171 170 0, … … 173 172 }; 174 173 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;174 static cfaPthread_attr_t * get(const pthread_attr_t * attr) { 175 static_assert(sizeof(pthread_attr_t) >= sizeof(cfaPthread_attr_t), "sizeof(pthread_attr_t) < sizeof(cfaPthread_attr_t)"); 176 return (cfaPthread_attr_t *)attr; 178 177 } 179 178 … … 190 189 191 190 // pthreads return value 192 void * joinval;191 void * joinval; 193 192 194 193 // pthread attributes 195 194 pthread_attr_t pthread_attr; 196 195 197 void *(* start_routine)(void *);198 void * start_arg;196 void *(* start_routine)(void *); 197 void * start_arg; 199 198 200 199 // thread local data 201 pthread_values * pthreadData;200 pthread_values * pthreadData; 202 201 203 202 // flag used for tryjoin … … 207 206 /* thread part routines */ 208 207 // cfaPthread entry point 209 void main(cfaPthread & _thread) with(_thread){210 joinval = 208 void main(cfaPthread & _thread) with(_thread) { 209 joinval = start_routine(start_arg); 211 210 isTerminated = true; 212 211 } 213 212 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::invokeTask220 pthread_values * value;221 pthread_keys * key;213 static cfaPthread * lookup( pthread_t p ) { 214 static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *),"sizeof(pthread_t) < sizeof(cfaPthread *)"); 215 return (cfaPthread *)p; 216 } 217 218 static void pthread_deletespecific_( pthread_values * values ) { // see uMachContext::invokeTask 219 pthread_values * value; 220 pthread_keys * key; 222 221 bool destcalled = true; 223 if (values != NULL) {222 if (values != NULL) { 224 223 for ( int attempts = 0; attempts < PTHREAD_DESTRUCTOR_ITERATIONS && destcalled ; attempts += 1 ) { 225 224 destcalled = false; 226 225 lock(key_lock); 227 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++){226 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) { 228 227 // for each valid key 229 if ( values[i].in_use) {228 if ( values[i].in_use) { 230 229 value = &values[i]; 231 230 key = &cfa_pthread_keys[i]; … … 234 233 // if a key value has a non-NULL destructor pointer, and the thread has a non-NULL value associated with that key, 235 234 // 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) { 237 236 unlock(key_lock); 238 237 key->destructor(value->value); // run destructor … … 249 248 } 250 249 251 static void ^?{}(cfaPthread & mutex t) {250 static void ^?{}(cfaPthread & mutex t) { 252 251 // delete pthread local storage 253 252 pthread_values * values = t.pthreadData; … … 255 254 } 256 255 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*)");256 static void ?{}(cfaPthread & t, pthread_t * _thread, const pthread_attr_t * _attr,void *(* start_routine)(void *), void * arg) { 257 static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *), "pthread_t too small to hold a pointer: sizeof(pthread_t) < sizeof(cfaPthread *)"); 259 258 260 259 // set up user thread stackSize … … 278 277 //######################### Pthread Attrs ######################### 279 278 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); 282 281 ?{}(*_attr, default_attrs); 283 282 return 0; 284 283 } 285 int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW {284 int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW { 286 285 ^?{}(*get(attr)); 287 286 return 0; 288 287 } 289 288 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 { 291 290 get( attr )->contentionscope = contentionscope; 292 291 return 0; 293 292 } // pthread_attr_setscope 294 293 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 { 296 295 *contentionscope = get( attr )->contentionscope; 297 296 return 0; 298 297 } // pthread_attr_getscope 299 298 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 { 301 300 get( attr )->detachstate = detachstate; 302 301 return 0; 303 302 } // pthread_attr_setdetachstate 304 303 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 { 306 305 *detachstate = get( attr )->detachstate; 307 306 return 0; 308 307 } // pthread_attr_getdetachstate 309 308 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 { 311 310 get( attr )->stacksize = stacksize; 312 311 return 0; 313 312 } // pthread_attr_setstacksize 314 313 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 { 316 315 *stacksize = get( attr )->stacksize; 317 316 return 0; … … 326 325 } // pthread_attr_setguardsize 327 326 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 { 329 328 get( attr )->stackaddr = stackaddr; 330 329 return 0; 331 330 } // pthread_attr_setstackaddr 332 331 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 { 334 333 *stackaddr = get( attr )->stackaddr; 335 334 return 0; 336 335 } // pthread_attr_getstackaddr 337 336 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 { 339 338 get( attr )->stackaddr = stackaddr; 340 339 get( attr )->stacksize = stacksize; … … 342 341 } // pthread_attr_setstack 343 342 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 { 345 344 *stackaddr = get( attr )->stackaddr; 346 345 *stacksize = get( attr )->stacksize; … … 351 350 // already running thread threadID. It shall be called on unitialized attr 352 351 // 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 extension352 int pthread_getattr_np( pthread_t threadID, pthread_attr_t * attr ) libcfa_public __THROW { // GNU extension 354 353 check_nonnull(attr); 355 354 … … 363 362 //######################### Threads ######################### 364 363 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(); 367 366 (*t){_thread, attr, start_routine, arg}; 368 367 return 0; 369 368 } 370 369 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 { 373 371 // if thread is invalid 374 372 if (_thread == NULL) return EINVAL; … … 376 374 377 375 // get user thr pointer 378 cfaPthread * p = lookup(_thread);376 cfaPthread * p = lookup(_thread); 379 377 try { 380 378 join(*p); … … 389 387 } 390 388 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 { 392 390 // if thread is invalid 393 391 if (_thread == NULL) return EINVAL; 394 392 if (_thread == pthread_self()) return EDEADLK; 395 393 396 cfaPthread * p = lookup(_thread);394 cfaPthread * p = lookup(_thread); 397 395 398 396 // thread not finished ? … … 412 410 void pthread_exit(void * status) libcfa_public __THROW { 413 411 pthread_t pid = pthread_self(); 414 cfaPthread * _thread = (cfaPthread*)pid;412 cfaPthread * _thread = (cfaPthread *)pid; 415 413 _thread->joinval = status; // set return value 416 414 _thread->isTerminated = 1; // set terminated flag … … 426 424 //######################### Mutex ######################### 427 425 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 { 429 427 check_nonnull(_mutex); 430 428 init(_mutex); … … 435 433 int pthread_mutex_destroy(pthread_mutex_t *_mutex) libcfa_public __THROW { 436 434 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) { 439 437 return EBUSY; 440 438 } … … 446 444 check_nonnull(_mutex); 447 445 mutex_check(_mutex); 448 simple_owner_lock * _lock = get(_mutex);446 simple_owner_lock * _lock = get(_mutex); 449 447 lock(*_lock); 450 448 return 0; … … 453 451 int pthread_mutex_unlock(pthread_mutex_t *_mutex) libcfa_public __THROW { 454 452 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()) { 457 455 return EPERM; 458 456 } // current thread does not hold the mutex … … 463 461 int pthread_mutex_trylock(pthread_mutex_t *_mutex) libcfa_public __THROW { 464 462 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) { 467 465 return EBUSY; 468 466 } // if mutex is owned … … 474 472 475 473 /* 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 { 477 475 check_nonnull(cond); 478 476 init(cond); … … 480 478 } //pthread_cond_init 481 479 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 { 483 481 check_nonnull(_mutex); 484 482 check_nonnull(cond); … … 494 492 } // pthread_cond_timedwait 495 493 496 int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW {494 int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW { 497 495 check_nonnull(cond); 498 496 return notify_one(*get(cond)); 499 497 } // pthread_cond_signal 500 498 501 int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW {499 int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW { 502 500 check_nonnull(cond); 503 501 return notify_all(*get(cond)); 504 502 } // pthread_cond_broadcast 505 503 506 int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW {504 int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW { 507 505 check_nonnull(cond); 508 506 destroy(cond); … … 514 512 //######################### Local storage ######################### 515 513 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 { 517 515 static_assert(sizeof(pthread_once_t) >= sizeof(int),"sizeof(pthread_once_t) < sizeof(int)"); 518 516 check_nonnull(once_control); … … 527 525 } // pthread_once 528 526 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 { 530 528 lock(key_lock); 531 529 for ( int i = 0; i < PTHREAD_KEYS_MAX; i += 1 ) { … … 562 560 } // pthread_key_delete 563 561 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 { 565 563 // get current thread 566 cfaPthread * t = lookup(pthread_self());564 cfaPthread * t = lookup(pthread_self()); 567 565 // 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) { 570 568 values = anew( PTHREAD_KEYS_MAX); 571 569 t->pthreadData = values; 572 for ( int i = 0;i < PTHREAD_KEYS_MAX; i++){570 for ( int i = 0;i < PTHREAD_KEYS_MAX; i++ ) { 573 571 t->pthreadData[i].in_use = false; 574 572 } // for … … 593 591 } //pthread_setspecific 594 592 595 void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW {593 void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW { 596 594 if (key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use) return NULL; 597 595 598 596 // get current thread 599 cfaPthread * t = lookup(pthread_self());597 cfaPthread * t = lookup(pthread_self()); 600 598 if (t->pthreadData == NULL) return NULL; 601 599 lock(key_lock); 602 pthread_values & entry = ((pthread_values *)t->pthreadData)[key];600 pthread_values & entry = ((pthread_values *)t->pthreadData)[key]; 603 601 if ( ! entry.in_use ) { 604 602 unlock( key_lock ); 605 603 return NULL; 606 604 } // if 607 void * value = entry.value;605 void * value = entry.value; 608 606 unlock(key_lock); 609 607 … … 875 873 //######################### Parallelism ######################### 876 874 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_np880 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_np884 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_np888 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_np875 // 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 892 890 893 891 //######################### Cancellation ######################### … … 906 904 } // pthread_cancel 907 905 908 int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW {906 int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW { 909 907 abort("pthread_setcancelstate not implemented"); 910 908 return 0; 911 909 } // pthread_setcancelstate 912 910 913 int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW {911 int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW { 914 912 abort("pthread_setcanceltype not implemented"); 915 913 return 0; … … 918 916 919 917 #pragma GCC diagnostic pop 920 -
libcfa/src/concurrency/ready_queue.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_READY_QUEUE__ -
libcfa/src/concurrency/select.hfa
r2ed94a9 rb110bcc 1 #pragma once 2 1 3 #include "containers/list.hfa" 2 4 #include <stdint.h> -
libcfa/src/concurrency/thread.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Dec 11 20:56:54 202213 // Update Count : 10 212 // Last Modified On : Mon Jan 9 08:42:33 2023 13 // Update Count : 103 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "thread.hfa" -
libcfa/src/containers/array.hfa
r2ed94a9 rb110bcc 9 9 10 10 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 // 15 37 forall( [N], S & | sized(S), Timmed &, Tbase & ) { 38 39 // 40 // Single-dim array sruct (with explicit packing and atom) 41 // 16 42 struct arpk { 17 43 S strides[N]; -
libcfa/src/containers/list.hfa
r2ed94a9 rb110bcc 32 32 static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; } 33 33 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 ) { \ 38 62 immedBase & ib = this; \ 39 63 Tbase & b = ib`inner; \ -
libcfa/src/containers/vector2.hfa
r2ed94a9 rb110bcc 9 9 // Author : Michael Brooks 10 10 // 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 15 17 16 18 #include <stdlib.hfa> -
libcfa/src/interpose.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed Mar 29 16:10:31 2017 11 11 // 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 17 16 #include <stdio.h> 18 #include <string.h> // strlen19 17 #include <unistd.h> // _exit, getpid 20 #include <signal.h>21 18 extern "C" { 22 19 #include <dlfcn.h> // dlopen, dlsym … … 24 21 } 25 22 26 #include "bits/debug.hfa"27 23 #include "bits/defs.hfa" 28 24 #include "bits/signal.hfa" // sigHandler_? … … 40 36 41 37 typedef void (* generic_fptr_t)(void); 38 42 39 static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) { 43 const char * error;44 45 40 union { generic_fptr_t fptr; void * ptr; } originalFunc; 46 41 47 42 #if defined( _GNU_SOURCE ) 48 49 50 51 52 }43 if ( version ) { 44 originalFunc.ptr = dlvsym( library, symbol, version ); 45 } else { 46 originalFunc.ptr = dlsym( library, symbol ); 47 } // if 53 48 #else 54 49 originalFunc.ptr = dlsym( library, symbol ); 55 50 #endif // _GNU_SOURCE 56 51 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 60 55 return originalFunc.fptr; 61 56 } 62 57 63 58 static 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() ); 79 68 } // 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 ); 94 72 } 95 73 … … 121 99 preload_libgcc(); 122 100 123 #pragma GCC diagnostic push124 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"101 #pragma GCC diagnostic push 102 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" 125 103 INTERPOSE_LIBC( abort, version ); 126 104 INTERPOSE_LIBC( exit , version ); 127 #pragma GCC diagnostic pop105 #pragma GCC diagnostic pop 128 106 129 107 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 130 118 131 119 // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because … … 293 281 va_start( args, fmt ); 294 282 __abort( false, fmt, args ); 295 283 // CONTROL NEVER REACHES HERE! 296 284 va_end( args ); 297 285 } 298 286 299 287 void abort( bool signalAbort, const char fmt[], ... ) { 300 301 302 303 304 288 va_list args; 289 va_start( args, fmt ); 290 __abort( signalAbort, fmt, args ); 291 // CONTROL NEVER REACHES HERE! 292 va_end( args ); 305 293 } 306 294 -
libcfa/src/interpose_thread.cfa
r2ed94a9 rb110bcc 14 14 // 15 15 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 19 21 #include <signal.h> 20 22 #include <pthread.h> 23 #include <signal.h> 21 24 extern "C" { 22 25 #include <dlfcn.h> // dlopen, dlsym 23 #include <execinfo.h> // backtrace, messages24 26 } 25 27 26 #include "bits/debug.hfa"27 28 #include "bits/defs.hfa" 28 #include <assert.h>29 29 30 30 //============================================================================================= … … 34 34 typedef void (* generic_fptr_t)(void); 35 35 36 generic_fptr_t interpose_symbol(36 generic_fptr_t libcfa_public interpose_symbol( 37 37 generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ), 38 38 const char symbol[], 39 39 const char version[] 40 ) libcfa_public{41 const char * error;40 ) { 41 void * library; 42 42 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() ); 55 50 } // if 51 #endif // RTLD_NEXT 56 52 57 return do_interpose_symbol( library, symbol, version);53 return do_interpose_symbol( library, symbol, version ); 58 54 } 59 55 … … 83 79 #pragma GCC diagnostic push 84 80 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" 85 INTERPOSE( pthread_create 86 INTERPOSE( pthread_join 87 INTERPOSE( pthread_self 88 INTERPOSE( pthread_attr_init 89 INTERPOSE( pthread_attr_destroy 90 INTERPOSE( pthread_attr_setstack 91 INTERPOSE( pthread_attr_getstacksize 92 INTERPOSE( pthread_sigmask 93 INTERPOSE( pthread_sigqueue 94 INTERPOSE( pthread_once 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 ); 95 91 #pragma GCC diagnostic pop 96 92 } -
libcfa/src/iostream.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 27 15:04:15 202213 // Update Count : 13 5812 // Last Modified On : Mon Jan 9 09:27:58 2023 13 // Update Count : 1361 14 14 // 15 15 … … 667 667 } /* if */ \ 668 668 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 */ ); \ 670 670 } else { \ 671 671 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \ -
libcfa/src/limits.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed Apr 6 18:06:52 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 5 22:27:40202313 // Update Count : 8 412 // Last Modified On : Fri Feb 17 12:25:39 2023 13 // Update Count : 87 14 14 // 15 15 16 #define _GNU_SOURCE // access long double M_*l in math.h17 16 #include <limits.h> 18 17 #include <float.h> -
libcfa/src/stdlib.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Thu Jan 28 17:10:29 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 9 15:11:30 202213 // Update Count : 63 112 // Last Modified On : Thu Feb 16 16:31:34 2023 13 // Update Count : 633 14 14 // 15 15 … … 20 20 //--------------------------------------- 21 21 22 #define _XOPEN_SOURCE 600 // posix_memalign, *rand4823 22 #include <string.h> // memcpy, memset 24 23 //#include <math.h> // fabsf, fabs, fabsl -
libcfa/src/vec/vec.hfa
r2ed94a9 rb110bcc 18 18 #include <math.hfa> 19 19 20 trait fromint(T) { 20 forall(T) 21 trait fromint { 21 22 void ?{}(T&, int); 22 23 }; 23 trait zeroinit(T) { 24 forall(T) 25 trait zeroinit { 24 26 void ?{}(T&, zero_t); 25 27 }; 26 trait zero_assign(T) { 28 forall(T) 29 trait zero_assign { 27 30 T ?=?(T&, zero_t); 28 31 }; 29 trait subtract(T) { 32 forall(T) 33 trait subtract { 30 34 T ?-?(T, T); 31 35 }; 32 trait negate(T) { 36 forall(T) 37 trait negate { 33 38 T -?(T); 34 39 }; 35 trait add(T) { 40 forall(T) 41 trait add { 36 42 T ?+?(T, T); 37 43 }; 38 trait multiply(T) { 44 forall(T) 45 trait multiply { 39 46 T ?*?(T, T); 40 47 }; 41 trait divide(T) { 48 forall(T) 49 trait divide { 42 50 T ?/?(T, T); 43 51 }; 44 trait lessthan(T) { 52 forall(T) 53 trait lessthan { 45 54 int ?<?(T, T); 46 55 }; 47 trait equality(T) { 56 forall(T) 57 trait equality { 48 58 int ?==?(T, T); 49 59 }; 50 trait sqrt(T) { 60 forall(T) 61 trait sqrt { 51 62 T sqrt(T); 52 63 }; -
src/AST/Attribute.hpp
r2ed94a9 rb110bcc 27 27 class Expr; 28 28 29 /// An entry in an attribute list: `__attribute__(( ... ))` 29 30 class Attribute final : public Node { 30 31 public: -
src/AST/Convert.cpp
r2ed94a9 rb110bcc 559 559 auto stmt = new SuspendStmt(); 560 560 stmt->then = get<CompoundStmt>().accept1( node->then ); 561 switch (node->type) {561 switch (node->kind) { 562 562 case ast::SuspendStmt::None : stmt->type = SuspendStmt::None ; break; 563 563 case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break; … … 1683 1683 GET_ACCEPT_V(attributes, Attribute), 1684 1684 { old->get_funcSpec().val }, 1685 old->type->isVarArgs1685 (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs 1686 1686 }; 1687 1687 … … 1989 1989 GET_ACCEPT_1(else_, Stmt), 1990 1990 GET_ACCEPT_V(initialization, Stmt), 1991 old->isDoWhile,1991 (old->isDoWhile) ? ast::DoWhile : ast::While, 1992 1992 GET_LABELS_V(old->labels) 1993 1993 ); … … 2131 2131 virtual void visit( const SuspendStmt * old ) override final { 2132 2132 if ( inCache( old ) ) return; 2133 ast::SuspendStmt:: Typetype;2133 ast::SuspendStmt::Kind type; 2134 2134 switch (old->type) { 2135 2135 case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break; -
src/AST/Create.cpp
r2ed94a9 rb110bcc 20 20 #include "AST/Decl.hpp" 21 21 #include "AST/Type.hpp" 22 #include "Common/Iterate.hpp" 22 23 23 24 namespace ast { -
src/AST/Decl.cpp
r2ed94a9 rb110bcc 20 20 #include <unordered_map> 21 21 22 #include "Common/ utility.h"22 #include "Common/Eval.h" // for eval 23 23 24 24 #include "Fwd.hpp" // for UniqueId … … 57 57 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 58 58 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 ) 60 60 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), 61 61 type_params(std::move(forall)), assertions(), 62 62 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 ); 64 64 for (auto & param : this->params) { 65 65 ftype->params.emplace_back(param->get_type()); … … 81 81 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 82 82 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 ) 84 84 : DeclWithType( location, name, storage, linkage, std::move(attrs), fs ), 85 85 type_params( std::move( forall) ), assertions( std::move( assertions ) ), 86 86 params( std::move(params) ), returns( std::move(returns) ), 87 87 type( nullptr ), stmts( stmts ) { 88 FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );88 FunctionType * type = new FunctionType( isVarArgs ); 89 89 for ( auto & param : this->params ) { 90 90 type->params.emplace_back( param->get_type() ); -
src/AST/Decl.hpp
r2ed94a9 rb110bcc 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:44:00 202213 // Update Count : 3 412 // Last Modified On : Wed Apr 5 10:42:00 2023 13 // Update Count : 35 14 14 // 15 15 … … 122 122 }; 123 123 124 /// Function variable arguments flag 125 enum ArgumentFlag { FixedArgs, VariableArgs }; 126 124 127 /// Object declaration `int foo()` 125 128 class FunctionDecl : public DeclWithType { … … 144 147 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 145 148 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 ); 147 150 148 151 FunctionDecl( const CodeLocation & location, const std::string & name, … … 150 153 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 151 154 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 ); 153 156 154 157 const Type * get_type() const override; … … 313 316 public: 314 317 bool isTyped; // isTyped indicated if the enum has a declaration like: 315 // enum (type_optional) Name {...} 318 // enum (type_optional) Name {...} 316 319 ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum 317 320 enum class EnumHiding { Visible, Hide } hide; … … 371 374 }; 372 375 376 /// Assembly declaration: `asm ... ( "..." : ... )` 373 377 class AsmDecl : public Decl { 374 378 public: -
src/AST/Expr.hpp
r2ed94a9 rb110bcc 254 254 }; 255 255 256 /// A name qualified by a namespace or type. 256 257 class QualifiedNameExpr final : public Expr { 257 258 public: … … 259 260 std::string name; 260 261 261 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 262 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 262 263 : Expr( loc ), type_decl( d ), name( n ) {} 263 264 … … 621 622 }; 622 623 624 /// A name that refers to a generic dimension parameter. 623 625 class DimensionExpr final : public Expr { 624 626 public: … … 910 912 }; 911 913 912 913 914 } 914 915 -
src/AST/Fwd.hpp
r2ed94a9 rb110bcc 15 15 16 16 #pragma once 17 18 template<typename> struct bitfield; 17 19 18 20 #include "AST/Node.hpp" … … 147 149 class TranslationGlobal; 148 150 151 // For the following types, only use the using type. 152 namespace CV { 153 struct qualifier_flags; 154 using Qualifiers = bitfield<qualifier_flags>; 149 155 } 156 namespace Function { 157 struct spec_flags; 158 using Specs = bitfield<spec_flags>; 159 } 160 namespace Storage { 161 struct class_flags; 162 using Classes = bitfield<class_flags>; 163 } 164 namespace Linkage { 165 struct spec_flags; 166 using Spec = bitfield<spec_flags>; 167 } 168 169 } -
src/AST/Init.hpp
r2ed94a9 rb110bcc 117 117 ptr<Init> init; 118 118 119 ConstructorInit( 119 ConstructorInit( 120 120 const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init ) 121 121 : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {} -
src/AST/Inspect.cpp
r2ed94a9 rb110bcc 10 10 // Created On : Fri Jun 24 13:16:31 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 3 11:04:00 202213 // Update Count : 312 // Last Modified On : Fri Apr 14 15:09:00 2023 13 // Update Count : 4 14 14 // 15 15 … … 168 168 } 169 169 170 bool isUnnamedBitfield( const ast::ObjectDecl * obj ) { 171 return obj && obj->name.empty() && obj->bitfieldWidth; 172 } 173 170 174 } // namespace ast -
src/AST/Inspect.hpp
r2ed94a9 rb110bcc 10 10 // Created On : Fri Jun 24 13:16:31 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Sep 22 13:44:00 202213 // Update Count : 212 // Last Modified On : Fri Apr 14 15:09:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 38 38 const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr ); 39 39 40 /// Returns true if obj's name is the empty string and it has a bitfield width. 41 bool isUnnamedBitfield( const ObjectDecl * obj ); 42 40 43 } -
src/AST/ParseNode.hpp
r2ed94a9 rb110bcc 40 40 template<typename node_t> 41 41 friend node_t * mutate(const node_t * node); 42 template<typename node_t> 43 friend node_t * shallowCopy(const node_t * node); 42 44 }; 43 45 -
src/AST/Pass.impl.hpp
r2ed94a9 rb110bcc 22 22 #include "AST/TranslationUnit.hpp" 23 23 #include "AST/TypeSubstitution.hpp" 24 #include "Common/Iterate.hpp" 24 25 25 26 #define VISIT_START( node ) \ … … 2041 2042 if ( __visit_children() ) { 2042 2043 maybe_accept( node, &TupleType::types ); 2043 maybe_accept( node, &TupleType::members );2044 2044 } 2045 2045 -
src/AST/Pass.proto.hpp
r2ed94a9 rb110bcc 18 18 19 19 #include "Common/Stats/Heap.h" 20 21 20 namespace 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 27 namespace ast::__pass { 28 29 typedef std::function<void( void * )> cleanup_func_t; 30 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 31 32 // boolean reference that may be null 33 // either refers to a boolean value or is null and returns true 34 class bool_ref { 35 public: 36 bool_ref() = default; 37 ~bool_ref() = default; 38 39 operator bool() { return m_ref ? *m_ref : true; } 40 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 41 42 private: 43 44 friend class visit_children_guard; 45 46 bool * set( bool * val ) { 47 bool * prev = m_ref; 48 m_ref = val; 49 return prev; 50 } 51 52 bool * m_ref = nullptr; 53 }; 54 55 // Implementation of the guard value 56 // Created inside the visit scope 57 class guard_value { 58 public: 59 /// Push onto the cleanup 60 guard_value( at_cleanup_t * at_cleanup ) { 61 if( at_cleanup ) { 62 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 63 push( std::move( func ), val ); 64 }; 65 } 66 } 67 68 ~guard_value() { 69 while( !cleanups.empty() ) { 70 auto& cleanup = cleanups.top(); 71 cleanup.func( cleanup.val ); 72 cleanups.pop(); 73 } 74 } 75 76 void push( cleanup_func_t && func, void* val ) { 77 cleanups.emplace( std::move(func), val ); 78 } 79 80 private: 81 struct cleanup_t { 82 cleanup_func_t func; 83 void * val; 84 85 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 58 86 }; 59 87 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 92 class visit_children_guard { 93 public: 94 95 visit_children_guard( bool_ref * ref ) 96 : m_val ( true ) 97 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 98 , m_ref ( ref ) 99 {} 100 101 ~visit_children_guard() { 102 if( m_ref ) { 103 m_ref->set( m_prev ); 104 } 105 } 106 107 operator bool() { return m_val; } 108 109 private: 110 bool m_val; 111 bool * m_prev; 112 bool_ref * m_ref; 113 }; 114 115 /// "Short hand" to check if this is a valid previsit function 116 /// Mostly used to make the static_assert look (and print) prettier 117 template<typename core_t, typename node_t> 118 struct is_valid_previsit { 119 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 120 121 static constexpr bool value = std::is_void< ret_t >::value || 122 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 123 }; 124 125 /// The result is a single node. 126 template< typename node_t > 127 struct result1 { 128 bool differs = false; 129 const node_t * value = nullptr; 130 131 template< typename object_t, typename super_t, typename field_t > 132 void apply( object_t *, field_t super_t::* field ); 133 }; 134 135 /// The result is a container of statements. 136 template< template<class...> class container_t > 137 struct resultNstmt { 138 /// The delta/change on a single node. 139 struct delta { 140 ptr<Stmt> new_val; 141 ssize_t old_idx; 142 bool is_old; 143 144 delta(const Stmt * s, ssize_t i, bool old) : 145 new_val(s), old_idx(i), is_old(old) {} 94 146 }; 95 147 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. 162 template< template<class...> class container_t, typename node_t > 163 struct resultN { 164 bool differs = false; 165 container_t<ptr<node_t>> values; 166 167 template< typename object_t, typename super_t, typename field_t > 168 void apply( object_t *, field_t super_t::* field ); 169 }; 170 171 /// Used by previsit implementation 172 /// We need to reassign the result to 'node', unless the function 173 /// returns void, then we just leave 'node' unchanged 174 template<bool is_void> 175 struct __assign; 176 177 template<> 178 struct __assign<true> { 122 179 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 185 template<> 186 struct __assign<false> { 237 187 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 197 template<bool is_void> 198 struct __return; 199 200 template<> 201 struct __return<true> { 251 202 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 209 template<> 210 struct __return<false> { 255 211 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 232 template<typename core_t, typename node_t> 233 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 234 static_assert( 235 is_valid_previsit<core_t, node_t>::value, 236 "Previsit may not change the type of the node. It must return its paremeter or void." 237 ); 238 239 __assign< 240 std::is_void< 241 decltype( core.previsit( node ) ) 242 >::value 243 >::result( core, node ); 244 } 245 246 template<typename core_t, typename node_t> 247 static inline auto previsit( core_t &, const node_t *, long ) {} 248 249 // PostVisit : never mutates the passed pointer but may return a different node 250 template<typename core_t, typename node_t> 251 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 252 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 253 { 254 return __return< 255 std::is_void< 256 decltype( core.postvisit( node ) ) 257 >::value 258 >::result( core, node ); 259 } 260 261 template<typename core_t, typename node_t> 262 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 263 264 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 265 // Deep magic (a.k.a template meta programming) continued 266 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 267 // from in order to get extra functionallity for example 268 // class ErrorChecker : WithShortCircuiting { ... }; 269 // Pass<ErrorChecker> checker; 270 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 271 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 272 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 273 // For several accessories, the feature is enabled by detecting that a specific field is present 274 // Use a macro the encapsulate the logic of detecting a particular field 275 // The type is not strictly enforced but does match the accessory 276 #define FIELD_PTR( name, default_type ) \ 277 template< typename core_t > \ 278 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 279 \ 280 template< typename core_t > \ 281 static inline default_type * name( core_t &, long ) { return nullptr; } 282 283 // List of fields and their expected types 284 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 285 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 286 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 287 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 288 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 289 FIELD_PTR( visit_children, __pass::bool_ref ) 290 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 291 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 292 293 // Remove the macro to make sure we don't clash 294 #undef FIELD_PTR 295 296 template< typename core_t > 297 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 298 // Stats::Heap::stacktrace_push(core_t::traceId); 299 } 300 301 template< typename core_t > 302 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 303 // Stats::Heap::stacktrace_pop(); 304 } 305 306 template< typename core_t > 307 static void beginTrace(core_t &, long) {} 308 309 template< typename core_t > 310 static void endTrace(core_t &, long) {} 311 312 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 313 // If on_error() returns false, the error will be ignored. By default, it returns true. 314 315 template< typename core_t > 316 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 317 318 template< typename core_t > 319 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 320 return core.on_error(decl); 321 } 322 323 template< typename core_t, typename node_t > 324 static auto make_location_guard( core_t & core, node_t * node, int ) 325 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 326 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 327 core.location = &node->location; 328 return guard; 329 } 330 331 template< typename core_t, typename node_t > 332 static auto make_location_guard( core_t &, node_t *, long ) -> int { 333 return 0; 334 } 335 336 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 337 // All passes which have such functions are assumed desire this behaviour 338 // detect it using the same strategy 339 namespace scope { 340 template<typename core_t> 341 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 342 core.beginScope(); 343 } 344 345 template<typename core_t> 346 static inline void enter( core_t &, long ) {} 347 348 template<typename core_t> 349 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 350 core.endScope(); 351 } 352 353 template<typename core_t> 354 static inline void leave( core_t &, long ) {} 355 } // namespace scope 356 357 // Certain passes desire an up to date symbol table automatically 358 // detect the presence of a member name `symtab` and call all the members appropriately 359 namespace symtab { 360 // Some simple scoping rules 361 template<typename core_t> 362 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 363 core.symtab.enterScope(); 364 } 365 366 template<typename core_t> 367 static inline auto enter( core_t &, long ) {} 368 369 template<typename core_t> 370 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 371 core.symtab.leaveScope(); 372 } 373 374 template<typename core_t> 375 static inline auto leave( core_t &, long ) {} 376 377 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 378 // Create macro to condense these common patterns 379 #define SYMTAB_FUNC1( func, type ) \ 380 template<typename core_t> \ 381 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 382 core.symtab.func( arg ); \ 383 } \ 284 384 \ 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 456 namespace forall { 457 // Some simple scoping rules 458 template<typename core_t> 459 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 460 -> decltype( core.subs, void() ) { 461 if ( ! type->forall.empty() ) core.subs.beginScope(); 462 } 463 464 template<typename core_t> 465 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 466 467 template<typename core_t> 468 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 469 -> decltype( core.subs, void() ) { 470 if ( ! type->forall.empty() ) { core.subs.endScope(); } 471 } 472 473 template<typename core_t> 474 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 475 476 // Replaces a TypeInstType's base TypeDecl according to the table 477 template<typename core_t> 478 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 479 -> decltype( core.subs, void() ) { 480 inst = ast::mutate_field( 481 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 482 } 483 484 template<typename core_t> 485 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 486 } // namespace forall 487 488 // For passes that need access to the global context. Searches `translationUnit` 489 namespace translation_unit { 490 template<typename core_t> 491 static inline auto get_cptr( core_t & core, int ) 492 -> decltype( &core.translationUnit ) { 493 return &core.translationUnit; 494 } 495 496 template<typename core_t> 497 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 498 return nullptr; 499 } 500 } 501 502 // For passes, usually utility passes, that have a result. 503 namespace result { 504 template<typename core_t> 505 static inline auto get( core_t & core, char ) -> decltype( core.result() ) { 506 return core.result(); 507 } 508 509 template<typename core_t> 510 static inline auto get( core_t & core, int ) -> decltype( core.result ) { 511 return core.result; 512 } 513 514 template<typename core_t> 515 static inline void get( core_t &, long ) {} 516 } 517 518 } // namespace ast::__pass -
src/AST/Print.cpp
r2ed94a9 rb110bcc 29 29 namespace ast { 30 30 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 }; 31 namespace { 32 33 template<typename C, typename... T> 34 constexpr array<C, sizeof...(T)> make_array( T&&... values ) { 35 return array<C, sizeof...(T)>{ std::forward<T>( values )... }; 36 } 37 38 namespace Names { 39 static constexpr auto FuncSpecifiers = make_array<const char*>( 40 "inline", "_Noreturn", "fortran" 41 ); 42 43 static constexpr auto StorageClasses = make_array<const char*>( 44 "extern", "static", "auto", "register", "__thread", "_Thread_local" 45 ); 46 47 static constexpr auto Qualifiers = make_array<const char*>( 48 "const", "restrict", "volatile", "mutex", "_Atomic" 49 ); 50 } 51 52 template<typename bits_t, size_t N> 53 void print( ostream & os, const bits_t & bits, 54 const array<const char *, N> & names ) { 55 if ( !bits.any() ) return; 56 for ( size_t i = 0 ; i < N ; i += 1 ) { 57 if ( bits[i] ) { 58 os << names[i] << ' '; 59 } 60 } 37 61 } 38 62 … … 80 104 static const char* Names[]; 81 105 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 119 106 void print( const std::vector<ast::Label> & labels ) { 120 107 if ( labels.empty() ) return; … … 230 217 } 231 218 232 print(node->storage );219 ast::print( os, node->storage ); 233 220 os << node->typeString(); 234 221 … … 272 259 273 260 void preprint( const ast::Type * node ) { 274 print(node->qualifiers );261 ast::print( os, node->qualifiers ); 275 262 } 276 263 … … 278 265 print( node->forall ); 279 266 print( node->assertions ); 280 print(node->qualifiers );267 ast::print( os, node->qualifiers ); 281 268 } 282 269 283 270 void preprint( const ast::BaseInstType * node ) { 284 271 print( node->attributes ); 285 print(node->qualifiers );272 ast::print( os, node->qualifiers ); 286 273 } 287 274 … … 294 281 } 295 282 296 print(node->storage );283 ast::print( os, node->storage ); 297 284 298 285 if ( node->type ) { … … 338 325 if ( ! short_mode ) printAll( node->attributes ); 339 326 340 print( node->storage ); 341 print( node->funcSpec ); 342 343 327 ast::print( os, node->storage ); 328 ast::print( os, node->funcSpec ); 344 329 345 330 if ( node->type && node->isTypeFixed ) { … … 384 369 --indent; 385 370 } 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; 386 379 } 387 380 … … 746 739 virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final { 747 740 os << "Suspend Statement"; 748 switch (node-> type) {749 750 751 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; 752 745 } 753 746 os << endl; … … 1627 1620 }; 1628 1621 1622 } // namespace 1623 1629 1624 void print( ostream & os, const ast::Node * node, Indenter indent ) { 1630 1625 Printer printer { os, indent, false }; … … 1637 1632 } 1638 1633 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; 1634 void print( ostream & os, Function::Specs specs ) { 1635 print( os, specs, Names::FuncSpecifiers ); 1645 1636 } 1637 1638 void print( ostream & os, Storage::Classes storage ) { 1639 print( os, storage, Names::StorageClasses ); 1640 } 1641 1642 void print( ostream & os, CV::Qualifiers qualifiers ) { 1643 print( os, qualifiers, Names::Qualifiers ); 1644 } 1645 1646 } // namespace ast -
src/AST/Print.hpp
r2ed94a9 rb110bcc 16 16 #pragma once 17 17 18 #include <iostream> 19 #include <utility> // for forward 18 #include <iosfwd> 20 19 21 #include "AST/ Node.hpp"20 #include "AST/Fwd.hpp" 22 21 #include "Common/Indenter.h" 23 22 24 23 namespace ast { 25 26 class Decl;27 24 28 25 /// Print a node with the given indenter … … 44 41 } 45 42 43 /// Print each cv-qualifier used in the set, followed by a space. 44 void print( std::ostream & os, CV::Qualifiers ); 45 /// Print each function specifier used in the set, followed by a space. 46 void print( std::ostream & os, Function::Specs ); 47 /// Print each storage class used in the set, followed by a space. 48 void print( std::ostream & os, Storage::Classes ); 49 46 50 } -
src/AST/Stmt.hpp
r2ed94a9 rb110bcc 10 10 // Created On : Wed May 8 13:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Apr 20 14:34:00 202213 // Update Count : 3 612 // Last Modified On : Wed Apr 5 10:34:00 2023 13 // Update Count : 37 14 14 // 15 15 … … 205 205 }; 206 206 207 // A while loop or a do-while loop: 208 enum WhileDoKind { While, DoWhile }; 209 207 210 // While loop: while (...) ... else ... or do ... while (...) else ...; 208 211 class WhileDoStmt final : public Stmt { … … 212 215 ptr<Stmt> else_; 213 216 std::vector<ptr<Stmt>> inits; 214 boolisDoWhile;217 WhileDoKind isDoWhile; 215 218 216 219 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 = {} ) 218 221 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {} 219 222 220 223 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 = {} ) 222 225 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {} 223 226 … … 364 367 public: 365 368 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) {} 370 373 371 374 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } … … 394 397 }; 395 398 399 // Clause in a waitfor statement: waitfor (..., ...) ... 396 400 class WaitForClause final : public StmtClause { 397 401 public: … … 454 458 MUTATE_FRIEND 455 459 }; 460 456 461 } // namespace ast 457 462 -
src/AST/SymbolTable.cpp
r2ed94a9 rb110bcc 70 70 if ( baseExpr ) { 71 71 if (baseExpr->env) { 72 Expr * base = shallowCopy(baseExpr);72 Expr * base = deepCopy(baseExpr); 73 73 const TypeSubstitution * subs = baseExpr->env; 74 74 base->env = nullptr; … … 260 260 void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) { 261 261 // 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 ); 263 263 } 264 264 265 265 void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) { 266 266 // default handling of conflicts is to raise an error 267 addId ( decl, OnConflict::error(), nullptr, deleter );267 addIdCommon( decl, OnConflict::error(), nullptr, deleter ); 268 268 } 269 269 … … 677 677 } 678 678 679 void SymbolTable::addId (680 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,681 const Decl * deleter ) {679 void SymbolTable::addIdCommon( 680 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, 681 const Expr * baseExpr, const Decl * deleter ) { 682 682 SpecialFunctionKind kind = getSpecialFunctionKind(decl->name); 683 683 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); 685 685 } 686 686 else { … … 695 695 assertf(false, "special decl with non-function type"); 696 696 } 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 701 void SymbolTable::addIdToTable( 702 const DeclWithType * decl, const std::string & lookupKey, 703 IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, 704 const Expr * baseExpr, const Decl * deleter ) { 704 705 ++*stats().add_calls; 705 706 const std::string &name = decl->name; … … 778 779 void SymbolTable::addMembers( 779 780 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 ); 798 799 } 799 800 } -
src/AST/SymbolTable.hpp
r2ed94a9 rb110bcc 192 192 193 193 /// 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 ); 197 197 198 198 /// 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, 201 202 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr); 202 203 203 204 /// adds all of the members of the Aggregate (addWith helper) 204 205 void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts ); -
src/AST/TranslationUnit.hpp
r2ed94a9 rb110bcc 10 10 // Created On : Tue Jun 11 15:30:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Mar 11 11:19:00 202213 // Update Count : 112 // Last Modified On : Thr Mar 9 16:41:00 2023 13 // Update Count : 2 14 14 // 15 15 … … 17 17 18 18 #include <map> 19 #include < vector>19 #include <list> 20 20 21 21 #include "Fwd.hpp" … … 28 28 29 29 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; 33 33 }; 34 34 -
src/AST/Type.cpp
r2ed94a9 rb110bcc 10 10 // Created On : Mon May 13 15:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:49:00 202213 // Update Count : 612 // Last Modified On : Thu Apr 6 15:59:00 2023 13 // Update Count : 7 14 14 // 15 15 … … 199 199 200 200 TupleType::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) ) {} 220 202 221 203 bool isUnboundType(const Type * type) { -
src/AST/Type.hpp
r2ed94a9 rb110bcc 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:47:00 202213 // Update Count : 812 // Last Modified On : Thu Apr 6 15:58:00 2023 13 // Update Count : 9 14 14 // 15 15 … … 265 265 }; 266 266 267 /// Function variable arguments flag268 enum ArgumentFlag { FixedArgs, VariableArgs };269 270 267 /// Type of a function `[R1, R2](*)(P1, P2, P3)` 271 268 class FunctionType final : public Type { … … 460 457 public: 461 458 std::vector<ptr<Type>> types; 462 std::vector<ptr<Decl>> members;463 459 464 460 TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} ); -
src/AST/porting.md
r2ed94a9 rb110bcc 213 213 * `get_statement()` exclusively used for code location, replaced with `CodeLocation` field 214 214 215 `CaseStmt` 215 `CaseStmt` => `CaseClause` 216 216 * `_isDefault` has been removed 217 217 * `isDefault` calculates value from `cond` … … 227 227 * `block` -> `body` and `finallyBlock` -> `finally` 228 228 229 `ThrowStmt` `CatchStmt`229 `ThrowStmt` and `CatchStmt` => `CatchClause` 230 230 * moved `Kind` enums to shared `ast::ExceptionKind` enum 231 231 232 `FinallyStmt` 232 `FinallyStmt` => `FinallyClause` 233 233 * `block` -> `body` 234 234 … … 280 280 * Template class, with specializations and using to implement some other types: 281 281 * `StructInstType`, `UnionInstType` & `EnumInstType` 282 * `baseStruct`, `baseUnion` & `baseEnum` => `base` 282 283 283 284 `TypeInstType` -
src/CodeGen/CodeGenerator.cc
r2ed94a9 rb110bcc 17 17 #include <cassert> // for assert, assertf 18 18 #include <list> // for _List_iterator, list, list<>::it... 19 #include <sstream> // for stringstream 19 20 20 21 #include "AST/Decl.hpp" // for DeclWithType 21 22 #include "Common/UniqueName.h" // for UniqueName 22 #include "Common/utility.h" // for CodeLocation, toString23 23 #include "GenType.h" // for genType 24 24 #include "InitTweak/InitTweak.h" // for getPointerBase -
src/Common/CodeLocationTools.cpp
r2ed94a9 rb110bcc 208 208 209 209 struct LeafKindVisitor : public ast::Visitor { 210 LeafKind kind;210 LeafKind result; 211 211 212 212 #define VISIT(node_type, return_type) \ 213 213 const ast::return_type * visit( const ast::node_type * ) final { \ 214 kind= LeafKind::node_type; \214 result = LeafKind::node_type; \ 215 215 return nullptr; \ 216 216 } … … 222 222 223 223 LeafKind 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 ); 227 225 } 228 226 -
src/Common/DeclStats.cpp
r2ed94a9 rb110bcc 23 23 #include <iostream> 24 24 #include <map> 25 #include <sstream> 25 26 #include <unordered_map> 26 27 #include <unordered_set> -
src/Common/Eval.cc
r2ed94a9 rb110bcc 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // utility.h --7 // Eval.cc -- Evaluate parts of the ast at compile time. 8 8 // 9 9 // Author : Richard C. Bilson … … 13 13 // Update Count : 119 14 14 // 15 16 #include "Eval.h" 15 17 16 18 #include <utility> // for pair -
src/Common/ResolvProtoDump.cpp
r2ed94a9 rb110bcc 19 19 #include <iostream> 20 20 #include <set> 21 #include <sstream> 21 22 #include <unordered_set> 22 23 … … 26 27 #include "AST/Type.hpp" 27 28 #include "CodeGen/OperatorTable.h" 28 #include "Common/utility.h"29 29 30 30 namespace { -
src/Common/SemanticError.h
r2ed94a9 rb110bcc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 2 10:59:10202313 // Update Count : 3 612 // Last Modified On : Sat Feb 25 12:01:31 2023 13 // Update Count : 37 14 14 // 15 15 … … 56 56 {"self-assign" , Severity::Warn , "self assignment of expression: %s" }, 57 57 {"reference-conversion" , Severity::Warn , "rvalue to reference conversion of rvalue: %s" }, 58 {"qualifiers-zero_t-one_t" , Severity::Warn , "questionable use of type qualifier %swith %s" },58 {"qualifiers-zero_t-one_t" , Severity::Warn , "questionable use of type qualifier(s) with %s" }, 59 59 {"aggregate-forward-decl" , Severity::Warn , "forward declaration of nested aggregate: %s" }, 60 60 {"superfluous-decl" , Severity::Warn , "declaration does not allocate storage: %s" }, -
src/Common/module.mk
r2ed94a9 rb110bcc 20 20 Common/CodeLocationTools.hpp \ 21 21 Common/CodeLocationTools.cpp \ 22 Common/CompilerError.h \23 Common/Debug.h \24 22 Common/DeclStats.hpp \ 25 23 Common/DeclStats.cpp \ 26 24 Common/ErrorObjects.h \ 27 25 Common/Eval.cc \ 26 Common/Eval.h \ 28 27 Common/Examine.cc \ 29 28 Common/Examine.h \ … … 31 30 Common/Indenter.h \ 32 31 Common/Indenter.cc \ 32 Common/Iterate.hpp \ 33 33 Common/PassVisitor.cc \ 34 34 Common/PassVisitor.h \ … … 52 52 Common/Stats/Time.cc \ 53 53 Common/Stats/Time.h \ 54 Common/ UnimplementedError.h\54 Common/ToString.hpp \ 55 55 Common/UniqueName.cc \ 56 56 Common/UniqueName.h \ -
src/Common/utility.h
r2ed94a9 rb110bcc 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // utility.h -- 7 // utility.h -- General utilities used across the compiler. 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Apr 25 14:26:00 202213 // Update Count : 5 112 // Last Modified On : Fri Feb 17 15:25:00 2023 13 // Update Count : 53 14 14 // 15 15 … … 19 19 #include <cctype> 20 20 #include <algorithm> 21 #include <functional>22 21 #include <iostream> 23 #include <iterator>24 22 #include <list> 25 23 #include <memory> 26 #include <sstream>27 24 #include <string> 28 25 #include <type_traits> 29 #include <utility>30 26 #include <vector> 31 27 #include <cstring> // memcmp … … 49 45 return 0; 50 46 } // 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 } // if61 }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;74 47 } 75 48 … … 168 141 splice( src, dst ); 169 142 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 list193 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 element206 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 );210 143 } 211 144 … … 236 169 } 237 170 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 amount250 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 273 171 // determines if pref is a prefix of str 274 172 static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) { 275 173 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 } 302 176 303 177 // ----------------------------------------------------------------------------- … … 356 230 ~ValueGuardPtr() { if( ref ) { swap( *ref, old ); } } 357 231 }; 358 359 // -----------------------------------------------------------------------------360 // Helper struct and function to support361 // for ( val : reverseIterate( container ) ) {}362 // syntax to have a for each that iterates backwards363 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 can470 // 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 support535 // for ( val : lazy_map( container1, f ) ) {}536 // syntax to have a for each that iterates a container, mapping each element by applying f537 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 }564 232 565 233 // ----------------------------------------------------------------------------- … … 583 251 } // ilog2 584 252 585 // -----------------------------------------------------------------------------586 /// evaluates expr as a long long int. If second is false, expr could not be evaluated587 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 the597 /// 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 position607 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 position611 ++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::less624 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 629 253 // Local Variables: // 630 254 // tab-width: 4 // -
src/CompilationState.cc
r2ed94a9 rb110bcc 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Henry Xue12 // Last Modified On : Tue Jul 20 04:27:35 202113 // Update Count : 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 19:12:50 2023 13 // Update Count : 6 14 14 // 15 15 … … 27 27 expraltp = false, 28 28 genericsp = false, 29 invariant = false, 29 30 libcfap = false, 30 31 nopreludep = false, -
src/CompilationState.h
r2ed94a9 rb110bcc 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Henry Xue12 // Last Modified On : Tue Jul 20 04:27:35 202113 // Update Count : 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 19:12:53 2023 13 // Update Count : 6 14 14 // 15 15 … … 26 26 expraltp, 27 27 genericsp, 28 invariant, 28 29 libcfap, 29 30 nopreludep, -
src/Concurrency/Actors.cpp
r2ed94a9 rb110bcc 45 45 // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass 46 46 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 } 53 60 } 54 61 … … 64 71 } 65 72 66 // this collects the valid actor and message struct decl pts73 // this collects the derived actor and message struct decl ptrs 67 74 void postvisit( const StructInstType * node ) { 68 75 if ( ! *actorDecl || ! *msgDecl ) return; 69 76 if ( insideStruct && !namedDecl ) { 70 if ( node->aggr() == *actorDecl ) { 77 auto actorIter = actorStructDecls.find( node->aggr() ); 78 if ( actorIter != actorStructDecls.end() ) { 71 79 actorStructDecls.insert( parentDecl ); 72 } else if ( node->aggr() == *msgDecl ) { 80 return; 81 } 82 auto messageIter = messageStructDecls.find( node->aggr() ); 83 if ( messageIter != messageStructDecls.end() ) { 73 84 messageStructDecls.insert( parentDecl ); 74 85 } … … 180 191 }; 181 192 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) 196 struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> { 185 197 unordered_set<const StructDecl *> & actorStructDecls; 186 198 unordered_set<const StructDecl *> & messageStructDecls; … … 191 203 FwdDeclTable & forwardDecls; 192 204 205 // generates the operator for actor message sends 193 206 void postvisit( const FunctionDecl * decl ) { 194 207 // return if not of the form receive( param1, param2 ) or if it is a forward decl … … 209 222 auto messageIter = messageStructDecls.find( arg2InstType->aggr() ); 210 223 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 216 224 ////////////////////////////////////////////////////////////////////// 217 225 // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions 218 226 /* 219 227 static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) { 220 request * new_req = alloc();228 request new_req; 221 229 Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive; 222 230 __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 ); 225 233 return receiver; 226 234 } 227 */ // C_TODO: update this with new no alloc version235 */ 228 236 CompoundStmt * sendBody = new CompoundStmt( decl->location ); 229 237 230 #if __ALLOC231 // 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 #else242 238 // Generates: request new_req; 243 239 sendBody->push_back( new DeclStmt( … … 249 245 ) 250 246 )); 251 #endif252 247 253 248 // Function type is: Allocation (*)( derived_actor &, derived_msg & ) … … 268 263 )); 269 264 270 // Function type is: Allocation (*)( actor &, mess sage & )265 // Function type is: Allocation (*)( actor &, message & ) 271 266 FunctionType * genericReceive = new FunctionType(); 272 267 genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) ); … … 274 269 genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) ); 275 270 276 // Generates: Allocation (*fn)( actor &, mess sage & ) = (Allocation (*)( actor &, messsage & ))my_work_fn;271 // Generates: Allocation (*fn)( actor &, message & ) = (Allocation (*)( actor &, message & ))my_work_fn; 277 272 // More readable synonymous code: 278 273 // typedef Allocation (*__receive_fn)(actor &, message &); … … 290 285 )); 291 286 292 #if __ALLOC293 // 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 #else323 287 // Generates: new_req{ &receiver, &msg, fn }; 324 288 sendBody->push_back( new ExprStmt( … … 350 314 ) 351 315 )); 352 #endif353 316 354 317 // Generates: return receiver; … … 358 321 FunctionDecl * sendOperatorFunction = new FunctionDecl( 359 322 decl->location, 360 "? |?",323 "?<<?", 361 324 {}, // forall 362 325 { … … 388 351 // forward decls to resolve use before decl problem for '|' routines 389 352 forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) ); 390 // forwardDecls.push_back( ast::deepCopy( sendOperatorFunction ) );391 353 392 354 sendOperatorFunction->stmts = sendBody; … … 396 358 397 359 public: 398 Gen ReceiveDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,360 GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls, 399 361 const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl, 400 362 FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), … … 402 364 }; 403 365 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 369 struct FwdDeclOperator : public ast::WithDeclsToAdd<> { 405 370 unordered_set<const StructDecl *> & actorStructDecls; 406 371 unordered_set<const StructDecl *> & messageStructDecls; 407 372 FwdDeclTable & forwardDecls; 408 373 374 // handles forward declaring the message operator 409 375 void postvisit( const StructDecl * decl ) { 410 376 list<FunctionDecl *> toAddAfter; … … 433 399 434 400 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) {} 438 403 }; 439 404 … … 461 426 Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl, 462 427 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 464 433 // second pass locates all receive() routines that overload the generic receive fn 465 434 // it then generates the appropriate operator '|' send routines for the receive routines 466 Pass<Gen ReceiveDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,435 Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl, 467 436 allocationDecl, actorDecl, msgDecl, forwardDecls ); 468 437 469 438 // The third pass forward declares operator '|' send routines 470 Pass< GenFwdDecls>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );439 Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls ); 471 440 } 472 441 -
src/Concurrency/Actors.hpp
r2ed94a9 rb110bcc 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Keywords.h-- Implement concurrency constructs from their keywords.7 // Actors.hpp -- Implement concurrency constructs from their keywords. 8 8 // 9 9 // Author : Colby Parsons -
src/Concurrency/KeywordsNew.cpp
r2ed94a9 rb110bcc 779 779 780 780 const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) { 781 switch ( stmt-> type) {781 switch ( stmt->kind ) { 782 782 case ast::SuspendStmt::None: 783 783 // Use the context to determain the implicit target. -
src/ControlStruct/ExceptDeclNew.cpp
r2ed94a9 rb110bcc 15 15 16 16 #include "ExceptDecl.h" 17 18 #include <sstream> 17 19 18 20 #include "AST/Decl.hpp" -
src/ControlStruct/ExceptTranslateNew.cpp
r2ed94a9 rb110bcc 314 314 nullptr, 315 315 ast::Storage::Classes{}, 316 ast::Linkage::Cforall 316 ast::Linkage::Cforall, 317 {}, 318 { ast::Function::Inline } 317 319 ); 318 320 } -
src/ControlStruct/MLEMutator.cc
r2ed94a9 rb110bcc 25 25 #include <memory> // for allocator_traits<>::value_... 26 26 27 #include "Common/ utility.h" // for toString, operator+27 #include "Common/ToString.hpp" // for toString 28 28 #include "ControlStruct/LabelGenerator.h" // for LabelGenerator 29 29 #include "MLEMutator.h" -
src/GenPoly/Box.cc
r2ed94a9 rb110bcc 31 31 #include "Common/SemanticError.h" // for SemanticError 32 32 #include "Common/UniqueName.h" // for UniqueName 33 #include "Common/ utility.h" // for toString33 #include "Common/ToString.hpp" // for toCString 34 34 #include "FindFunction.h" // for findFunction, findAndReplace... 35 35 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::const_i... … … 80 80 CallAdapter(); 81 81 82 void premutate( Declaration * declaration ); 82 83 void premutate( FunctionDecl * functionDecl ); 83 84 void premutate( TypeDecl * typeDecl ); … … 454 455 455 456 CallAdapter::CallAdapter() : tempNamer( "_temp" ) {} 457 458 void CallAdapter::premutate( Declaration * ) { 459 // Prevent type declaration information from leaking out. 460 GuardScope( scopeTyVars ); 461 } 456 462 457 463 void CallAdapter::premutate( FunctionDecl *functionDecl ) { -
src/GenPoly/FindFunction.cc
r2ed94a9 rb110bcc 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Fri Feb 05 12:22:20 201613 // Update Count : 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 7 17:05:20 2022 13 // Update Count : 7 14 14 // 15 15 … … 18 18 #include <utility> // for pair 19 19 20 #include "AST/Pass.hpp" // for Pass 21 #include "AST/Type.hpp" 20 22 #include "Common/PassVisitor.h" // for PassVisitor 21 23 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::iterator … … 89 91 handleForall( pointerType->get_forall() ); 90 92 } 93 94 namespace { 95 96 struct FindFunctionCore : 97 public ast::WithGuards, 98 public ast::WithShortCircuiting, 99 public ast::WithVisitorRef<FindFunctionCore> { 100 FindFunctionCore( 101 std::vector<ast::ptr<ast::FunctionType>> & functions, 102 const TypeVarMap & typeVars, FindFunctionPred predicate, 103 bool replaceMode ); 104 105 void previsit( ast::FunctionType const * type ); 106 ast::Type const * postvisit( ast::FunctionType const * type ); 107 void previsit( ast::PointerType const * type ); 108 private: 109 void handleForall( const ast::FunctionType::ForallList & forall ); 110 111 std::vector<ast::ptr<ast::FunctionType>> &functions; 112 TypeVarMap typeVars; 113 FindFunctionPred predicate; 114 bool replaceMode; 115 }; 116 117 FindFunctionCore::FindFunctionCore( 118 std::vector<ast::ptr<ast::FunctionType>> & functions, 119 const TypeVarMap &typeVars, FindFunctionPred predicate, 120 bool replaceMode ) : 121 functions( functions ), typeVars( typeVars ), 122 predicate( predicate ), replaceMode( replaceMode ) {} 123 124 void FindFunctionCore::handleForall( const ast::FunctionType::ForallList & forall ) { 125 for ( const ast::ptr<ast::TypeInstType> & td : forall ) { 126 TypeVarMap::iterator var = typeVars.find( *td ); 127 if ( var != typeVars.end() ) { 128 typeVars.erase( var->first ); 129 } // if 130 } // for 131 } 132 133 void FindFunctionCore::previsit( ast::FunctionType const * type ) { 134 visit_children = false; 135 GuardScope( typeVars ); 136 handleForall( type->forall ); 137 //ast::accept_all( type->returns, *visitor ); 138 // This might have to become ast::mutate_each with return. 139 ast::accept_each( type->returns, *visitor ); 140 } 141 142 ast::Type const * FindFunctionCore::postvisit( ast::FunctionType const * type ) { 143 ast::Type const * ret = type; 144 if ( predicate( type, typeVars ) ) { 145 functions.push_back( type ); 146 if ( replaceMode ) { 147 // replace type parameters in function type with void* 148 ret = scrubTypeVars( ast::deepCopy( type ), typeVars ); 149 } // if 150 } // if 151 return ret; 152 } 153 154 void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) { 155 GuardScope( typeVars ); 156 //handleForall( type->forall ); 157 } 158 159 } // namespace 160 161 void findFunction( const ast::Type * type, 162 std::vector<ast::ptr<ast::FunctionType>> & functions, 163 const TypeVarMap & typeVars, FindFunctionPred predicate ) { 164 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false ); 165 type->accept( pass ); 166 //(void)type; 167 //(void)functions; 168 //(void)typeVars; 169 //(void)predicate; 170 } 171 172 const ast::Type * findAndReplaceFunction( const ast::Type * type, 173 std::vector<ast::ptr<ast::FunctionType>> & functions, 174 const TypeVarMap & typeVars, FindFunctionPred predicate ) { 175 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true ); 176 return type->accept( pass ); 177 //(void)functions; 178 //(void)typeVars; 179 //(void)predicate; 180 //return type; 181 } 182 91 183 } // namespace GenPoly 92 184 -
src/GenPoly/FindFunction.h
r2ed94a9 rb110bcc 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:23:36 201713 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 7 10:30:00 2022 13 // Update Count : 3 14 14 // 15 15 … … 30 30 /// like `findFunction`, but also replaces the function type with void ()(void) 31 31 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ); 32 33 typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & ); 34 35 /// Recursively walks `type`, placing all functions that match `predicate` 36 /// under `typeVars` into `functions`. 37 void findFunction( const ast::Type * type, 38 std::vector<ast::ptr<ast::FunctionType>> & functions, 39 const TypeVarMap & typeVars, FindFunctionPred predicate ); 40 /// Like findFunction, but also replaces the function type with `void ()(void)`. 41 const ast::Type * findAndReplaceFunction( const ast::Type * type, 42 std::vector<ast::ptr<ast::FunctionType>> & functions, 43 const TypeVarMap & typeVars, FindFunctionPred predicate ); 44 32 45 } // namespace GenPoly 33 46 -
src/GenPoly/GenPoly.cc
r2ed94a9 rb110bcc 275 275 } 276 276 277 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) { 278 if ( func->returns.empty() ) return nullptr; 279 280 TypeVarMap forallTypes = { ast::TypeData() }; 281 makeTypeVarMap( func, forallTypes ); 282 return isDynType( func->returns.front(), forallTypes ); 283 } 284 277 285 bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) { 278 286 // if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) { … … 319 327 return 0; 320 328 } 329 330 const ast::Type * isPolyPtr( 331 const ast::Type * type, const TypeVarMap & typeVars, 332 const ast::TypeSubstitution * typeSubs ) { 333 type = replaceTypeInst( type, typeSubs ); 334 335 if ( auto * ptr = dynamic_cast<ast::PointerType const *>( type ) ) { 336 return isPolyType( ptr->base, typeVars, typeSubs ); 337 } 338 return nullptr; 339 } 321 340 322 341 Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) { … … 796 815 } 797 816 817 void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) { 818 typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) ); 819 } 820 798 821 void 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 ) ); 800 823 } 801 824 … … 822 845 } 823 846 847 void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ) { 848 for ( auto & typeDecl : decl->type_params ) { 849 addToTypeVarMap( typeDecl, typeVars ); 850 } 851 } 852 824 853 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) { 825 854 for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) { -
src/GenPoly/GenPoly.h
r2ed94a9 rb110bcc 111 111 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ); 112 112 void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars ); 113 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ); 113 114 114 115 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 115 116 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ); 116 117 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ); 118 void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ); 117 119 118 120 /// Prints type variable map -
src/GenPoly/Lvalue.cc
r2ed94a9 rb110bcc 17 17 #include <string> // for string 18 18 19 #include "Common/ToString.hpp" // for toCString 19 20 #include "Common/UniqueName.h" 20 21 #include "Common/PassVisitor.h" -
src/GenPoly/LvalueNew.cpp
r2ed94a9 rb110bcc 25 25 #include "AST/Pass.hpp" 26 26 #include "Common/SemanticError.h" // for SemanticWarning 27 #include "Common/ToString.hpp" // for toCString 27 28 #include "Common/UniqueName.h" // for UniqueName 28 29 #include "GenPoly/GenPoly.h" // for genFunctionType -
src/InitTweak/FixInit.cc
r2ed94a9 rb110bcc 32 32 #include "Common/PassVisitor.h" // for PassVisitor, WithStmtsToAdd 33 33 #include "Common/SemanticError.h" // for SemanticError 34 #include "Common/ToString.hpp" // for toCString 34 35 #include "Common/UniqueName.h" // for UniqueName 35 #include "Common/utility.h" // for CodeLocation, ValueGuard, toSt...36 36 #include "FixGlobalInit.h" // for fixGlobalInit 37 37 #include "GenInit.h" // for genCtorDtor … … 1233 1233 } 1234 1234 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 1241 1235 template< typename... Params > 1242 1236 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 ); 1246 1239 } 1247 1240 -
src/InitTweak/FixInitNew.cpp
r2ed94a9 rb110bcc 14 14 #include <utility> // for pair 15 15 16 #include "AST/DeclReplacer.hpp" 17 #include "AST/Expr.hpp" 16 18 #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" 17 24 #include "CodeGen/GenType.h" // for genPrettyType 18 25 #include "CodeGen/OperatorTable.h" 19 #include "Common/CodeLocationTools.hpp"20 26 #include "Common/PassVisitor.h" // for PassVisitor, WithStmtsToAdd 21 27 #include "Common/SemanticError.h" // for SemanticError 28 #include "Common/ToString.hpp" // for toCString 22 29 #include "Common/UniqueName.h" // for UniqueName 23 #include "Common/utility.h" // for CodeLocation, ValueGuard, toSt...24 30 #include "FixGlobalInit.h" // for fixGlobalInit 25 31 #include "GenInit.h" // for genCtorDtor … … 28 34 #include "ResolvExpr/Unify.h" // for typesCompatible 29 35 #include "SymTab/Autogen.h" // for genImplicitCall 36 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 30 37 #include "SymTab/Indexer.h" // for Indexer 31 38 #include "SymTab/Mangler.h" // for Mangler … … 45 52 #include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy 46 53 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 55 54 extern bool ctordtorp; // print all debug 56 55 extern bool ctorp; // print ctor debug … … 63 62 namespace InitTweak { 64 63 namespace { 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 65 102 struct SelfAssignChecker { 66 103 void previsit( const ast::ApplicationExpr * appExpr ); … … 107 144 private: 108 145 /// 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; 111 148 }; 112 149 … … 121 158 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 122 159 123 160 protected: 124 161 ObjectSet curVars; 125 162 }; … … 202 239 203 240 SemanticErrorException errors; 204 241 private: 205 242 template< typename... Params > 206 243 void emit( CodeLocation, const Params &... params ); … … 288 325 static UniqueName dtorNamer( "__cleanup_dtor" ); 289 326 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 ); 291 328 stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) ); 292 329 … … 522 559 { 523 560 static UniqueName tempNamer("_tmp_cp"); 524 assert( env );525 561 const CodeLocation loc = impCpCtorExpr->location; 526 562 // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; ) … … 534 570 535 571 // xxx - this originally mutates arg->result in place. is it correct? 572 assert( env ); 536 573 result = env->applyFree( result.get() ).node; 537 574 auto mutResult = result.get_and_mutate(); … … 1080 1117 void InsertDtors::previsit( const ast::BranchStmt * stmt ) { 1081 1118 switch( stmt->kind ) { 1082 1083 1119 case ast::BranchStmt::Continue: 1120 case ast::BranchStmt::Break: 1084 1121 // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should 1085 1122 // always be empty), but it serves as a small sanity check. 1086 1123 case ast::BranchStmt::Goto: 1087 1124 handleGoto( stmt ); 1088 1125 break; 1089 1126 default: 1090 1127 assert( false ); 1091 1128 } // switch … … 1303 1340 } 1304 1341 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 1311 1342 template< typename... Params > 1312 1343 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 ); 1316 1346 } 1317 1347 … … 1319 1349 // xxx - functions returning ast::ptr seems wrong... 1320 1350 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(); 1324 1352 } 1325 1353 -
src/InitTweak/GenInit.cc
r2ed94a9 rb110bcc 31 31 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort... 32 32 #include "Common/SemanticError.h" // for SemanticError 33 #include "Common/ToString.hpp" // for toCString 33 34 #include "Common/UniqueName.h" // for UniqueName 34 35 #include "Common/utility.h" // for ValueGuard, maybeClone … … 38 39 #include "ResolvExpr/Resolver.h" 39 40 #include "SymTab/Autogen.h" // for genImplicitCall 41 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 40 42 #include "SymTab/Mangler.h" // for Mangler 41 43 #include "SynTree/LinkageSpec.h" // for isOverridable, C -
src/Parser/DeclarationNode.cc
r2ed94a9 rb110bcc 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 12:34:05 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Aug 8 17:07:00 202213 // Update Count : 1 18511 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Apr 20 11:46:00 2023 13 // Update Count : 1393 14 14 // 15 16 #include "DeclarationNode.h" 15 17 16 18 #include <cassert> // for assert, assertf, strict_dynamic_cast … … 21 23 #include <string> // for string, operator+, allocator, char... 22 24 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 23 35 #include "Common/SemanticError.h" // for SemanticError 24 36 #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 33 41 #include "TypeData.h" // for TypeData, TypeData::Aggregate_t 34 42 #include "TypedefTable.h" // for TypedefTable … … 41 49 42 50 // 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" }; 51 const char * DeclarationNode::basicTypeNames[] = { 52 "void", "_Bool", "char", "int", "int128", 53 "float", "double", "long double", "float80", "float128", 54 "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames" 55 }; 56 const char * DeclarationNode::complexTypeNames[] = { 57 "_Complex", "NoComplexTypeNames", "_Imaginary" 58 }; // Imaginary unsupported => parse, but make invisible and print error message 59 const char * DeclarationNode::signednessNames[] = { 60 "signed", "unsigned", "NoSignednessNames" 61 }; 62 const char * DeclarationNode::lengthNames[] = { 63 "short", "long", "long long", "NoLengthNames" 64 }; 65 const char * DeclarationNode::builtinTypeNames[] = { 66 "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" 67 }; 50 68 51 69 UniqueName DeclarationNode::anonymous( "__anonymous" ); 52 70 53 extern LinkageSpec::Spec linkage; // defined in parser.yy71 extern ast::Linkage::Spec linkage; // defined in parser.yy 54 72 55 73 DeclarationNode::DeclarationNode() : … … 57 75 58 76 // variable.name = nullptr; 59 variable.tyClass = TypeDecl::NUMBER_OF_KINDS;77 variable.tyClass = ast::TypeDecl::NUMBER_OF_KINDS; 60 78 variable.assertions = nullptr; 61 79 variable.initializer = nullptr; 62 80 63 // attr.name = nullptr;64 attr.expr = nullptr;65 attr.type = nullptr;66 67 81 assert.condition = nullptr; 68 82 assert.message = nullptr; … … 70 84 71 85 DeclarationNode::~DeclarationNode() { 72 // delete attr.name;73 delete attr.expr;74 delete attr.type;75 76 86 // delete variable.name; 77 87 delete variable.assertions; 78 88 delete variable.initializer; 79 89 80 // 90 // delete type; 81 91 delete bitfieldWidth; 82 92 … … 103 113 newnode->hasEllipsis = hasEllipsis; 104 114 newnode->linkage = linkage; 105 newnode->asmName = maybeC lone( asmName );106 cloneAll( attributes, newnode->attributes );115 newnode->asmName = maybeCopy( asmName ); 116 newnode->attributes = attributes; 107 117 newnode->initializer = maybeClone( initializer ); 108 118 newnode->extension = extension; … … 115 125 newnode->variable.initializer = maybeClone( variable.initializer ); 116 126 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 121 127 newnode->assert.condition = maybeClone( assert.condition ); 122 newnode->assert.message = maybeC lone( assert.message );128 newnode->assert.message = maybeCopy( assert.message ); 123 129 return newnode; 124 130 } // DeclarationNode::clone … … 130 136 } // if 131 137 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 ); 138 144 139 145 if ( type ) { … … 154 160 } // if 155 161 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 159 168 160 169 os << endl; … … 168 177 } 169 178 170 DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) {179 DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) { 171 180 DeclarationNode * newnode = new DeclarationNode; 172 181 newnode->storageClasses = sc; … … 174 183 } // DeclarationNode::newStorageClass 175 184 176 DeclarationNode * DeclarationNode::newFuncSpecifier( Type::FuncSpecifiers fs ) {185 DeclarationNode * DeclarationNode::newFuncSpecifier( ast::Function::Specs fs ) { 177 186 DeclarationNode * newnode = new DeclarationNode; 178 187 newnode->funcSpecs = fs; … … 180 189 } // DeclarationNode::newFuncSpecifier 181 190 182 DeclarationNode * DeclarationNode::newTypeQualifier( Type::Qualifiers tq ) {191 DeclarationNode * DeclarationNode::newTypeQualifier( ast::CV::Qualifiers tq ) { 183 192 DeclarationNode * newnode = new DeclarationNode; 184 193 newnode->type = new TypeData(); … … 240 249 } 241 250 242 DeclarationNode * DeclarationNode::newAggregate( AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {251 DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) { 243 252 DeclarationNode * newnode = new DeclarationNode; 244 253 newnode->type = new TypeData( TypeData::Aggregate ); 245 254 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; 247 257 newnode->type->aggregate.actuals = actuals; 248 258 newnode->type->aggregate.fields = fields; … … 250 260 newnode->type->aggregate.tagged = false; 251 261 newnode->type->aggregate.parent = nullptr; 252 newnode->type->aggregate.anon = name == nullptr;253 262 return newnode; 254 263 } // DeclarationNode::newAggregate … … 257 266 DeclarationNode * newnode = new DeclarationNode; 258 267 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; 260 270 newnode->type->enumeration.constants = constants; 261 271 newnode->type->enumeration.body = body; 262 newnode->type->enumeration.anon = name == nullptr;263 272 newnode->type->enumeration.typed = typed; 264 273 newnode->type->enumeration.hiding = hiding; 265 if ( base && base->type ) {274 if ( base && base->type ) { 266 275 newnode->type->base = base->type; 267 276 } // if … … 269 278 return newnode; 270 279 } // DeclarationNode::newEnum 271 272 273 280 274 281 DeclarationNode * DeclarationNode::newName( const string * name ) { … … 323 330 } // DeclarationNode::newFromTypeGen 324 331 325 DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {332 DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) { 326 333 DeclarationNode * newnode = newName( name ); 327 334 newnode->type = nullptr; … … 335 342 newnode->type = new TypeData( TypeData::Aggregate ); 336 343 newnode->type->aggregate.name = name; 337 newnode->type->aggregate.kind = AggregateDecl::Trait;344 newnode->type->aggregate.kind = ast::AggregateDecl::Trait; 338 345 newnode->type->aggregate.params = params; 339 346 newnode->type->aggregate.fields = asserts; … … 345 352 newnode->type = new TypeData( TypeData::AggregateInst ); 346 353 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; 348 355 newnode->type->aggInst.aggregate->aggregate.name = name; 349 356 newnode->type->aggInst.params = params; … … 380 387 newnode->type->array.dimension = size; 381 388 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 *>() ) { 383 390 newnode->type->array.isVarLen = false; 384 391 } else { … … 450 457 DeclarationNode * newnode = new DeclarationNode; 451 458 newnode->type = nullptr; 452 std:: list< Expression *> exprs;459 std::vector<ast::ptr<ast::Expr>> exprs; 453 460 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 ) ) ); 455 463 delete name; 456 464 return newnode; … … 469 477 } 470 478 471 DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, Expression* message ) {479 DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, ast::Expr * message ) { 472 480 DeclarationNode * newnode = new DeclarationNode; 473 481 newnode->assert.condition = condition; … … 476 484 } 477 485 478 479 void appendError( string & dst, const string & src ) { 486 static void appendError( string & dst, const string & src ) { 480 487 if ( src.empty() ) return; 481 488 if ( dst.empty() ) { dst = src; return; } … … 484 491 485 492 void 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() ); 494 502 } // for 495 503 } // DeclarationNode::checkQualifiers 496 504 497 505 void 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 } 519 537 } // if 520 538 … … 526 544 storageClasses |= q->storageClasses; 527 545 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 531 553 return this; 532 554 } // DeclarationNode::copySpecifiers … … 576 598 577 599 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] ); 580 602 } // if 581 603 addQualifiersToType( q->type, type ); … … 598 620 } else { 599 621 switch ( dst->kind ) { 600 622 case TypeData::Unknown: 601 623 src->qualifiers |= dst->qualifiers; 602 624 dst = src; 603 625 src = nullptr; 604 626 break; 605 627 case TypeData::Basic: 606 628 dst->qualifiers |= src->qualifiers; 607 629 if ( src->kind != TypeData::Unknown ) { … … 631 653 } // if 632 654 break; 633 655 default: 634 656 switch ( src->kind ) { 635 636 657 case TypeData::Aggregate: 658 case TypeData::Enum: 637 659 dst->base = new TypeData( TypeData::AggregateInst ); 638 660 dst->base->aggInst.aggregate = src; … … 643 665 src = nullptr; 644 666 break; 645 667 default: 646 668 if ( dst->forall ) { 647 669 dst->forall->appendList( src->forall ); … … 714 736 715 737 DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) { 716 if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {717 718 719 720 721 722 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; 723 745 } // if 724 746 725 747 assert( type ); 726 748 switch ( type->kind ) { 727 749 case TypeData::Symbolic: 728 750 if ( type->symbolic.assertions ) { 729 751 type->symbolic.assertions->appendList( assertions ); … … 732 754 } // if 733 755 break; 734 756 default: 735 757 assert( false ); 736 758 } // switch … … 796 818 DeclarationNode * DeclarationNode::copyAttribute( DeclarationNode * a ) { 797 819 if ( a ) { 798 for ( Attribute *attr: reverseIterate( a->attributes ) ) { 799 attributes.push_front( attr ); 800 } // for 820 spliceBegin( attributes, a->attributes ); 801 821 a->attributes.clear(); 802 822 } // if … … 831 851 if ( type ) { 832 852 switch ( type->kind ) { 833 834 853 case TypeData::Aggregate: 854 case TypeData::Enum: 835 855 p->type->base = new TypeData( TypeData::AggregateInst ); 836 856 p->type->base->aggInst.aggregate = type; … … 841 861 break; 842 862 843 863 default: 844 864 p->type->base = type; 845 865 } // switch … … 863 883 864 884 DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) { 865 885 if ( ! a ) return this; 866 886 assert( a->type->kind == TypeData::Array ); 867 887 TypeData * lastArray = findLast( a->type ); 868 888 if ( type ) { 869 889 switch ( type->kind ) { 870 871 890 case TypeData::Aggregate: 891 case TypeData::Enum: 872 892 lastArray->base = new TypeData( TypeData::AggregateInst ); 873 893 lastArray->base->aggInst.aggregate = type; … … 877 897 lastArray->base->qualifiers |= type->qualifiers; 878 898 break; 879 899 default: 880 900 lastArray->base = type; 881 901 } // switch … … 919 939 920 940 DeclarationNode * 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." ); 922 942 variable.initializer = init; 923 943 return this; … … 983 1003 } 984 1004 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. 1007 static void nameTypedefedDecl( 1008 DeclarationNode * innerDecl, 1009 const DeclarationNode * outerDecl ) { 1010 TypeData * outer = outerDecl->type; 1011 assert( outer ); 1012 // First make sure this is a typedef: 1013 if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) { 1014 return; 1015 } 1016 TypeData * inner = innerDecl->type; 1017 assert( inner ); 1018 // Always clear any CVs associated with the aggregate: 1019 inner->qualifiers.reset(); 1020 // Handle anonymous aggregates: typedef struct { int i; } foo 1021 if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) { 1022 delete inner->aggregate.name; 1023 inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name ); 1024 inner->aggregate.anon = false; 1025 assert( outer->base ); 1026 delete outer->base->aggInst.aggregate->aggregate.name; 1027 outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name ); 1028 outer->base->aggInst.aggregate->aggregate.anon = false; 1029 outer->base->aggInst.aggregate->qualifiers.reset(); 1030 // Handle anonymous enumeration: typedef enum { A, B, C } foo 1031 } else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) { 1032 delete inner->enumeration.name; 1033 inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name ); 1034 inner->enumeration.anon = false; 1035 assert( outer->base ); 1036 delete outer->base->aggInst.aggregate->enumeration.name; 1037 outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name ); 1038 outer->base->aggInst.aggregate->enumeration.anon = false; 1039 // No qualifiers.reset() here. 1040 } 1041 } 1042 1043 // This code handles a special issue with the attribute transparent_union. 1044 // 1045 // typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union )) 1046 // 1047 // Here the attribute aligned goes with the typedef_name, so variables declared of this type are 1048 // aligned. However, the attribute transparent_union must be moved from the typedef_name to 1049 // alias union U. Currently, this is the only know attribute that must be moved from typedef to 1050 // alias. 1051 static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) { 1052 if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) { 1053 // Is the typedef alias a union aggregate? 1054 if ( nullptr == unionDecl ) return; 1055 1056 // If typedef is an alias for a union, then its alias type was hoisted above and remembered. 1057 if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) { 1058 auto instType = ast::mutate( unionInstType ); 1059 // Remove all transparent_union attributes from typedef and move to alias union. 1060 for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) { 1061 assert( *attr ); 1062 if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) { 1063 unionDecl->attributes.emplace_back( attr->release() ); 1064 attr = instType->attributes.erase( attr ); 1065 } else { 1066 attr++; 1067 } 1068 } 1069 typedefDecl->base = instType; 1070 } 1071 } 1072 } 1073 1074 // Get the non-anonymous name of the instance type of the declaration, 1075 // if one exists. 1076 static const std::string * getInstTypeOfName( ast::Decl * decl ) { 1077 if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) { 1078 if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) { 1079 if ( aggr->name.find("anonymous") == std::string::npos ) { 1080 return &aggr->name; 1081 } 1082 } 1083 } 1084 return nullptr; 1085 } 1086 1087 void buildList( DeclarationNode * firstNode, 1088 std::vector<ast::ptr<ast::Decl>> & outputList ) { 986 1089 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 ) ) { 990 1093 try { 991 bool extracted = false; 992 bool anon = false; 1094 bool extracted_named = false; 1095 ast::UnionDecl * unionDecl = nullptr; 1096 993 1097 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; 1000 1106 1001 1107 // need to remember the cases where a declaration contains an anonymous aggregate definition 1002 extracted = true;1003 1108 assert( extr->type ); 1004 1109 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; 1006 1112 } 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; 1009 1117 } 1010 1118 } // if … … 1012 1120 } // if 1013 1121 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 } 1038 1142 } // if 1143 *out++ = decl; 1039 1144 } // if 1040 } catch ( SemanticErrorException & e ) {1145 } catch ( SemanticErrorException & e ) { 1041 1146 errors.append( e ); 1042 1147 } // try … … 1049 1154 1050 1155 // currently only builds assertions, function parameters, and return values 1051 void buildList( const DeclarationNode * firstNode, std::list< DeclarationWithType *> & outputList ) {1156 void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) { 1052 1157 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 ) ) { 1056 1161 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 ) ) { 1060 1165 dwt->location = cur->location; 1061 1166 *out++ = dwt; 1062 } else if ( StructDecl * agg = dynamic_cast< StructDecl *>( decl ) ) {1167 } else if ( ast::StructDecl * agg = dynamic_cast<ast::StructDecl *>( decl ) ) { 1063 1168 // 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->l ocation = cur->location;1169 auto inst = new ast::StructInstType( agg->name ); 1170 auto obj = new ast::ObjectDecl( cur->location, "", inst ); 1171 obj->linkage = linkage; 1067 1172 *out++ = obj; 1068 1173 delete agg; 1069 } else if ( UnionDecl * agg = dynamic_cast< UnionDecl *>( decl ) ) {1174 } else if ( ast::UnionDecl * agg = dynamic_cast<ast::UnionDecl *>( decl ) ) { 1070 1175 // 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 ); 1074 1180 *out++ = obj; 1075 } else if ( EnumDecl * agg = dynamic_cast< EnumDecl *>( decl ) ) {1181 } else if ( ast::EnumDecl * agg = dynamic_cast<ast::EnumDecl *>( decl ) ) { 1076 1182 // 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 ); 1080 1191 *out++ = obj; 1192 } else { 1193 assertf( false, "buildList: Could not convert to ast::DeclWithType." ); 1081 1194 } // if 1082 } catch ( SemanticErrorException & e ) {1195 } catch ( SemanticErrorException & e ) { 1083 1196 errors.append( e ); 1084 1197 } // try … … 1090 1203 } // buildList 1091 1204 1092 void buildTypeList( const DeclarationNode * firstNode, std::list< Type * > & outputList ) { 1205 void buildTypeList( const DeclarationNode * firstNode, 1206 std::vector<ast::ptr<ast::Type>> & outputList ) { 1093 1207 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 ) ) { 1098 1211 try { 1099 1212 * out++ = cur->buildType(); 1100 } catch ( SemanticErrorException & e ) {1213 } catch ( SemanticErrorException & e ) { 1101 1214 errors.append( e ); 1102 1215 } // try 1103 cur = dynamic_cast< DeclarationNode * >( cur->get_next() ); 1104 } // while 1216 } // for 1105 1217 1106 1218 if ( ! errors.isEmpty() ) { … … 1109 1221 } // buildTypeList 1110 1222 1111 Declaration* DeclarationNode::build() const {1223 ast::Decl * DeclarationNode::build() const { 1112 1224 if ( ! error.empty() ) SemanticError( this, error + " in declaration of " ); 1113 1225 1114 1226 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 ); 1116 1229 } // if 1117 1230 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 ) { 1122 1236 // 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." ); 1125 1239 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 ); 1128 1249 return ret; 1129 1250 } // if … … 1147 1268 } // if 1148 1269 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 ); 1150 1281 if ( isDelete ) { 1151 DeclarationWithType * dwt = strict_dynamic_cast<DeclarationWithType *>( decl );1282 auto dwt = strict_dynamic_cast<ast::DeclWithType *>( decl ); 1152 1283 dwt->isDeleted = true; 1153 1284 } … … 1156 1287 1157 1288 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 ); 1159 1292 } 1160 1293 … … 1167 1300 } // if 1168 1301 if ( enumInLine ) { 1169 return new InlineMemberDecl( *name, storageClasses, linkage, nullptr ); 1302 return new ast::InlineMemberDecl( location, 1303 *name, (ast::Type*)nullptr, storageClasses, linkage ); 1170 1304 } // if 1171 1305 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 1319 ast::Type * DeclarationNode::buildType() const { 1176 1320 assert( type ); 1177 1321 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 } // if1183 1184 1322 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; 1199 1344 return simpletypes; 1200 1345 } // switch -
src/Parser/ExpressionNode.cc
r2ed94a9 rb110bcc 9 9 // Author : Peter A. Buhr 10 10 // 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" 15 17 16 18 #include <cassert> // for assert … … 21 23 #include <string> // for string, operator+, operator== 22 24 25 #include "AST/Expr.hpp" // for NameExpr 26 #include "AST/Type.hpp" // for BaseType, SueInstType 23 27 #include "Common/SemanticError.h" // for SemanticError 24 28 #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 31 31 #include "parserutility.h" // for notZeroExpr 32 33 class Initializer;34 32 35 33 using namespace std; … … 48 46 // because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their 49 47 // type. 50 51 extern const Type::Qualifiers noQualifiers; // no qualifiers on constants52 48 53 49 // static inline bool checkH( char c ) { return c == 'h' || c == 'H'; } … … 71 67 size_t end = str.length() - 1; 72 68 if ( posn == end ) { type = 3; return; } // no length after 'l' => long 73 69 74 70 string::size_type next = posn + 1; // advance to length 75 71 if ( str[next] == '3' ) { // 32 … … 122 118 if ( str[i] == '1' ) v |= 1; 123 119 i += 1; 124 120 if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break; 125 121 v <<= 1; 126 122 } // for 127 123 } // scanbin 128 124 129 Expression * build_constantInteger( string & str ) { 130 static const BasicType::Kind kind[2][6] = { 125 ast::Expr * build_constantInteger( 126 const CodeLocation & location, string & str ) { 127 static const ast::BasicType::Kind kind[2][6] = { 131 128 // 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, }, 134 131 }; 135 132 … … 141 138 string str2( "0x0" ); 142 139 unsigned long long int v, v2 = 0; // converted integral value 143 Expression* ret, * ret2;140 ast::Expr * ret, * ret2; 144 141 145 142 int type = -1; // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128 … … 149 146 // special constants 150 147 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 ); 152 149 goto CLEANUP; 153 150 } // if 154 151 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 ); 156 153 goto CLEANUP; 157 154 } // if 158 159 string::size_type posn;160 155 161 156 // 'u' can appear before or after length suffix … … 166 161 } else { 167 162 // 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 191 190 } // if 192 191 … … 196 195 if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target " + str ); 197 196 #endif // ! __SIZEOF_INT128__ 198 197 199 198 if ( str[0] == '0' ) { // radix character ? 200 199 dec = false; … … 206 205 unsigned int len = str.length(); 207 206 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 213 213 sscanf( (char *)str.c_str(), "%llx", &v ); 214 214 #endif // __SIZEOF_INT128__ … … 301 301 302 302 // 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 ); 304 305 if ( Unsigned && type < 2 ) { // hh or h, less than int ? 305 306 // 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 ); 307 311 } else if ( ltype != -1 ) { // explicit length ? 308 312 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 ); 313 325 } 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 ); 315 330 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 ) ); 317 335 } // if 318 336 } // if … … 358 376 359 377 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 }, 378 ast::Expr * build_constantFloat( 379 const CodeLocation & location, string & str ) { 380 static const ast::BasicType::Kind kind[2][12] = { 381 { ast::BasicType::Float, ast::BasicType::Double, ast::BasicType::LongDouble, ast::BasicType::uuFloat80, ast::BasicType::uuFloat128, ast::BasicType::uFloat16, ast::BasicType::uFloat32, ast::BasicType::uFloat32x, ast::BasicType::uFloat64, ast::BasicType::uFloat64x, ast::BasicType::uFloat128, ast::BasicType::uFloat128x }, 382 { ast::BasicType::FloatComplex, ast::BasicType::DoubleComplex, ast::BasicType::LongDoubleComplex, ast::BasicType::NUMBER_OF_BASIC_TYPES, ast::BasicType::NUMBER_OF_BASIC_TYPES, ast::BasicType::uFloat16Complex, ast::BasicType::uFloat32Complex, ast::BasicType::uFloat32xComplex, ast::BasicType::uFloat64Complex, ast::BasicType::uFloat64xComplex, ast::BasicType::uFloat128Complex, ast::BasicType::uFloat128xComplex }, 364 383 }; 365 384 … … 398 417 399 418 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 ); 403 429 } // if 404 430 … … 415 441 } // sepString 416 442 417 Expression * build_constantChar(string & str ) {443 ast::Expr * build_constantChar( const CodeLocation & location, string & str ) { 418 444 string units; // units 419 445 sepString( str, units, '\'' ); // separate constant from units 420 446 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] ); 422 451 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 } ); 424 455 } // if 425 456 … … 428 459 } // build_constantChar 429 460 430 Expression * build_constantStr( string & str ) { 461 ast::Expr * build_constantStr( 462 const CodeLocation & location, 463 string & str ) { 431 464 assert( str.length() > 0 ); 432 465 string units; // units 433 466 sepString( str, units, '"' ); // separate constant from units 434 467 435 Type * strtype;468 ast::Type * strtype; 436 469 switch ( str[0] ) { // str has >= 2 characters, i.e, null string "" => safe to look at subscripts 0/1 437 470 case 'u': 438 471 if ( str[1] == '8' ) goto Default; // utf-8 characters => array of char 439 472 // lookup type of associated typedef 440 strtype = new TypeInstType( Type::Qualifiers( ), "char16_t", false );473 strtype = new ast::TypeInstType( "char16_t", ast::TypeDecl::Dtype ); 441 474 break; 442 443 strtype = new TypeInstType( Type::Qualifiers( ), "char32_t", false );475 case 'U': 476 strtype = new ast::TypeInstType( "char32_t", ast::TypeDecl::Dtype ); 444 477 break; 445 446 strtype = new TypeInstType( Type::Qualifiers( ), "wchar_t", false );478 case 'L': 479 strtype = new ast::TypeInstType( "wchar_t", ast::TypeDecl::Dtype ); 447 480 break; 448 449 450 strtype = new BasicType( Type::Qualifiers( ),BasicType::Char );481 Default: // char default string type 482 default: 483 strtype = new ast::BasicType( ast::BasicType::Char ); 451 484 } // 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 ); 456 492 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 } ); 458 496 } // if 459 497 … … 462 500 } // build_constantStr 463 501 464 Expression * build_field_name_FLOATING_FRACTIONconstant( const string & str ) { 502 ast::Expr * build_field_name_FLOATING_FRACTIONconstant( 503 const CodeLocation & location, const string & str ) { 465 504 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) ) ); 467 507 delete &str; 468 508 return ret; 469 509 } // build_field_name_FLOATING_FRACTIONconstant 470 510 471 Expression * build_field_name_FLOATING_DECIMALconstant( const string & str ) { 511 ast::Expr * build_field_name_FLOATING_DECIMALconstant( 512 const CodeLocation & location, const string & str ) { 472 513 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 ) ) ); 474 516 delete &str; 475 517 return ret; 476 518 } // build_field_name_FLOATING_DECIMALconstant 477 519 478 Expression * build_field_name_FLOATINGconstant( const string & str ) { 520 ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation & location, 521 const string & str ) { 479 522 // str is of the form A.B -> separate at the . and return member expression 480 523 int a, b; … … 482 525 stringstream ss( str ); 483 526 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 ); 485 531 delete &str; 486 532 return ret; 487 533 } // build_field_name_FLOATINGconstant 488 534 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; 535 ast::Expr * make_field_name_fraction_constants( const CodeLocation & location, 536 ast::Expr * fieldName, 537 ast::Expr * fracts ) { 538 if ( nullptr == fracts ) { 539 return fieldName; 540 } else if ( auto memberExpr = dynamic_cast<ast::UntypedMemberExpr *>( fracts ) ) { 541 memberExpr->member = make_field_name_fraction_constants( location, 542 fieldName, 543 ast::mutate( memberExpr->aggregate.get() ) ); 544 return memberExpr; 545 } else { 546 return new ast::UntypedMemberExpr( location, fracts, fieldName ); 547 } // if 499 548 } // make_field_name_fraction_constants 500 549 501 Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ) { 502 return make_field_name_fraction_constants( fieldName, maybeMoveBuild< Expression >( fracts ) ); 550 ast::Expr * build_field_name_fraction_constants( const CodeLocation & location, 551 ast::Expr * fieldName, 552 ExpressionNode * fracts ) { 553 return make_field_name_fraction_constants( location, fieldName, maybeMoveBuild( fracts ) ); 503 554 } // build_field_name_fraction_constants 504 555 505 NameExpr * build_varref( const string * name ) { 506 NameExpr * expr = new NameExpr( *name ); 556 ast::NameExpr * build_varref( const CodeLocation & location, 557 const string * name ) { 558 ast::NameExpr * expr = new ast::NameExpr( location, *name ); 507 559 delete name; 508 560 return expr; 509 561 } // build_varref 510 562 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 ); 563 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location, 564 const DeclarationNode * decl_node, 565 const ast::NameExpr * name ) { 566 ast::Decl * newDecl = maybeBuild( decl_node ); 567 if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) { 568 if ( const ast::Type * t = newDeclWithType->get_type() ) { 569 if ( auto typeInst = dynamic_cast<const ast::TypeInstType *>( t ) ) { 570 newDecl = new ast::EnumDecl( location, typeInst->name ); 518 571 } 519 572 } 520 573 } 521 return new QualifiedNameExpr(newDecl, name->name );574 return new ast::QualifiedNameExpr( location, newDecl, name->name ); 522 575 } 523 576 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 ); 577 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location, 578 const ast::EnumDecl * decl, 579 const ast::NameExpr * name ) { 580 return new ast::QualifiedNameExpr( location, decl, name->name ); 527 581 } 528 582 529 DimensionExpr * build_dimensionref( const string * name ) { 530 DimensionExpr * expr = new DimensionExpr( *name ); 583 ast::DimensionExpr * build_dimensionref( const CodeLocation & location, 584 const string * name ) { 585 ast::DimensionExpr * expr = new ast::DimensionExpr( location, *name ); 531 586 delete name; 532 587 return expr; … … 544 599 }; // OperName 545 600 546 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) { 547 Type * targetType = maybeMoveBuildType( decl_node ); 548 if ( dynamic_cast< VoidType * >( targetType ) ) { 601 ast::Expr * build_cast( const CodeLocation & location, 602 DeclarationNode * decl_node, 603 ExpressionNode * expr_node ) { 604 ast::Type * targetType = maybeMoveBuildType( decl_node ); 605 if ( dynamic_cast<ast::VoidType *>( targetType ) ) { 549 606 delete targetType; 550 return new CastExpr( maybeMoveBuild< Expression >(expr_node), false ); 607 return new ast::CastExpr( location, 608 maybeMoveBuild( expr_node ), 609 ast::ExplicitCast ); 551 610 } 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 ); 553 615 } // if 554 616 } // build_cast 555 617 556 Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node ) { 557 return new KeywordCastExpr( maybeMoveBuild< Expression >(expr_node), target ); 618 ast::Expr * build_keyword_cast( const CodeLocation & location, 619 ast::AggregateDecl::Aggregate target, 620 ExpressionNode * expr_node ) { 621 return new ast::KeywordCastExpr( location, 622 maybeMoveBuild( expr_node ), 623 target 624 ); 558 625 } 559 626 560 Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) { 561 return new VirtualCastExpr( maybeMoveBuild< Expression >( expr_node ), maybeMoveBuildType( decl_node ) ); 627 ast::Expr * build_virtual_cast( const CodeLocation & location, 628 DeclarationNode * decl_node, 629 ExpressionNode * expr_node ) { 630 return new ast::VirtualCastExpr( location, 631 maybeMoveBuild( expr_node ), 632 maybeMoveBuildType( decl_node ) 633 ); 562 634 } // build_virtual_cast 563 635 564 Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member ) { 565 return new UntypedMemberExpr( member, maybeMoveBuild< Expression >(expr_node) ); 636 ast::Expr * build_fieldSel( const CodeLocation & location, 637 ExpressionNode * expr_node, 638 ast::Expr * member ) { 639 return new ast::UntypedMemberExpr( location, 640 member, 641 maybeMoveBuild( expr_node ) 642 ); 566 643 } // build_fieldSel 567 644 568 Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member ) { 569 UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) ); 645 ast::Expr * build_pfieldSel( const CodeLocation & location, 646 ExpressionNode * expr_node, 647 ast::Expr * member ) { 648 auto deref = new ast::UntypedExpr( location, 649 new ast::NameExpr( location, "*?" ) 650 ); 570 651 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 ); 573 654 return ret; 574 655 } // build_pfieldSel 575 656 576 Expression * build_offsetOf( DeclarationNode * decl_node, NameExpr * member ) { 577 Expression * ret = new UntypedOffsetofExpr( maybeMoveBuildType( decl_node ), member->get_name() ); 657 ast::Expr * build_offsetOf( const CodeLocation & location, 658 DeclarationNode * decl_node, 659 ast::NameExpr * member ) { 660 ast::Expr * ret = new ast::UntypedOffsetofExpr( location, 661 maybeMoveBuildType( decl_node ), 662 member->name 663 ); 664 ret->result = new ast::BasicType( ast::BasicType::LongUnsignedInt ); 578 665 delete member; 579 666 return ret; 580 667 } // build_offsetOf 581 668 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 ); 669 ast::Expr * build_and_or( const CodeLocation & location, 670 ExpressionNode * expr_node1, 671 ExpressionNode * expr_node2, 672 ast::LogicalFlag flag ) { 673 return new ast::LogicalExpr( location, 674 notZeroExpr( maybeMoveBuild( expr_node1 ) ), 675 notZeroExpr( maybeMoveBuild( expr_node2 ) ), 676 flag 677 ); 584 678 } // build_and_or 585 679 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 ); 680 ast::Expr * build_unary_val( const CodeLocation & location, 681 OperKinds op, 682 ExpressionNode * expr_node ) { 683 std::vector<ast::ptr<ast::Expr>> args; 684 args.push_back( maybeMoveBuild( expr_node ) ); 685 return new ast::UntypedExpr( location, 686 new ast::NameExpr( location, OperName[ (int)op ] ), 687 std::move( args ) 688 ); 590 689 } // build_unary_val 591 690 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);691 ast::Expr * build_binary_val( const CodeLocation & location, 692 OperKinds op, 693 ExpressionNode * expr_node1, 694 ExpressionNode * expr_node2 ) { 695 std::vector<ast::ptr<ast::Expr>> args; 696 args.push_back( maybeMoveBuild( expr_node1 ) ); 697 args.push_back( maybeMoveBuild( expr_node2 ) ); 698 return new ast::UntypedExpr( location, 699 new ast::NameExpr( location, OperName[ (int)op ] ), 700 std::move( args ) 701 ); 603 702 } // build_binary_val 604 703 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));704 ast::Expr * build_cond( const CodeLocation & location, 705 ExpressionNode * expr_node1, 706 ExpressionNode * expr_node2, 707 ExpressionNode * expr_node3 ) { 708 return new ast::ConditionalExpr( location, 709 notZeroExpr( maybeMoveBuild( expr_node1 ) ), 710 maybeMoveBuild( expr_node2 ), 711 maybeMoveBuild( expr_node3 ) 712 ); 614 713 } // build_cond 615 714 616 Expression * build_tuple( ExpressionNode * expr_node ) { 617 list< Expression * > exprs; 715 ast::Expr * build_tuple( const CodeLocation & location, 716 ExpressionNode * expr_node ) { 717 std::vector<ast::ptr<ast::Expr>> exprs; 618 718 buildMoveList( expr_node, exprs ); 619 return new UntypedTupleExpr( exprs );;719 return new ast::UntypedTupleExpr( location, std::move( exprs ) ); 620 720 } // build_tuple 621 721 622 Expression * build_func( ExpressionNode * function, ExpressionNode * expr_node ) { 623 list< Expression * > args; 722 ast::Expr * build_func( const CodeLocation & location, 723 ExpressionNode * function, 724 ExpressionNode * expr_node ) { 725 std::vector<ast::ptr<ast::Expr>> args; 624 726 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 ); 626 731 } // build_func 627 732 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) ); 733 ast::Expr * build_compoundLiteral( const CodeLocation & location, 734 DeclarationNode * decl_node, 735 InitializerNode * kids ) { 736 // compound literal type 737 ast::Decl * newDecl = maybeBuild( decl_node ); 738 // non-sue compound-literal type 739 if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) { 740 return new ast::CompoundLiteralExpr( location, 741 newDeclWithType->get_type(), 742 maybeMoveBuild( kids ) ); 632 743 // 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 ) ); 636 749 } 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 ) ); 642 759 } 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 ) ); 648 769 } 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 ) ); 650 773 } // if 651 774 } else { … … 656 779 // Local Variables: // 657 780 // tab-width: 4 // 658 // mode: c++ //659 // compile-command: "make install" //660 781 // End: // -
src/Parser/InitializerNode.cc
r2ed94a9 rb110bcc 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 13:20:24 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 28 23:27:20 201713 // Update Count : 2 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Apr 4 11:18:00 2023 13 // Update Count : 27 14 14 // 15 16 #include "InitializerNode.h" 15 17 16 18 #include <iostream> // for operator<<, ostream, basic_ostream … … 18 20 #include <string> // for operator<<, string 19 21 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 20 29 using namespace std; 21 30 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 31 static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) { 32 return maybeConstructed ? ast::MaybeConstruct : ast::NoConstruct; 33 } 27 34 28 35 InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des ) … … 33 40 if ( kids ) 34 41 set_last( nullptr ); 35 } // InitializerNode::InitializerNode 42 } // InitializerNode::InitializerNode 36 43 37 44 InitializerNode::InitializerNode( InitializerNode * init, bool aggrp, ExpressionNode * des ) … … 85 92 } // InitializerNode::printOneLine 86 93 87 Initializer* InitializerNode::build() const {94 ast::Init * InitializerNode::build() const { 88 95 assertf( ! isDelete, "Should not build delete stmt InitializerNode" ); 89 96 if ( aggregate ) { 90 97 // steal designators from children 91 std:: list< Designation *> designlist;98 std::vector<ast::ptr<ast::Designation>> designlist; 92 99 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 ) ) ); 97 105 } // 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 ); 106 119 } // if 107 120 return nullptr; -
src/Parser/ParseNode.h
r2ed94a9 rb110bcc 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 13:28:16 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Nov 2 21:27:07 202213 // Update Count : 9 3911 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Apr 3 17:55:00 2023 13 // Update Count : 942 14 14 // 15 15 … … 24 24 #include <string> // for string 25 25 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 26 29 #include "Common/CodeLocation.h" // for CodeLocation 27 30 #include "Common/SemanticError.h" // for SemanticError 28 31 #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 36 34 37 35 class Attribute; … … 40 38 class DeclarationWithType; 41 39 class Initializer; 40 class InitializerNode; 42 41 class ExpressionNode; 43 42 struct StatementNode; … … 82 81 }; // ParseNode 83 82 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 list114 InitializerNode * kids;115 bool maybeConstructed;116 bool isDelete;117 }; // InitializerNode118 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 implications141 private:142 bool extension = false;143 }; // ExpressionNode144 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 } // if156 }157 };158 159 83 // Must harmonize with OperName. 160 84 enum class OperKinds { … … 172 96 173 97 struct LabelNode { 174 std:: list< Label> labels;98 std::vector<ast::Label> labels; 175 99 }; 176 100 177 Expression * build_constantInteger( std::string & str ); // these 4 routines modify the string178 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 message219 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 attributes259 static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement260 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement261 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 functions289 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 }; // DeclarationNode362 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 }; // StatementNode397 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 } // if466 } catch( SemanticErrorException & e ) {467 errors.append( e );468 } // try469 const ParseNode * temp = (cur->get_next());470 cur = dynamic_cast< const NodeType * >( temp ); // should not return nullptr471 if ( ! cur && temp ) { // non-homogeneous nodes ?472 SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );473 } // if474 } // while475 if ( ! errors.isEmpty() ) {476 throw errors;477 } // if478 }479 480 // in DeclarationNode.cc481 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.cc492 101 std::ostream & operator<<( std::ostream & out, const ParseNode * node ); 493 102 -
src/Parser/ParserTypes.h
r2ed94a9 rb110bcc 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. 6 // 7 // parser.hh -- 8 // 6 // 7 // parser.hh -- 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Sep 22 08:58:10 2001 -
src/Parser/RunParser.cpp
r2ed94a9 rb110bcc 10 10 // Created On : Mon Dec 19 11:00:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Dec 22 10:18:00 202213 // Update Count : 112 // Last Modified On : Mon Mar 6 9:42:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 20 20 #include "CodeTools/TrackLoc.h" // for fillLocations 21 21 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 22 #include "Parser/ ParseNode.h"// for DeclarationNode, buildList22 #include "Parser/DeclarationNode.h" // for DeclarationNode, buildList 23 23 #include "Parser/TypedefTable.h" // for TypedefTable 24 24 25 25 // Variables global to the parsing code. 26 LinkageSpec::Spec linkage = LinkageSpec::Cforall;26 ast::Linkage::Spec linkage = ast::Linkage::Cforall; 27 27 TypedefTable typedefTable; 28 28 DeclarationNode * parseTree = nullptr; 29 29 30 void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit ) {30 void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit ) { 31 31 extern int yyparse( void ); 32 32 extern FILE * yyin; … … 46 46 47 47 ast::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 ); 51 50 delete parseTree; 52 51 parseTree = nullptr; 53 52 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 } 60 57 return transUnit; 61 58 } -
src/Parser/RunParser.hpp
r2ed94a9 rb110bcc 10 10 // Created On : Mon Dec 19 10:42:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Dec 22 10:23:00 202213 // Update Count : 112 // Last Modified On : Thr Feb 16 10:08:00 2023 13 // Update Count : 2 14 14 // 15 15 … … 18 18 #include <iosfwd> // for ostream 19 19 20 #include " SynTree/LinkageSpec.h"// for Spec20 #include "AST/LinkageSpec.hpp" // for Spec 21 21 namespace ast { 22 22 class TranslationUnit; … … 29 29 /// The input file is closed when complete. Exits instead of returning on 30 30 /// error or if alwaysExit is true. 31 void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit = false );31 void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit = false ); 32 32 33 33 /// Drain the internal accumulator of parsed code and build a translation -
src/Parser/StatementNode.cc
r2ed94a9 rb110bcc 10 10 // Author : Rodolfo G. Esteves 11 11 // Created On : Sat May 16 14:59:41 2015 12 // Last Modified By : Peter A. Buhr13 // Last Modified On : Wed Feb 2 20:29:30 202214 // Update Count : 42 512 // Last Modified By : Andrew Beach 13 // Last Modified On : Tue Apr 11 10:16:00 2023 14 // Update Count : 428 15 15 // 16 16 17 #include "StatementNode.h" 18 17 19 #include <cassert> // for assert, strict_dynamic_cast, assertf 18 #include <list> // for list19 20 #include <memory> // for unique_ptr 20 21 #include <string> // for string 21 22 23 #include "AST/Label.hpp" // for Label 24 #include "AST/Stmt.hpp" // for Stmt, AsmStmt, BranchStmt, CaseCla... 22 25 #include "Common/SemanticError.h" // for SemanticError 23 26 #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 29 29 #include "parserutility.h" // for notZeroExpr 30 30 … … 33 33 using namespace std; 34 34 35 // Some helpers for cases that really want a single node but check for lists. 36 static const ast::Stmt * buildMoveSingle( StatementNode * node ) { 37 std::vector<ast::ptr<ast::Stmt>> list; 38 buildMoveList( node, list ); 39 assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" ); 40 return list.front().release(); 41 } 42 43 static const ast::Stmt * buildMoveOptional( StatementNode * node ) { 44 std::vector<ast::ptr<ast::Stmt>> list; 45 buildMoveList( node, list ); 46 assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" ); 47 return list.empty() ? nullptr : list.front().release(); 48 } 35 49 36 50 StatementNode::StatementNode( DeclarationNode * decl ) { … … 38 52 DeclarationNode * agg = decl->extractAggregate(); 39 53 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 ) ) ); 41 56 set_next( nextStmt ); 42 57 if ( decl->get_next() ) { … … 51 66 agg = decl; 52 67 } // 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 ) ) ); 54 71 } // StatementNode::StatementNode 55 72 56 StatementNode * StatementNode::append_last_case( StatementNode * stmt ) { 57 StatementNode * prev = this; 73 StatementNode * StatementNode::add_label( 74 const CodeLocation & location, 75 const std::string * name, 76 DeclarationNode * attr ) { 77 stmt->labels.emplace_back( location, 78 *name, 79 attr ? std::move( attr->attributes ) 80 : std::vector<ast::ptr<ast::Attribute>>{} ); 81 delete attr; 82 delete name; 83 return this; 84 } 85 86 ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) { 87 ClauseNode * prev = this; 58 88 // 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() ) ); 62 92 prev = curr; 63 93 } // for 94 ClauseNode * node = dynamic_cast< ClauseNode * >(prev); 64 95 // 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; 67 97 buildMoveList( stmt, stmts ); 68 98 // 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(); 71 104 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 107 ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) { 108 if ( ast::Expr * e = maybeMoveBuild( ctl ) ) { 109 return new ast::ExprStmt( location, e ); 110 } else { 111 return new ast::NullStmt( location ); 112 } 79 113 } // build_expr 80 114 81 Expression * build_if_control( CondCtl * ctl, list< Statement * > & init ) { 82 if ( ctl->init != 0 ) { 83 buildMoveList( ctl->init, init ); 115 static ast::Expr * build_if_control( CondCtl * ctl, 116 std::vector<ast::ptr<ast::Stmt>> & inits ) { 117 assert( inits.empty() ); 118 if ( nullptr != ctl->init ) { 119 buildMoveList( ctl->init, inits ); 84 120 } // if 85 121 86 Expression* cond = nullptr;122 ast::Expr * cond = nullptr; 87 123 if ( ctl->condition ) { 88 124 // compare the provided condition against 0 89 cond = notZeroExpr( maybeMoveBuild < Expression >(ctl->condition) );125 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) ); 90 126 } else { 91 for ( Statement * stmt : init) {127 for ( ast::ptr<ast::Stmt> & stmt : inits ) { 92 128 // 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; 97 133 } 98 134 } … … 101 137 } // build_if_control 102 138 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 ); 139 ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) { 140 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty 141 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set 142 143 ast::Stmt const * astthen = buildMoveSingle( then ); 144 ast::Stmt const * astelse = buildMoveOptional( else_ ); 145 146 return new ast::IfStmt( location, astcond, astthen, astelse, 147 std::move( astinit ) 148 ); 121 149 } // build_if 122 150 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 ) ); 151 ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) { 152 std::vector<ast::ptr<ast::CaseClause>> aststmt; 153 buildMoveList( stmt, aststmt ); 154 // If it is not a switch it is a choose statement. 155 if ( ! isSwitch ) { 156 for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) { 157 // Code after "case" is the end of case list. 158 if ( !stmt->stmts.empty() ) { 159 auto mutStmt = ast::mutate( stmt.get() ); 160 // I believe the stmts are actually always one block. 161 auto stmts = mutStmt->stmts.front().get_and_mutate(); 162 auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts ); 163 block->kids.push_back( new ast::BranchStmt( block->location, 164 ast::BranchStmt::Break, 165 ast::Label( block->location ) ) ); 166 stmt = mutStmt; 132 167 } // if 133 168 } // for 134 169 } // if 135 170 // 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 ) ); 137 173 } // build_switch 138 174 139 Statement * build_case( ExpressionNode * ctl ) { 140 return new CaseStmt( maybeMoveBuild< Expression >(ctl), {} ); // stmt starts empty and then added to 175 ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) { 176 // stmt starts empty and then added to 177 auto expr = maybeMoveBuild( ctl ); 178 return new ast::CaseClause( location, expr, {} ); 141 179 } // build_case 142 180 143 Statement * build_default() { 144 return new CaseStmt( nullptr, {}, true ); // stmt starts empty and then added to 181 ast::CaseClause * build_default( const CodeLocation & location ) { 182 // stmt starts empty and then added to 183 return new ast::CaseClause( location, nullptr, {} ); 145 184 } // build_default 146 185 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 ); 186 ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) { 187 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty 188 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set 189 190 return new ast::WhileDoStmt( location, 191 astcond, 192 buildMoveSingle( stmt ), 193 buildMoveOptional( else_ ), 194 std::move( astinit ), 195 ast::While 196 ); 159 197 } // build_while 160 198 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 199 ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) { 169 200 // 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 ); 171 208 } // build_do_while 172 209 173 Statement * build_for(ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {174 list< Statement *> astinit; // maybe empty210 ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) { 211 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty 175 212 buildMoveList( forctl->init, astinit ); 176 213 177 Expression* astcond = nullptr; // maybe empty178 astcond = notZeroExpr( maybeMoveBuild < Expression >(forctl->condition) );179 180 Expression* astincr = nullptr; // maybe empty181 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 ); 182 219 delete forctl; 183 220 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 ); 192 228 } // build_for 193 229 194 Statement * build_branch( BranchStmt::Type kind ) { 195 Statement * ret = new BranchStmt( "", kind ); 196 return ret; 230 ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) { 231 return new ast::BranchStmt( location, 232 kind, 233 ast::Label( location ) 234 ); 197 235 } // build_branch 198 236 199 Statement * build_branch( string * identifier, BranchStmt::Type kind ) { 200 Statement * ret = new BranchStmt( * identifier, kind ); 237 ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) { 238 ast::Stmt * ret = new ast::BranchStmt( location, 239 kind, 240 ast::Label( location, *identifier ) 241 ); 201 242 delete identifier; // allocated by lexer 202 243 return ret; 203 244 } // build_branch 204 245 205 Statement * build_computedgoto( ExpressionNode * ctl ) { 206 return new BranchStmt( maybeMoveBuild< Expression >(ctl), BranchStmt::Goto ); 246 ast::Stmt * build_computedgoto( ExpressionNode * ctl ) { 247 ast::Expr * expr = maybeMoveBuild( ctl ); 248 return new ast::BranchStmt( expr->location, expr ); 207 249 } // build_computedgoto 208 250 209 Statement * build_return(ExpressionNode * ctl ) {210 list< Expression *> exps;251 ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) { 252 std::vector<ast::ptr<ast::Expr>> exps; 211 253 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 ); 213 257 } // build_return 214 258 215 Statement * build_throw( ExpressionNode * ctl ) { 216 list< Expression * > exps; 259 static ast::Stmt * build_throw_stmt( 260 const CodeLocation & location, 261 ExpressionNode * ctl, 262 ast::ExceptionKind kind ) { 263 std::vector<ast::ptr<ast::Expr>> exps; 217 264 buildMoveList( ctl, exps ); 218 265 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 273 ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) { 274 return build_throw_stmt( loc, ctl, ast::Terminate ); 220 275 } // build_throw 221 276 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 ); 277 ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) { 278 return build_throw_stmt( loc, ctl, ast::Resume ); 227 279 } // build_resume 228 280 229 Statement * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {281 ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) { 230 282 (void)ctl; 231 283 (void)target; … … 233 285 } // build_resume_at 234 286 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 ); 287 ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) { 288 std::vector<ast::ptr<ast::CatchClause>> aststmt; 289 buildMoveList( catch_, aststmt ); 290 ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) ); 291 ast::FinallyClause * finallyBlock = nullptr; 292 if ( finally_ ) { 293 finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() ); 294 } 295 return new ast::TryStmt( location, 296 tryBlock, 297 std::move( aststmt ), 298 finallyBlock 299 ); 241 300 } // build_try 242 301 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() ); 302 ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) { 303 return new ast::CatchClause( location, 304 kind, 305 maybeMoveBuild( decl ), 306 maybeMoveBuild( cond ), 307 buildMoveSingle( body ) 308 ); 248 309 } // build_catch 249 310 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() ) ); 311 ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) { 312 return new ast::FinallyClause( location, 313 strict_dynamic_cast<const ast::CompoundStmt *>( 314 buildMoveSingle( stmt ) 315 ) 316 ); 255 317 } // build_finally 256 318 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 ); 319 ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) { 320 return new ast::SuspendStmt( location, 321 strict_dynamic_cast<const ast::CompoundStmt *, nullptr>( 322 buildMoveOptional( then ) 323 ), 324 kind 325 ); 326 } // build_suspend 327 328 ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { 329 auto clause = new ast::WaitForClause( location ); 330 clause->target_func = maybeBuild( targetExpr ); 331 clause->stmt = maybeMoveBuild( stmt ); 332 clause->cond = notZeroExpr( maybeMoveBuild( when ) ); 277 333 278 334 ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() ); 279 335 targetExpr->set_next( nullptr ); 280 buildMoveList < Expression >( next, target.arguments );336 buildMoveList( next, clause->target_args ); 281 337 282 338 delete targetExpr; 283 339 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; 291 343 } // build_waitfor 292 344 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; 345 ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) { 346 existing->else_stmt = maybeMoveBuild( stmt ); 347 existing->else_cond = notZeroExpr( maybeMoveBuild( when ) ); 348 349 (void)location; 350 return existing; 351 } // build_waitfor_else 352 353 ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) { 354 existing->timeout_time = maybeMoveBuild( timeout ); 355 existing->timeout_stmt = maybeMoveBuild( stmt ); 356 existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) ); 357 358 (void)location; 359 return existing; 325 360 } // build_waitfor_timeout 326 361 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; 362 ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) { 363 std::vector<ast::ptr<ast::Expr>> e; 342 364 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 ) ); 345 367 } // build_with 346 368 347 Statement * build_compound(StatementNode * first ) {348 CompoundStmt * cs = new CompoundStmt();349 buildMoveList( first, cs-> get_kids());369 ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) { 370 auto cs = new ast::CompoundStmt( location ); 371 buildMoveList( first, cs->kids ); 350 372 return cs; 351 373 } // build_compound … … 355 377 // statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a 356 378 // conical form for code generation. 357 StatementNode * maybe_build_compound( StatementNode * first ) {379 StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) { 358 380 // Optimization: if the control-structure statement is a compound statement, do not wrap it. 359 381 // 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 ) ); 364 384 } // if 365 385 return first; … … 367 387 368 388 // 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;389 ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { 390 std::vector<ast::ptr<ast::Expr>> out, in; 391 std::vector<ast::ptr<ast::ConstantExpr>> clob; 372 392 373 393 buildMoveList( output, out ); 374 394 buildMoveList( input, in ); 375 395 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 ); 377 404 } // build_asm 378 405 379 Statement * build_directive( string * directive ) { 380 return new DirectiveStmt( *directive ); 406 ast::Stmt * build_directive( const CodeLocation & location, string * directive ) { 407 auto stmt = new ast::DirectiveStmt( location, *directive ); 408 delete directive; 409 return stmt; 381 410 } // build_directive 382 411 383 Statement * build_mutex(ExpressionNode * exprs, StatementNode * stmt ) {384 list< Expression *> expList;412 ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) { 413 std::vector<ast::ptr<ast::Expr>> expList; 385 414 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 ) ); 388 417 } // build_mutex 389 418 -
src/Parser/TypeData.cc
r2ed94a9 rb110bcc 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 15:12:51 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue May 10 22:36:52 202213 // Update Count : 6 7711 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Apr 4 13:39:00 2023 13 // Update Count : 680 14 14 // 15 16 #include "TypeData.h" 15 17 16 18 #include <cassert> // for assert 17 19 #include <ostream> // for operator<<, ostream, basic_ostream 18 20 21 #include "AST/Decl.hpp" // for AggregateDecl, ObjectDecl, TypeDe... 22 #include "AST/Init.hpp" // for SingleInit, ListInit 23 #include "AST/Print.hpp" // for print 19 24 #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 28 28 29 29 class Attribute; … … 33 33 TypeData::TypeData( Kind k ) : location( yylloc ), kind( k ), base( nullptr ), forall( nullptr ) /*, PTR1( (void*)(0xdeadbeefdeadbeef)), PTR2( (void*)(0xdeadbeefdeadbeef) ) */ { 34 34 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: 47 44 array.dimension = nullptr; 48 45 array.isVarLen = false; 49 46 array.isStatic = false; 50 47 break; 51 case Function: 52 // function = new Function_t; 48 case Function: 53 49 function.params = nullptr; 54 50 function.idList = nullptr; … … 57 53 function.withExprs = nullptr; 58 54 break; 59 // Enum is an Aggregate, so both structures are initialized together. 60 case Enum: 61 // enumeration = new Enumeration_t; 55 case Enum: 62 56 enumeration.name = nullptr; 63 57 enumeration.constants = nullptr; … … 65 59 enumeration.anon = false; 66 60 break; 67 case Aggregate: 68 // aggregate = new Aggregate_t; 69 aggregate.kind = AggregateDecl::NoAggregate; 61 case Aggregate: 62 aggregate.kind = ast::AggregateDecl::NoAggregate; 70 63 aggregate.name = nullptr; 71 64 aggregate.params = nullptr; … … 77 70 aggregate.anon = false; 78 71 break; 79 case AggregateInst: 80 // aggInst = new AggInst_t; 72 case AggregateInst: 81 73 aggInst.aggregate = nullptr; 82 74 aggInst.params = nullptr; 83 75 aggInst.hoistType = false; 84 76 break; 85 case Symbolic: 86 case SymbolicInst: 87 // symbolic = new Symbolic_t; 77 case Symbolic: 78 case SymbolicInst: 88 79 symbolic.name = nullptr; 89 80 symbolic.params = nullptr; … … 91 82 symbolic.assertions = nullptr; 92 83 break; 93 case Tuple: 94 // tuple = new Tuple_t; 84 case Tuple: 95 85 tuple = nullptr; 96 86 break; 97 case Typeof: 98 case Basetypeof: 99 // typeexpr = new Typeof_t; 87 case Typeof: 88 case Basetypeof: 100 89 typeexpr = nullptr; 101 90 break; 102 103 break;104 case Builtin:105 // builtin = new Builtin_t;106 91 case Vtable: 92 case Builtin: 93 // No unique data to initialize. 94 break; 95 case Qualified: 107 96 qualified.parent = nullptr; 108 97 qualified.child = nullptr; … … 117 106 118 107 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: 130 117 delete array.dimension; 131 // delete array; 132 break; 133 case Function: 118 break; 119 case Function: 134 120 delete function.params; 135 121 delete function.idList; … … 137 123 delete function.body; 138 124 delete function.withExprs; 139 // delete function; 140 break; 141 case Aggregate: 125 break; 126 case Aggregate: 142 127 delete aggregate.name; 143 128 delete aggregate.params; 144 129 delete aggregate.actuals; 145 130 delete aggregate.fields; 146 // delete aggregate; 147 break; 148 case AggregateInst: 131 break; 132 case AggregateInst: 149 133 delete aggInst.aggregate; 150 134 delete aggInst.params; 151 // delete aggInst; 152 break; 153 case Enum: 135 break; 136 case Enum: 154 137 delete enumeration.name; 155 138 delete enumeration.constants; 156 // delete enumeration; 157 break; 158 case Symbolic: 159 case SymbolicInst: 139 break; 140 case Symbolic: 141 case SymbolicInst: 160 142 delete symbolic.name; 161 143 delete symbolic.params; 162 144 delete symbolic.actuals; 163 145 delete symbolic.assertions; 164 // delete symbolic; 165 break; 166 case Tuple: 167 // delete tuple->members; 146 break; 147 case Tuple: 168 148 delete tuple; 169 149 break; 170 case Typeof: 171 case Basetypeof: 172 // delete typeexpr->expr; 150 case Typeof: 151 case Basetypeof: 173 152 delete typeexpr; 174 153 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: 181 159 delete qualified.parent; 182 160 delete qualified.child; 161 break; 183 162 } // switch 184 163 } // TypeData::~TypeData … … 192 171 193 172 switch ( kind ) { 194 195 196 197 198 173 case Unknown: 174 case EnumConstant: 175 case Pointer: 176 case Reference: 177 case GlobalScope: 199 178 // nothing else to copy 200 179 break; 201 180 case Basic: 202 181 newtype->basictype = basictype; 203 182 newtype->complextype = complextype; … … 205 184 newtype->length = length; 206 185 break; 207 186 case Array: 208 187 newtype->array.dimension = maybeClone( array.dimension ); 209 188 newtype->array.isVarLen = array.isVarLen; 210 189 newtype->array.isStatic = array.isStatic; 211 190 break; 212 191 case Function: 213 192 newtype->function.params = maybeClone( function.params ); 214 193 newtype->function.idList = maybeClone( function.idList ); … … 217 196 newtype->function.withExprs = maybeClone( function.withExprs ); 218 197 break; 219 198 case Aggregate: 220 199 newtype->aggregate.kind = aggregate.kind; 221 200 newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr; … … 228 207 newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr; 229 208 break; 230 209 case AggregateInst: 231 210 newtype->aggInst.aggregate = maybeClone( aggInst.aggregate ); 232 211 newtype->aggInst.params = maybeClone( aggInst.params ); 233 212 newtype->aggInst.hoistType = aggInst.hoistType; 234 213 break; 235 214 case Enum: 236 215 newtype->enumeration.name = enumeration.name ? new string( *enumeration.name ) : nullptr; 237 216 newtype->enumeration.constants = maybeClone( enumeration.constants ); … … 239 218 newtype->enumeration.anon = enumeration.anon; 240 219 break; 241 242 220 case Symbolic: 221 case SymbolicInst: 243 222 newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr; 244 223 newtype->symbolic.params = maybeClone( symbolic.params ); … … 247 226 newtype->symbolic.isTypedef = symbolic.isTypedef; 248 227 break; 249 228 case Tuple: 250 229 newtype->tuple = maybeClone( tuple ); 251 230 break; 252 253 231 case Typeof: 232 case Basetypeof: 254 233 newtype->typeexpr = maybeClone( typeexpr ); 255 234 break; 256 257 break; 258 235 case Vtable: 236 break; 237 case Builtin: 259 238 assert( builtintype == DeclarationNode::Zero || builtintype == DeclarationNode::One ); 260 239 newtype->builtintype = builtintype; 261 240 break; 262 241 case Qualified: 263 242 newtype->qualified.parent = maybeClone( qualified.parent ); 264 243 newtype->qualified.child = maybeClone( qualified.child ); … … 270 249 271 250 void 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 ); 275 252 276 253 if ( forall ) { … … 280 257 281 258 switch ( kind ) { 282 259 case Basic: 283 260 if ( signedness != DeclarationNode::NoSignedness ) os << DeclarationNode::signednessNames[ signedness ] << " "; 284 261 if ( length != DeclarationNode::NoLength ) os << DeclarationNode::lengthNames[ length ] << " "; … … 286 263 if ( basictype != DeclarationNode::NoBasicType ) os << DeclarationNode::basicTypeNames[ basictype ] << " "; 287 264 break; 288 265 case Pointer: 289 266 os << "pointer "; 290 267 if ( base ) { … … 293 270 } // if 294 271 break; 295 272 case Reference: 296 273 os << "reference "; 297 274 if ( base ) { … … 300 277 } // if 301 278 break; 302 279 case Array: 303 280 if ( array.isStatic ) { 304 281 os << "static "; … … 316 293 } // if 317 294 break; 318 295 case Function: 319 296 os << "function" << endl; 320 297 if ( function.params ) { … … 344 321 } // if 345 322 break; 346 347 os << AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;323 case Aggregate: 324 os << ast::AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl; 348 325 if ( aggregate.params ) { 349 326 os << string( indent + 2, ' ' ) << "with type parameters" << endl; … … 362 339 } // if 363 340 break; 364 341 case AggregateInst: 365 342 if ( aggInst.aggregate ) { 366 343 os << "instance of " ; … … 374 351 } // if 375 352 break; 376 377 os << "enumeration " ;353 case Enum: 354 os << "enumeration " << *enumeration.name << endl;; 378 355 if ( enumeration.constants ) { 379 356 os << "with constants" << endl; … … 388 365 } // if 389 366 break; 390 367 case EnumConstant: 391 368 os << "enumeration constant "; 392 369 break; 393 370 case Symbolic: 394 371 if ( symbolic.isTypedef ) { 395 372 os << "typedef definition "; … … 411 388 } // if 412 389 break; 413 390 case SymbolicInst: 414 391 os << *symbolic.name; 415 392 if ( symbolic.actuals ) { … … 419 396 } // if 420 397 break; 421 398 case Tuple: 422 399 os << "tuple "; 423 400 if ( tuple ) { … … 426 403 } // if 427 404 break; 428 405 case Basetypeof: 429 406 os << "base-"; 430 407 #if defined(__GNUC__) && __GNUC__ >= 7 … … 432 409 #endif 433 410 // FALL THROUGH 434 411 case Typeof: 435 412 os << "type-of expression "; 436 413 if ( typeexpr ) { … … 438 415 } // if 439 416 break; 440 417 case Vtable: 441 418 os << "vtable"; 442 419 break; 443 420 case Builtin: 444 421 os << DeclarationNode::builtinTypeNames[builtintype]; 445 422 break; 446 447 break; 448 423 case GlobalScope: 424 break; 425 case Qualified: 449 426 qualified.parent->print( os ); 450 427 os << "."; 451 428 qualified.child->print( os ); 452 429 break; 453 430 case Unknown: 454 431 os << "entity of unknown type "; 455 432 break; 456 433 default: 457 434 os << "internal error: TypeData::print " << kind << endl; 458 435 assert( false ); … … 462 439 const std::string * TypeData::leafName() const { 463 440 switch ( kind ) { 464 465 466 467 468 469 470 471 472 473 474 475 476 477 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: 478 455 assertf(false, "Tried to get leaf name from kind without a name: %d", kind); 479 456 break; 480 457 case Aggregate: 481 458 return aggregate.name; 482 459 case Enum: 483 460 return enumeration.name; 484 485 461 case Symbolic: 462 case SymbolicInst: 486 463 return symbolic.name; 487 464 case Qualified: 488 465 return qualified.child->leafName(); 489 466 } // switch … … 492 469 493 470 494 template< typename ForallList > 495 void buildForall( const DeclarationNode * firstNode, ForallList &outputList ) { 496 buildList( firstNode, outputList ); 471 void buildForall( 472 const DeclarationNode * firstNode, 473 std::vector<ast::ptr<ast::TypeInstType>> &outputList ) { 474 { 475 std::vector<ast::ptr<ast::Type>> tmpList; 476 buildTypeList( firstNode, tmpList ); 477 for ( auto tmp : tmpList ) { 478 outputList.emplace_back( 479 strict_dynamic_cast<const ast::TypeInstType *>( 480 tmp.release() ) ); 481 } 482 } 497 483 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 624 void buildForall( 625 const DeclarationNode * firstNode, 626 std::vector<ast::ptr<ast::TypeDecl>> &outputForall ) { 627 buildList( firstNode, outputForall ); 628 auto n = firstNode; 629 for ( auto i = outputForall.begin() ; 630 i != outputForall.end() ; 631 ++i, n = (DeclarationNode*)n->get_next() ) { 632 // Only the object type class adds additional assertions. 633 if ( n->variable.tyClass != ast::TypeDecl::Otype ) { 634 continue; 635 } 636 637 ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>(); 638 std::vector<ast::ptr<ast::DeclWithType>> newAssertions; 639 auto mutTypeDecl = ast::mutate( td ); 640 const CodeLocation & location = mutTypeDecl->location; 641 *i = mutTypeDecl; 642 643 // add assertion parameters to `type' tyvars in reverse order 644 // add assignment operator: T * ?=?(T *, T) 645 newAssertions.push_back( new ast::FunctionDecl( 646 location, 647 "?=?", 648 {}, // forall 649 {}, // assertions 650 { 651 new ast::ObjectDecl( 652 location, 653 "", 654 new ast::ReferenceType( new ast::TypeInstType( td->name, *i ) ), 655 (ast::Init *)nullptr, 656 ast::Storage::Classes(), 657 ast::Linkage::Cforall, 658 (ast::Expr *)nullptr 659 ), 660 new ast::ObjectDecl( 661 location, 662 "", 663 new ast::TypeInstType( td->name, *i ), 664 (ast::Init *)nullptr, 665 ast::Storage::Classes(), 666 ast::Linkage::Cforall, 667 (ast::Expr *)nullptr 668 ), 669 }, // params 670 { 671 new ast::ObjectDecl( 672 location, 673 "", 674 new ast::TypeInstType( td->name, *i ), 675 (ast::Init *)nullptr, 676 ast::Storage::Classes(), 677 ast::Linkage::Cforall, 678 (ast::Expr *)nullptr 679 ), 680 }, // returns 681 (ast::CompoundStmt *)nullptr, 682 ast::Storage::Classes(), 683 ast::Linkage::Cforall 684 ) ); 685 686 // add default ctor: void ?{}(T *) 687 newAssertions.push_back( new ast::FunctionDecl( 688 location, 689 "?{}", 690 {}, // forall 691 {}, // assertions 692 { 693 new ast::ObjectDecl( 694 location, 695 "", 696 new ast::ReferenceType( 697 new ast::TypeInstType( td->name, i->get() ) ), 698 (ast::Init *)nullptr, 699 ast::Storage::Classes(), 700 ast::Linkage::Cforall, 701 (ast::Expr *)nullptr 702 ), 703 }, // params 704 {}, // returns 705 (ast::CompoundStmt *)nullptr, 706 ast::Storage::Classes(), 707 ast::Linkage::Cforall 708 ) ); 709 710 // add copy ctor: void ?{}(T *, T) 711 newAssertions.push_back( new ast::FunctionDecl( 712 location, 713 "?{}", 714 {}, // forall 715 {}, // assertions 716 { 717 new ast::ObjectDecl( 718 location, 719 "", 720 new ast::ReferenceType( 721 new ast::TypeInstType( td->name, *i ) ), 722 (ast::Init *)nullptr, 723 ast::Storage::Classes(), 724 ast::Linkage::Cforall, 725 (ast::Expr *)nullptr 726 ), 727 new ast::ObjectDecl( 728 location, 729 "", 730 new ast::TypeInstType( td->name, *i ), 731 (ast::Init *)nullptr, 732 ast::Storage::Classes(), 733 ast::Linkage::Cforall, 734 (ast::Expr *)nullptr 735 ), 736 }, // params 737 {}, // returns 738 (ast::CompoundStmt *)nullptr, 739 ast::Storage::Classes(), 740 ast::Linkage::Cforall 741 ) ); 742 743 // add dtor: void ^?{}(T *) 744 newAssertions.push_back( new ast::FunctionDecl( 745 location, 746 "^?{}", 747 {}, // forall 748 {}, // assertions 749 { 750 new ast::ObjectDecl( 751 location, 752 "", 753 new ast::ReferenceType( 754 new ast::TypeInstType( i->get() ) 755 ), 756 (ast::Init *)nullptr, 757 ast::Storage::Classes(), 758 ast::Linkage::Cforall, 759 (ast::Expr *)nullptr 760 ), 761 }, // params 762 {}, // returns 763 (ast::CompoundStmt *)nullptr, 764 ast::Storage::Classes(), 765 ast::Linkage::Cforall 766 ) ); 767 768 spliceBegin( mutTypeDecl->assertions, newAssertions ); 525 769 } // for 526 770 } // buildForall 527 771 528 772 529 Type * typebuild( const TypeData * td ) {773 ast::Type * typebuild( const TypeData * td ) { 530 774 assert( td ); 531 775 switch ( td->kind ) { 532 776 case TypeData::Unknown: 533 777 // 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: 536 783 return buildBasicType( td ); 537 784 case TypeData::Pointer: 538 785 return buildPointer( td ); 539 786 case TypeData::Array: 540 787 return buildArray( td ); 541 788 case TypeData::Reference: 542 789 return buildReference( td ); 543 544 return buildFunction ( td );545 790 case TypeData::Function: 791 return buildFunctionType( td ); 792 case TypeData::AggregateInst: 546 793 return buildAggInst( td ); 547 548 return new EnumInstType( buildQualifiers( td ), "");549 794 case TypeData::EnumConstant: 795 return new ast::EnumInstType( "", buildQualifiers( td ) ); 796 case TypeData::SymbolicInst: 550 797 return buildSymbolicInst( td ); 551 798 case TypeData::Tuple: 552 799 return buildTuple( td ); 553 554 800 case TypeData::Typeof: 801 case TypeData::Basetypeof: 555 802 return buildTypeof( td ); 556 803 case TypeData::Vtable: 557 804 return buildVtable( td ); 558 805 case TypeData::Builtin: 559 806 switch ( td->builtintype ) { 560 561 return new ZeroType( noQualifiers);562 563 return new OneType( noQualifiers);564 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 ) ); 566 813 } // 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: 574 825 assert( false ); 575 826 } // switch … … 583 834 584 835 switch ( td->kind ) { 585 836 case TypeData::Aggregate: 586 837 if ( ! toplevel && td->aggregate.body ) { 587 838 ret = td->clone(); 588 839 } // if 589 840 break; 590 841 case TypeData::Enum: 591 842 if ( ! toplevel && td->enumeration.body ) { 592 843 ret = td->clone(); 593 844 } // if 594 845 break; 595 846 case TypeData::AggregateInst: 596 847 if ( td->aggInst.aggregate ) { 597 848 ret = typeextractAggregate( td->aggInst.aggregate, false ); 598 849 } // if 599 850 break; 600 851 default: 601 852 if ( td->base ) { 602 853 ret = typeextractAggregate( td->base, false ); … … 607 858 608 859 609 Type::Qualifiers buildQualifiers( const TypeData * td ) {860 ast::CV::Qualifiers buildQualifiers( const TypeData * td ) { 610 861 return td->qualifiers; 611 862 } // buildQualifiers … … 616 867 } // genTSError 617 868 618 Type * buildBasicType( const TypeData * td ) {619 BasicType::Kind ret;869 ast::Type * buildBasicType( const TypeData * td ) { 870 ast::BasicType::Kind ret; 620 871 621 872 switch ( td->basictype ) { 622 873 case DeclarationNode::Void: 623 874 if ( td->signedness != DeclarationNode::NoSignedness ) { 624 875 genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype ); … … 627 878 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); 628 879 } // if 629 return new VoidType( buildQualifiers( td ) );630 break; 631 632 880 return new ast::VoidType( buildQualifiers( td ) ); 881 break; 882 883 case DeclarationNode::Bool: 633 884 if ( td->signedness != DeclarationNode::NoSignedness ) { 634 885 genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype ); … … 638 889 } // if 639 890 640 ret = BasicType::Bool;641 break; 642 643 891 ret = ast::BasicType::Bool; 892 break; 893 894 case DeclarationNode::Char: 644 895 // C11 Standard 6.2.5.15: The three types char, signed char, and unsigned char are collectively called the 645 896 // character types. The implementation shall define char to have the same range, representation, and behavior as 646 897 // 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 }; 648 899 649 900 if ( td->length != DeclarationNode::NoLength ) { … … 654 905 break; 655 906 656 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 }, 660 911 }; 661 912 662 913 Integral: ; 663 914 if ( td->signedness == DeclarationNode::NoSignedness ) { 664 915 const_cast<TypeData *>(td)->signedness = DeclarationNode::Signed; … … 667 918 break; 668 919 669 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; 671 922 if ( td->length != DeclarationNode::NoLength ) { 672 923 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); … … 674 925 break; 675 926 676 677 678 679 680 681 682 683 684 685 686 687 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, }, 691 942 }; 692 943 693 944 FloatingPoint: ; 694 945 if ( td->signedness != DeclarationNode::NoSignedness ) { 695 946 genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype ); … … 715 966 break; 716 967 717 968 case DeclarationNode::NoBasicType: 718 969 // No basic type in declaration => default double for Complex/Imaginary and int type for integral types 719 970 if ( td->complextype == DeclarationNode::Complex || td->complextype == DeclarationNode::Imaginary ) { … … 724 975 const_cast<TypeData *>(td)->basictype = DeclarationNode::Int; 725 976 goto Integral; 726 727 977 default: 978 assertf( false, "unknown basic type" ); 728 979 return nullptr; 729 980 } // switch 730 981 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 ) ); 733 983 return bt; 734 984 } // buildBasicType 735 985 736 986 737 PointerType * buildPointer( const TypeData * td ) {738 PointerType * pt;987 ast::PointerType * buildPointer( const TypeData * td ) { 988 ast::PointerType * pt; 739 989 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 ); 741 994 } 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 ); 743 999 } // if 744 buildForall( td->forall, pt->get_forall() );745 1000 return pt; 746 1001 } // buildPointer 747 1002 748 1003 749 ArrayType * buildArray( const TypeData * td ) {750 ArrayType * at;1004 ast::ArrayType * buildArray( const TypeData * td ) { 1005 ast::ArrayType * at; 751 1006 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 ); 754 1014 } 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 ); 757 1022 } // if 758 buildForall( td->forall, at->get_forall() );759 1023 return at; 760 1024 } // buildArray 761 1025 762 1026 763 ReferenceType * buildReference( const TypeData * td ) {764 ReferenceType * rt;1027 ast::ReferenceType * buildReference( const TypeData * td ) { 1028 ast::ReferenceType * rt; 765 1029 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 ); 767 1034 } 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 ); 769 1039 } // if 770 buildForall( td->forall, rt->get_forall() );771 1040 return rt; 772 1041 } // buildReference 773 1042 774 1043 775 AggregateDecl * buildAggregate( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {1044 ast::AggregateDecl * buildAggregate( const TypeData * td, std::vector<ast::ptr<ast::Attribute>> attributes, ast::Linkage::Spec linkage ) { 776 1045 assert( td->kind == TypeData::Aggregate ); 777 AggregateDecl * at;1046 ast::AggregateDecl * at; 778 1047 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: 797 1079 assert( false ); 798 1080 } // switch 799 1081 800 buildList( td->aggregate.fields, at-> get_members());1082 buildList( td->aggregate.fields, at->members ); 801 1083 at->set_body( td->aggregate.body ); 802 1084 … … 805 1087 806 1088 807 ReferenceToType * buildComAggInst( const TypeData * type, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) { 1089 ast::BaseInstType * buildComAggInst( 1090 const TypeData * type, 1091 std::vector<ast::ptr<ast::Attribute>> && attributes, 1092 ast::Linkage::Spec linkage ) { 808 1093 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: 859 1160 assert( false ); 860 1161 } // switch 1162 assert( false ); 861 1163 } // buildAggInst 862 1164 863 1165 864 ReferenceToType * buildAggInst( const TypeData * td ) {1166 ast::BaseInstType * buildAggInst( const TypeData * td ) { 865 1167 assert( td->kind == TypeData::AggregateInst ); 866 1168 867 // ReferenceToType * ret = buildComAggInst( td->aggInst.aggregate, std::list< Attribute * >() ); 868 ReferenceToType * ret = nullptr; 1169 ast::BaseInstType * ret = nullptr; 869 1170 TypeData * type = td->aggInst.aggregate; 870 1171 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: 894 1205 assert( false ); 895 1206 } // switch 896 1207 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 ); 900 1210 return ret; 901 1211 } // buildAggInst 902 1212 903 1213 904 NamedTypeDecl * buildSymbolic( const TypeData * td, std::list< Attribute * > attributes, const string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) { 1214 ast::NamedTypeDecl * buildSymbolic( 1215 const TypeData * td, 1216 std::vector<ast::ptr<ast::Attribute>> attributes, 1217 const std::string & name, 1218 ast::Storage::Classes scs, 1219 ast::Linkage::Spec linkage ) { 905 1220 assert( td->kind == TypeData::Symbolic ); 906 NamedTypeDecl * ret;1221 ast::NamedTypeDecl * ret; 907 1222 assert( td->base ); 908 1223 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 ); 910 1231 } 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 ); 912 1240 } // 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 ); 915 1243 return ret; 916 1244 } // buildSymbolic 917 1245 918 1246 919 EnumDecl * buildEnum( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) { 1247 ast::EnumDecl * buildEnum( 1248 const TypeData * td, 1249 std::vector<ast::ptr<ast::Attribute>> && attributes, 1250 ast::Linkage::Spec linkage ) { 920 1251 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; 926 1264 for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) { 927 1265 if ( cur->enumInLine ) { … … 930 1268 SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." ); 931 1269 } 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 ); 934 1277 } 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())) { 936 1279 SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." ); 937 1280 } … … 940 1283 // if 941 1284 } // for 942 ret-> set_body( td->enumeration.body );1285 ret->body = td->enumeration.body; 943 1286 return ret; 944 1287 } // buildEnum 945 1288 946 1289 947 TypeInstType * buildSymbolicInst( const TypeData * td ) {1290 ast::TypeInstType * buildSymbolicInst( const TypeData * td ) { 948 1291 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 ); 952 1298 return ret; 953 1299 } // buildSymbolicInst 954 1300 955 1301 956 TupleType * buildTuple( const TypeData * td ) {1302 ast::TupleType * buildTuple( const TypeData * td ) { 957 1303 assert( td->kind == TypeData::Tuple ); 958 std:: list< Type *> types;1304 std::vector<ast::ptr<ast::Type>> types; 959 1305 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 ); 962 1310 return ret; 963 1311 } // buildTuple 964 1312 965 1313 966 TypeofType * buildTypeof( const TypeData * td ) {1314 ast::TypeofType * buildTypeof( const TypeData * td ) { 967 1315 assert( td->kind == TypeData::Typeof || td->kind == TypeData::Basetypeof ); 968 1316 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 ); 971 1323 } // buildTypeof 972 1324 973 1325 974 VTableType * buildVtable( const TypeData * td ) {1326 ast::VTableType * buildVtable( const TypeData * td ) { 975 1327 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 ); 977 1332 } // buildVtable 978 1333 979 1334 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 ) { 1335 ast::FunctionDecl * buildFunctionDecl( 1336 const TypeData * td, 1337 const string &name, 1338 ast::Storage::Classes scs, 1339 ast::Function::Specs funcSpec, 1340 ast::Linkage::Spec linkage, 1341 ast::Expr * asmName, 1342 std::vector<ast::ptr<ast::Attribute>> && attributes ) { 1343 assert( td->kind == TypeData::Function ); 1344 // For some reason FunctionDecl takes a bool instead of an ArgumentFlag. 1345 bool isVarArgs = !td->function.params || td->function.params->hasEllipsis; 1346 ast::CV::Qualifiers cvq = buildQualifiers( td ); 1347 std::vector<ast::ptr<ast::TypeDecl>> forall; 1348 std::vector<ast::ptr<ast::DeclWithType>> assertions; 1349 std::vector<ast::ptr<ast::DeclWithType>> params; 1350 std::vector<ast::ptr<ast::DeclWithType>> returns; 1351 buildList( td->function.params, params ); 1352 buildForall( td->forall, forall ); 1353 // Functions do not store their assertions there anymore. 1354 for ( ast::ptr<ast::TypeDecl> & type_param : forall ) { 1355 auto mut = type_param.get_and_mutate(); 1356 splice( assertions, mut->assertions ); 1357 } 1358 if ( td->base ) { 1359 switch ( td->base->kind ) { 1360 case TypeData::Tuple: 1361 buildList( td->base->tuple, returns ); 1362 break; 1363 default: 1364 returns.push_back( dynamic_cast<ast::DeclWithType *>( 1365 buildDecl( 1366 td->base, 1367 "", 1368 ast::Storage::Classes(), 1369 (ast::Expr *)nullptr, // bitfieldWidth 1370 ast::Function::Specs(), 1371 ast::Linkage::Cforall, 1372 (ast::Expr *)nullptr // asmName 1373 ) 1374 ) ); 1375 } // switch 1376 } else { 1377 returns.push_back( new ast::ObjectDecl( 1378 td->location, 1379 "", 1380 new ast::BasicType( ast::BasicType::SignedInt ), 1381 (ast::Init *)nullptr, 1382 ast::Storage::Classes(), 1383 ast::Linkage::Cforall 1384 ) ); 1385 } // if 1386 ast::Stmt * stmt = maybeBuild( td->function.body ); 1387 ast::CompoundStmt * body = dynamic_cast<ast::CompoundStmt *>( stmt ); 1388 ast::FunctionDecl * decl = new ast::FunctionDecl( td->location, 1389 name, 1390 std::move( forall ), 1391 std::move( assertions ), 1392 std::move( params ), 1393 std::move( returns ), 1394 body, 1395 scs, 1396 linkage, 1397 std::move( attributes ), 1398 funcSpec, 1399 (isVarArgs) ? ast::VariableArgs : ast::FixedArgs 1400 ); 1401 buildList( td->function.withExprs, decl->withExprs ); 1402 decl->asmName = asmName; 1403 // This may be redundant on a declaration. 1404 decl->type.get_and_mutate()->qualifiers = cvq; 1405 return decl; 1406 } // buildFunctionDecl 1407 1408 1409 ast::Decl * buildDecl( 1410 const TypeData * td, 1411 const string &name, 1412 ast::Storage::Classes scs, 1413 ast::Expr * bitfieldWidth, 1414 ast::Function::Specs funcSpec, 1415 ast::Linkage::Spec linkage, 1416 ast::Expr * asmName, 1417 ast::Init * init, 1418 std::vector<ast::ptr<ast::Attribute>> && attributes ) { 981 1419 if ( td->kind == TypeData::Function ) { 982 1420 if ( td->function.idList ) { // KR function ? … … 984 1422 } // if 985 1423 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 ) ); 992 1427 } else if ( td->kind == TypeData::Aggregate ) { 993 return buildAggregate( td, attributes, linkage );1428 return buildAggregate( td, std::move( attributes ), linkage ); 994 1429 } else if ( td->kind == TypeData::Enum ) { 995 return buildEnum( td, attributes, linkage );1430 return buildEnum( td, std::move( attributes ), linkage ); 996 1431 } else if ( td->kind == TypeData::Symbolic ) { 997 return buildSymbolic( td, attributes, name, scs, linkage );1432 return buildSymbolic( td, std::move( attributes ), name, scs, linkage ); 998 1433 } 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; 1000 1445 } // if 1001 1446 return nullptr; … … 1003 1448 1004 1449 1005 FunctionType * buildFunction( const TypeData * td ) {1450 ast::FunctionType * buildFunctionType( const TypeData * td ) { 1006 1451 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 ); 1009 1458 buildForall( td->forall, ft->forall ); 1010 1459 if ( td->base ) { 1011 1460 switch ( td->base->kind ) { 1012 1013 build List( td->base->tuple, ft->returnVals );1461 case TypeData::Tuple: 1462 buildTypeList( td->base->tuple, ft->returns ); 1014 1463 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; 1017 1467 } // switch 1018 1468 } 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 ) ); 1020 1471 } // if 1021 1472 return ft; 1022 } // buildFunction 1473 } // buildFunctionType 1023 1474 1024 1475 … … 1051 1502 param->type = decl->type; // set copy declaration type to parameter type 1052 1503 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 ); 1054 1506 } // if 1055 1507 } // for -
src/Parser/TypeData.h
r2ed94a9 rb110bcc 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat May 16 15:18:36 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue May 10 22:18:49 202213 // Update Count : 20 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Mar 1 10:44:00 2023 13 // Update Count : 206 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <iosfwd> 19 #include <list> 20 #include <string> 18 #include <iosfwd> // for ostream 19 #include <list> // for list 20 #include <string> // for string 21 21 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 26 24 27 25 struct TypeData { … … 30 28 31 29 struct Aggregate_t { 32 AggregateDecl::Aggregate kind;30 ast::AggregateDecl::Aggregate kind; 33 31 const std::string * name = nullptr; 34 32 DeclarationNode * params = nullptr; … … 37 35 bool body; 38 36 bool anon; 39 40 37 bool tagged; 41 38 const std::string * parent = nullptr; … … 94 91 DeclarationNode::BuiltinType builtintype = DeclarationNode::NoBuiltinType; 95 92 96 Type::Qualifiers qualifiers;93 ast::CV::Qualifiers qualifiers; 97 94 DeclarationNode * forall = nullptr; 98 95 … … 115 112 }; 116 113 117 Type * typebuild( const TypeData * );114 ast::Type * typebuild( const TypeData * ); 118 115 TypeData * 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 * ); 116 ast::CV::Qualifiers buildQualifiers( const TypeData * td ); 117 ast::Type * buildBasicType( const TypeData * ); 118 ast::PointerType * buildPointer( const TypeData * ); 119 ast::ArrayType * buildArray( const TypeData * ); 120 ast::ReferenceType * buildReference( const TypeData * ); 121 ast::AggregateDecl * buildAggregate( const TypeData *, std::vector<ast::ptr<ast::Attribute>> ); 122 ast::BaseInstType * buildComAggInst( const TypeData *, std::vector<ast::ptr<ast::Attribute>> && attributes, ast::Linkage::Spec linkage ); 123 ast::BaseInstType * buildAggInst( const TypeData * ); 124 ast::TypeDecl * buildVariable( const TypeData * ); 125 ast::EnumDecl * buildEnum( const TypeData *, std::vector<ast::ptr<ast::Attribute>> &&, ast::Linkage::Spec ); 126 ast::TypeInstType * buildSymbolicInst( const TypeData * ); 127 ast::TupleType * buildTuple( const TypeData * ); 128 ast::TypeofType * buildTypeof( const TypeData * ); 129 ast::VTableType * buildVtable( const TypeData * ); 130 ast::Decl * buildDecl( 131 const TypeData *, const std::string &, ast::Storage::Classes, ast::Expr *, 132 ast::Function::Specs funcSpec, ast::Linkage::Spec, ast::Expr * asmName, 133 ast::Init * init = nullptr, std::vector<ast::ptr<ast::Attribute>> && attributes = std::vector<ast::ptr<ast::Attribute>>() ); 134 ast::FunctionType * buildFunctionType( const TypeData * ); 135 ast::Decl * addEnumBase( Declaration *, const TypeData * ); 137 136 void buildKRFunction( const TypeData::Function_t & function ); 138 137 -
src/Parser/TypedefTable.cc
r2ed94a9 rb110bcc 16 16 17 17 #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 20 29 using namespace std; 21 30 22 31 #if 0 23 32 #define debugPrint( code ) code 33 34 static const char *kindName( int kind ) { 35 switch ( kind ) { 36 case IDENTIFIER: return "identifier"; 37 case TYPEDIMname: return "typedim"; 38 case TYPEDEFname: return "typedef"; 39 case TYPEGENname: return "typegen"; 40 default: 41 cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl; 42 abort(); 43 } // switch 44 } // kindName 24 45 #else 25 46 #define debugPrint( code ) 26 47 #endif 27 28 using namespace std; // string, iostream29 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 } // switch41 } // kindName42 );43 48 44 49 TypedefTable::~TypedefTable() { … … 78 83 typedefTable.addToEnclosingScope( name, kind, "MTD" ); 79 84 } // if 85 } // TypedefTable::makeTypedef 86 87 void TypedefTable::makeTypedef( const string & name ) { 88 return makeTypedef( name, TYPEDEFname ); 80 89 } // TypedefTable::makeTypedef 81 90 -
src/Parser/TypedefTable.h
r2ed94a9 rb110bcc 19 19 20 20 #include "Common/ScopedMap.h" // for ScopedMap 21 #include "ParserTypes.h"22 #include "parser.hh" // for IDENTIFIER, TYPEDEFname, TYPEGENname23 21 24 22 class TypedefTable { 25 23 struct Note { size_t level; bool forall; }; 26 24 typedef ScopedMap< std::string, int, Note > KindTable; 27 KindTable kindTable; 25 KindTable kindTable; 28 26 unsigned int level = 0; 29 27 public: … … 33 31 bool existsCurr( const std::string & identifier ) const; 34 32 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 ); 36 35 void addToScope( const std::string & identifier, int kind, const char * ); 37 36 void addToEnclosingScope( const std::string & identifier, int kind, const char * ); -
src/Parser/lex.ll
r2ed94a9 rb110bcc 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Mon Jan 30 19:03:34202313 * Update Count : 76 712 * Last Modified On : Sat Mar 25 08:09:03 2023 13 * Update Count : 768 14 14 */ 15 15 … … 23 23 // line-number directives) and C/C++ style comments, which are ignored. 24 24 25 // **************************** Includes and Defines ****************************25 // *************************** Includes and Defines **************************** 26 26 27 27 #ifdef __clang__ … … 44 44 45 45 #include "config.h" // configure info 46 #include "DeclarationNode.h" // for DeclarationNode 47 #include "ExpressionNode.h" // for LabelNode 48 #include "InitializerNode.h" // for InitializerNode 46 49 #include "ParseNode.h" 50 #include "ParserTypes.h" // for Token 51 #include "StatementNode.h" // for CondCtl, ForCtrl 47 52 #include "TypedefTable.h" 53 // This (generated) header must come late as it is missing includes. 54 #include "parser.hh" // generated info 48 55 49 56 string * build_postfix_name( string * name ); … … 214 221 __alignof { KEYWORD_RETURN(ALIGNOF); } // GCC 215 222 __alignof__ { KEYWORD_RETURN(ALIGNOF); } // GCC 223 and { QKEYWORD_RETURN(WAND); } // CFA 216 224 asm { KEYWORD_RETURN(ASM); } 217 225 __asm { KEYWORD_RETURN(ASM); } // GCC -
src/Parser/module.mk
r2ed94a9 rb110bcc 21 21 SRC += \ 22 22 Parser/DeclarationNode.cc \ 23 Parser/DeclarationNode.h \ 23 24 Parser/ExpressionNode.cc \ 25 Parser/ExpressionNode.h \ 24 26 Parser/InitializerNode.cc \ 27 Parser/InitializerNode.h \ 25 28 Parser/lex.ll \ 26 29 Parser/ParseNode.cc \ … … 33 36 Parser/RunParser.hpp \ 34 37 Parser/StatementNode.cc \ 38 Parser/StatementNode.h \ 35 39 Parser/TypeData.cc \ 36 40 Parser/TypeData.h \ -
src/Parser/parser.yy
r2ed94a9 rb110bcc 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : T hu Feb 2 21:36:16202313 // Update Count : 586511 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Apr 4 14:02:00 2023 13 // Update Count : 6329 14 14 // 15 15 … … 44 44 45 45 #include <cstdio> 46 #include <sstream> 46 47 #include <stack> 47 48 using namespace std; 48 49 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_... 51 56 #include "TypedefTable.h" 52 57 #include "TypeData.h" 53 #include "SynTree/LinkageSpec.h"54 58 #include "Common/SemanticError.h" // error_str 55 59 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... 56 60 57 #include "SynTree/Attribute.h" 61 #include "SynTree/Attribute.h" // for Attribute 58 62 59 63 // lex uses __null in a boolean context, it's fine. … … 63 67 64 68 extern DeclarationNode * parseTree; 65 extern LinkageSpec::Spec linkage;69 extern ast::Linkage::Spec linkage; 66 70 extern TypedefTable typedefTable; 67 71 68 stack< LinkageSpec::Spec> linkageStack;72 stack<ast::Linkage::Spec> linkageStack; 69 73 70 74 bool appendStr( string & to, string & from ) { … … 199 203 } // fieldDecl 200 204 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" ) ) ) 203 207 #define UPDOWN( compop, left, right ) (compop == OperKinds::LThan || compop == OperKinds::LEThan ? left : right) 204 208 #define MISSING_ANON_FIELD "Missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body." … … 206 210 #define MISSING_HIGH "Missing high value for down-to range so index is uninitialized." 207 211 208 ForCtrl * forCtrl( DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 212 static ForCtrl * makeForCtrl( 213 const CodeLocation & location, 214 DeclarationNode * init, 215 enum OperKinds compop, 216 ExpressionNode * comp, 217 ExpressionNode * inc ) { 218 // Wrap both comp/inc if they are non-null. 219 if ( comp ) comp = new ExpressionNode( build_binary_val( location, 220 compop, 221 new ExpressionNode( build_varref( location, new string( *init->name ) ) ), 222 comp ) ); 223 if ( inc ) inc = new ExpressionNode( build_binary_val( location, 224 // choose += or -= for upto/downto 225 compop == OperKinds::LThan || compop == OperKinds::LEThan ? OperKinds::PlusAssn : OperKinds::MinusAssn, 226 new ExpressionNode( build_varref( location, new string( *init->name ) ) ), 227 inc ) ); 228 // The StatementNode call frees init->name, it must happen later. 229 return new ForCtrl( new StatementNode( init ), comp, inc ); 230 } 231 232 ForCtrl * forCtrl( const CodeLocation & location, DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 209 233 if ( index->initializer ) { 210 234 SemanticError( yylloc, "Direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." ); … … 213 237 SemanticError( yylloc, "Multiple loop indexes disallowed in for-loop declaration." ); 214 238 } // 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 ); 220 241 } // forCtrl 221 242 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 ) ) );243 ForCtrl * forCtrl( const CodeLocation & location, ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 244 ast::ConstantExpr * constant = dynamic_cast<ast::ConstantExpr *>(type->expr.get()); 245 if ( constant && (constant->rep == "0" || constant->rep == "1") ) { 246 type = new ExpressionNode( new ast::CastExpr( location, maybeMoveBuild(type), new ast::BasicType( ast::BasicType::SignedInt ) ) ); 226 247 } // 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 ); 234 253 } // forCtrl 235 254 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 );255 ForCtrl * forCtrl( const CodeLocation & location, ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 256 if ( auto identifier = dynamic_cast<ast::NameExpr *>(index->expr.get()) ) { 257 return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc ); 258 } else if ( auto commaExpr = dynamic_cast<ast::CommaExpr *>( index->expr.get() ) ) { 259 if ( auto identifier = commaExpr->arg1.as<ast::NameExpr>() ) { 260 return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc ); 242 261 } else { 243 262 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr; … … 281 300 %union { 282 301 Token tok; 283 ParseNode * pn; 284 ExpressionNode * en; 302 ExpressionNode * expr; 285 303 DeclarationNode * decl; 286 AggregateDecl::Aggregate aggKey;287 TypeDecl::Kind tclass;288 StatementNode * s n;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; 291 309 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; 297 314 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; 302 319 } 303 320 304 // ************************* TERMINAL TOKENS ********************************321 // ************************ TERMINAL TOKENS ******************************** 305 322 306 323 // keywords … … 337 354 338 355 // names and constants: lexer differentiates between identifier and typedef names 339 %token<tok> IDENTIFIER QUOTED_IDENTIFIERTYPEDIMname TYPEDEFname TYPEGENname340 %token<tok> TIMEOUT W ORCATCH RECOVER CATCHRESUME FIXUP FINALLY // CFA356 %token<tok> IDENTIFIER TYPEDIMname TYPEDEFname TYPEGENname 357 %token<tok> TIMEOUT WAND WOR CATCH RECOVER CATCHRESUME FIXUP FINALLY // CFA 341 358 %token<tok> INTEGERconstant CHARACTERconstant STRINGliteral 342 359 %token<tok> DIRECTIVE … … 364 381 %type<tok> identifier identifier_at identifier_or_type_name attr_name 365 382 %type<tok> quasi_keyword 366 %type< constant> string_literal383 %type<expr> string_literal 367 384 %type<str> string_literal_list 368 385 369 %type< hide> hide_opt visible_hide_opt386 %type<enum_hiding> hide_opt visible_hide_opt 370 387 371 388 // expressions 372 %type<e n> constant373 %type<e n> tuple tuple_expression_list374 %type<op > ptrref_operator unary_operator assignment_operator simple_assignment_operator compound_assignment_operator375 %type<e n> primary_expression postfix_expression unary_expression376 %type<e n> cast_expression_list cast_expression exponential_expression multiplicative_expression additive_expression377 %type<e n> shift_expression relational_expression equality_expression378 %type<e n> AND_expression exclusive_OR_expression inclusive_OR_expression379 %type<e n> logical_AND_expression logical_OR_expression380 %type<e n> conditional_expression constant_expression assignment_expression assignment_expression_opt381 %type<e n> comma_expression comma_expression_opt382 %type<e n> argument_expression_list_opt argument_expression_list argument_expression default_initializer_opt389 %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 383 400 %type<ifctl> conditional_declaration 384 %type<f ctl> for_control_expression for_control_expression_list385 %type< compop> upupeq updown updowneq downupdowneq386 %type<e n> subrange401 %type<forctl> for_control_expression for_control_expression_list 402 %type<oper> upupeq updown updowneq downupdowneq 403 %type<expr> subrange 387 404 %type<decl> asm_name_opt 388 %type<e n> asm_operands_opt asm_operands_list asm_operand389 %type<label > label_list390 %type<e n> asm_clobbers_list_opt391 %type< flag> asm_volatile_opt392 %type<e n> handler_predicate_opt405 %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 393 410 %type<genexpr> generic_association generic_assoc_list 394 411 395 412 // 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 412 430 413 431 // declarations … … 421 439 %type<decl> assertion assertion_list assertion_list_opt 422 440 423 %type<e n> bit_subrange_size_opt bit_subrange_size441 %type<expr> bit_subrange_size_opt bit_subrange_size 424 442 425 443 %type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type … … 434 452 435 453 %type<decl> enumerator_list enum_type enum_type_nobody 436 %type<in > enumerator_value_opt454 %type<init> enumerator_value_opt 437 455 438 456 %type<decl> external_definition external_definition_list external_definition_list_opt … … 441 459 442 460 %type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract 443 %type<e n> field field_name_list field_name fraction_constants_opt461 %type<expr> field field_name_list field_name fraction_constants_opt 444 462 445 463 %type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr … … 482 500 %type<decl> typedef_name typedef_declaration typedef_expression 483 501 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 485 504 486 505 %type<decl> type_parameter_redeclarator type_parameter_ptr type_parameter_array type_parameter_function … … 489 508 %type<decl> type_parameter type_parameter_list type_initializer_opt 490 509 491 %type<e n> type_parameters_opt type_list array_type_list510 %type<expr> type_parameters_opt type_list array_type_list 492 511 493 512 %type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list … … 500 519 501 520 // initializers 502 %type<in > initializer initializer_list_opt initializer_opt521 %type<init> initializer initializer_list_opt initializer_opt 503 522 504 523 // designators 505 %type<e n> designator designator_list designation524 %type<expr> designator designator_list designation 506 525 507 526 … … 512 531 // Similar issues exit with the waitfor statement. 513 532 514 // Order of these lines matters (low-to-high precedence). THEN is left associative over W OR/TIMEOUT/ELSE, WOR is left515 // 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. 516 535 %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 517 539 %precedence WOR // token precedence for start of WOR in WAITFOR statement 518 540 %precedence TIMEOUT // token precedence for start of TIMEOUT in WAITFOR statement … … 592 614 constant: 593 615 // 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 ) ); } 599 621 ; 600 622 601 623 quasi_keyword: // CFA 602 624 TIMEOUT 625 | WAND 603 626 | WOR 604 627 | CATCH … … 621 644 622 645 string_literal: 623 string_literal_list { $$ = build_constantStr( *$1); }646 string_literal_list { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); } 624 647 ; 625 648 … … 638 661 primary_expression: 639 662 IDENTIFIER // typedef name cannot be used as a variable name 640 { $$ = new ExpressionNode( build_varref( $1 ) ); }663 { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); } 641 664 | quasi_keyword 642 { $$ = new ExpressionNode( build_varref( $1 ) ); }665 { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); } 643 666 | TYPEDIMname // CFA, generic length argument 644 667 // { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( DeclarationNode::newFromTypedef( $1 ) ) ) ); } 645 668 // { $$ = new ExpressionNode( build_varref( $1 ) ); } 646 { $$ = new ExpressionNode( build_dimensionref( $1 ) ); }669 { $$ = new ExpressionNode( build_dimensionref( yylloc, $1 ) ); } 647 670 | tuple 648 671 | '(' comma_expression ')' 649 672 { $$ = $2; } 650 673 | '(' 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 ) ) ) ); } 652 675 | 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 ) ) ); } 654 677 | type_name '.' '[' field_name_list ']' // CFA, nested type / tuple field selector 655 678 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } … … 657 680 { 658 681 // add the missing control expression to the GenericExpr and return it 659 $5->control = maybeMoveBuild <Expression>( $3 );682 $5->control = maybeMoveBuild( $3 ); 660 683 $$ = new ExpressionNode( $5 ); 661 684 } … … 683 706 { 684 707 // 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() ); 686 710 delete $3; 687 711 $$ = $1; … … 693 717 { 694 718 // 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 ) } } ); 696 720 } 697 721 | DEFAULT ':' assignment_expression 698 { $$ = new GenericExpr( nullptr, { { maybeMoveBuild<Expression>( $3 ) } } ); }722 { $$ = new ast::GenericExpr( yylloc, nullptr, { { maybeMoveBuild( $3 ) } } ); } 699 723 ; 700 724 … … 705 729 // Switching to this behaviour may help check if a C compatibilty case uses comma-exprs in subscripts. 706 730 // 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 ) ) )) ) ); } 708 732 | postfix_expression '[' assignment_expression ']' 709 733 // CFA, comma_expression disallowed in this context because it results in a common user error: subscripting a … … 711 735 // little advantage to this feature and many disadvantages. It is possible to write x[(i,j)] in CFA, which is 712 736 // 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 ) ); } 714 738 | 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 ) ); } 716 740 | 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 ) ); } 718 742 | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call 719 743 { 720 744 Token fn; 721 745 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 ) ) ) ); 723 747 } 724 748 | postfix_expression '(' argument_expression_list_opt ')' 725 { $$ = new ExpressionNode( build_func( $1, $3 ) ); }749 { $$ = new ExpressionNode( build_func( yylloc, $1, $3 ) ); } 726 750 | VA_ARG '(' primary_expression ',' declaration_specifier_nobody abstract_parameter_declarator_opt ')' 727 751 // { 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") ) ), 729 753 (ExpressionNode *)($3->set_last( (ExpressionNode *)($6 ? $6->addType( $5 ) : $5) )) ) ); } 730 754 | 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 ) ); } 732 756 | 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 ) ); } 734 758 | 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 ) ); } 736 760 | postfix_expression '.' identifier 737 { $$ = new ExpressionNode( build_fieldSel( $1, build_varref($3 ) ) ); }761 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); } 738 762 | 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 ) ) ); } 740 764 | 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 ) ) ); } 742 766 | 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 ) ) ); } 744 768 | postfix_expression '.' aggregate_control 745 { $$ = new ExpressionNode( build_keyword_cast( $3, $1 ) ); }769 { $$ = new ExpressionNode( build_keyword_cast( yylloc, $3, $1 ) ); } 746 770 | postfix_expression ARROW identifier 747 { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref($3 ) ) ); }771 { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); } 748 772 | 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 ) ) ); } 750 774 | 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 ) ) ); } 752 776 | postfix_expression ICR 753 { $$ = new ExpressionNode( build_unary_ptr(OperKinds::IncrPost, $1 ) ); }777 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::IncrPost, $1 ) ); } 754 778 | postfix_expression DECR 755 { $$ = new ExpressionNode( build_unary_ptr(OperKinds::DecrPost, $1 ) ); }779 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::DecrPost, $1 ) ); } 756 780 | '(' 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 ) ) ); } 758 782 | '(' 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 ) ) ); } 760 784 | '^' primary_expression '{' argument_expression_list_opt '}' // CFA, destructor call 761 785 { 762 786 Token fn; 763 787 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 ) ) ); 765 789 } 766 790 ; … … 781 805 '@' // CFA, default parameter 782 806 { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; } 783 807 // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); } 784 808 | assignment_expression 785 809 ; … … 793 817 field_name 794 818 | 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 ) ) ); } 796 820 | 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 ) ) ); } 798 822 | field_name '.' field 799 { $$ = new ExpressionNode( build_fieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }823 { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); } 800 824 | 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 ) ) ); } 802 826 | field_name ARROW field 803 { $$ = new ExpressionNode( build_pfieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }827 { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); } 804 828 | 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 ) ) ); } 806 830 ; 807 831 808 832 field_name: 809 833 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 ) ); } 811 835 | 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 ) ); } 813 837 | identifier_at fraction_constants_opt // CFA, allow anonymous fields 814 838 { 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 ) ); 816 840 } 817 841 ; … … 822 846 | fraction_constants_opt FLOATING_FRACTIONconstant 823 847 { 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 ); 826 850 } 827 851 ; … … 833 857 | constant 834 858 | string_literal 835 { $$ = new ExpressionNode( $1 ); }859 { $$ = $1; } 836 860 | EXTENSION cast_expression // GCC 837 861 { $$ = $2->set_extension( true ); } … … 842 866 { 843 867 switch ( $1 ) { 844 845 $$ = new ExpressionNode( new AddressExpr( maybeMoveBuild<Expression>( $2 ) ) );868 case OperKinds::AddressOf: 869 $$ = new ExpressionNode( new ast::AddressExpr( maybeMoveBuild( $2 ) ) ); 846 870 break; 847 848 $$ = new ExpressionNode( build_unary_val( $1, $2 ) );871 case OperKinds::PointTo: 872 $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) ); 849 873 break; 850 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 ) ) ) ); 852 876 break; 853 877 default: 854 878 assert( false ); 855 879 } 856 880 } 857 881 | unary_operator cast_expression 858 { $$ = new ExpressionNode( build_unary_val($1, $2 ) ); }882 { $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) ); } 859 883 | ICR unary_expression 860 { $$ = new ExpressionNode( build_unary_ptr(OperKinds::Incr, $2 ) ); }884 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Incr, $2 ) ); } 861 885 | DECR unary_expression 862 { $$ = new ExpressionNode( build_unary_ptr(OperKinds::Decr, $2 ) ); }886 { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Decr, $2 ) ); } 863 887 | SIZEOF unary_expression 864 { $$ = new ExpressionNode( new SizeofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }888 { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuild( $2 ) ) ); } 865 889 | SIZEOF '(' type_no_function ')' 866 { $$ = new ExpressionNode( new SizeofExpr(maybeMoveBuildType( $3 ) ) ); }890 { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); } 867 891 | ALIGNOF unary_expression // GCC, variable alignment 868 { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }892 { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuild( $2 ) ) ); } 869 893 | ALIGNOF '(' type_no_function ')' // GCC, type alignment 870 { $$ = new ExpressionNode( new AlignofExpr(maybeMoveBuildType( $3 ) ) ); }894 { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); } 871 895 | 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 ) ) ); } 873 897 | TYPEID '(' type_no_function ')' 874 898 { … … 895 919 unary_expression 896 920 | '(' type_no_function ')' cast_expression 897 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }921 { $$ = new ExpressionNode( build_cast( yylloc, $2, $4 ) ); } 898 922 | '(' aggregate_control '&' ')' cast_expression // CFA 899 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }923 { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); } 900 924 | '(' aggregate_control '*' ')' cast_expression // CFA 901 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }925 { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); } 902 926 | '(' 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 ) ) ); } 904 928 | '(' 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 ) ) ); } 906 930 | '(' RETURN type_no_function ')' cast_expression // CFA 907 931 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; } … … 911 935 { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; } 912 936 // | '(' type_no_function ')' tuple 913 // { $$ = new ExpressionNode( build_cast($2, $4 ) ); }937 // { $$ = new ast::ExpressionNode( build_cast( yylloc, $2, $4 ) ); } 914 938 ; 915 939 … … 929 953 cast_expression 930 954 | 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 ) ); } 932 956 ; 933 957 … … 935 959 exponential_expression 936 960 | 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 ) ); } 938 962 | 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 ) ); } 940 964 | 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 ) ); } 942 966 ; 943 967 … … 945 969 multiplicative_expression 946 970 | 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 ) ); } 948 972 | 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 ) ); } 950 974 ; 951 975 … … 953 977 additive_expression 954 978 | 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 ) ); } 956 980 | 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 ) ); } 958 982 ; 959 983 … … 961 985 shift_expression 962 986 | 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 ) ); } 964 988 | 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 ) ); } 966 990 | 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 ) ); } 968 992 | 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 ) ); } 970 994 ; 971 995 … … 973 997 relational_expression 974 998 | 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 ) ); } 976 1000 | 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 ) ); } 978 1002 ; 979 1003 … … 981 1005 equality_expression 982 1006 | 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 ) ); } 984 1008 ; 985 1009 … … 987 1011 AND_expression 988 1012 | 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 ) ); } 990 1014 ; 991 1015 … … 993 1017 exclusive_OR_expression 994 1018 | 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 ) ); } 996 1020 ; 997 1021 … … 999 1023 inclusive_OR_expression 1000 1024 | 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 ) ); } 1002 1026 ; 1003 1027 … … 1005 1029 logical_AND_expression 1006 1030 | 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 ) ); } 1008 1032 ; 1009 1033 … … 1011 1035 logical_OR_expression 1012 1036 | logical_OR_expression '?' comma_expression ':' conditional_expression 1013 { $$ = new ExpressionNode( build_cond( $1, $3, $5 ) ); }1037 { $$ = new ExpressionNode( build_cond( yylloc, $1, $3, $5 ) ); } 1014 1038 // FIX ME: computes $1 twice 1015 1039 | 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 ) ); } 1017 1041 ; 1018 1042 … … 1029 1053 // SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr; 1030 1054 // } else { 1031 $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) );1055 $$ = new ExpressionNode( build_binary_val( yylloc, $2, $1, $3 ) ); 1032 1056 // } // if 1033 1057 } … … 1074 1098 // { $$ = new ExpressionNode( build_tuple( $3 ) ); } 1075 1099 '[' ',' 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 ) ) ); } 1077 1101 | '[' 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 ) ) )); } 1079 1103 ; 1080 1104 … … 1092 1116 assignment_expression 1093 1117 | 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 ) ) ); } 1095 1119 ; 1096 1120 … … 1113 1137 | mutex_statement 1114 1138 | waitfor_statement 1139 | waituntil_statement 1115 1140 | exception_statement 1116 1141 | enable_disable_statement … … 1118 1143 | asm_statement 1119 1144 | DIRECTIVE 1120 { $$ = new StatementNode( build_directive( $1 ) ); }1145 { $$ = new StatementNode( build_directive( yylloc, $1 ) ); } 1121 1146 ; 1122 1147 … … 1124 1149 // labels cannot be identifiers 0 or 1 1125 1150 identifier_or_type_name ':' attribute_list_opt statement 1126 { $$ = $4->add_label( $1, $3 ); }1151 { $$ = $4->add_label( yylloc, $1, $3 ); } 1127 1152 | identifier_or_type_name ':' attribute_list_opt error // syntax error 1128 1153 { … … 1136 1161 compound_statement: 1137 1162 '{' '}' 1138 { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); }1163 { $$ = new StatementNode( build_compound( yylloc, (StatementNode *)0 ) ); } 1139 1164 | '{' push 1140 1165 local_label_declaration_opt // GCC, local labels appear at start of block 1141 1166 statement_decl_list // C99, intermix declarations and statements 1142 1167 pop '}' 1143 { $$ = new StatementNode( build_compound( $4 ) ); }1168 { $$ = new StatementNode( build_compound( yylloc, $4 ) ); } 1144 1169 ; 1145 1170 … … 1172 1197 expression_statement: 1173 1198 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 ) ); } 1177 1200 ; 1178 1201 … … 1183 1206 { $$ = $2; } 1184 1207 | SWITCH '(' comma_expression ')' case_clause 1185 { $$ = new StatementNode( build_switch( true, $3, $5 ) ); }1208 { $$ = new StatementNode( build_switch( yylloc, true, $3, $5 ) ); } 1186 1209 | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA 1187 1210 { 1188 StatementNode *sw = new StatementNode( build_switch( true, $3, $8 ) );1211 StatementNode *sw = new StatementNode( build_switch( yylloc, true, $3, $8 ) ); 1189 1212 // The semantics of the declaration list is changed to include associated initialization, which is performed 1190 1213 // *before* the transfer to the appropriate case clause by hoisting the declarations into a compound … … 1192 1215 // therefore, are removed from the grammar even though C allows it. The change also applies to choose 1193 1216 // 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; 1195 1218 } 1196 1219 | SWITCH '(' comma_expression ')' '{' error '}' // CFA, syntax error 1197 1220 { SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; } 1198 1221 | CHOOSE '(' comma_expression ')' case_clause // CFA 1199 { $$ = new StatementNode( build_switch( false, $3, $5 ) ); }1222 { $$ = new StatementNode( build_switch( yylloc, false, $3, $5 ) ); } 1200 1223 | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA 1201 1224 { 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; 1204 1227 } 1205 1228 | CHOOSE '(' comma_expression ')' '{' error '}' // CFA, syntax error … … 1210 1233 IF '(' conditional_declaration ')' statement %prec THEN 1211 1234 // 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 ) ); } 1213 1236 | 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 ) ) ); } 1215 1238 ; 1216 1239 … … 1224 1247 | declaration comma_expression // semi-colon separated 1225 1248 { $$ = new CondCtl( $1, $2 ); } 1226 1249 ; 1227 1250 1228 1251 // CASE and DEFAULT clauses are only allowed in the SWITCH statement, precluding Duff's device. In addition, a case … … 1232 1255 constant_expression { $$ = $1; } 1233 1256 | 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 ) ) ); } 1235 1258 | subrange // CFA, subrange 1236 1259 ; 1237 1260 1238 1261 case_value_list: // CFA 1239 case_value { $$ = new StatementNode( build_case($1 ) ); }1262 case_value { $$ = new ClauseNode( build_case( yylloc, $1 ) ); } 1240 1263 // 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 ) ) ); } 1242 1265 ; 1243 1266 … … 1248 1271 | CASE case_value_list error // syntax error 1249 1272 { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; } 1250 | DEFAULT ':' { $$ = new StatementNode( build_default() ); }1273 | DEFAULT ':' { $$ = new ClauseNode( build_default( yylloc ) ); } 1251 1274 // A semantic check is required to ensure only one default clause per switch/choose statement. 1252 1275 | DEFAULT error // syntax error … … 1256 1279 case_label_list: // CFA 1257 1280 case_label 1258 | case_label_list case_label { $$ = (StatementNode *)( $1->set_last( $2 )); }1281 | case_label_list case_label { $$ = $1->set_last( $2 ); } 1259 1282 ; 1260 1283 1261 1284 case_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 ) ); } 1263 1286 ; 1264 1287 … … 1271 1294 switch_clause_list: // CFA 1272 1295 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 ) ) ); } 1274 1297 | 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 ) ) ) ); } 1276 1299 ; 1277 1300 1278 1301 iteration_statement: 1279 1302 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 ) ) ); } 1281 1304 | WHILE '(' ')' statement ELSE statement // CFA 1282 1305 { 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 ); 1285 1308 } 1286 1309 | 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 ) ) ); } 1288 1311 | 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 ) ); } 1290 1313 | 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 ) ) ); } 1292 1315 | DO statement WHILE '(' ')' ELSE statement // CFA 1293 1316 { 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 ); 1296 1319 } 1297 1320 | 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 ) ) ); } 1299 1322 | 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 ) ); } 1301 1324 | 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 ) ) ); } 1303 1326 | FOR '(' ')' statement ELSE statement // CFA 1304 1327 { 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 ); 1307 1330 } 1308 1331 | 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 ) ) ); } 1310 1333 | 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 ) ); } 1312 1335 ; 1313 1336 … … 1323 1346 if ( $1->condition ) { 1324 1347 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 ) ); 1326 1349 } // if 1327 1350 } else $1->condition = $3->condition; 1328 1351 if ( $1->change ) { 1329 1352 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() ) ); 1331 1354 } // if 1332 1355 } else $1->change = $3->change; … … 1337 1360 for_control_expression: 1338 1361 ';' comma_expression_opt ';' comma_expression_opt 1339 { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); }1362 { $$ = new ForCtrl( nullptr, $2, $4 ); } 1340 1363 | 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 } 1342 1368 | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';' 1343 { $$ = new ForCtrl( $1, $2, $4 ); }1369 { $$ = new ForCtrl( new StatementNode( $1 ), $2, $4 ); } 1344 1370 1345 1371 | '@' ';' comma_expression // CFA, empty loop-index 1346 { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, nullptr ); }1372 { $$ = new ForCtrl( nullptr, $3, nullptr ); } 1347 1373 | '@' ';' comma_expression ';' comma_expression // CFA, empty loop-index 1348 { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, $5 ); }1374 { $$ = new ForCtrl( nullptr, $3, $5 ); } 1349 1375 1350 1376 | 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 ); } 1352 1378 | 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 ); } 1354 1380 1355 1381 | 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 ); } 1357 1383 | '@' updowneq comma_expression // CFA, anonymous loop-index 1358 1384 { 1359 1385 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 ); 1361 1387 } 1362 1388 | comma_expression updowneq '@' // CFA, anonymous loop-index … … 1366 1392 } 1367 1393 | 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 ); } 1369 1395 | '@' updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index 1370 1396 { 1371 1397 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 ); 1373 1399 } 1374 1400 | comma_expression updowneq '@' '~' comma_expression // CFA, anonymous loop-index … … 1389 1415 1390 1416 | 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 ); } 1392 1418 | 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 ); } 1394 1420 1395 1421 | 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 ); } 1397 1423 | comma_expression ';' '@' updowneq comma_expression // CFA 1398 1424 { 1399 1425 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 ); 1401 1427 } 1402 1428 | comma_expression ';' comma_expression updowneq '@' // CFA … … 1404 1430 if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1405 1431 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 ); 1407 1433 } 1408 1434 | comma_expression ';' '@' updowneq '@' // CFA, error … … 1410 1436 1411 1437 | 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 ); } 1413 1439 | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, error 1414 1440 { 1415 1441 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 ); 1417 1443 } 1418 1444 | comma_expression ';' comma_expression updowneq '@' '~' comma_expression // CFA … … 1420 1446 if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1421 1447 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 ); 1423 1449 } 1424 1450 | 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 ); } 1426 1452 | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, error 1427 1453 { 1428 1454 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 ); 1430 1456 } 1431 1457 | comma_expression ';' comma_expression updowneq '@' '~' '@' // CFA … … 1433 1459 if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1434 1460 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 ); 1436 1462 } 1437 1463 | comma_expression ';' '@' updowneq '@' '~' '@' // CFA … … 1439 1465 1440 1466 | 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 ); } 1442 1468 | 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 ); } 1444 1470 1445 1471 | 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 ); } 1447 1473 | declaration '@' updowneq comma_expression // CFA 1448 1474 { 1449 1475 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 ); 1451 1477 } 1452 1478 | declaration comma_expression updowneq '@' // CFA … … 1454 1480 if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1455 1481 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 ); 1457 1483 } 1458 1484 1459 1485 | 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 ); } 1461 1487 | declaration '@' updowneq comma_expression '~' comma_expression // CFA 1462 1488 { 1463 1489 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 ); 1465 1491 } 1466 1492 | declaration comma_expression updowneq '@' '~' comma_expression // CFA … … 1468 1494 if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1469 1495 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 ); 1471 1497 } 1472 1498 | 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 ); } 1474 1500 | declaration '@' updowneq comma_expression '~' '@' // CFA 1475 1501 { 1476 1502 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 ); 1478 1504 } 1479 1505 | declaration comma_expression updowneq '@' '~' '@' // CFA … … 1481 1507 if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1482 1508 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 ); 1484 1510 } 1485 1511 | declaration '@' updowneq '@' '~' '@' // CFA, error … … 1496 1522 SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr; 1497 1523 } 1498 1524 ; 1499 1525 1500 1526 downupdowneq: … … 1505 1531 | ErangeDownEq 1506 1532 { $$ = OperKinds::GEThan; } 1507 1533 ; 1508 1534 1509 1535 updown: … … 1512 1538 | ErangeDown 1513 1539 { $$ = OperKinds::GThan; } 1514 1540 ; 1515 1541 1516 1542 updowneq: … … 1520 1546 | ErangeDownEq 1521 1547 { $$ = OperKinds::GEThan; } 1522 1548 ; 1523 1549 1524 1550 jump_statement: 1525 1551 GOTO identifier_or_type_name ';' 1526 { $$ = new StatementNode( build_branch( $2,BranchStmt::Goto ) ); }1552 { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Goto ) ); } 1527 1553 | GOTO '*' comma_expression ';' // GCC, computed goto 1528 1554 // The syntax for the GCC computed goto violates normal expression precedence, e.g., goto *i+3; => goto *(i+3); … … 1531 1557 // A semantic check is required to ensure fallthru appears only in the body of a choose statement. 1532 1558 | fall_through_name ';' // CFA 1533 { $$ = new StatementNode( build_branch( BranchStmt::FallThrough ) ); }1559 { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThrough ) ); } 1534 1560 | 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 ) ); } 1536 1562 | fall_through_name DEFAULT ';' // CFA 1537 { $$ = new StatementNode( build_branch( BranchStmt::FallThroughDefault ) ); }1563 { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThroughDefault ) ); } 1538 1564 | CONTINUE ';' 1539 1565 // 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 ) ); } 1541 1567 | CONTINUE identifier_or_type_name ';' // CFA, multi-level continue 1542 1568 // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and 1543 1569 // 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 ) ); } 1545 1571 | BREAK ';' 1546 1572 // 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 ) ); } 1548 1574 | BREAK identifier_or_type_name ';' // CFA, multi-level exit 1549 1575 // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and 1550 1576 // 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 ) ); } 1552 1578 | RETURN comma_expression_opt ';' 1553 { $$ = new StatementNode( build_return( $2 ) ); }1579 { $$ = new StatementNode( build_return( yylloc, $2 ) ); } 1554 1580 | RETURN '{' initializer_list_opt comma_opt '}' ';' 1555 1581 { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; } 1556 1582 | SUSPEND ';' 1557 { $$ = new StatementNode( build_suspend( nullptr) ); }1583 { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::None ) ); } 1558 1584 | SUSPEND compound_statement 1559 { $$ = new StatementNode( build_suspend( $2) ); }1585 { $$ = new StatementNode( build_suspend( yylloc, $2, ast::SuspendStmt::None ) ); } 1560 1586 | SUSPEND COROUTINE ';' 1561 { $$ = new StatementNode( build_suspend( nullptr,SuspendStmt::Coroutine ) ); }1587 { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Coroutine ) ); } 1562 1588 | SUSPEND COROUTINE compound_statement 1563 { $$ = new StatementNode( build_suspend( $3,SuspendStmt::Coroutine ) ); }1589 { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Coroutine ) ); } 1564 1590 | SUSPEND GENERATOR ';' 1565 { $$ = new StatementNode( build_suspend( nullptr,SuspendStmt::Generator ) ); }1591 { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Generator ) ); } 1566 1592 | SUSPEND GENERATOR compound_statement 1567 { $$ = new StatementNode( build_suspend( $3,SuspendStmt::Generator ) ); }1593 { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Generator ) ); } 1568 1594 | THROW assignment_expression_opt ';' // handles rethrow 1569 { $$ = new StatementNode( build_throw( $2 ) ); }1595 { $$ = new StatementNode( build_throw( yylloc, $2 ) ); } 1570 1596 | THROWRESUME assignment_expression_opt ';' // handles reresume 1571 { $$ = new StatementNode( build_resume( $2 ) ); }1597 { $$ = new StatementNode( build_resume( yylloc, $2 ) ); } 1572 1598 | THROWRESUME assignment_expression_opt AT assignment_expression ';' // handles reresume 1573 1599 { $$ = new StatementNode( build_resume_at( $2, $4 ) ); } … … 1581 1607 with_statement: 1582 1608 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". 1587 1613 mutex_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 } 1590 1619 ; 1591 1620 … … 1598 1627 { $$ = nullptr; } 1599 1628 | 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 )); }1609 1629 ; 1610 1630 … … 1617 1637 1618 1638 timeout: 1619 TIMEOUT '(' comma_expression ')' { $$ = $3; } 1620 ; 1621 1622 waitfor_clause: 1639 TIMEOUT '(' comma_expression ')' { $$ = $3; } 1640 ; 1641 1642 wor: 1643 OROR 1644 | WOR 1645 1646 waitfor: 1647 WAITFOR '(' cast_expression ')' 1648 { $$ = $3; } 1649 | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')' 1650 { $$ = (ExpressionNode *)($3->set_last( $5 )); } 1651 ; 1652 1653 wor_waitfor_clause: 1623 1654 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 ) ); } 1631 1663 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1632 | w hen_clause_opt timeout statement WORELSE statement // syntax error1664 | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error 1633 1665 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1634 | w hen_clause_opt timeout statement WORwhen_clause ELSE statement1635 { $$ = 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 ) ); } 1636 1668 ; 1637 1669 1638 1670 waitfor_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 1675 wand: 1676 ANDAND 1677 | WAND 1678 ; 1679 1680 waituntil: 1681 WAITUNTIL '(' cast_expression ')' 1682 { $$ = $3; } 1683 ; 1684 1685 waituntil_clause: 1686 when_clause_opt waituntil statement 1687 { printf( "waituntil_clause 1\n" ); $$ = nullptr; } 1688 | '(' wor_waituntil_clause ')' 1689 { printf( "waituntil_clause 2\n" ); $$ = nullptr; } 1690 ; 1691 1692 wand_waituntil_clause: 1693 waituntil_clause %prec THEN 1694 { printf( "wand_waituntil_clause 1\n" ); $$ = nullptr; } 1695 | waituntil_clause wand wand_waituntil_clause 1696 { printf( "wand_waituntil_clause 2\n" ); $$ = nullptr; } 1697 ; 1698 1699 wor_waituntil_clause: 1700 wand_waituntil_clause 1701 { printf( "wor_waituntil_clause 1\n" ); $$ = nullptr; } 1702 | wor_waituntil_clause wor wand_waituntil_clause 1703 { printf( "wor_waituntil_clause 2\n" ); $$ = nullptr; } 1704 | wor_waituntil_clause wor when_clause_opt ELSE statement 1705 { printf( "wor_waituntil_clause 3\n" ); $$ = nullptr; } 1706 | wor_waituntil_clause wor when_clause_opt timeout statement %prec THEN 1707 { printf( "wor_waituntil_clause 4\n" ); $$ = nullptr; } 1708 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1709 | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error 1710 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1711 | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement 1712 { printf( "wor_waituntil_clause 6\n" ); $$ = nullptr; } 1713 ; 1714 1715 waituntil_statement: 1716 wor_waituntil_clause %prec THEN 1717 // SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement. 1718 { $$ = new StatementNode( build_compound( yylloc, nullptr ) ); } 1643 1719 ; 1644 1720 1645 1721 exception_statement: 1646 TRY compound_statement handler_clause 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 ) ); } 1648 1724 | TRY compound_statement finally_clause 1649 { $$ = new StatementNode( build_try( $2, nullptr, $3 ) ); }1725 { $$ = new StatementNode( build_try( yylloc, $2, nullptr, $3 ) ); } 1650 1726 | TRY compound_statement handler_clause finally_clause 1651 { $$ = new StatementNode( build_try( $2, $3, $4 ) ); }1727 { $$ = new StatementNode( build_try( yylloc, $2, $3, $4 ) ); } 1652 1728 ; 1653 1729 1654 1730 handler_clause: 1655 1731 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 ) ); } 1657 1733 | 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 ) ) ); } 1659 1735 ; 1660 1736 … … 1666 1742 1667 1743 handler_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; } 1672 1748 ; 1673 1749 1674 1750 finally_clause: 1675 FINALLY compound_statement { $$ = new StatementNode( build_finally($2 ) ); }1751 FINALLY compound_statement { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); } 1676 1752 ; 1677 1753 … … 1699 1775 asm_statement: 1700 1776 ASM asm_volatile_opt '(' string_literal ')' ';' 1701 { $$ = new StatementNode( build_asm( $2, $4, nullptr ) ); }1777 { $$ = new StatementNode( build_asm( yylloc, $2, $4, nullptr ) ); } 1702 1778 | 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 ) ); } 1704 1780 | 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 ) ); } 1706 1782 | 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 ) ); } 1708 1784 | 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 ) ); } 1710 1786 ; 1711 1787 … … 1731 1807 asm_operand: // GCC 1732 1808 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 ) ) ); } 1734 1810 | '[' 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 } 1736 1815 ; 1737 1816 … … 1740 1819 { $$ = nullptr; } // use default argument 1741 1820 | string_literal 1742 { $$ = new ExpressionNode( $1 ); }1821 { $$ = $1; } 1743 1822 | asm_clobbers_list_opt ',' string_literal 1744 { $$ = (ExpressionNode *)( $1->set_last( new ExpressionNode( $3 ) )); }1823 { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); } 1745 1824 ; 1746 1825 … … 1748 1827 identifier 1749 1828 { 1750 $$ = new LabelNode(); $$->labels. push_back(*$1 );1829 $$ = new LabelNode(); $$->labels.emplace_back( yylloc, *$1 ); 1751 1830 delete $1; // allocated by lexer 1752 1831 } 1753 1832 | label_list ',' identifier 1754 1833 { 1755 $$ = $1; $1->labels. push_back(*$3 );1834 $$ = $1; $1->labels.emplace_back( yylloc, *$3 ); 1756 1835 delete $3; // allocated by lexer 1757 1836 } … … 1804 1883 { 1805 1884 // printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" ); 1806 1885 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) { 1807 1886 // printf( "\tattr %s\n", attr->name.c_str() ); 1808 1887 // } // for … … 1814 1893 static_assert: 1815 1894 STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11 1816 { $$ = DeclarationNode::newStaticAssert( $3, $5); }1895 { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); } 1817 1896 | STATICASSERT '(' constant_expression ')' ';' // CFA 1818 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( *new string( "\"\"" ) ) ); }1897 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); } 1819 1898 1820 1899 // C declaration syntax is notoriously confusing and error prone. Cforall provides its own type, variable and function … … 1939 2018 TYPEDEF type_specifier declarator 1940 2019 { 1941 // if type_specifier is an anon aggregate => name1942 2020 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 1944 2024 } 1945 2025 | typedef_declaration pop ',' push declarator … … 1949 2029 } 1950 2030 | 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; } 1955 2032 | 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; } 1960 2034 | 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; } 1965 2036 ; 1966 2037 … … 1969 2040 TYPEDEF identifier '=' assignment_expression 1970 2041 { 1971 SemanticError( yylloc, "T ypedefexpression is deprecated, use typeof(...) instead." ); $$ = nullptr;2042 SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr; 1972 2043 } 1973 2044 | typedef_expression pop ',' push identifier '=' assignment_expression 1974 2045 { 1975 SemanticError( yylloc, "T ypedefexpression is deprecated, use typeof(...) instead." ); $$ = nullptr;2046 SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr; 1976 2047 } 1977 2048 ; … … 1983 2054 | typedef_expression // deprecated GCC, naming expression type 1984 2055 | 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 } 1985 2066 ; 1986 2067 … … 1988 2069 // A semantic check is required to ensure asm_name only appears on declarations with implicit or explicit static 1989 2070 // storage-class 1990 declarator asm_name_opt initializer_opt2071 variable_declarator asm_name_opt initializer_opt 1991 2072 { $$ = $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 1992 2081 | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt 1993 2082 { $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); } 2083 ; 2084 2085 general_function_declarator: 2086 function_type_redeclarator 2087 | function_declarator 1994 2088 ; 1995 2089 … … 2000 2094 | sue_declaration_specifier invalid_types 2001 2095 { 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" ) ); 2006 2099 $$ = nullptr; 2007 2100 } … … 2028 2121 basic_type_specifier 2029 2122 | 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 // } // for2035 }2036 2123 | type_type_specifier 2037 2124 ; … … 2242 2329 { $$ = DeclarationNode::newTypeof( $3 ); } 2243 2330 | 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 ); } 2245 2332 | BASETYPEOF '(' comma_expression ')' // CFA: basetypeof( a+b ) y; 2246 2333 { $$ = DeclarationNode::newTypeof( $3, true ); } … … 2255 2342 { 2256 2343 // printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" ); 2257 2344 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) { 2258 2345 // printf( "\tattr %s\n", attr->name.c_str() ); 2259 2346 // } // for … … 2271 2358 { 2272 2359 // printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" ); 2273 2360 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) { 2274 2361 // printf( "\tattr %s\n", attr->name.c_str() ); 2275 2362 // } // for … … 2349 2436 { 2350 2437 // printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" ); 2351 2438 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) { 2352 2439 // printf( "\tattr %s\n", attr->name.c_str() ); 2353 2440 // } // for … … 2373 2460 '{' field_declaration_list_opt '}' type_parameters_opt 2374 2461 { 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 // } // for2380 2462 $$ = 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 // } // for2385 2463 } 2386 2464 | aggregate_key attribute_list_opt TYPEDEFname // unqualified type name … … 2391 2469 '{' field_declaration_list_opt '}' type_parameters_opt 2392 2470 { 2393 // printf( "AGG3\n" );2394 2471 DeclarationNode::newFromTypedef( $3 ); 2395 2472 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); … … 2402 2479 '{' field_declaration_list_opt '}' type_parameters_opt 2403 2480 { 2404 // printf( "AGG4\n" );2405 2481 DeclarationNode::newFromTypeGen( $3, nullptr ); 2406 2482 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); … … 2429 2505 // switched to a TYPEGENname. Link any generic arguments from typegen_name to new generic declaration and 2430 2506 // 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 } 2435 2515 } 2436 2516 ; … … 2443 2523 aggregate_data: 2444 2524 STRUCT vtable_opt 2445 { $$ = AggregateDecl::Struct; }2525 { $$ = ast::AggregateDecl::Struct; } 2446 2526 | UNION 2447 { $$ = AggregateDecl::Union; }2527 { $$ = ast::AggregateDecl::Union; } 2448 2528 | 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; } 2451 2531 ; 2452 2532 2453 2533 aggregate_control: // CFA 2454 2534 MONITOR 2455 { $$ = AggregateDecl::Monitor; }2535 { $$ = ast::AggregateDecl::Monitor; } 2456 2536 | MUTEX STRUCT 2457 { $$ = AggregateDecl::Monitor; }2537 { $$ = ast::AggregateDecl::Monitor; } 2458 2538 | GENERATOR 2459 { $$ = AggregateDecl::Generator; }2539 { $$ = ast::AggregateDecl::Generator; } 2460 2540 | 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 } 2462 2545 | COROUTINE 2463 { $$ = AggregateDecl::Coroutine; }2546 { $$ = ast::AggregateDecl::Coroutine; } 2464 2547 | 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 } 2466 2552 | THREAD 2467 { $$ = AggregateDecl::Thread; }2553 { $$ = ast::AggregateDecl::Thread; } 2468 2554 | 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 } 2470 2559 ; 2471 2560 … … 2483 2572 $$ = fieldDecl( $1, $2 ); 2484 2573 // printf( "type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" ); 2485 2574 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) { 2486 2575 // printf( "\tattr %s\n", attr->name.c_str() ); 2487 2576 // } // for … … 2490 2579 { $$ = fieldDecl( $2, $3 ); distExt( $$ ); } 2491 2580 | STATIC type_specifier field_declaring_list_opt ';' // CFA 2492 2581 { SemanticError( yylloc, "STATIC aggregate field qualifier currently unimplemented." ); $$ = nullptr; } 2493 2582 | INLINE type_specifier field_abstract_list_opt ';' // CFA 2494 2583 { … … 2501 2590 } 2502 2591 | INLINE aggregate_control ';' // CFA 2503 2592 { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; } 2504 2593 | typedef_declaration ';' // CFA 2505 2594 | cfa_field_declaring_list ';' // CFA, new style field declaration … … 2527 2616 { $$ = $1->addBitfield( $2 ); } 2528 2617 | 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 2529 2621 // A semantic check is required to ensure bit_subrange only appears on integral types. 2530 2622 { $$ = $1->addBitfield( $2 ); } … … 2581 2673 { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); } 2582 2674 | 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() ) 2585 2677 { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2586 2678 … … 2589 2681 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt 2590 2682 { 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." ); } 2592 2684 typedefTable.makeTypedef( *$6 ); 2593 2685 } … … 2757 2849 type_no_function: // sizeof, alignof, cast (constructor) 2758 2850 cfa_abstract_declarator_tuple // CFA 2759 | type_specifier 2851 | type_specifier // cannot be type_specifier_nobody, e.g., (struct S {}){} is a thing 2760 2852 | type_specifier abstract_declarator 2761 2853 { $$ = $2->addType( $1 ); } … … 2802 2894 designator_list ':' // C99, CFA uses ":" instead of "=" 2803 2895 | identifier_at ':' // GCC, field name 2804 { $$ = new ExpressionNode( build_varref( $1 ) ); }2896 { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); } 2805 2897 ; 2806 2898 … … 2814 2906 designator: 2815 2907 '.' identifier_at // C99, field name 2816 { $$ = new ExpressionNode( build_varref( $2 ) ); }2908 { $$ = new ExpressionNode( build_varref( yylloc, $2 ) ); } 2817 2909 | '[' push assignment_expression pop ']' // C99, single array element 2818 2910 // assignment_expression used instead of constant_expression because of shift/reduce conflicts with tuple. … … 2821 2913 { $$ = $3; } 2822 2914 | '[' 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 ) ) ); } 2824 2916 | '.' '[' push field_name_list pop ']' // CFA, tuple field selector 2825 2917 { $$ = $4; } … … 2861 2953 { 2862 2954 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 ..." ); } 2866 2958 } 2867 2959 type_initializer_opt assertion_list_opt … … 2874 2966 { 2875 2967 typedefTable.addToScope( *$2, TYPEDIMname, "9" ); 2876 $$ = DeclarationNode::newTypeParam( TypeDecl::Dimension, $2 );2968 $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dimension, $2 ); 2877 2969 } 2878 2970 // | type_specifier identifier_parameter_declarator 2879 2971 | 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 ); } 2881 2973 ; 2882 2974 2883 2975 new_type_class: // CFA 2884 2976 // empty 2885 { $$ = TypeDecl::Otype; }2977 { $$ = ast::TypeDecl::Otype; } 2886 2978 | '&' 2887 { $$ = TypeDecl::Dtype; }2979 { $$ = ast::TypeDecl::Dtype; } 2888 2980 | '*' 2889 { $$ = TypeDecl::DStype; } // dtype + sized2981 { $$ = ast::TypeDecl::DStype; } // dtype + sized 2890 2982 // | '(' '*' ')' 2891 // { $$ = TypeDecl::Ftype; }2983 // { $$ = ast::TypeDecl::Ftype; } 2892 2984 | ELLIPSIS 2893 { $$ = TypeDecl::Ttype; }2985 { $$ = ast::TypeDecl::Ttype; } 2894 2986 ; 2895 2987 2896 2988 type_class: // CFA 2897 2989 OTYPE 2898 { $$ = TypeDecl::Otype; }2990 { $$ = ast::TypeDecl::Otype; } 2899 2991 | DTYPE 2900 { $$ = TypeDecl::Dtype; }2992 { $$ = ast::TypeDecl::Dtype; } 2901 2993 | FTYPE 2902 { $$ = TypeDecl::Ftype; }2994 { $$ = ast::TypeDecl::Ftype; } 2903 2995 | TTYPE 2904 { $$ = TypeDecl::Ttype; }2996 { $$ = ast::TypeDecl::Ttype; } 2905 2997 ; 2906 2998 … … 2928 3020 type_list: // CFA 2929 3021 type 2930 { $$ = new ExpressionNode( new TypeExpr(maybeMoveBuildType( $1 ) ) ); }3022 { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); } 2931 3023 | assignment_expression 2932 3024 | 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 ) ) ) )); } 2934 3026 | type_list ',' assignment_expression 2935 3027 { $$ = (ExpressionNode *)( $1->set_last( $3 )); } … … 2968 3060 TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' '}' 2969 3061 { 2970 SemanticWarning( yylloc, Warning::DeprecTraitSyntax , "");3062 SemanticWarning( yylloc, Warning::DeprecTraitSyntax ); 2971 3063 $$ = DeclarationNode::newTrait( $2, $4, nullptr ); 2972 3064 } … … 2975 3067 | TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' push trait_declaration_list pop '}' 2976 3068 { 2977 SemanticWarning( yylloc, Warning::DeprecTraitSyntax , "");3069 SemanticWarning( yylloc, Warning::DeprecTraitSyntax ); 2978 3070 $$ = DeclarationNode::newTrait( $2, $4, $8 ); 2979 3071 } … … 3038 3130 external_definition: 3039 3131 DIRECTIVE 3040 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); }3132 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( yylloc, $1 ) ) ); } 3041 3133 | 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 } 3042 3146 | IDENTIFIER IDENTIFIER 3043 3147 { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; } … … 3059 3163 } 3060 3164 | 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 ) ) ); } 3062 3166 | EXTERN STRINGliteral 3063 3167 { 3064 3168 linkageStack.push( linkage ); // handle nested extern "C"/"Cforall" 3065 linkage = LinkageSpec::update( yylloc, linkage, $2 );3169 linkage = ast::Linkage::update( yylloc, linkage, $2 ); 3066 3170 } 3067 3171 up external_definition down … … 3074 3178 { 3075 3179 linkageStack.push( linkage ); // handle nested extern "C"/"Cforall" 3076 linkage = LinkageSpec::update( yylloc, linkage, $2 );3180 linkage = ast::Linkage::update( yylloc, linkage, $2 ); 3077 3181 } 3078 3182 '{' up external_definition_list_opt down '}' … … 3085 3189 | type_qualifier_list 3086 3190 { 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." ); } 3088 3192 if ( $1->type->forall ) forall = true; // remember generic type 3089 3193 } … … 3091 3195 { 3092 3196 distQual( $5, $1 ); 3093 3197 forall = false; 3094 3198 $$ = $5; 3095 3199 } 3096 3200 | declaration_qualifier_list 3097 3201 { 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." ); } 3099 3203 if ( $1->type && $1->type->forall ) forall = true; // remember generic type 3100 3204 } … … 3102 3206 { 3103 3207 distQual( $5, $1 ); 3104 3208 forall = false; 3105 3209 $$ = $5; 3106 3210 } 3107 3211 | declaration_qualifier_list type_qualifier_list 3108 3212 { 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." ); } 3110 3214 if ( ($1->type && $1->type->forall) || ($2->type && $2->type->forall) ) forall = true; // remember generic type 3111 3215 } … … 3113 3217 { 3114 3218 distQual( $6, $1->addQualifiers( $2 ) ); 3115 3219 forall = false; 3116 3220 $$ = $6; 3117 3221 } … … 3157 3261 $$ = $2->addFunctionBody( $4, $3 )->addType( $1 ); 3158 3262 } 3159 | declaration_specifier variable_type_redeclarator with_clause_opt compound_statement3263 | declaration_specifier function_type_redeclarator with_clause_opt compound_statement 3160 3264 { 3161 3265 rebindForall( $1, $2 ); … … 3193 3297 | variable_type_redeclarator 3194 3298 | function_declarator 3299 | function_type_redeclarator 3195 3300 ; 3196 3301 3197 3302 subrange: 3198 3303 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 ) ) ); } 3200 3305 ; 3201 3306 … … 3206 3311 { 3207 3312 DeclarationNode * name = new DeclarationNode(); 3208 name->asmName = $3;3313 name->asmName = maybeMoveBuild( $3 ); 3209 3314 $$ = name->addQualifiers( $5 ); 3210 3315 } … … 3319 3424 | '(' attribute_list variable_ptr ')' array_dimension 3320 3425 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 3321 | '(' variable_array ')' multi_array_dimension 3426 | '(' variable_array ')' multi_array_dimension // redundant parenthesis 3322 3427 { $$ = $2->addArray( $4 ); } 3323 3428 | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis … … 3443 3548 ; 3444 3549 3445 // This pattern parses a declaration for a variable or function prototypethat redefines a type name, e.g.:3550 // This pattern parses a declaration for a variable that redefines a type name, e.g.: 3446 3551 // 3447 3552 // typedef int foo; … … 3449 3554 // int foo; // redefine typedef name in new scope 3450 3555 // } 3451 //3452 // The pattern precludes declaring an array of functions versus a pointer to an array of functions, and returning arrays3453 // and functions versus pointers to arrays and functions.3454 3556 3455 3557 paren_type: … … 3466 3568 paren_type attribute_list_opt 3467 3569 { $$ = $1->addQualifiers( $2 ); } 3468 | type_ptr3469 | type_array attribute_list_opt3570 | variable_type_ptr 3571 | variable_type_array attribute_list_opt 3470 3572 { $$ = $1->addQualifiers( $2 ); } 3471 | type_function attribute_list_opt3573 | variable_type_function attribute_list_opt 3472 3574 { $$ = $1->addQualifiers( $2 ); } 3473 3575 ; 3474 3576 3475 type_ptr:3577 variable_type_ptr: 3476 3578 ptrref_operator variable_type_redeclarator 3477 3579 { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); } 3478 3580 | ptrref_operator type_qualifier_list variable_type_redeclarator 3479 3581 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3480 | '(' type_ptr ')' attribute_list_opt// redundant parenthesis3582 | '(' variable_type_ptr ')' attribute_list_opt // redundant parenthesis 3481 3583 { $$ = $2->addQualifiers( $4 ); } 3482 | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis3584 | '(' attribute_list variable_type_ptr ')' attribute_list_opt // redundant parenthesis 3483 3585 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 3484 3586 ; 3485 3587 3486 type_array:3588 variable_type_array: 3487 3589 paren_type array_dimension 3488 3590 { $$ = $1->addArray( $2 ); } 3489 | '(' type_ptr ')' array_dimension3591 | '(' variable_type_ptr ')' array_dimension 3490 3592 { $$ = $2->addArray( $4 ); } 3491 | '(' attribute_list type_ptr ')' array_dimension3593 | '(' attribute_list variable_type_ptr ')' array_dimension 3492 3594 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 3493 | '(' type_array ')' multi_array_dimension// redundant parenthesis3595 | '(' variable_type_array ')' multi_array_dimension // redundant parenthesis 3494 3596 { $$ = $2->addArray( $4 ); } 3495 | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis3597 | '(' attribute_list variable_type_array ')' multi_array_dimension // redundant parenthesis 3496 3598 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 3497 | '(' type_array ')'// redundant parenthesis3599 | '(' variable_type_array ')' // redundant parenthesis 3498 3600 { $$ = $2; } 3499 | '(' attribute_list type_array ')'// redundant parenthesis3601 | '(' attribute_list variable_type_array ')' // redundant parenthesis 3500 3602 { $$ = $3->addQualifiers( $2 ); } 3501 3603 ; 3502 3604 3503 type_function: 3605 variable_type_function: 3606 '(' variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3607 { $$ = $2->addParamList( $6 ); } 3608 | '(' attribute_list variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3609 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); } 3610 | '(' variable_type_function ')' // redundant parenthesis 3611 { $$ = $2; } 3612 | '(' attribute_list variable_type_function ')' // redundant parenthesis 3613 { $$ = $3->addQualifiers( $2 ); } 3614 ; 3615 3616 // This pattern parses a declaration for a function prototype that redefines a type name. It precludes declaring an 3617 // array of functions versus a pointer to an array of functions, and returning arrays and functions versus pointers to 3618 // arrays and functions. 3619 3620 function_type_redeclarator: 3621 function_type_no_ptr attribute_list_opt 3622 { $$ = $1->addQualifiers( $2 ); } 3623 | function_type_ptr 3624 | function_type_array attribute_list_opt 3625 { $$ = $1->addQualifiers( $2 ); } 3626 ; 3627 3628 function_type_no_ptr: 3504 3629 paren_type '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3505 3630 { $$ = $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 ')' 3507 3632 { $$ = $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 ')' 3509 3634 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); } 3510 | '(' type_function ')'// redundant parenthesis3635 | '(' function_type_no_ptr ')' // redundant parenthesis 3511 3636 { $$ = $2; } 3512 | '(' attribute_list type_function ')' // redundant parenthesis 3637 | '(' attribute_list function_type_no_ptr ')' // redundant parenthesis 3638 { $$ = $3->addQualifiers( $2 ); } 3639 ; 3640 3641 function_type_ptr: 3642 ptrref_operator function_type_redeclarator 3643 { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); } 3644 | ptrref_operator type_qualifier_list function_type_redeclarator 3645 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3646 | '(' function_type_ptr ')' attribute_list_opt 3647 { $$ = $2->addQualifiers( $4 ); } 3648 | '(' attribute_list function_type_ptr ')' attribute_list_opt 3649 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 3650 ; 3651 3652 function_type_array: 3653 '(' function_type_ptr ')' array_dimension 3654 { $$ = $2->addArray( $4 ); } 3655 | '(' attribute_list function_type_ptr ')' array_dimension 3656 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 3657 | '(' function_type_array ')' multi_array_dimension // redundant parenthesis 3658 { $$ = $2->addArray( $4 ); } 3659 | '(' attribute_list function_type_array ')' multi_array_dimension // redundant parenthesis 3660 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 3661 | '(' function_type_array ')' // redundant parenthesis 3662 { $$ = $2; } 3663 | '(' attribute_list function_type_array ')' // redundant parenthesis 3513 3664 { $$ = $3->addQualifiers( $2 ); } 3514 3665 ; … … 3680 3831 array_type_list: 3681 3832 basic_type_name 3682 { $$ = new ExpressionNode( new TypeExpr(maybeMoveBuildType( $1 ) ) ); }3833 { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); } 3683 3834 | type_name 3684 { $$ = new ExpressionNode( new TypeExpr(maybeMoveBuildType( $1 ) ) ); }3835 { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); } 3685 3836 | assignment_expression upupeq assignment_expression 3686 3837 | 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 ) ) ) )); } 3690 3841 | array_type_list ',' assignment_expression upupeq assignment_expression 3691 3842 ; … … 3696 3847 | ErangeUpEq 3697 3848 { $$ = OperKinds::LEThan; } 3698 3849 ; 3699 3850 3700 3851 multi_array_dimension: -
src/Parser/parserutility.cc
r2ed94a9 rb110bcc 10 10 // Created On : Sat May 16 15:30:39 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tus Jul 18 10:12:00 201713 // Update Count : 812 // Last Modified On : Wed Mar 1 10:42:00 2023 13 // Update Count : 9 14 14 // 15 15 … … 19 19 #include <string> // for string 20 20 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... 24 23 25 24 // rewrite … … 28 27 // if ( (int)(x != 0) ) ... 29 28 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 ) ); 29 ast::Expr * notZeroExpr( ast::Expr * orig ) { 30 return ( !orig ) ? nullptr : new ast::CastExpr( orig->location, 31 ast::UntypedExpr::createCall( orig->location, 32 "?!=?", 33 { 34 orig, 35 new ast::ConstantExpr( orig->location, 36 new ast::ZeroType(), 37 "0", 38 std::optional<unsigned long long>( 0 ) 39 ), 40 } 41 ), 42 new ast::BasicType( ast::BasicType::SignedInt ) 43 ); 36 44 } 37 45 -
src/Parser/parserutility.h
r2ed94a9 rb110bcc 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // parserutility.h -- 7 // parserutility.h -- Collected utilities for the parser. 8 8 // 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 15:31:46 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:32:58 201713 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Apr 4 14:03:00 2023 13 // Update Count : 7 14 14 // 15 15 16 16 #pragma once 17 17 18 class Expression; 18 #include "AST/Copy.hpp" // for shallowCopy 19 namespace ast { 20 class Expr; 21 } 19 22 20 Expression *notZeroExpr( Expression *orig ); 23 ast::Expr * notZeroExpr( ast::Expr *orig ); 24 25 template< typename T > 26 static inline auto maybeBuild( T * orig ) -> decltype(orig->build()) { 27 return (orig) ? orig->build() : nullptr; 28 } 29 30 template< typename T > 31 static inline auto maybeMoveBuild( T * orig ) -> decltype(orig->build()) { 32 auto ret = maybeBuild<T>(orig); 33 delete orig; 34 return ret; 35 } 36 37 template<typename node_t> 38 node_t * maybeCopy( node_t const * node ) { 39 return node ? ast::shallowCopy( node ) : nullptr; 40 } 21 41 22 42 // Local Variables: // -
src/ResolvExpr/Candidate.cpp
r2ed94a9 rb110bcc 17 17 18 18 #include <iostream> 19 #include <sstream> 19 20 20 21 #include "AST/Print.hpp" … … 44 45 sorted.reserve(cands.size()); 45 46 for(const auto & c : cands) { 46 std:: stringstream ss;47 std::ostringstream ss; 47 48 print( ss, *c, indent ); 48 49 sorted.push_back(ss.str()); -
src/ResolvExpr/CandidateFinder.cpp
r2ed94a9 rb110bcc 55 55 namespace ResolvExpr { 56 56 57 /// Unique identifier for matching expression resolutions to their requesting expression 58 UniqueId globalResnSlot = 0; 59 60 namespace { 61 /// First index is which argument, second is which alternative, third is which exploded element 62 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >; 63 64 /// Returns a list of alternatives with the minimum cost in the given list 65 CandidateList findMinCost( const CandidateList & candidates ) { 66 CandidateList out; 67 Cost minCost = Cost::infinity; 68 for ( const CandidateRef & r : candidates ) { 69 if ( r->cost < minCost ) { 70 minCost = r->cost; 71 out.clear(); 72 out.emplace_back( r ); 73 } else if ( r->cost == minCost ) { 74 out.emplace_back( r ); 75 } 76 } 77 return out; 78 } 79 80 /// Computes conversion cost for a given expression to a given type 81 const ast::Expr * computeExpressionConversionCost( 82 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 83 ) { 84 Cost convCost = computeConversionCost( 85 arg->result, paramType, arg->get_lvalue(), symtab, env ); 86 outCost += convCost; 87 88 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 89 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 90 // infer parameters and this does not currently work for the reason stated below 91 Cost tmpCost = convCost; 92 tmpCost.incPoly( -tmpCost.get_polyCost() ); 93 if ( tmpCost != Cost::zero ) { 94 ast::ptr< ast::Type > newType = paramType; 95 env.apply( newType ); 96 return new ast::CastExpr{ arg, newType }; 97 98 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 99 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 100 // once this is fixed it should be possible to resolve the cast. 101 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 102 // but it shouldn't be because this makes the conversion from DT* to DT* since 103 // commontype(zero_t, DT*) is DT*, rather than nothing 104 105 // CandidateFinder finder{ symtab, env }; 106 // finder.find( arg, ResolvMode::withAdjustment() ); 107 // assertf( finder.candidates.size() > 0, 108 // "Somehow castable expression failed to find alternatives." ); 109 // assertf( finder.candidates.size() == 1, 110 // "Somehow got multiple alternatives for known cast expression." ); 111 // return finder.candidates.front()->expr; 112 } 113 114 return arg; 115 } 116 117 /// Computes conversion cost for a given candidate 118 Cost computeApplicationConversionCost( 119 CandidateRef cand, const ast::SymbolTable & symtab 120 ) { 121 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); 122 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 123 auto function = pointer->base.strict_as< ast::FunctionType >(); 124 125 Cost convCost = Cost::zero; 126 const auto & params = function->params; 127 auto param = params.begin(); 128 auto & args = appExpr->args; 129 130 for ( unsigned i = 0; i < args.size(); ++i ) { 131 const ast::Type * argType = args[i]->result; 132 PRINT( 133 std::cerr << "arg expression:" << std::endl; 134 ast::print( std::cerr, args[i], 2 ); 135 std::cerr << "--- results are" << std::endl; 136 ast::print( std::cerr, argType, 2 ); 137 ) 138 139 if ( param == params.end() ) { 140 if ( function->isVarArgs ) { 141 convCost.incUnsafe(); 142 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 143 << convCost << std::endl; ; ) 144 // convert reference-typed expressions into value-typed expressions 145 cand->expr = ast::mutate_field_index( 146 appExpr, &ast::ApplicationExpr::args, i, 147 referenceToRvalueConversion( args[i], convCost ) ); 148 continue; 149 } else return Cost::infinity; 150 } 151 152 if ( auto def = args[i].as< ast::DefaultArgExpr >() ) { 153 // Default arguments should be free - don't include conversion cost. 154 // Unwrap them here because they are not relevant to the rest of the system 155 cand->expr = ast::mutate_field_index( 156 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 157 ++param; 158 continue; 159 } 160 161 // mark conversion cost and also specialization cost of param type 162 // const ast::Type * paramType = (*param)->get_type(); 163 cand->expr = ast::mutate_field_index( 164 appExpr, &ast::ApplicationExpr::args, i, 165 computeExpressionConversionCost( 166 args[i], *param, symtab, cand->env, convCost ) ); 167 convCost.decSpec( specCost( *param ) ); 168 ++param; // can't be in for-loop update because of the continue 169 } 170 171 if ( param != params.end() ) return Cost::infinity; 172 173 // specialization cost of return types can't be accounted for directly, it disables 174 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 175 // 176 // forall(otype OS) { 177 // void ?|?(OS&, int); // with newline 178 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization 179 // } 180 181 // mark type variable and specialization cost of forall clause 182 convCost.incVar( function->forall.size() ); 183 convCost.decSpec( function->assertions.size() ); 184 185 return convCost; 186 } 187 188 void makeUnifiableVars( 189 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars, 190 ast::AssertionSet & need 191 ) { 192 for ( auto & tyvar : type->forall ) { 193 unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base }; 194 } 195 for ( auto & assn : type->assertions ) { 196 need[ assn ].isUsed = true; 197 } 198 } 199 200 /// Gets a default value from an initializer, nullptr if not present 201 const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) { 202 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) { 203 if ( auto ce = si->value.as< ast::CastExpr >() ) { 204 return ce->arg.as< ast::ConstantExpr >(); 205 } else { 206 return si->value.as< ast::ConstantExpr >(); 207 } 208 } 209 return nullptr; 210 } 211 212 /// State to iteratively build a match of parameter expressions to arguments 213 struct ArgPack { 214 std::size_t parent; ///< Index of parent pack 215 ast::ptr< ast::Expr > expr; ///< The argument stored here 216 Cost cost; ///< The cost of this argument 217 ast::TypeEnvironment env; ///< Environment for this pack 218 ast::AssertionSet need; ///< Assertions outstanding for this pack 219 ast::AssertionSet have; ///< Assertions found for this pack 220 ast::OpenVarSet open; ///< Open variables for this pack 221 unsigned nextArg; ///< Index of next argument in arguments list 222 unsigned tupleStart; ///< Number of tuples that start at this index 223 unsigned nextExpl; ///< Index of next exploded element 224 unsigned explAlt; ///< Index of alternative for nextExpl > 0 225 226 ArgPack() 227 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 228 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 229 230 ArgPack( 231 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 232 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 233 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 234 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 235 236 ArgPack( 237 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 238 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 239 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 240 unsigned nextExpl = 0, unsigned explAlt = 0 ) 241 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ), 242 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 243 nextExpl( nextExpl ), explAlt( explAlt ) {} 244 245 ArgPack( 246 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 247 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 248 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ), 249 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), 250 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 251 252 /// true if this pack is in the middle of an exploded argument 253 bool hasExpl() const { return nextExpl > 0; } 254 255 /// Gets the list of exploded candidates for this pack 256 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const { 257 return args[ nextArg-1 ][ explAlt ]; 258 } 259 260 /// Ends a tuple expression, consolidating the appropriate args 261 void endTuple( const std::vector< ArgPack > & packs ) { 262 // add all expressions in tuple to list, summing cost 263 std::deque< const ast::Expr * > exprs; 264 const ArgPack * pack = this; 265 if ( expr ) { exprs.emplace_front( expr ); } 266 while ( pack->tupleStart == 0 ) { 267 pack = &packs[pack->parent]; 268 exprs.emplace_front( pack->expr ); 269 cost += pack->cost; 270 } 271 // reset pack to appropriate tuple 272 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() ); 273 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) }; 274 tupleStart = pack->tupleStart - 1; 275 parent = pack->parent; 276 } 277 }; 278 279 /// Instantiates an argument to match a parameter, returns false if no matching results left 280 bool instantiateArgument( 281 const CodeLocation & location, 282 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 283 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 284 unsigned nTuples = 0 285 ) { 286 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { 287 // paramType is a TupleType -- group args into a TupleExpr 288 ++nTuples; 289 for ( const ast::Type * type : *tupleType ) { 290 // xxx - dropping initializer changes behaviour from previous, but seems correct 291 // ^^^ need to handle the case where a tuple has a default argument 292 if ( ! instantiateArgument( location, 293 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 294 nTuples = 0; 295 } 296 // re-constitute tuples for final generation 297 for ( auto i = genStart; i < results.size(); ++i ) { 298 results[i].endTuple( results ); 299 } 300 return true; 301 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 302 // paramType is a ttype, consumes all remaining arguments 303 304 // completed tuples; will be spliced to end of results to finish 305 std::vector< ArgPack > finalResults{}; 306 307 // iterate until all results completed 308 std::size_t genEnd; 309 ++nTuples; 310 do { 311 genEnd = results.size(); 312 313 // add another argument to results 314 for ( std::size_t i = genStart; i < genEnd; ++i ) { 315 unsigned nextArg = results[i].nextArg; 316 317 // use next element of exploded tuple if present 318 if ( results[i].hasExpl() ) { 319 const ExplodedArg & expl = results[i].getExpl( args ); 320 321 unsigned nextExpl = results[i].nextExpl + 1; 322 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 323 324 results.emplace_back( 325 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 326 copy( results[i].need ), copy( results[i].have ), 327 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 328 results[i].explAlt ); 329 330 continue; 331 } 332 333 // finish result when out of arguments 334 if ( nextArg >= args.size() ) { 335 ArgPack newResult{ 336 results[i].env, results[i].need, results[i].have, results[i].open }; 337 newResult.nextArg = nextArg; 338 const ast::Type * argType = nullptr; 339 340 if ( nTuples > 0 || ! results[i].expr ) { 341 // first iteration or no expression to clone, 342 // push empty tuple expression 343 newResult.parent = i; 344 newResult.expr = new ast::TupleExpr( location, {} ); 345 argType = newResult.expr->result; 346 } else { 347 // clone result to collect tuple 348 newResult.parent = results[i].parent; 349 newResult.cost = results[i].cost; 350 newResult.tupleStart = results[i].tupleStart; 351 newResult.expr = results[i].expr; 352 argType = newResult.expr->result; 353 354 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) { 355 // the case where a ttype value is passed directly is special, 356 // e.g. for argument forwarding purposes 357 // xxx - what if passing multiple arguments, last of which is 358 // ttype? 359 // xxx - what would happen if unify was changed so that unifying 360 // tuple 361 // types flattened both before unifying lists? then pass in 362 // TupleType (ttype) below. 363 --newResult.tupleStart; 364 } else { 365 // collapse leftover arguments into tuple 366 newResult.endTuple( results ); 367 argType = newResult.expr->result; 368 } 369 } 370 371 // check unification for ttype before adding to final 372 if ( 373 unify( 374 ttype, argType, newResult.env, newResult.need, newResult.have, 375 newResult.open, symtab ) 376 ) { 377 finalResults.emplace_back( std::move( newResult ) ); 378 } 379 380 continue; 381 } 382 383 // add each possible next argument 384 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 385 const ExplodedArg & expl = args[nextArg][j]; 386 387 // fresh copies of parent parameters for this iteration 388 ast::TypeEnvironment env = results[i].env; 389 ast::OpenVarSet open = results[i].open; 390 391 env.addActual( expl.env, open ); 392 393 // skip empty tuple arguments by (nearly) cloning parent into next gen 394 if ( expl.exprs.empty() ) { 395 results.emplace_back( 396 results[i], std::move( env ), copy( results[i].need ), 397 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost ); 398 399 continue; 400 } 401 402 // add new result 403 results.emplace_back( 404 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 405 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples, 406 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 407 } 408 } 409 410 // reset for next round 411 genStart = genEnd; 412 nTuples = 0; 413 } while ( genEnd != results.size() ); 414 415 // splice final results onto results 416 for ( std::size_t i = 0; i < finalResults.size(); ++i ) { 417 results.emplace_back( std::move( finalResults[i] ) ); 418 } 419 return ! finalResults.empty(); 420 } 421 422 // iterate each current subresult 423 std::size_t genEnd = results.size(); 424 for ( std::size_t i = genStart; i < genEnd; ++i ) { 425 unsigned nextArg = results[i].nextArg; 426 427 // use remainder of exploded tuple if present 428 if ( results[i].hasExpl() ) { 429 const ExplodedArg & expl = results[i].getExpl( args ); 430 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ]; 431 432 ast::TypeEnvironment env = results[i].env; 433 ast::AssertionSet need = results[i].need, have = results[i].have; 434 ast::OpenVarSet open = results[i].open; 435 436 const ast::Type * argType = expr->result; 437 438 PRINT( 439 std::cerr << "param type is "; 440 ast::print( std::cerr, paramType ); 441 std::cerr << std::endl << "arg type is "; 442 ast::print( std::cerr, argType ); 443 std::cerr << std::endl; 444 ) 445 446 if ( unify( paramType, argType, env, need, have, open, symtab ) ) { 447 unsigned nextExpl = results[i].nextExpl + 1; 448 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 449 450 results.emplace_back( 451 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg, 452 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 453 } 454 455 continue; 456 } 457 458 // use default initializers if out of arguments 459 if ( nextArg >= args.size() ) { 460 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) { 461 ast::TypeEnvironment env = results[i].env; 462 ast::AssertionSet need = results[i].need, have = results[i].have; 463 ast::OpenVarSet open = results[i].open; 464 465 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 466 results.emplace_back( 467 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ), 468 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples ); 469 } 470 } 471 472 continue; 473 } 474 475 // Check each possible next argument 476 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 477 const ExplodedArg & expl = args[nextArg][j]; 478 479 // fresh copies of parent parameters for this iteration 480 ast::TypeEnvironment env = results[i].env; 481 ast::AssertionSet need = results[i].need, have = results[i].have; 482 ast::OpenVarSet open = results[i].open; 483 484 env.addActual( expl.env, open ); 485 486 // skip empty tuple arguments by (nearly) cloning parent into next gen 487 if ( expl.exprs.empty() ) { 488 results.emplace_back( 489 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ), 490 nextArg + 1, expl.cost ); 491 492 continue; 493 } 494 495 // consider only first exploded arg 496 const ast::Expr * expr = expl.exprs.front(); 497 const ast::Type * argType = expr->result; 498 499 PRINT( 500 std::cerr << "param type is "; 501 ast::print( std::cerr, paramType ); 502 std::cerr << std::endl << "arg type is "; 503 ast::print( std::cerr, argType ); 504 std::cerr << std::endl; 505 ) 506 507 // attempt to unify types 508 if ( unify( paramType, argType, env, need, have, open, symtab ) ) { 509 // add new result 510 results.emplace_back( 511 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), 512 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 513 } 514 } 515 } 516 517 // reset for next parameter 518 genStart = genEnd; 519 520 return genEnd != results.size(); // were any new results added? 521 } 522 523 /// Generate a cast expression from `arg` to `toType` 524 const ast::Expr * restructureCast( 525 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 526 ) { 527 if ( 528 arg->result->size() > 1 529 && ! toType->isVoid() 530 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 531 ) { 532 // Argument is a tuple and the target type is neither void nor a reference. Cast each 533 // member of the tuple to its corresponding target type, producing the tuple of those 534 // cast expressions. If there are more components of the tuple than components in the 535 // target type, then excess components do not come out in the result expression (but 536 // UniqueExpr ensures that the side effects will still be produced) 537 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 538 // expressions which may contain side effects require a single unique instance of 539 // the expression 540 arg = new ast::UniqueExpr{ arg->location, arg }; 541 } 542 std::vector< ast::ptr< ast::Expr > > components; 543 for ( unsigned i = 0; i < toType->size(); ++i ) { 544 // cast each component 545 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 546 components.emplace_back( 547 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 548 } 549 return new ast::TupleExpr{ arg->location, std::move( components ) }; 550 } else { 551 // handle normally 552 return new ast::CastExpr{ arg->location, arg, toType, isGenerated }; 553 } 554 } 555 556 /// Gets the name from an untyped member expression (must be NameExpr) 557 const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) { 558 if ( memberExpr->member.as< ast::ConstantExpr >() ) { 559 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " ); 560 } 561 562 return memberExpr->member.strict_as< ast::NameExpr >()->name; 563 } 564 565 /// Actually visits expressions to find their candidate interpretations 566 class Finder final : public ast::WithShortCircuiting { 567 const ResolveContext & context; 568 const ast::SymbolTable & symtab; 569 public: 570 // static size_t traceId; 571 CandidateFinder & selfFinder; 572 CandidateList & candidates; 573 const ast::TypeEnvironment & tenv; 574 ast::ptr< ast::Type > & targetType; 575 576 enum Errors { 577 NotFound, 578 NoMatch, 579 ArgsToFew, 580 ArgsToMany, 581 RetsToFew, 582 RetsToMany, 583 NoReason 584 }; 585 586 struct { 587 Errors code = NotFound; 588 } reason; 589 590 Finder( CandidateFinder & f ) 591 : context( f.context ), symtab( context.symtab ), selfFinder( f ), 592 candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {} 593 594 void previsit( const ast::Node * ) { visit_children = false; } 595 596 /// Convenience to add candidate to list 597 template<typename... Args> 598 void addCandidate( Args &&... args ) { 599 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 600 reason.code = NoReason; 601 } 602 603 void postvisit( const ast::ApplicationExpr * applicationExpr ) { 604 addCandidate( applicationExpr, tenv ); 605 } 606 607 /// Set up candidate assertions for inference 608 void inferParameters( CandidateRef & newCand, CandidateList & out ); 609 610 /// Completes a function candidate with arguments located 611 void validateFunctionCandidate( 612 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 613 CandidateList & out ); 614 615 /// Builds a list of candidates for a function, storing them in out 616 void makeFunctionCandidates( 617 const CodeLocation & location, 618 const CandidateRef & func, const ast::FunctionType * funcType, 619 const ExplodedArgs_new & args, CandidateList & out ); 620 621 /// Adds implicit struct-conversions to the alternative list 622 void addAnonConversions( const CandidateRef & cand ); 623 624 /// Adds aggregate member interpretations 625 void addAggMembers( 626 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 627 const Candidate & cand, const Cost & addedCost, const std::string & name 628 ); 629 630 /// Adds tuple member interpretations 631 void addTupleMembers( 632 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 633 const Cost & addedCost, const ast::Expr * member 634 ); 635 636 /// true if expression is an lvalue 637 static bool isLvalue( const ast::Expr * x ) { 638 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 639 } 640 641 void postvisit( const ast::UntypedExpr * untypedExpr ); 642 void postvisit( const ast::VariableExpr * variableExpr ); 643 void postvisit( const ast::ConstantExpr * constantExpr ); 644 void postvisit( const ast::SizeofExpr * sizeofExpr ); 645 void postvisit( const ast::AlignofExpr * alignofExpr ); 646 void postvisit( const ast::AddressExpr * addressExpr ); 647 void postvisit( const ast::LabelAddressExpr * labelExpr ); 648 void postvisit( const ast::CastExpr * castExpr ); 649 void postvisit( const ast::VirtualCastExpr * castExpr ); 650 void postvisit( const ast::KeywordCastExpr * castExpr ); 651 void postvisit( const ast::UntypedMemberExpr * memberExpr ); 652 void postvisit( const ast::MemberExpr * memberExpr ); 653 void postvisit( const ast::NameExpr * nameExpr ); 654 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ); 655 void postvisit( const ast::OffsetofExpr * offsetofExpr ); 656 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ); 657 void postvisit( const ast::LogicalExpr * logicalExpr ); 658 void postvisit( const ast::ConditionalExpr * conditionalExpr ); 659 void postvisit( const ast::CommaExpr * commaExpr ); 660 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ); 661 void postvisit( const ast::ConstructorExpr * ctorExpr ); 662 void postvisit( const ast::RangeExpr * rangeExpr ); 663 void postvisit( const ast::UntypedTupleExpr * tupleExpr ); 664 void postvisit( const ast::TupleExpr * tupleExpr ); 665 void postvisit( const ast::TupleIndexExpr * tupleExpr ); 666 void postvisit( const ast::TupleAssignExpr * tupleExpr ); 667 void postvisit( const ast::UniqueExpr * unqExpr ); 668 void postvisit( const ast::StmtExpr * stmtExpr ); 669 void postvisit( const ast::UntypedInitExpr * initExpr ); 670 671 void postvisit( const ast::InitExpr * ) { 672 assertf( false, "CandidateFinder should never see a resolved InitExpr." ); 673 } 674 675 void postvisit( const ast::DeletedExpr * ) { 676 assertf( false, "CandidateFinder should never see a DeletedExpr." ); 677 } 678 679 void postvisit( const ast::GenericExpr * ) { 680 assertf( false, "_Generic is not yet supported." ); 681 } 682 }; 683 684 /// Set up candidate assertions for inference 685 void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) { 686 // Set need bindings for any unbound assertions 687 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions 688 for ( auto & assn : newCand->need ) { 689 // skip already-matched assertions 690 if ( assn.second.resnSlot != 0 ) continue; 691 // assign slot for expression if needed 692 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; } 693 // fix slot to assertion 694 assn.second.resnSlot = crntResnSlot; 695 } 696 // pair slot to expression 697 if ( crntResnSlot != 0 ) { 698 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot ); 699 } 700 701 // add to output list; assertion satisfaction will occur later 702 out.emplace_back( newCand ); 703 } 704 705 /// Completes a function candidate with arguments located 706 void Finder::validateFunctionCandidate( 707 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 708 CandidateList & out 709 ) { 710 ast::ApplicationExpr * appExpr = 711 new ast::ApplicationExpr{ func->expr->location, func->expr }; 712 // sum cost and accumulate arguments 713 std::deque< const ast::Expr * > args; 714 Cost cost = func->cost; 715 const ArgPack * pack = &result; 716 while ( pack->expr ) { 717 args.emplace_front( pack->expr ); 718 cost += pack->cost; 719 pack = &results[pack->parent]; 720 } 721 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() ); 722 appExpr->args = std::move( vargs ); 723 // build and validate new candidate 724 auto newCand = 725 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 726 PRINT( 727 std::cerr << "instantiate function success: " << appExpr << std::endl; 728 std::cerr << "need assertions:" << std::endl; 729 ast::print( std::cerr, result.need, 2 ); 730 ) 731 inferParameters( newCand, out ); 732 } 733 734 /// Builds a list of candidates for a function, storing them in out 735 void Finder::makeFunctionCandidates( 736 const CodeLocation & location, 737 const CandidateRef & func, const ast::FunctionType * funcType, 738 const ExplodedArgs_new & args, CandidateList & out 739 ) { 740 ast::OpenVarSet funcOpen; 741 ast::AssertionSet funcNeed, funcHave; 742 ast::TypeEnvironment funcEnv{ func->env }; 743 makeUnifiableVars( funcType, funcOpen, funcNeed ); 744 // add all type variables as open variables now so that those not used in the 745 // parameter list are still considered open 746 funcEnv.add( funcType->forall ); 747 748 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) { 749 // attempt to narrow based on expected target type 750 const ast::Type * returnType = funcType->returns.front(); 751 if ( ! unify( 752 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 753 ) { 754 // unification failed, do not pursue this candidate 755 return; 756 } 757 } 758 759 // iteratively build matches, one parameter at a time 760 std::vector< ArgPack > results; 761 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen ); 762 std::size_t genStart = 0; 763 764 // xxx - how to handle default arg after change to ftype representation? 765 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) { 766 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) { 767 // function may have default args only if directly calling by name 768 // must use types on candidate however, due to RenameVars substitution 769 auto nParams = funcType->params.size(); 770 771 for (size_t i=0; i<nParams; ++i) { 772 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 773 if (!instantiateArgument( location, 774 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 775 } 776 goto endMatch; 777 } 778 } 779 for ( const auto & param : funcType->params ) { 780 // Try adding the arguments corresponding to the current parameter to the existing 781 // matches 782 // no default args for indirect calls 783 if ( ! instantiateArgument( location, 784 param, nullptr, args, results, genStart, symtab ) ) return; 785 } 786 787 endMatch: 788 if ( funcType->isVarArgs ) { 789 // append any unused arguments to vararg pack 790 std::size_t genEnd; 791 do { 792 genEnd = results.size(); 793 794 // iterate results 795 for ( std::size_t i = genStart; i < genEnd; ++i ) { 796 unsigned nextArg = results[i].nextArg; 797 798 // use remainder of exploded tuple if present 799 if ( results[i].hasExpl() ) { 800 const ExplodedArg & expl = results[i].getExpl( args ); 801 802 unsigned nextExpl = results[i].nextExpl + 1; 803 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 804 805 results.emplace_back( 806 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 807 copy( results[i].need ), copy( results[i].have ), 808 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl, 809 results[i].explAlt ); 810 811 continue; 812 } 813 814 // finish result when out of arguments 815 if ( nextArg >= args.size() ) { 816 validateFunctionCandidate( func, results[i], results, out ); 817 818 continue; 819 } 820 821 // add each possible next argument 822 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 823 const ExplodedArg & expl = args[nextArg][j]; 824 825 // fresh copies of parent parameters for this iteration 826 ast::TypeEnvironment env = results[i].env; 827 ast::OpenVarSet open = results[i].open; 828 829 env.addActual( expl.env, open ); 830 831 // skip empty tuple arguments by (nearly) cloning parent into next gen 832 if ( expl.exprs.empty() ) { 833 results.emplace_back( 834 results[i], std::move( env ), copy( results[i].need ), 835 copy( results[i].have ), std::move( open ), nextArg + 1, 836 expl.cost ); 837 838 continue; 839 } 840 841 // add new result 842 results.emplace_back( 843 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 844 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost, 845 expl.exprs.size() == 1 ? 0 : 1, j ); 846 } 847 } 848 849 genStart = genEnd; 850 } while( genEnd != results.size() ); 851 } else { 852 // filter out the results that don't use all the arguments 853 for ( std::size_t i = genStart; i < results.size(); ++i ) { 854 ArgPack & result = results[i]; 855 if ( ! result.hasExpl() && result.nextArg >= args.size() ) { 856 validateFunctionCandidate( func, result, results, out ); 857 } 858 } 859 } 860 } 861 862 /// Adds implicit struct-conversions to the alternative list 863 void Finder::addAnonConversions( const CandidateRef & cand ) { 864 // adds anonymous member interpretations whenever an aggregate value type is seen. 865 // it's okay for the aggregate expression to have reference type -- cast it to the 866 // base type to treat the aggregate as the referenced value 867 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 868 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 869 cand->env.apply( aggrType ); 870 871 if ( aggrType.as< ast::ReferenceType >() ) { 872 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; 873 } 874 875 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) { 876 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" ); 877 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) { 878 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" ); 879 } 880 } 881 882 /// Adds aggregate member interpretations 883 void Finder::addAggMembers( 884 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 885 const Candidate & cand, const Cost & addedCost, const std::string & name 886 ) { 887 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 888 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 889 CandidateRef newCand = std::make_shared<Candidate>( 890 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 891 // add anonymous member interpretations whenever an aggregate value type is seen 892 // as a member expression 893 addAnonConversions( newCand ); 894 candidates.emplace_back( std::move( newCand ) ); 895 } 896 } 897 898 /// Adds tuple member interpretations 899 void Finder::addTupleMembers( 900 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 901 const Cost & addedCost, const ast::Expr * member 902 ) { 903 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 904 // get the value of the constant expression as an int, must be between 0 and the 905 // length of the tuple to have meaning 906 long long val = constantExpr->intValue(); 907 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 908 addCandidate( 909 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 910 addedCost ); 911 } 912 } 913 } 914 915 void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) { 916 std::vector< CandidateFinder > argCandidates = 917 selfFinder.findSubExprs( untypedExpr->args ); 918 919 // take care of possible tuple assignments 920 // if not tuple assignment, handled as normal function call 921 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates ); 922 923 CandidateFinder funcFinder( context, tenv ); 924 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) { 925 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 926 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 927 assertf(!argCandidates.empty(), "special function call without argument"); 928 for (auto & firstArgCand: argCandidates[0]) { 929 ast::ptr<ast::Type> argType = firstArgCand->expr->result; 930 firstArgCand->env.apply(argType); 931 // strip references 932 // xxx - is this correct? 933 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base; 934 935 // convert 1-tuple to plain type 936 if (auto tuple = argType.as<ast::TupleType>()) { 937 if (tuple->size() == 1) { 938 argType = tuple->types[0]; 939 } 940 } 941 942 // if argType is an unbound type parameter, all special functions need to be searched. 943 if (isUnboundType(argType)) { 944 funcFinder.otypeKeys.clear(); 945 break; 946 } 947 948 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 949 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) { 950 // const ast::EnumDecl * enumDecl = enumInst->base; // Here 951 // if ( const ast::Type* enumType = enumDecl->base ) { 952 // // instance of enum (T) is a instance of type (T) 953 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type)); 954 // } else { 955 // // instance of an untyped enum is techically int 956 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type)); 957 // } 958 // } 959 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type)); 960 } 961 } 962 } 963 // if candidates are already produced, do not fail 964 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates? 965 // this means there exists ctor/assign functions with a tuple as first parameter. 966 ResolvMode mode = { 967 true, // adjust 968 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name 969 selfFinder.candidates.empty() // failfast if other options are not found 970 }; 971 funcFinder.find( untypedExpr->func, mode ); 972 // short-circuit if no candidates 973 // if ( funcFinder.candidates.empty() ) return; 974 975 reason.code = NoMatch; 976 977 // find function operators 978 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{} 979 CandidateFinder opFinder( context, tenv ); 980 // okay if there aren't any function operations 981 opFinder.find( opExpr, ResolvMode::withoutFailFast() ); 982 PRINT( 983 std::cerr << "known function ops:" << std::endl; 984 print( std::cerr, opFinder.candidates, 1 ); 985 ) 986 987 // pre-explode arguments 988 ExplodedArgs_new argExpansions; 989 for ( const CandidateFinder & args : argCandidates ) { 990 argExpansions.emplace_back(); 991 auto & argE = argExpansions.back(); 992 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); } 993 } 994 995 // Find function matches 996 CandidateList found; 997 SemanticErrorException errors; 998 for ( CandidateRef & func : funcFinder ) { 999 try { 1000 PRINT( 1001 std::cerr << "working on alternative:" << std::endl; 1002 print( std::cerr, *func, 2 ); 1003 ) 1004 1005 // check if the type is a pointer to function 1006 const ast::Type * funcResult = func->expr->result->stripReferences(); 1007 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) { 1008 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1009 CandidateRef newFunc{ new Candidate{ *func } }; 1010 newFunc->expr = 1011 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1012 makeFunctionCandidates( untypedExpr->location, 1013 newFunc, function, argExpansions, found ); 1014 } 1015 } else if ( 1016 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 1017 ) { 1018 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 1019 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 1020 CandidateRef newFunc{ new Candidate{ *func } }; 1021 newFunc->expr = 1022 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1023 makeFunctionCandidates( untypedExpr->location, 1024 newFunc, function, argExpansions, found ); 1025 } 1026 } 1027 } 1028 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1029 } 1030 1031 // Find matches on function operators `?()` 1032 if ( ! opFinder.candidates.empty() ) { 1033 // add exploded function alternatives to front of argument list 1034 std::vector< ExplodedArg > funcE; 1035 funcE.reserve( funcFinder.candidates.size() ); 1036 for ( const CandidateRef & func : funcFinder ) { 1037 funcE.emplace_back( *func, symtab ); 1038 } 1039 argExpansions.emplace_front( std::move( funcE ) ); 1040 1041 for ( const CandidateRef & op : opFinder ) { 1042 try { 1043 // check if type is pointer-to-function 1044 const ast::Type * opResult = op->expr->result->stripReferences(); 1045 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) { 1046 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1047 CandidateRef newOp{ new Candidate{ *op} }; 1048 newOp->expr = 1049 referenceToRvalueConversion( newOp->expr, newOp->cost ); 1050 makeFunctionCandidates( untypedExpr->location, 1051 newOp, function, argExpansions, found ); 1052 } 1053 } 1054 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1055 } 1056 } 1057 1058 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 1059 // candidates 1060 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } 1061 1062 // Compute conversion costs 1063 for ( CandidateRef & withFunc : found ) { 1064 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab ); 1065 1066 PRINT( 1067 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >(); 1068 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 1069 auto function = pointer->base.strict_as< ast::FunctionType >(); 1070 1071 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 1072 std::cerr << "parameters are:" << std::endl; 1073 ast::printAll( std::cerr, function->params, 2 ); 1074 std::cerr << "arguments are:" << std::endl; 1075 ast::printAll( std::cerr, appExpr->args, 2 ); 1076 std::cerr << "bindings are:" << std::endl; 1077 ast::print( std::cerr, withFunc->env, 2 ); 1078 std::cerr << "cost is: " << withFunc->cost << std::endl; 1079 std::cerr << "cost of conversion is:" << cvtCost << std::endl; 1080 ) 1081 1082 if ( cvtCost != Cost::infinity ) { 1083 withFunc->cvtCost = cvtCost; 1084 candidates.emplace_back( std::move( withFunc ) ); 1085 } 1086 } 1087 found = std::move( candidates ); 1088 1089 // use a new list so that candidates are not examined by addAnonConversions twice 1090 CandidateList winners = findMinCost( found ); 1091 promoteCvtCost( winners ); 1092 1093 // function may return a struct/union value, in which case we need to add candidates 1094 // for implicit conversions to each of the anonymous members, which must happen after 1095 // `findMinCost`, since anon conversions are never the cheapest 1096 for ( const CandidateRef & c : winners ) { 1097 addAnonConversions( c ); 1098 } 1099 spliceBegin( candidates, winners ); 1100 1101 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 1102 // If resolution is unsuccessful with a target type, try again without, since it 1103 // will sometimes succeed when it wouldn't with a target type binding. 1104 // For example: 1105 // forall( otype T ) T & ?[]( T *, ptrdiff_t ); 1106 // const char * x = "hello world"; 1107 // unsigned char ch = x[0]; 1108 // Fails with simple return type binding (xxx -- check this!) as follows: 1109 // * T is bound to unsigned char 1110 // * (x: const char *) is unified with unsigned char *, which fails 1111 // xxx -- fix this better 1112 targetType = nullptr; 1113 postvisit( untypedExpr ); 1114 } 1115 } 1116 1117 void Finder::postvisit( const ast::AddressExpr * addressExpr ) { 1118 CandidateFinder finder( context, tenv ); 1119 finder.find( addressExpr->arg ); 1120 1121 if ( finder.candidates.empty() ) return; 1122 1123 reason.code = NoMatch; 1124 1125 for ( CandidateRef & r : finder.candidates ) { 1126 if ( ! isLvalue( r->expr ) ) continue; 1127 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } ); 1128 } 1129 } 1130 1131 void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) { 1132 addCandidate( labelExpr, tenv ); 1133 } 1134 1135 void Finder::postvisit( const ast::CastExpr * castExpr ) { 1136 ast::ptr< ast::Type > toType = castExpr->result; 1137 assert( toType ); 1138 toType = resolveTypeof( toType, context ); 1139 toType = adjustExprType( toType, tenv, symtab ); 1140 1141 CandidateFinder finder( context, tenv, toType ); 1142 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1143 1144 if ( !finder.candidates.empty() ) reason.code = NoMatch; 1145 1146 CandidateList matches; 1147 for ( CandidateRef & cand : finder.candidates ) { 1148 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1149 ast::OpenVarSet open( cand->open ); 1150 1151 cand->env.extractOpenVars( open ); 1152 1153 // It is possible that a cast can throw away some values in a multiply-valued 1154 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1155 // subexpression results that are cast directly. The candidate is invalid if it 1156 // has fewer results than there are types to cast to. 1157 int discardedValues = cand->expr->result->size() - toType->size(); 1158 if ( discardedValues < 0 ) continue; 1159 1160 // unification run for side-effects 1161 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1162 Cost thisCost = 1163 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast) 1164 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ) 1165 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ); 1166 1167 PRINT( 1168 std::cerr << "working on cast with result: " << toType << std::endl; 1169 std::cerr << "and expr type: " << cand->expr->result << std::endl; 1170 std::cerr << "env: " << cand->env << std::endl; 1171 ) 1172 if ( thisCost != Cost::infinity ) { 1173 PRINT( 1174 std::cerr << "has finite cost." << std::endl; 1175 ) 1176 // count one safe conversion for each value that is thrown away 1177 thisCost.incSafe( discardedValues ); 1178 CandidateRef newCand = std::make_shared<Candidate>( 1179 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1180 copy( cand->env ), std::move( open ), std::move( need ), cand->cost, 1181 cand->cost + thisCost ); 1182 inferParameters( newCand, matches ); 1183 } 1184 } 1185 1186 // select first on argument cost, then conversion cost 1187 CandidateList minArgCost = findMinCost( matches ); 1188 promoteCvtCost( minArgCost ); 1189 candidates = findMinCost( minArgCost ); 1190 } 1191 1192 void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) { 1193 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." ); 1194 CandidateFinder finder( context, tenv ); 1195 // don't prune here, all alternatives guaranteed to have same type 1196 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1197 for ( CandidateRef & r : finder.candidates ) { 1198 addCandidate( 1199 *r, 1200 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1201 } 1202 } 1203 1204 void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) { 1205 const auto & loc = castExpr->location; 1206 assertf( castExpr->result, "Cast target should have been set in Validate." ); 1207 auto ref = castExpr->result.strict_as<ast::ReferenceType>(); 1208 auto inst = ref->base.strict_as<ast::StructInstType>(); 1209 auto target = inst->base.get(); 1210 1211 CandidateFinder finder( context, tenv ); 1212 1213 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) { 1214 for (auto & cand : found) { 1215 const ast::Type * expr = cand->expr->result.get(); 1216 if (expect_ref) { 1217 auto res = dynamic_cast<const ast::ReferenceType*>(expr); 1218 if (!res) { continue; } 1219 expr = res->base.get(); 1220 } 1221 1222 if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) { 1223 auto td = cand->env.lookup(*insttype); 1224 if (!td) { continue; } 1225 expr = td->bound.get(); 1226 } 1227 1228 if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) { 1229 if (base->base == target) { 1230 candidates.push_back( std::move(cand) ); 1231 reason.code = NoReason; 1232 } 1233 } 1234 } 1235 }; 1236 1237 try { 1238 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd 1239 // Clone is purely for memory management 1240 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) }; 1241 1242 // don't prune here, since it's guaranteed all alternatives will have the same type 1243 finder.find( tech1.get(), ResolvMode::withoutPrune() ); 1244 pick_alternatives(finder.candidates, false); 1245 1246 return; 1247 } catch(SemanticErrorException & ) {} 1248 1249 // Fallback : turn (thread&)X into (thread$&)get_thread(X) 1250 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) }; 1251 // don't prune here, since it's guaranteed all alternatives will have the same type 1252 finder.find( fallback.get(), ResolvMode::withoutPrune() ); 1253 1254 pick_alternatives(finder.candidates, true); 1255 1256 // Whatever happens here, we have no more fallbacks 1257 } 1258 1259 void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) { 1260 CandidateFinder aggFinder( context, tenv ); 1261 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1262 for ( CandidateRef & agg : aggFinder.candidates ) { 1263 // it's okay for the aggregate expression to have reference type -- cast it to the 1264 // base type to treat the aggregate as the referenced value 1265 Cost addedCost = Cost::zero; 1266 agg->expr = referenceToRvalueConversion( agg->expr, addedCost ); 1267 1268 // find member of the given type 1269 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1270 addAggMembers( 1271 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1272 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1273 addAggMembers( 1274 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1275 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { 1276 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member ); 1277 } 1278 } 1279 } 1280 1281 void Finder::postvisit( const ast::MemberExpr * memberExpr ) { 1282 addCandidate( memberExpr, tenv ); 1283 } 1284 1285 void Finder::postvisit( const ast::NameExpr * nameExpr ) { 1286 std::vector< ast::SymbolTable::IdData > declList; 1287 if (!selfFinder.otypeKeys.empty()) { 1288 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 1289 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str()); 1290 1291 for (auto & otypeKey: selfFinder.otypeKeys) { 1292 auto result = symtab.specialLookupId(kind, otypeKey); 1293 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end())); 1294 } 1295 } else { 1296 declList = symtab.lookupId( nameExpr->name ); 1297 } 1298 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1299 1300 if ( declList.empty() ) return; 1301 1302 reason.code = NoMatch; 1303 1304 for ( auto & data : declList ) { 1305 Cost cost = Cost::zero; 1306 ast::Expr * newExpr = data.combine( nameExpr->location, cost ); 1307 1308 CandidateRef newCand = std::make_shared<Candidate>( 1309 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1310 cost ); 1311 1312 if (newCand->expr->env) { 1313 newCand->env.add(*newCand->expr->env); 1314 auto mutExpr = newCand->expr.get_and_mutate(); 1315 mutExpr->env = nullptr; 1316 newCand->expr = mutExpr; 1317 } 1318 1319 PRINT( 1320 std::cerr << "decl is "; 1321 ast::print( std::cerr, data.id ); 1322 std::cerr << std::endl; 1323 std::cerr << "newExpr is "; 1324 ast::print( std::cerr, newExpr ); 1325 std::cerr << std::endl; 1326 ) 1327 newCand->expr = ast::mutate_field( 1328 newCand->expr.get(), &ast::Expr::result, 1329 renameTyVars( newCand->expr->result ) ); 1330 // add anonymous member interpretations whenever an aggregate value type is seen 1331 // as a name expression 1332 addAnonConversions( newCand ); 1333 candidates.emplace_back( std::move( newCand ) ); 1334 } 1335 } 1336 1337 void Finder::postvisit( const ast::VariableExpr * variableExpr ) { 1338 // not sufficient to just pass `variableExpr` here, type might have changed since 1339 // creation 1340 addCandidate( 1341 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1342 } 1343 1344 void Finder::postvisit( const ast::ConstantExpr * constantExpr ) { 1345 addCandidate( constantExpr, tenv ); 1346 } 1347 1348 void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) { 1349 if ( sizeofExpr->type ) { 1350 addCandidate( 1351 new ast::SizeofExpr{ 1352 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) }, 1353 tenv ); 1354 } else { 1355 // find all candidates for the argument to sizeof 1356 CandidateFinder finder( context, tenv ); 1357 finder.find( sizeofExpr->expr ); 1358 // find the lowest-cost candidate, otherwise ambiguous 1359 CandidateList winners = findMinCost( finder.candidates ); 1360 if ( winners.size() != 1 ) { 1361 SemanticError( 1362 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1363 } 1364 // return the lowest-cost candidate 1365 CandidateRef & choice = winners.front(); 1366 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1367 choice->cost = Cost::zero; 1368 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } ); 1369 } 1370 } 1371 1372 void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) { 1373 if ( alignofExpr->type ) { 1374 addCandidate( 1375 new ast::AlignofExpr{ 1376 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) }, 1377 tenv ); 1378 } else { 1379 // find all candidates for the argument to alignof 1380 CandidateFinder finder( context, tenv ); 1381 finder.find( alignofExpr->expr ); 1382 // find the lowest-cost candidate, otherwise ambiguous 1383 CandidateList winners = findMinCost( finder.candidates ); 1384 if ( winners.size() != 1 ) { 1385 SemanticError( 1386 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1387 } 1388 // return the lowest-cost candidate 1389 CandidateRef & choice = winners.front(); 1390 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1391 choice->cost = Cost::zero; 1392 addCandidate( 1393 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1394 } 1395 } 1396 1397 void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) { 1398 const ast::BaseInstType * aggInst; 1399 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ; 1400 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ; 1401 else return; 1402 1403 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1404 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1405 addCandidate( 1406 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1407 } 1408 } 1409 1410 void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) { 1411 addCandidate( offsetofExpr, tenv ); 1412 } 1413 1414 void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) { 1415 addCandidate( offsetPackExpr, tenv ); 1416 } 1417 1418 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1419 CandidateFinder finder1( context, tenv ); 1420 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() ); 1421 if ( finder1.candidates.empty() ) return; 1422 1423 CandidateFinder finder2( context, tenv ); 1424 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1425 if ( finder2.candidates.empty() ) return; 1426 1427 reason.code = NoMatch; 1428 1429 for ( const CandidateRef & r1 : finder1.candidates ) { 1430 for ( const CandidateRef & r2 : finder2.candidates ) { 1431 ast::TypeEnvironment env{ r1->env }; 1432 env.simpleCombine( r2->env ); 1433 ast::OpenVarSet open{ r1->open }; 1434 mergeOpenVars( open, r2->open ); 1435 ast::AssertionSet need; 1436 mergeAssertionSet( need, r1->need ); 1437 mergeAssertionSet( need, r2->need ); 1438 1439 addCandidate( 1440 new ast::LogicalExpr{ 1441 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1442 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost ); 1443 } 1444 } 1445 } 1446 1447 void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) { 1448 // candidates for condition 1449 CandidateFinder finder1( context, tenv ); 1450 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() ); 1451 if ( finder1.candidates.empty() ) return; 1452 1453 // candidates for true result 1454 CandidateFinder finder2( context, tenv ); 1455 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() ); 1456 if ( finder2.candidates.empty() ) return; 1457 1458 // candidates for false result 1459 CandidateFinder finder3( context, tenv ); 1460 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1461 if ( finder3.candidates.empty() ) return; 1462 1463 reason.code = NoMatch; 1464 1465 for ( const CandidateRef & r1 : finder1.candidates ) { 1466 for ( const CandidateRef & r2 : finder2.candidates ) { 1467 for ( const CandidateRef & r3 : finder3.candidates ) { 1468 ast::TypeEnvironment env{ r1->env }; 1469 env.simpleCombine( r2->env ); 1470 env.simpleCombine( r3->env ); 1471 ast::OpenVarSet open{ r1->open }; 1472 mergeOpenVars( open, r2->open ); 1473 mergeOpenVars( open, r3->open ); 1474 ast::AssertionSet need; 1475 mergeAssertionSet( need, r1->need ); 1476 mergeAssertionSet( need, r2->need ); 1477 mergeAssertionSet( need, r3->need ); 1478 ast::AssertionSet have; 1479 1480 // unify true and false results, then infer parameters to produce new 1481 // candidates 1482 ast::ptr< ast::Type > common; 1483 if ( 1484 unify( 1485 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1486 common ) 1487 ) { 1488 // generate typed expression 1489 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1490 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1491 newExpr->result = common ? common : r2->expr->result; 1492 // convert both options to result type 1493 Cost cost = r1->cost + r2->cost + r3->cost; 1494 newExpr->arg2 = computeExpressionConversionCost( 1495 newExpr->arg2, newExpr->result, symtab, env, cost ); 1496 newExpr->arg3 = computeExpressionConversionCost( 1497 newExpr->arg3, newExpr->result, symtab, env, cost ); 1498 // output candidate 1499 CandidateRef newCand = std::make_shared<Candidate>( 1500 newExpr, std::move( env ), std::move( open ), std::move( need ), cost ); 1501 inferParameters( newCand, candidates ); 1502 } 1503 } 1504 } 1505 } 1506 } 1507 1508 void Finder::postvisit( const ast::CommaExpr * commaExpr ) { 1509 ast::TypeEnvironment env{ tenv }; 1510 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env ); 1511 1512 CandidateFinder finder2( context, env ); 1513 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); 1514 1515 for ( const CandidateRef & r2 : finder2.candidates ) { 1516 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } ); 1517 } 1518 } 1519 1520 void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) { 1521 addCandidate( ctorExpr, tenv ); 1522 } 1523 1524 void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1525 CandidateFinder finder( context, tenv ); 1526 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() ); 1527 for ( CandidateRef & r : finder.candidates ) { 1528 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } ); 1529 } 1530 } 1531 1532 void Finder::postvisit( const ast::RangeExpr * rangeExpr ) { 1533 // resolve low and high, accept candidates where low and high types unify 1534 CandidateFinder finder1( context, tenv ); 1535 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() ); 1536 if ( finder1.candidates.empty() ) return; 1537 1538 CandidateFinder finder2( context, tenv ); 1539 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1540 if ( finder2.candidates.empty() ) return; 1541 1542 reason.code = NoMatch; 1543 1544 for ( const CandidateRef & r1 : finder1.candidates ) { 1545 for ( const CandidateRef & r2 : finder2.candidates ) { 1546 ast::TypeEnvironment env{ r1->env }; 1547 env.simpleCombine( r2->env ); 1548 ast::OpenVarSet open{ r1->open }; 1549 mergeOpenVars( open, r2->open ); 1550 ast::AssertionSet need; 1551 mergeAssertionSet( need, r1->need ); 1552 mergeAssertionSet( need, r2->need ); 1553 ast::AssertionSet have; 1554 1555 ast::ptr< ast::Type > common; 1556 if ( 1557 unify( 1558 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1559 common ) 1560 ) { 1561 // generate new expression 1562 ast::RangeExpr * newExpr = 1563 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1564 newExpr->result = common ? common : r1->expr->result; 1565 // add candidate 1566 CandidateRef newCand = std::make_shared<Candidate>( 1567 newExpr, std::move( env ), std::move( open ), std::move( need ), 1568 r1->cost + r2->cost ); 1569 inferParameters( newCand, candidates ); 1570 } 1571 } 1572 } 1573 } 1574 1575 void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1576 std::vector< CandidateFinder > subCandidates = 1577 selfFinder.findSubExprs( tupleExpr->exprs ); 1578 std::vector< CandidateList > possibilities; 1579 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) ); 1580 1581 for ( const CandidateList & subs : possibilities ) { 1582 std::vector< ast::ptr< ast::Expr > > exprs; 1583 exprs.reserve( subs.size() ); 1584 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); } 1585 1586 ast::TypeEnvironment env; 1587 ast::OpenVarSet open; 1588 ast::AssertionSet need; 1589 for ( const CandidateRef & sub : subs ) { 1590 env.simpleCombine( sub->env ); 1591 mergeOpenVars( open, sub->open ); 1592 mergeAssertionSet( need, sub->need ); 1593 } 1594 1595 addCandidate( 1596 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) }, 1597 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) ); 1598 } 1599 } 1600 1601 void Finder::postvisit( const ast::TupleExpr * tupleExpr ) { 1602 addCandidate( tupleExpr, tenv ); 1603 } 1604 1605 void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) { 1606 addCandidate( tupleExpr, tenv ); 1607 } 1608 1609 void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) { 1610 addCandidate( tupleExpr, tenv ); 1611 } 1612 1613 void Finder::postvisit( const ast::UniqueExpr * unqExpr ) { 1614 CandidateFinder finder( context, tenv ); 1615 finder.find( unqExpr->expr, ResolvMode::withAdjustment() ); 1616 for ( CandidateRef & r : finder.candidates ) { 1617 // ensure that the the id is passed on so that the expressions are "linked" 1618 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } ); 1619 } 1620 } 1621 1622 void Finder::postvisit( const ast::StmtExpr * stmtExpr ) { 1623 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv ); 1624 } 1625 1626 void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) { 1627 // handle each option like a cast 1628 CandidateList matches; 1629 PRINT( 1630 std::cerr << "untyped init expr: " << initExpr << std::endl; 1631 ) 1632 // O(n^2) checks of d-types with e-types 1633 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) { 1634 // calculate target type 1635 const ast::Type * toType = resolveTypeof( initAlt.type, context ); 1636 toType = adjustExprType( toType, tenv, symtab ); 1637 // The call to find must occur inside this loop, otherwise polymorphic return 1638 // types are not bound to the initialization type, since return type variables are 1639 // only open for the duration of resolving the UntypedExpr. 1640 CandidateFinder finder( context, tenv, toType ); 1641 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1642 for ( CandidateRef & cand : finder.candidates ) { 1643 if (reason.code == NotFound) reason.code = NoMatch; 1644 1645 ast::TypeEnvironment env{ cand->env }; 1646 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1647 ast::OpenVarSet open{ cand->open }; 1648 1649 PRINT( 1650 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; 1651 ) 1652 1653 // It is possible that a cast can throw away some values in a multiply-valued 1654 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1655 // the subexpression results that are cast directly. The candidate is invalid 1656 // if it has fewer results than there are types to cast to. 1657 int discardedValues = cand->expr->result->size() - toType->size(); 1658 if ( discardedValues < 0 ) continue; 1659 1660 // unification run for side-effects 1661 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab ); 1662 (void) canUnify; 1663 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1664 symtab, env ); 1665 PRINT( 1666 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1667 symtab, env ); 1668 std::cerr << "Considering initialization:"; 1669 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl; 1670 std::cerr << std::endl << " TO: " << toType << std::endl; 1671 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1672 std::cerr << std::endl << " Legacy cost " << legacyCost; 1673 std::cerr << std::endl << " New cost " << thisCost; 1674 std::cerr << std::endl; 1675 ) 1676 if ( thisCost != Cost::infinity ) { 1677 // count one safe conversion for each value that is thrown away 1678 thisCost.incSafe( discardedValues ); 1679 CandidateRef newCand = std::make_shared<Candidate>( 1680 new ast::InitExpr{ 1681 initExpr->location, restructureCast( cand->expr, toType ), 1682 initAlt.designation }, 1683 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost ); 1684 inferParameters( newCand, matches ); 1685 } 1686 } 1687 } 1688 1689 // select first on argument cost, then conversion cost 1690 CandidateList minArgCost = findMinCost( matches ); 1691 promoteCvtCost( minArgCost ); 1692 candidates = findMinCost( minArgCost ); 1693 } 1694 1695 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1696 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1697 /// return type. Skips ambiguous candidates. 1698 1699 } // anonymous namespace 1700 1701 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) { 1702 struct PruneStruct { 1703 CandidateRef candidate; 1704 bool ambiguous; 1705 1706 PruneStruct() = default; 1707 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1708 }; 1709 1710 // find lowest-cost candidate for each type 1711 std::unordered_map< std::string, PruneStruct > selected; 1712 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found 1713 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;}); 1714 for ( CandidateRef & candidate : candidates ) { 1715 std::string mangleName; 1716 { 1717 ast::ptr< ast::Type > newType = candidate->expr->result; 1718 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1719 candidate->env.apply( newType ); 1720 mangleName = Mangle::mangle( newType ); 1721 } 1722 1723 auto found = selected.find( mangleName ); 1724 if (found != selected.end() && found->second.candidate->cost < candidate->cost) { 1725 PRINT( 1726 std::cerr << "cost " << candidate->cost << " loses to " 1727 << found->second.candidate->cost << std::endl; 1728 ) 1729 continue; 1730 } 1731 1732 // xxx - when do satisfyAssertions produce more than 1 result? 1733 // this should only happen when initial result type contains 1734 // unbound type parameters, then it should never be pruned by 1735 // the previous step, since renameTyVars guarantees the mangled name 1736 // is unique. 1737 CandidateList satisfied; 1738 bool needRecomputeKey = false; 1739 if (candidate->need.empty()) { 1740 satisfied.emplace_back(candidate); 1741 } 1742 else { 1743 satisfyAssertions(candidate, context.symtab, satisfied, errors); 1744 needRecomputeKey = true; 1745 } 1746 1747 for (auto & newCand : satisfied) { 1748 // recomputes type key, if satisfyAssertions changed it 1749 if (needRecomputeKey) 1750 { 1751 ast::ptr< ast::Type > newType = newCand->expr->result; 1752 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get()); 1753 newCand->env.apply( newType ); 1754 mangleName = Mangle::mangle( newType ); 1755 } 1756 auto found = selected.find( mangleName ); 1757 if ( found != selected.end() ) { 1758 if ( newCand->cost < found->second.candidate->cost ) { 1759 PRINT( 1760 std::cerr << "cost " << newCand->cost << " beats " 1761 << found->second.candidate->cost << std::endl; 1762 ) 1763 1764 found->second = PruneStruct{ newCand }; 1765 } else if ( newCand->cost == found->second.candidate->cost ) { 1766 // if one of the candidates contains a deleted identifier, can pick the other, 1767 // since deleted expressions should not be ambiguous if there is another option 1768 // that is at least as good 1769 if ( findDeletedExpr( newCand->expr ) ) { 1770 // do nothing 1771 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 1772 } else if ( findDeletedExpr( found->second.candidate->expr ) ) { 1773 PRINT( std::cerr << "current is deleted" << std::endl; ) 1774 found->second = PruneStruct{ newCand }; 1775 } else { 1776 PRINT( std::cerr << "marking ambiguous" << std::endl; ) 1777 found->second.ambiguous = true; 1778 } 1779 } else { 1780 // xxx - can satisfyAssertions increase the cost? 1781 PRINT( 1782 std::cerr << "cost " << newCand->cost << " loses to " 1783 << found->second.candidate->cost << std::endl; 1784 ) 1785 } 1786 } else { 1787 selected.emplace_hint( found, mangleName, newCand ); 1788 } 1789 } 1790 } 1791 1792 // report unambiguous min-cost candidates 1793 // CandidateList out; 1794 for ( auto & target : selected ) { 1795 if ( target.second.ambiguous ) continue; 1796 1797 CandidateRef cand = target.second.candidate; 1798 1799 ast::ptr< ast::Type > newResult = cand->expr->result; 1800 cand->env.applyFree( newResult ); 1801 cand->expr = ast::mutate_field( 1802 cand->expr.get(), &ast::Expr::result, std::move( newResult ) ); 1803 1804 out.emplace_back( cand ); 1805 } 1806 // if everything is lost in satisfyAssertions, report the error 1807 return !selected.empty(); 1808 } 1809 1810 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) { 1811 // Find alternatives for expression 1812 ast::Pass<Finder> finder{ *this }; 1813 expr->accept( finder ); 1814 1815 if ( mode.failFast && candidates.empty() ) { 1816 switch(finder.core.reason.code) { 1817 case Finder::NotFound: 1818 { SemanticError( expr, "No alternatives for expression " ); break; } 1819 case Finder::NoMatch: 1820 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1821 case Finder::ArgsToFew: 1822 case Finder::ArgsToMany: 1823 case Finder::RetsToFew: 1824 case Finder::RetsToMany: 1825 case Finder::NoReason: 1826 default: 1827 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1828 } 1829 } 1830 1831 /* 1832 if ( mode.satisfyAssns || mode.prune ) { 1833 // trim candidates to just those where the assertions are satisfiable 1834 // - necessary pre-requisite to pruning 1835 CandidateList satisfied; 1836 std::vector< std::string > errors; 1837 for ( CandidateRef & candidate : candidates ) { 1838 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1839 } 1840 1841 // fail early if none such 1842 if ( mode.failFast && satisfied.empty() ) { 1843 std::ostringstream stream; 1844 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1845 for ( const auto& err : errors ) { 1846 stream << err; 1847 } 1848 SemanticError( expr->location, stream.str() ); 1849 } 1850 1851 // reset candidates 1852 candidates = move( satisfied ); 1853 } 1854 */ 1855 1856 if ( mode.prune ) { 1857 // trim candidates to single best one 1858 PRINT( 1859 std::cerr << "alternatives before prune:" << std::endl; 1860 print( std::cerr, candidates ); 1861 ) 1862 1863 CandidateList pruned; 1864 std::vector<std::string> errors; 1865 bool found = pruneCandidates( candidates, pruned, errors ); 1866 1867 if ( mode.failFast && pruned.empty() ) { 1868 std::ostringstream stream; 1869 if (found) { 1870 CandidateList winners = findMinCost( candidates ); 1871 stream << "Cannot choose between " << winners.size() << " alternatives for " 1872 "expression\n"; 1873 ast::print( stream, expr ); 1874 stream << " Alternatives are:\n"; 1875 print( stream, winners, 1 ); 1876 SemanticError( expr->location, stream.str() ); 1877 } 1878 else { 1879 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1880 for ( const auto& err : errors ) { 1881 stream << err; 1882 } 1883 SemanticError( expr->location, stream.str() ); 1884 } 1885 } 1886 1887 auto oldsize = candidates.size(); 1888 candidates = std::move( pruned ); 1889 1890 PRINT( 1891 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; 1892 ) 1893 PRINT( 1894 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1895 << std::endl; 1896 ) 1897 } 1898 1899 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1900 // adjusted 1901 if ( mode.adjust ) { 1902 for ( CandidateRef & r : candidates ) { 1903 r->expr = ast::mutate_field( 1904 r->expr.get(), &ast::Expr::result, 1905 adjustExprType( r->expr->result, r->env, context.symtab ) ); 1906 } 1907 } 1908 1909 // Central location to handle gcc extension keyword, etc. for all expressions 1910 for ( CandidateRef & r : candidates ) { 1911 if ( r->expr->extension != expr->extension ) { 1912 r->expr.get_and_mutate()->extension = expr->extension; 1913 } 1914 } 1915 } 1916 1917 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1918 const std::vector< ast::ptr< ast::Expr > > & xs 1919 ) { 1920 std::vector< CandidateFinder > out; 1921 1922 for ( const auto & x : xs ) { 1923 out.emplace_back( context, env ); 1924 out.back().find( x, ResolvMode::withAdjustment() ); 1925 1926 PRINT( 1927 std::cerr << "findSubExprs" << std::endl; 1928 print( std::cerr, out.back().candidates ); 1929 ) 1930 } 1931 1932 return out; 1933 } 1934 57 1935 const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) { 58 1936 if ( expr->result.as< ast::ReferenceType >() ) { … … 64 1942 return expr; 65 1943 } 66 67 /// Unique identifier for matching expression resolutions to their requesting expression68 UniqueId globalResnSlot = 0;69 1944 70 1945 Cost computeConversionCost( … … 93 1968 } 94 1969 95 namespace {96 /// First index is which argument, second is which alternative, third is which exploded element97 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;98 99 /// Returns a list of alternatives with the minimum cost in the given list100 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 type116 const ast::Expr * computeExpressionConversionCost(117 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost118 ) {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 requires124 // conversion. Ignore poly cost for now, since this requires resolution of the cast to125 // infer parameters and this does not currently work for the reason stated below126 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 not134 // 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* since138 // commontype(zero_t, DT*) is DT*, rather than nothing139 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 candidate153 Cost computeApplicationConversionCost(154 CandidateRef cand, const ast::SymbolTable & symtab155 ) {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 expressions180 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 system190 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 type197 // 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 continue204 }205 206 if ( param != params.end() ) return Cost::infinity;207 208 // specialization cost of return types can't be accounted for directly, it disables209 // 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 newline213 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization214 // }215 216 // mark type variable and specialization cost of forall clause217 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 & need226 ) {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 present236 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 arguments248 struct ArgPack {249 std::size_t parent; ///< Index of parent pack250 ast::ptr< ast::Expr > expr; ///< The argument stored here251 Cost cost; ///< The cost of this argument252 ast::TypeEnvironment env; ///< Environment for this pack253 ast::AssertionSet need; ///< Assertions outstanding for this pack254 ast::AssertionSet have; ///< Assertions found for this pack255 ast::OpenVarSet open; ///< Open variables for this pack256 unsigned nextArg; ///< Index of next argument in arguments list257 unsigned tupleStart; ///< Number of tuples that start at this index258 unsigned nextExpl; ///< Index of next exploded element259 unsigned explAlt; ///< Index of alternative for nextExpl > 0260 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 argument288 bool hasExpl() const { return nextExpl > 0; }289 290 /// Gets the list of exploded candidates for this pack291 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {292 return args[ nextArg-1 ][ explAlt ];293 }294 295 /// Ends a tuple expression, consolidating the appropriate args296 void endTuple( const std::vector< ArgPack > & packs ) {297 // add all expressions in tuple to list, summing cost298 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 tuple307 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 left315 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 = 0319 ) {320 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {321 // paramType is a TupleType -- group args into a TupleExpr322 ++nTuples;323 for ( const ast::Type * type : *tupleType ) {324 // xxx - dropping initializer changes behaviour from previous, but seems correct325 // ^^^ need to handle the case where a tuple has a default argument326 if ( ! instantiateArgument(327 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;328 nTuples = 0;329 }330 // re-constitute tuples for final generation331 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 arguments337 338 // completed tuples; will be spliced to end of results to finish339 std::vector< ArgPack > finalResults{};340 341 // iterate until all results completed342 std::size_t genEnd;343 ++nTuples;344 do {345 genEnd = results.size();346 347 // add another argument to results348 for ( std::size_t i = genStart; i < genEnd; ++i ) {349 unsigned nextArg = results[i].nextArg;350 351 // use next element of exploded tuple if present352 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 arguments368 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 expression377 newResult.parent = i;378 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };379 argType = newResult.expr->result;380 } else {381 // clone result to collect tuple382 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 purposes391 // xxx - what if passing multiple arguments, last of which is392 // ttype?393 // xxx - what would happen if unify was changed so that unifying394 // tuple395 // types flattened both before unifying lists? then pass in396 // TupleType (ttype) below.397 --newResult.tupleStart;398 } else {399 // collapse leftover arguments into tuple400 newResult.endTuple( results );401 argType = newResult.expr->result;402 }403 }404 405 // check unification for ttype before adding to final406 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 argument418 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 iteration422 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 gen428 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 result437 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 round445 genStart = genEnd;446 nTuples = 0;447 } while ( genEnd != results.size() );448 449 // splice final results onto results450 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 subresult457 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 present462 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 arguments493 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 argument510 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 iteration514 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 gen521 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 arg530 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 types542 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {543 // add new result544 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 parameter552 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::GeneratedCast560 ) {561 if (562 arg->result->size() > 1563 && ! 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 each567 // member of the tuple to its corresponding target type, producing the tuple of those568 // cast expressions. If there are more components of the tuple than components in the569 // target type, then excess components do not come out in the result expression (but570 // 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 of573 // the expression574 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 component579 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 normally586 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 interpretations600 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 NoReason618 };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 list631 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 inference642 void inferParameters( CandidateRef & newCand, CandidateList & out ) {643 // Set need bindings for any unbound assertions644 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions645 for ( auto & assn : newCand->need ) {646 // skip already-matched assertions647 if ( assn.second.resnSlot != 0 ) continue;648 // assign slot for expression if needed649 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }650 // fix slot to assertion651 assn.second.resnSlot = crntResnSlot;652 }653 // pair slot to expression654 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 later659 out.emplace_back( newCand );660 }661 662 /// Completes a function candidate with arguments located663 void validateFunctionCandidate(664 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,665 CandidateList & out666 ) {667 ast::ApplicationExpr * appExpr =668 new ast::ApplicationExpr{ func->expr->location, func->expr };669 // sum cost and accumulate arguments670 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 candidate681 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 out692 void makeFunctionCandidates(693 const CandidateRef & func, const ast::FunctionType * funcType,694 const ExplodedArgs_new & args, CandidateList & out695 ) {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 the701 // parameter list are still considered open702 funcEnv.add( funcType->forall );703 704 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {705 // attempt to narrow based on expected target type706 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 candidate711 return;712 }713 }714 715 // iteratively build matches, one parameter at a time716 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 name724 // must use types on candidate however, due to RenameVars substitution725 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 existing737 // matches738 // no default args for indirect calls739 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 pack746 std::size_t genEnd;747 do {748 genEnd = results.size();749 750 // iterate results751 for ( std::size_t i = genStart; i < genEnd; ++i ) {752 unsigned nextArg = results[i].nextArg;753 754 // use remainder of exploded tuple if present755 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 arguments771 if ( nextArg >= args.size() ) {772 validateFunctionCandidate( func, results[i], results, out );773 774 continue;775 }776 777 // add each possible next argument778 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 iteration782 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 gen788 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 result798 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 arguments809 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 list819 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 the822 // base type to treat the aggregate as the referenced value823 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 interpretations839 void addAggMembers(840 const ast::BaseInstType * aggrInst, const ast::Expr * expr,841 const Candidate & cand, const Cost & addedCost, const std::string & name842 ) {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 seen848 // as a member expression849 addAnonConversions( newCand );850 candidates.emplace_back( std::move( newCand ) );851 }852 }853 854 /// Adds tuple member interpretations855 void addTupleMembers(856 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,857 const Cost & addedCost, const ast::Expr * member858 ) {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 the861 // length of the tuple to have meaning862 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 assignments876 // if not tuple assignment, handled as normal function call877 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 references888 // xxx - is this correct?889 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;890 891 // convert 1-tuple to plain type892 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; // Here907 // 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 int912 // 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 fail920 // 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, // adjust924 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name925 selfFinder.candidates.empty() // failfast if other options are not found926 };927 funcFinder.find( untypedExpr->func, mode );928 // short-circuit if no candidates929 // if ( funcFinder.candidates.empty() ) return;930 931 reason.code = NoMatch;932 933 // find function operators934 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 operations937 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 arguments944 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 matches952 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 function962 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 list988 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-function998 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-error1012 // candidates1013 if ( found.empty() && ! errors.isEmpty() ) { throw errors; }1014 1015 // Compute conversion costs1016 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 twice1043 CandidateList winners = findMinCost( found );1044 promoteCvtCost( winners );1045 1046 // function may return a struct/union value, in which case we need to add candidates1047 // for implicit conversions to each of the anonymous members, which must happen after1048 // `findMinCost`, since anon conversions are never the cheapest1049 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 it1056 // 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 char1063 // * (x: const char *) is unified with unsigned char *, which fails1064 // xxx -- fix this better1065 targetType = nullptr;1066 postvisit( untypedExpr );1067 }1068 }1069 1070 /// true if expression is an lvalue1071 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-valued1112 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the1113 // subexpression results that are cast directly. The candidate is invalid if it1114 // 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-effects1119 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 away1135 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 cost1145 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 type1154 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.__thrd1197 // Clone is purely for memory management1198 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 type1201 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 type1210 finder.find( fallback.get(), ResolvMode::withoutPrune() );1211 1212 pick_alternatives(finder.candidates, true);1213 1214 // Whatever happens here, we have no more fallbacks1215 }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 the1222 // base type to treat the aggregate as the referenced value1223 Cost addedCost = Cost::zero;1224 agg->expr = referenceToRvalueConversion( agg->expr, addedCost );1225 1226 // find member of the given type1227 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 seen1290 // as a name expression1291 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 since1298 // creation1299 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 sizeof1315 CandidateFinder finder( context, tenv );1316 finder.find( sizeofExpr->expr );1317 // find the lowest-cost candidate, otherwise ambiguous1318 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 candidate1324 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 alignof1339 CandidateFinder finder( context, tenv );1340 finder.find( alignofExpr->expr );1341 // find the lowest-cost candidate, otherwise ambiguous1342 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 candidate1348 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 condition1408 CandidateFinder finder1( context, tenv );1409 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );1410 if ( finder1.candidates.empty() ) return;1411 1412 // candidates for true result1413 CandidateFinder finder2( context, tenv );1414 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );1415 if ( finder2.candidates.empty() ) return;1416 1417 // candidates for false result1418 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 new1440 // candidates1441 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 expression1448 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 type1452 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 candidate1458 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 unify1493 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 expression1521 ast::RangeExpr * newExpr =1522 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };1523 newExpr->result = common ? common : r1->expr->result;1524 // add candidate1525 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 cast1587 CandidateList matches;1588 PRINT(1589 std::cerr << "untyped init expr: " << initExpr << std::endl;1590 )1591 // O(n^2) checks of d-types with e-types1592 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {1593 // calculate target type1594 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 return1597 // types are not bound to the initialization type, since return type variables are1598 // 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-valued1613 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of1614 // the subexpression results that are cast directly. The candidate is invalid1615 // 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-effects1620 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 away1637 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 cost1650 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 given1670 /// return type. Skips ambiguous candidates.1671 1672 } // anonymous namespace1673 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 type1684 std::unordered_map< std::string, PruneStruct > selected;1685 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found1686 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 contains1707 // unbound type parameters, then it should never be pruned by1708 // the previous step, since renameTyVars guarantees the mangled name1709 // 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 it1722 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 option1741 // that is at least as good1742 if ( findDeletedExpr( newCand->expr ) ) {1743 // do nothing1744 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 candidates1766 // 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 error1780 return !selected.empty();1781 }1782 1783 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {1784 // Find alternatives for expression1785 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 satisfiable1807 // - necessary pre-requisite to pruning1808 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 such1815 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 candidates1825 candidates = move( satisfied );1826 }1827 */1828 1829 if ( mode.prune ) {1830 // trim candidates to single best one1831 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 correctly1873 // adjusted1874 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 expressions1883 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 > > & xs1892 ) {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 1908 1970 } // namespace ResolvExpr 1909 1971 -
src/ResolvExpr/CurrentObject.cc
r2ed94a9 rb110bcc 9 9 // Author : Rob Schluntz 10 10 // Created On : Tue Jun 13 15:28:32 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 1 09:16:01 202213 // Update Count : 1 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Apr 10 9:40:00 2023 13 // Update Count : 18 14 14 // 15 15 … … 26 26 #include "AST/Init.hpp" // for Designation 27 27 #include "AST/Node.hpp" // for readonly 28 #include "AST/Print.hpp" 28 #include "AST/Print.hpp" // for readonly 29 29 #include "AST/Type.hpp" 30 #include "Common/Eval.h" // for eval 30 31 #include "Common/Indenter.h" // for Indenter, operator<< 31 32 #include "Common/SemanticError.h" // for SemanticError … … 592 593 593 594 namespace 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 594 634 /// create a new MemberIterator that traverses a type correctly 595 635 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ); … … 631 671 }; 632 672 633 /// Iterates array types 634 class ArrayIterator final : public MemberIterator { 673 /// Iterates over an indexed type: 674 class IndexIterator : public MemberIterator { 675 protected: 635 676 CodeLocation location; 636 const ArrayType * array = nullptr;637 const Type * base = nullptr;638 677 size_t index = 0; 639 678 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 {} 659 684 660 685 void setPosition( const Expr * expr ) { … … 665 690 auto arg = eval( expr ); 666 691 index = arg.first; 667 return;668 692 669 693 // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 683 707 684 708 void setPosition( 685 std::deque< ptr< Expr >>::const_iterator begin,686 std::deque< ptr< Expr >>::const_iterator end709 std::deque<ast::ptr<ast::Expr>>::const_iterator begin, 710 std::deque<ast::ptr<ast::Expr>>::const_iterator end 687 711 ) override { 688 712 if ( begin == end ) return; … … 695 719 696 720 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 } 697 746 698 747 ArrayIterator & bigStep() override { … … 833 882 834 883 const Type * getNext() final { 835 return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr; 884 bool hasMember = memberIter && *memberIter; 885 return hasMember ? memberIter->getType() : nullptr; 836 886 } 837 887 … … 897 947 }; 898 948 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() ) ); 908 963 } 909 964 910 965 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 ); 919 969 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 {}; 920 1004 } 921 1005 }; -
src/ResolvExpr/CurrentObject.h
r2ed94a9 rb110bcc 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Jun 8 11:07:25 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:36:48 201713 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Apr 6 16:14:00 2023 13 // Update Count : 4 14 14 // 15 15 … … 65 65 66 66 /// 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; 104 68 105 69 /// Builds initializer lists in resolution -
src/ResolvExpr/ExplodedArg.hpp
r2ed94a9 rb110bcc 35 35 ExplodedArg() : env(), cost( Cost::zero ), exprs() {} 36 36 ExplodedArg( const Candidate & arg, const ast::SymbolTable & symtab ); 37 37 38 38 ExplodedArg( ExplodedArg && ) = default; 39 39 ExplodedArg & operator= ( ExplodedArg && ) = default; -
src/ResolvExpr/ResolveAssertions.cc
r2ed94a9 rb110bcc 30 30 #include "Common/FilterCombos.h" // for filterCombos 31 31 #include "Common/Indenter.h" // for Indenter 32 #include "Common/utility.h" // for sort_mins33 32 #include "GenPoly/GenPoly.h" // for getFunctionType 34 33 #include "ResolvExpr/AlternativeFinder.h" // for computeConversionCost -
src/ResolvExpr/Resolver.cc
r2ed94a9 rb110bcc 38 38 #include "AST/SymbolTable.hpp" 39 39 #include "AST/Type.hpp" 40 #include "Common/Eval.h" // for eval 41 #include "Common/Iterate.hpp" // for group_iterate 40 42 #include "Common/PassVisitor.h" // for PassVisitor 41 43 #include "Common/SemanticError.h" // for SemanticError 42 44 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 43 #include "Common/ utility.h" // for ValueGuard, group_iterate45 #include "Common/ToString.hpp" // for toCString 44 46 #include "InitTweak/GenInit.h" 45 47 #include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt -
src/ResolvExpr/Resolver.h
r2ed94a9 rb110bcc 34 34 class Decl; 35 35 class DeletedExpr; 36 class Expr; 36 37 class Init; 37 38 class StmtExpr; -
src/SymTab/Autogen.cc
r2ed94a9 rb110bcc 10 10 // Created On : Thu Mar 03 15:45:56 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Apr 27 14:39:06 201813 // Update Count : 6 312 // Last Modified On : Fri Apr 14 15:03:00 2023 13 // Update Count : 64 14 14 // 15 15 … … 211 211 } 212 212 213 bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {214 return obj && obj->name.empty() && obj->bitfieldWidth;215 }216 217 213 /// inserts a forward declaration for functionDecl into declsToAdd 218 214 void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) { … … 234 230 } 235 231 236 // shallow copy the pointer list for return237 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 247 232 /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *) 248 233 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) { … … 256 241 ftype->parameters.push_back( dstParam ); 257 242 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);266 243 } 267 244 -
src/SymTab/Autogen.h
r2ed94a9 rb110bcc 9 9 // Author : Rob Schluntz 10 10 // Created On : Sun May 17 21:53:34 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 16:38:06 201913 // Update Count : 1 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Apr 14 15:06:00 2023 13 // Update Count : 17 14 14 // 15 15 … … 45 45 /// returns true if obj's name is the empty string and it has a bitfield width 46 46 bool isUnnamedBitfield( ObjectDecl * obj ); 47 bool isUnnamedBitfield( const ast::ObjectDecl * obj );48 47 49 48 /// generate the type of an assignment function for paramType. … … 55 54 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true ); 56 55 57 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);58 59 56 /// generate the type of a copy constructor for paramType. 60 57 /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic … … 67 64 template< typename OutputIterator > 68 65 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 );75 66 76 67 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types. … … 121 112 122 113 *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 and130 /// srcParam. Should only be called with non-array types.131 /// optionally returns a statement which must be inserted prior to the containing loop, if132 /// there is one133 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 = nullptr138 ) {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 cast143 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 of150 // "?=?", "?{}", 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 and155 // destructed with the same functions as non-qualified objects. Unfortunately, lvalue156 // is considered a qualifier - for AddressExpr to resolve, its argument must have an157 // 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 addCast160 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 arguments171 ++srcParam;172 173 // return if adding reference fails -- will happen on default ctor and dtor174 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 };180 114 181 115 srcParam.clearArrayIndices(); … … 248 182 } 249 183 250 /// Store in out a loop which calls fname on each element of the array with srcParam and251 /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0252 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 = LoopForward258 ) {259 static UniqueName indexName( "_index" );260 261 // for a flexible array member nothing is done -- user must define own assignment262 if ( ! array->dimension ) return;263 264 if ( addCast ) {265 // peel off array layer from cast266 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/or302 // array list initializer303 srcParam.addArrayIndex( indexVar, array->dimension );304 305 // for stmt's body, eventually containing call306 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 variable312 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 320 184 template< typename OutputIterator > 321 185 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) { … … 325 189 } else { 326 190 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 forward335 ) {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 );344 191 } 345 192 } … … 379 226 } 380 227 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 = LoopForward385 ) {386 // unnamed bit fields are not copied as they cannot be accessed387 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 are405 // 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 }414 228 } // namespace SymTab 415 229 -
src/SymTab/FixFunction.cc
r2ed94a9 rb110bcc 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/utility.h" // for maybeClone,copy23 #include "Common/utility.h" // for copy 24 24 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarati... 25 25 #include "SynTree/Expression.h" // for Expression -
src/SymTab/Mangler.cc
r2ed94a9 rb110bcc 24 24 #include "CodeGen/OperatorTable.h" // for OperatorInfo, operatorLookup 25 25 #include "Common/PassVisitor.h" 26 #include "Common/ToString.hpp" // for toCString 26 27 #include "Common/SemanticError.h" // for SemanticError 27 #include "Common/utility.h" // for toString28 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment 29 29 #include "SynTree/LinkageSpec.h" // for Spec, isOverridable, AutoGen, Int... -
src/SymTab/Validate.cc
r2ed94a9 rb110bcc 55 55 #include "Common/ScopedMap.h" // for ScopedMap 56 56 #include "Common/SemanticError.h" // for SemanticError 57 #include "Common/ToString.hpp" // for toCString 57 58 #include "Common/UniqueName.h" // for UniqueName 58 #include "Common/utility.h" // for operator+,cloneAll, deleteAll59 #include "Common/utility.h" // for cloneAll, deleteAll 59 60 #include "CompilationState.h" // skip some passes in new-ast build 60 61 #include "Concurrency/Keywords.h" // for applyKeywords -
src/SymTab/ValidateType.cc
r2ed94a9 rb110bcc 18 18 #include "CodeGen/OperatorTable.h" 19 19 #include "Common/PassVisitor.h" 20 #include "Common/ToString.hpp" 20 21 #include "SymTab/FixFunction.h" 21 22 #include "SynTree/Declaration.h" -
src/SymTab/module.mk
r2ed94a9 rb110bcc 20 20 SymTab/FixFunction.cc \ 21 21 SymTab/FixFunction.h \ 22 SymTab/GenImplicitCall.cpp \ 23 SymTab/GenImplicitCall.hpp \ 22 24 SymTab/Indexer.cc \ 23 25 SymTab/Indexer.h \ -
src/SynTree/AggregateDecl.cc
r2ed94a9 rb110bcc 19 19 20 20 #include "Attribute.h" // for Attribute 21 #include "Common/Eval.h" // for eval 21 22 #include "Common/utility.h" // for printAll, cloneAll, deleteAll 22 23 #include "Declaration.h" // for AggregateDecl, TypeDecl, Declaration -
src/SynTree/FunctionDecl.cc
r2ed94a9 rb110bcc 87 87 } // if 88 88 89 if ( !withExprs.empty() ) { 90 os << indent << "... with clause" << std::endl; 91 os << indent + 1; 92 printAll( withExprs, os, indent + 1 ); 93 } 94 89 95 if ( statements ) { 90 96 os << indent << "... with body" << endl << indent+1; -
src/SynTree/Type.cc
r2ed94a9 rb110bcc 16 16 17 17 #include "Attribute.h" // for Attribute 18 #include "Common/ToString.hpp" // for toCString 18 19 #include "Common/utility.h" // for cloneAll, deleteAll, printAll 19 20 #include "InitTweak/InitTweak.h" // for getPointerBase … … 105 106 int Type::referenceDepth() const { return 0; } 106 107 108 AggregateDecl * Type::getAggr() const { 109 assertf( false, "Non-aggregate type: %s", toCString( this ) ); 110 } 111 107 112 TypeSubstitution Type::genericSubstitution() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); } 108 113 -
src/SynTree/Type.h
r2ed94a9 rb110bcc 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Wed Jul 14 15:40:00 202113 // Update Count : 17 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 19 22:37:10 2023 13 // Update Count : 176 14 14 // 15 15 … … 23 23 24 24 #include "BaseSyntaxNode.h" // for BaseSyntaxNode 25 #include "Common/ utility.h"// for operator+25 #include "Common/Iterate.hpp"// for operator+ 26 26 #include "Mutator.h" // for Mutator 27 27 #include "SynTree.h" // for AST nodes … … 124 124 bool operator!=( Qualifiers other ) const { return (val & Mask) != (other.val & Mask); } 125 125 bool operator<=( Qualifiers other ) const { 126 return is_const <= other.is_const // Any non-const converts to const without cost127 && is_volatile <= other.is_volatile //Any non-volatile converts to volatile without cost128 && is_mutex >= other.is_mutex //Any mutex converts to non-mutex without cost129 && is_atomic == other.is_atomic; //No conversion from atomic to non atomic is free126 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 130 130 } 131 131 bool operator<( Qualifiers other ) const { return *this != other && *this <= other; } … … 185 185 virtual bool isComplete() const { return true; } 186 186 187 virtual AggregateDecl * getAggr() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }187 virtual AggregateDecl * getAggr() const; 188 188 189 189 virtual TypeSubstitution genericSubstitution() const; 190 190 191 virtual Type * clone() const = 0;191 virtual Type * clone() const = 0; 192 192 virtual void accept( Visitor & v ) = 0; 193 193 virtual void accept( Visitor & v ) const = 0; 194 virtual Type * acceptMutator( Mutator & m ) = 0;194 virtual Type * acceptMutator( Mutator & m ) = 0; 195 195 virtual void print( std::ostream & os, Indenter indent = {} ) const; 196 196 }; … … 207 207 virtual bool isComplete() const override { return false; } 208 208 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 ); } 213 213 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 214 214 }; … … 259 259 // GENERATED END 260 260 261 static const char * typeNames[];// string names for basic types, MUST MATCH with Kind261 static const char * typeNames[]; // string names for basic types, MUST MATCH with Kind 262 262 263 263 BasicType( const Type::Qualifiers & tq, Kind bt, const std::list< Attribute * > & attributes = std::list< Attribute * >() ); … … 266 266 void set_kind( Kind newValue ) { kind = newValue; } 267 267 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 ); } 272 272 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 273 273 bool isInteger() const; … … 279 279 280 280 // In C99, pointer types can be qualified in many ways e.g., int f( int a[ static 3 ] ) 281 Expression * dimension;281 Expression * dimension; 282 282 bool isVarLen; 283 283 bool isStatic; 284 284 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 * >() ); 287 287 PointerType( const PointerType& ); 288 288 virtual ~PointerType(); 289 289 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; } 294 294 bool get_isVarLen() { return isVarLen; } 295 295 void set_isVarLen( bool newValue ) { isVarLen = newValue; } … … 301 301 virtual bool isComplete() const override { return ! isVarLen; } 302 302 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 ); } 307 307 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 308 308 }; … … 310 310 class ArrayType : public Type { 311 311 public: 312 Type * base;313 Expression * dimension;312 Type * base; 313 Expression * dimension; 314 314 bool isVarLen; 315 315 bool isStatic; 316 316 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 * >() ); 318 318 ArrayType( const ArrayType& ); 319 319 virtual ~ArrayType(); 320 320 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; } 325 325 bool get_isVarLen() { return isVarLen; } 326 326 void set_isVarLen( bool newValue ) { isVarLen = newValue; } … … 333 333 virtual bool isComplete() const override { return dimension || isVarLen; } 334 334 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 ); } 339 339 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 340 340 }; … … 348 348 virtual ~QualifiedType(); 349 349 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 ); } 354 354 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 355 355 }; … … 357 357 class ReferenceType : public Type { 358 358 public: 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 * >() ); 362 362 ReferenceType( const ReferenceType & ); 363 363 virtual ~ReferenceType(); 364 364 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; } 367 367 368 368 virtual int referenceDepth() const override; … … 375 375 virtual TypeSubstitution genericSubstitution() const override; 376 376 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 ); } 381 381 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 382 382 }; … … 405 405 bool isUnprototyped() const { return isVarArgs && parameters.size() == 0; } 406 406 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 ); } 411 411 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 412 412 }; … … 414 414 class ReferenceToType : public Type { 415 415 public: 416 std::list< Expression * > parameters;416 std::list< Expression * > parameters; 417 417 std::string name; 418 418 bool hoistType; … … 428 428 void set_hoistType( bool newValue ) { hoistType = newValue; } 429 429 430 virtual ReferenceToType * clone() const override = 0;430 virtual ReferenceToType * clone() const override = 0; 431 431 virtual void accept( Visitor & v ) override = 0; 432 virtual Type * acceptMutator( Mutator & m ) override = 0;432 virtual Type * acceptMutator( Mutator & m ) override = 0; 433 433 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 434 434 … … 443 443 // this decl is not "owned" by the struct inst; it is merely a pointer to elsewhere in the tree, 444 444 // where the structure used in this type is actually defined 445 StructDecl * baseStruct;445 StructDecl * baseStruct; 446 446 447 447 StructInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >() ) : Parent( tq, name, attributes ), baseStruct( 0 ) {} … … 449 449 StructInstType( const StructInstType & other ) : Parent( other ), baseStruct( other.baseStruct ) {} 450 450 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; } 453 453 454 454 /// Accesses generic parameters of base struct (NULL if none such) … … 466 466 void lookup( const std::string & name, std::list< Declaration* > & foundDecls ) const override; 467 467 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 ); } 472 472 473 473 virtual void print( std::ostream & os, Indenter indent = {} ) const override; … … 481 481 // this decl is not "owned" by the union inst; it is merely a pointer to elsewhere in the tree, 482 482 // where the union used in this type is actually defined 483 UnionDecl * baseUnion;483 UnionDecl * baseUnion; 484 484 485 485 UnionInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >() ) : Parent( tq, name, attributes ), baseUnion( 0 ) {} … … 487 487 UnionInstType( const UnionInstType & other ) : Parent( other ), baseUnion( other.baseUnion ) {} 488 488 489 UnionDecl * get_baseUnion() const { return baseUnion; }489 UnionDecl * get_baseUnion() const { return baseUnion; } 490 490 void set_baseUnion( UnionDecl * newValue ) { baseUnion = newValue; } 491 491 … … 504 504 void lookup( const std::string & name, std::list< Declaration* > & foundDecls ) const override; 505 505 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 ); } 510 510 511 511 virtual void print( std::ostream & os, Indenter indent = {} ) const override; … … 519 519 // this decl is not "owned" by the enum inst; it is merely a pointer to elsewhere in the tree, 520 520 // where the enum used in this type is actually defined 521 EnumDecl * baseEnum = nullptr;521 EnumDecl * baseEnum = nullptr; 522 522 523 523 EnumInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >() ) : Parent( tq, name, attributes ) {} … … 525 525 EnumInstType( const EnumInstType & other ) : Parent( other ), baseEnum( other.baseEnum ) {} 526 526 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; } 529 529 530 530 virtual bool isComplete() const override; … … 532 532 virtual AggregateDecl * getAggr() const override; 533 533 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 ); } 538 538 539 539 virtual void print( std::ostream & os, Indenter indent = {} ) const override; … … 556 556 virtual bool isComplete() const override; 557 557 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 ); } 562 562 private: 563 563 virtual std::string typeString() const override; … … 569 569 // this decl is not "owned" by the type inst; it is merely a pointer to elsewhere in the tree, 570 570 // where the type used here is actually defined 571 TypeDecl * baseType;571 TypeDecl * baseType; 572 572 bool isFtype; 573 573 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 * >() ); 575 575 TypeInstType( const Type::Qualifiers & tq, const std::string & name, bool isFtype, const std::list< Attribute * > & attributes = std::list< Attribute * >() ); 576 576 TypeInstType( const TypeInstType & other ); 577 577 ~TypeInstType(); 578 578 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 ); 581 581 bool get_isFtype() const { return isFtype; } 582 582 void set_isFtype( bool newValue ) { isFtype = newValue; } … … 584 584 virtual bool isComplete() const override; 585 585 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 ); } 590 590 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 591 591 private: … … 622 622 // virtual bool isComplete() const override { return true; } // xxx - not sure if this is right, might need to recursively check complete-ness 623 623 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 ); } 628 628 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 629 629 }; … … 631 631 class TypeofType : public Type { 632 632 public: 633 Expression * expr;///< expression to take the type of634 bool is_basetypeof; 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, 638 638 const std::list< Attribute * > & attributes = std::list< Attribute * >() ); 639 639 TypeofType( const TypeofType& ); 640 640 virtual ~TypeofType(); 641 641 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; } 644 644 645 645 virtual bool isComplete() const override { assert( false ); return false; } 646 646 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 ); } 651 651 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 652 652 }; … … 654 654 class VTableType : public Type { 655 655 public: 656 Type * base;657 658 VTableType( const Type::Qualifiers & tq, Type * base,656 Type * base; 657 658 VTableType( const Type::Qualifiers & tq, Type * base, 659 659 const std::list< Attribute * > & attributes = std::list< Attribute * >() ); 660 660 VTableType( const VTableType & ); 661 661 virtual ~VTableType(); 662 662 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 ); } 670 670 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 671 671 }; … … 674 674 public: 675 675 std::string name; 676 Expression * expr;677 Type * type;676 Expression * expr; 677 Type * type; 678 678 bool isType; 679 679 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 * >() ); 682 682 AttrType( const AttrType& ); 683 683 virtual ~AttrType(); … … 685 685 const std::string & get_name() const { return name; } 686 686 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; } 691 691 bool get_isType() const { return isType; } 692 692 void set_isType( bool newValue ) { isType = newValue; } … … 694 694 virtual bool isComplete() const override { assert( false ); } // xxx - not sure what to do here 695 695 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 ); } 700 700 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 701 701 }; … … 709 709 virtual bool isComplete() const override{ return true; } // xxx - is this right? 710 710 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 ); } 715 715 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 716 716 }; … … 722 722 ZeroType( Type::Qualifiers tq, const std::list< Attribute * > & attributes = std::list< Attribute * >() ); 723 723 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 ); } 728 728 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 729 729 }; … … 735 735 OneType( Type::Qualifiers tq, const std::list< Attribute * > & attributes = std::list< Attribute * >() ); 736 736 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 ); } 741 741 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 742 742 }; … … 746 746 GlobalScopeType(); 747 747 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 ); } 752 752 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 753 753 }; -
src/Validate/Autogen.cpp
r2ed94a9 rb110bcc 39 39 #include "InitTweak/GenInit.h" // for fixReturnStatements 40 40 #include "InitTweak/InitTweak.h" // for isAssignment, isCopyConstructor 41 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 41 42 #include "SymTab/Mangler.h" // for Mangler 42 43 #include "CompilationState.h" … … 423 424 for ( unsigned int index = 0 ; index < fields ; ++index ) { 424 425 auto member = aggr->members[index].strict_as<ast::DeclWithType>(); 425 if ( SymTab::isUnnamedBitfield(426 if ( ast::isUnnamedBitfield( 426 427 dynamic_cast<const ast::ObjectDecl *>( member ) ) ) { 427 428 if ( index == fields - 1 ) { … … 599 600 // Not sure why it could be null. 600 601 // 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 ) ) { 602 603 continue; 603 604 // Matching Parameter: Initialize the field by copy. -
src/Validate/FixQualifiedTypes.cpp
r2ed94a9 rb110bcc 16 16 #include "Validate/FixQualifiedTypes.hpp" 17 17 18 #include "AST/LinkageSpec.hpp" // for Linkage 18 19 #include "AST/Pass.hpp" 19 20 #include "AST/TranslationUnit.hpp" 21 #include "Common/ToString.hpp" // for toString 22 #include "SymTab/Mangler.h" // for Mangler 20 23 #include "Validate/NoIdSymbolTable.hpp" 21 #include "SymTab/Mangler.h" // for Mangler22 #include "AST/LinkageSpec.hpp" // for Linkage23 24 24 25 namespace Validate { -
src/Validate/ForallPointerDecay.cpp
r2ed94a9 rb110bcc 22 22 #include "CodeGen/OperatorTable.h" 23 23 #include "Common/CodeLocation.h" 24 #include "Common/ToString.hpp" 24 25 #include "SymTab/FixFunction.h" 25 26 -
src/Validate/HandleAttributes.cc
r2ed94a9 rb110bcc 17 17 18 18 #include "CompilationState.h" 19 #include "Common/Eval.h" 19 20 #include "Common/PassVisitor.h" 21 #include "Common/ToString.hpp" 20 22 #include "Common/SemanticError.h" 21 23 #include "ResolvExpr/Resolver.h" -
src/Validate/HoistStruct.cpp
r2ed94a9 rb110bcc 16 16 #include "Validate/HoistStruct.hpp" 17 17 18 #include <sstream> 19 18 20 #include "AST/Pass.hpp" 19 21 #include "AST/TranslationUnit.hpp" 20 #include "Common/utility.h"21 22 22 23 namespace Validate { -
src/Virtual/module.mk
r2ed94a9 rb110bcc 19 19 Virtual/ExpandCasts.h \ 20 20 Virtual/Tables.cc \ 21 Virtual/Tables.h 21 Virtual/Tables.h \ 22 Virtual/VirtualDtor.cpp \ 23 Virtual/VirtualDtor.hpp -
src/include/cassert
r2ed94a9 rb110bcc 20 20 #include_next <cassert> 21 21 22 #include <string> 23 24 template < typename ... Params > 25 std::string toString( const Params & ... params ); 22 #include "Common/ToString.hpp" 26 23 27 24 #ifdef NDEBUG -
src/main.cc
r2ed94a9 rb110bcc 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Wed Oct 5 12:06:00 202213 // Update Count : 6 7911 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 21:12:17 2023 13 // Update Count : 682 14 14 // 15 15 … … 32 32 33 33 #include "AST/Convert.hpp" 34 #include "AST/Util.hpp" // for checkInvariants 34 35 #include "CompilationState.h" 35 36 #include "../config.h" // for CFA_LIBDIR … … 40 41 #include "CodeTools/TrackLoc.h" // for fillLocations 41 42 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 42 #include "Common/CompilerError.h" // for CompilerError43 43 #include "Common/DeclStats.hpp" // for printDeclStats 44 44 #include "Common/ResolvProtoDump.hpp" // for dumpAsResolverProto 45 45 #include "Common/Stats.h" // for Stats 46 #include "Common/UnimplementedError.h" // for UnimplementedError47 46 #include "Common/utility.h" // for deleteAll, filter, printAll 48 47 #include "Concurrency/Actors.hpp" // for implementActors … … 84 83 #include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign 85 84 #include "Virtual/ExpandCasts.h" // for expandCasts 85 #include "Virtual/VirtualDtor.hpp" // for implementVirtDtors 86 86 87 87 static void NewPass( const char * const name ) { … … 102 102 } 103 103 104 #define PASS( name, pass ) \ 104 // Helpers for checkInvariant: 105 void checkInvariants( std::list< Declaration * > & ) {} 106 using ast::checkInvariants; 107 108 #define PASS( name, pass, unit, ... ) \ 105 109 if ( errorp ) { cerr << name << endl; } \ 106 110 NewPass(name); \ 107 111 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 } 110 123 111 124 static bool waiting_for_gdb = false; // flag to set cfa-cpp to wait for gdb on start … … 274 287 FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" ); 275 288 assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" ); 276 parse( gcc_builtins, LinkageSpec::Compiler );289 parse( gcc_builtins, ast::Linkage::Compiler ); 277 290 278 291 // read the extra prelude in, if not generating the cfa library 279 292 FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" ); 280 293 assertf( extras, "cannot open extras.cf\n" ); 281 parse( extras, LinkageSpec::BuiltinC );294 parse( extras, ast::Linkage::BuiltinC ); 282 295 283 296 if ( ! libcfap ) { … … 285 298 FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" ); 286 299 assertf( prelude, "cannot open prelude.cfa\n" ); 287 parse( prelude, LinkageSpec::Intrinsic );300 parse( prelude, ast::Linkage::Intrinsic ); 288 301 289 302 // Read to cfa builtins, if not generating the cfa library 290 303 FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" ); 291 304 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 ); 297 310 298 311 transUnit = buildUnit(); 299 312 300 if ( astp ) { 301 dump( std::move( transUnit ) ); 302 return EXIT_SUCCESS; 303 } // if 313 DUMP( astp, std::move( transUnit ) ); 304 314 305 315 Stats::Time::StopBlock(); … … 310 320 } 311 321 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 ); 352 354 353 355 if ( symtabp ) { … … 360 362 } // if 361 363 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 ); 372 371 373 372 if ( libcfap ) { … … 381 380 } // if 382 381 383 if ( bresolvep ) { 384 dump( std::move( transUnit ) ); 385 return EXIT_SUCCESS; 386 } // if 382 DUMP( bresolvep, std::move( transUnit ) ); 387 383 388 384 if ( resolvprotop ) { … … 391 387 } // if 392 388 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() ); 402 393 403 394 // 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 ) ); 408 396 409 397 // 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 reused411 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 ); 414 402 415 403 // 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 ) ); 424 408 425 409 // 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 ); 435 416 436 417 translationUnit = convert( std::move( transUnit ) ); 437 418 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 ); 445 423 446 424 // Code has been lowered to C, now we can start generation. 447 425 448 if ( bcodegenp ) { 449 dump( translationUnit ); 450 return EXIT_SUCCESS; 451 } // if 426 DUMP( bcodegenp, translationUnit ); 452 427 453 428 if ( optind < argc ) { // any commands after the flags and input file ? => output file name … … 456 431 457 432 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 ); 459 434 460 435 CodeGen::FixMain::fix( translationUnit, *output, … … 476 451 } // if 477 452 e.print(); 478 if ( output != &cout ) {479 delete output;480 } // if481 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 } // if487 return EXIT_FAILURE;488 } catch ( CompilerError & e ) {489 cerr << "Compiler Error: " << e.get_what() << endl;490 cerr << "(please report bugs to [REDACTED])" << endl;491 453 if ( output != &cout ) { 492 454 delete output; … … 517 479 518 480 519 static const char optstring[] = ":c:gh lLmNnpdP:S:twW:D:";481 static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:"; 520 482 521 483 enum { PreludeDir = 128 }; … … 524 486 { "gdb", no_argument, nullptr, 'g' }, 525 487 { "help", no_argument, nullptr, 'h' }, 488 { "invariant", no_argument, nullptr, 'i' }, 526 489 { "libcfa", no_argument, nullptr, 'l' }, 527 490 { "linemarks", no_argument, nullptr, 'L' }, 528 { "no-main", no_argument, 0, 'm' },491 { "no-main", no_argument, nullptr, 'm' }, 529 492 { "no-linemarks", no_argument, nullptr, 'N' }, 530 493 { "no-prelude", no_argument, nullptr, 'n' }, … … 545 508 "wait for gdb to attach", // -g 546 509 "print translator help message", // -h 510 "invariant checking during AST passes", // -i 547 511 "generate libcfa.c", // -l 548 512 "generate line marks", // -L … … 638 602 usage( argv ); // no return 639 603 break; 604 case 'i': // invariant checking 605 invariant = true; 606 break; 640 607 case 'l': // generate libcfa.c 641 608 libcfap = true; -
tests/.expect/PRNG.x64.txt
r2ed94a9 rb110bcc 1 2 CFA xoshiro256pp 1 3 2 4 PRNG() PRNG(5) PRNG(0,5) 3 8464106481 4 44 5215204710507639537 1 25 1880401021892145483 0 46 12503840966285181348 2 57 801971300205459356 0 28 6123812066052045228 3 19 7691074772031490538 4 310 4793575011534070065 0011 1 0647551928893428440 1 312 1 0865128702974868079 0 313 530720947131684825 3014 10520125295812061287 1515 7539957561855178679 4 416 1 3739826796006269835 0 217 4289714351582916365 3 218 1 6911914987551424434 2119 5327155553462670435 4 020 1 6251986870929071204 4 421 1 3394433706240223001 0 322 4814982023332666924 4 05 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 23 25 seed 1009 24 26 25 27 Sequential 26 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%28 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 27 29 28 30 Concurrent 29 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%30 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%31 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%32 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%31 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 32 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 33 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 34 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 33 35 34 36 prng() prng(5) prng(0,5) 35 8464106481 4 436 5215204710507639537 1 237 1880401021892145483 0 438 12503840966285181348 2 539 801971300205459356 0 240 6123812066052045228 3 141 7691074772031490538 4 342 4793575011534070065 0043 1 0647551928893428440 1 344 1 0865128702974868079 0 345 530720947131684825 3046 10520125295812061287 1547 7539957561855178679 4 448 1 3739826796006269835 0 249 4289714351582916365 3 250 1 6911914987551424434 2151 5327155553462670435 4 052 1 6251986870929071204 4 453 1 3394433706240223001 0 354 4814982023332666924 4 037 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 55 57 seed 1009 56 58 57 59 Sequential 58 trials 100000000 buckets 100000 min 871 max 1144 avg 1000.0 std 31.6 rstd 3.2%60 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0% 59 61 60 62 Concurrent 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%63 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0% 64 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0% 65 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0% 66 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0% 65 67 66 68 prng(t) prng(t,5) prng(t,0,5) 67 8464106481 4 468 5215204710507639537 1 269 1880401021892145483 0 470 12503840966285181348 2 571 801971300205459356 0 272 6123812066052045228 3 173 7691074772031490538 4 374 4793575011534070065 0075 1 0647551928893428440 1 376 1 0865128702974868079 0 377 530720947131684825 3078 10520125295812061287 1579 7539957561855178679 4 480 1 3739826796006269835 0 281 4289714351582916365 3 282 1 6911914987551424434 2183 5327155553462670435 4 084 1 6251986870929071204 4 485 1 3394433706240223001 0 386 4814982023332666924 4 069 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 87 89 seed 1009 88 90 89 91 Sequential 90 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%92 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 91 93 92 94 Concurrent 93 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%94 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%95 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%96 trials 100000000 buckets 100000 min 87 1 max 1144avg 1000.0 std 31.6 rstd 3.2%95 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 96 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 97 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% 98 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2% -
tests/.expect/PRNG.x86.txt
r2ed94a9 rb110bcc 1 2 CFA xoshiro128pp 1 3 2 4 PRNG() PRNG(5) PRNG(0,5) 3 130161 1 14 4074541490 0 05 927506267 0 36 1991273445 1 37 669918146 2 38 519546860 119 1136699882 4310 2130185384 3 111 992239050 0 512 2250903111 0 113 1544429724 3 214 1591091660 3 315 2511657707 2 416 1065770984 2417 2412763405 4418 18 34447239 4 219 360289337 0 420 2449452027 1 121 3370425396 2 122 3109103043 0 35 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 23 25 seed 1009 24 26 25 27 Sequential 26 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%28 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 27 29 28 30 Concurrent 29 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%30 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%31 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%32 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%31 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 32 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 33 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 34 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 33 35 34 36 prng() prng(5) prng(0,5) 35 130161 1 136 4074541490 0 037 927506267 0 338 1991273445 1 339 669918146 2 340 519546860 1141 1136699882 4342 2130185384 3 143 992239050 0 544 2250903111 0 145 1544429724 3 246 1591091660 3 347 2511657707 2 448 1065770984 2449 2412763405 4450 18 34447239 4 251 360289337 0 452 2449452027 1 153 3370425396 2 154 3109103043 0 337 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 55 57 seed 1009 56 58 57 59 Sequential 58 trials 100000000 buckets 100000 min 867 max 1135 avg 1000.0 std 31.7 rstd 3.2%60 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1% 59 61 60 62 Concurrent 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%63 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1% 64 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1% 65 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1% 66 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1% 65 67 66 68 prng(t) prng(t,5) prng(t,0,5) 67 130161 1 168 4074541490 0 069 927506267 0 370 1991273445 1 371 669918146 2 372 519546860 1173 1136699882 4374 2130185384 3 175 992239050 0 576 2250903111 0 177 1544429724 3 278 1591091660 3 379 2511657707 2 480 1065770984 2481 2412763405 4482 18 34447239 4 283 360289337 0 484 2449452027 1 185 3370425396 2 186 3109103043 0 369 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 87 89 seed 1009 88 90 89 91 Sequential 90 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%92 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 91 93 92 94 Concurrent 93 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%94 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%95 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%96 trials 100000000 buckets 100000 min 8 67 max 1135 avg 1000.0 std 31.7rstd 3.2%95 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 96 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 97 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% 98 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2% -
tests/.expect/attributes.arm64.txt
r2ed94a9 rb110bcc 26 26 return _X4_retS12__anonymous0_1; 27 27 } 28 __attribute__ ((unused)) st ruct __anonymous0 _X5DummyS12__anonymous0_1;28 __attribute__ ((unused)) static struct __anonymous0 _X5DummyS12__anonymous0_1; 29 29 struct __attribute__ ((unused)) Agn1; 30 30 struct __attribute__ ((unused)) Agn2 { … … 1351 1351 signed 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)); 1352 1352 signed 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));1353 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(__attribute__ ((unused)) signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __param_0)); 1354 1354 struct Vad { 1355 1355 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.x64.txt
r2ed94a9 rb110bcc 26 26 return _X4_retS12__anonymous0_1; 27 27 } 28 __attribute__ ((unused)) st ruct __anonymous0 _X5DummyS12__anonymous0_1;28 __attribute__ ((unused)) static struct __anonymous0 _X5DummyS12__anonymous0_1; 29 29 struct __attribute__ ((unused)) Agn1; 30 30 struct __attribute__ ((unused)) Agn2 { … … 1351 1351 signed 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)); 1352 1352 signed 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));1353 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(__attribute__ ((unused)) signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __param_0)); 1354 1354 struct Vad { 1355 1355 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.x86.txt
r2ed94a9 rb110bcc 26 26 return _X4_retS12__anonymous0_1; 27 27 } 28 __attribute__ ((unused)) st ruct __anonymous0 _X5DummyS12__anonymous0_1;28 __attribute__ ((unused)) static struct __anonymous0 _X5DummyS12__anonymous0_1; 29 29 struct __attribute__ ((unused)) Agn1; 30 30 struct __attribute__ ((unused)) Agn2 { … … 1351 1351 signed 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)); 1352 1352 signed 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));1353 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(__attribute__ ((unused)) signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __param_0)); 1354 1354 struct Vad { 1355 1355 __attribute__ ((unused)) signed int :4; -
tests/.expect/declarationSpecifier.arm64.txt
r2ed94a9 rb110bcc 51 51 52 52 } 53 volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;53 static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1; 54 54 struct __anonymous1 { 55 55 signed int _X1ii_1; … … 96 96 97 97 } 98 volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;98 static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1; 99 99 struct __anonymous2 { 100 100 signed int _X1ii_1; … … 141 141 142 142 } 143 volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;143 static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1; 144 144 struct __anonymous3 { 145 145 signed int _X1ii_1; … … 322 322 } 323 323 static 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;369 324 volatile const signed short int _X3x20KVs_1; 370 325 static volatile const signed short int _X3x21KVs_1; … … 375 330 static volatile const signed short int _X3x26KVs_1; 376 331 static volatile const signed short int _X3x27KVs_1; 332 struct __anonymous7 { 333 signed short int _X1is_1; 334 }; 335 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1); 336 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1); 337 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1); 338 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1); 339 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1); 340 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){ 341 { 342 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ?{} */); 343 } 344 345 } 346 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){ 347 { 348 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1) /* ?{} */); 349 } 350 351 } 352 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){ 353 { 354 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ^?{} */); 355 } 356 357 } 358 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){ 359 struct __anonymous7 _X4_retS12__anonymous7_1; 360 { 361 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1)); 362 } 363 364 { 365 ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1))); 366 } 367 368 return _X4_retS12__anonymous7_1; 369 } 370 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1){ 371 { 372 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X1is_1) /* ?{} */); 373 } 374 375 } 376 static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1; 377 377 struct __anonymous8 { 378 378 signed short int _X1is_1; … … 419 419 420 420 } 421 volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;421 static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1; 422 422 struct __anonymous9 { 423 423 signed short int _X1is_1; … … 464 464 465 465 } 466 volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;466 static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1; 467 467 struct __anonymous10 { 468 468 signed short int _X1is_1; … … 509 509 510 510 } 511 volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;511 static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1; 512 512 struct __anonymous11 { 513 513 signed short int _X1is_1; … … 554 554 555 555 } 556 static volatile const struct __anonymous11 _X3x3 2KVS13__anonymous11_1;556 static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1; 557 557 struct __anonymous12 { 558 558 signed short int _X1is_1; … … 599 599 600 600 } 601 static volatile const struct __anonymous12 _X3x3 3KVS13__anonymous12_1;601 static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1; 602 602 struct __anonymous13 { 603 603 signed short int _X1is_1; … … 644 644 645 645 } 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; 646 static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1; 737 647 _Thread_local signed int _X3x37i_1; 738 648 __thread signed int _X3x38i_1; … … 753 663 static inline volatile const signed short int _X3f27Fs___1(); 754 664 static inline volatile const signed short int _X3f28Fs___1(); 665 struct __anonymous14 { 666 signed int _X1ii_1; 667 }; 668 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1); 669 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1); 670 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1); 671 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1); 672 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1); 673 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){ 674 { 675 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ?{} */); 676 } 677 678 } 679 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){ 680 { 681 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1) /* ?{} */); 682 } 683 684 } 685 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){ 686 { 687 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ^?{} */); 688 } 689 690 } 691 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){ 692 struct __anonymous14 _X4_retS13__anonymous14_1; 693 { 694 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1)); 695 } 696 697 { 698 ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1))); 699 } 700 701 return _X4_retS13__anonymous14_1; 702 } 703 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1){ 704 { 705 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X1ii_1) /* ?{} */); 706 } 707 708 } 709 static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1(); 710 struct __anonymous15 { 711 signed int _X1ii_1; 712 }; 713 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1); 714 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1); 715 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1); 716 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1); 717 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1); 718 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){ 719 { 720 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ?{} */); 721 } 722 723 } 724 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){ 725 { 726 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1) /* ?{} */); 727 } 728 729 } 730 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){ 731 { 732 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ^?{} */); 733 } 734 735 } 736 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){ 737 struct __anonymous15 _X4_retS13__anonymous15_1; 738 { 739 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1)); 740 } 741 742 { 743 ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1))); 744 } 745 746 return _X4_retS13__anonymous15_1; 747 } 748 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1){ 749 { 750 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X1ii_1) /* ?{} */); 751 } 752 753 } 754 static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1(); 755 755 struct __anonymous16 { 756 756 signed int _X1ii_1; … … 797 797 798 798 } 799 static inline volatile const struct __anonymous16 _X3f3 1FS13__anonymous16___1();799 static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1(); 800 800 struct __anonymous17 { 801 801 signed int _X1ii_1; … … 842 842 843 843 } 844 static inline volatile const struct __anonymous17 _X3f3 2FS13__anonymous17___1();844 static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1(); 845 845 struct __anonymous18 { 846 846 signed int _X1ii_1; … … 887 887 888 888 } 889 static inline volatile const struct __anonymous18 _X3f3 3FS13__anonymous18___1();889 static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1(); 890 890 struct __anonymous19 { 891 891 signed int _X1ii_1; … … 932 932 933 933 } 934 static inline volatile const struct __anonymous19 _X3f3 4FS13__anonymous19___1();934 static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1(); 935 935 struct __anonymous20 { 936 936 signed int _X1ii_1; … … 977 977 978 978 } 979 static inline volatile const struct __anonymous20 _X3f3 5FS13__anonymous20___1();979 static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1(); 980 980 struct __anonymous21 { 981 981 signed int _X1ii_1; … … 1022 1022 1023 1023 } 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(); 1024 static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1(); 1115 1025 static inline volatile const signed short int _X3f41Fs___1(); 1116 1026 static inline volatile const signed short int _X3f42Fs___1(); -
tests/.expect/declarationSpecifier.x64.txt
r2ed94a9 rb110bcc 51 51 52 52 } 53 volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;53 static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1; 54 54 struct __anonymous1 { 55 55 signed int _X1ii_1; … … 96 96 97 97 } 98 volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;98 static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1; 99 99 struct __anonymous2 { 100 100 signed int _X1ii_1; … … 141 141 142 142 } 143 volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;143 static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1; 144 144 struct __anonymous3 { 145 145 signed int _X1ii_1; … … 322 322 } 323 323 static 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;369 324 volatile const signed short int _X3x20KVs_1; 370 325 static volatile const signed short int _X3x21KVs_1; … … 375 330 static volatile const signed short int _X3x26KVs_1; 376 331 static volatile const signed short int _X3x27KVs_1; 332 struct __anonymous7 { 333 signed short int _X1is_1; 334 }; 335 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1); 336 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1); 337 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1); 338 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1); 339 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1); 340 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){ 341 { 342 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ?{} */); 343 } 344 345 } 346 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){ 347 { 348 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1) /* ?{} */); 349 } 350 351 } 352 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){ 353 { 354 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ^?{} */); 355 } 356 357 } 358 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){ 359 struct __anonymous7 _X4_retS12__anonymous7_1; 360 { 361 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1)); 362 } 363 364 { 365 ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1))); 366 } 367 368 return _X4_retS12__anonymous7_1; 369 } 370 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1){ 371 { 372 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X1is_1) /* ?{} */); 373 } 374 375 } 376 static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1; 377 377 struct __anonymous8 { 378 378 signed short int _X1is_1; … … 419 419 420 420 } 421 volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;421 static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1; 422 422 struct __anonymous9 { 423 423 signed short int _X1is_1; … … 464 464 465 465 } 466 volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;466 static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1; 467 467 struct __anonymous10 { 468 468 signed short int _X1is_1; … … 509 509 510 510 } 511 volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;511 static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1; 512 512 struct __anonymous11 { 513 513 signed short int _X1is_1; … … 554 554 555 555 } 556 static volatile const struct __anonymous11 _X3x3 2KVS13__anonymous11_1;556 static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1; 557 557 struct __anonymous12 { 558 558 signed short int _X1is_1; … … 599 599 600 600 } 601 static volatile const struct __anonymous12 _X3x3 3KVS13__anonymous12_1;601 static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1; 602 602 struct __anonymous13 { 603 603 signed short int _X1is_1; … … 644 644 645 645 } 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; 646 static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1; 737 647 _Thread_local signed int _X3x37i_1; 738 648 __thread signed int _X3x38i_1; … … 753 663 static inline volatile const signed short int _X3f27Fs___1(); 754 664 static inline volatile const signed short int _X3f28Fs___1(); 665 struct __anonymous14 { 666 signed int _X1ii_1; 667 }; 668 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1); 669 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1); 670 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1); 671 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1); 672 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1); 673 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){ 674 { 675 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ?{} */); 676 } 677 678 } 679 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){ 680 { 681 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1) /* ?{} */); 682 } 683 684 } 685 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){ 686 { 687 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ^?{} */); 688 } 689 690 } 691 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){ 692 struct __anonymous14 _X4_retS13__anonymous14_1; 693 { 694 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1)); 695 } 696 697 { 698 ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1))); 699 } 700 701 return _X4_retS13__anonymous14_1; 702 } 703 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1){ 704 { 705 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X1ii_1) /* ?{} */); 706 } 707 708 } 709 static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1(); 710 struct __anonymous15 { 711 signed int _X1ii_1; 712 }; 713 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1); 714 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1); 715 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1); 716 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1); 717 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1); 718 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){ 719 { 720 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ?{} */); 721 } 722 723 } 724 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){ 725 { 726 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1) /* ?{} */); 727 } 728 729 } 730 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){ 731 { 732 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ^?{} */); 733 } 734 735 } 736 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){ 737 struct __anonymous15 _X4_retS13__anonymous15_1; 738 { 739 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1)); 740 } 741 742 { 743 ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1))); 744 } 745 746 return _X4_retS13__anonymous15_1; 747 } 748 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1){ 749 { 750 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X1ii_1) /* ?{} */); 751 } 752 753 } 754 static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1(); 755 755 struct __anonymous16 { 756 756 signed int _X1ii_1; … … 797 797 798 798 } 799 static inline volatile const struct __anonymous16 _X3f3 1FS13__anonymous16___1();799 static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1(); 800 800 struct __anonymous17 { 801 801 signed int _X1ii_1; … … 842 842 843 843 } 844 static inline volatile const struct __anonymous17 _X3f3 2FS13__anonymous17___1();844 static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1(); 845 845 struct __anonymous18 { 846 846 signed int _X1ii_1; … … 887 887 888 888 } 889 static inline volatile const struct __anonymous18 _X3f3 3FS13__anonymous18___1();889 static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1(); 890 890 struct __anonymous19 { 891 891 signed int _X1ii_1; … … 932 932 933 933 } 934 static inline volatile const struct __anonymous19 _X3f3 4FS13__anonymous19___1();934 static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1(); 935 935 struct __anonymous20 { 936 936 signed int _X1ii_1; … … 977 977 978 978 } 979 static inline volatile const struct __anonymous20 _X3f3 5FS13__anonymous20___1();979 static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1(); 980 980 struct __anonymous21 { 981 981 signed int _X1ii_1; … … 1022 1022 1023 1023 } 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(); 1024 static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1(); 1115 1025 static inline volatile const signed short int _X3f41Fs___1(); 1116 1026 static inline volatile const signed short int _X3f42Fs___1(); -
tests/.expect/declarationSpecifier.x86.txt
r2ed94a9 rb110bcc 51 51 52 52 } 53 volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1;53 static volatile const struct __anonymous0 _X3x10KVS12__anonymous0_1; 54 54 struct __anonymous1 { 55 55 signed int _X1ii_1; … … 96 96 97 97 } 98 volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1;98 static volatile const struct __anonymous1 _X3x11KVS12__anonymous1_1; 99 99 struct __anonymous2 { 100 100 signed int _X1ii_1; … … 141 141 142 142 } 143 volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1;143 static volatile const struct __anonymous2 _X3x12KVS12__anonymous2_1; 144 144 struct __anonymous3 { 145 145 signed int _X1ii_1; … … 322 322 } 323 323 static 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;369 324 volatile const signed short int _X3x20KVs_1; 370 325 static volatile const signed short int _X3x21KVs_1; … … 375 330 static volatile const signed short int _X3x26KVs_1; 376 331 static volatile const signed short int _X3x27KVs_1; 332 struct __anonymous7 { 333 signed short int _X1is_1; 334 }; 335 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1); 336 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1); 337 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1); 338 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1); 339 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1); 340 static inline void _X12_constructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){ 341 { 342 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ?{} */); 343 } 344 345 } 346 static inline void _X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){ 347 { 348 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1) /* ?{} */); 349 } 350 351 } 352 static inline void _X11_destructorFv_S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1){ 353 { 354 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1) /* ^?{} */); 355 } 356 357 } 358 static inline struct __anonymous7 _X16_operator_assignFS12__anonymous7_S12__anonymous7S12__anonymous7_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, struct __anonymous7 _X4_srcS12__anonymous7_1){ 359 struct __anonymous7 _X4_retS12__anonymous7_1; 360 { 361 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X4_srcS12__anonymous7_1._X1is_1)); 362 } 363 364 { 365 ((void)_X12_constructorFv_S12__anonymous7S12__anonymous7_autogen___1((&_X4_retS12__anonymous7_1), (*_X4_dstS12__anonymous7_1))); 366 } 367 368 return _X4_retS12__anonymous7_1; 369 } 370 static inline void _X12_constructorFv_S12__anonymous7s_autogen___1(struct __anonymous7 *_X4_dstS12__anonymous7_1, signed short int _X1is_1){ 371 { 372 ((void)((*_X4_dstS12__anonymous7_1)._X1is_1=_X1is_1) /* ?{} */); 373 } 374 375 } 376 static volatile const struct __anonymous7 _X3x29KVS12__anonymous7_1; 377 377 struct __anonymous8 { 378 378 signed short int _X1is_1; … … 419 419 420 420 } 421 volatile const struct __anonymous8 _X3x29KVS12__anonymous8_1;421 static volatile const struct __anonymous8 _X3x30KVS12__anonymous8_1; 422 422 struct __anonymous9 { 423 423 signed short int _X1is_1; … … 464 464 465 465 } 466 volatile const struct __anonymous9 _X3x30KVS12__anonymous9_1;466 static volatile const struct __anonymous9 _X3x31KVS12__anonymous9_1; 467 467 struct __anonymous10 { 468 468 signed short int _X1is_1; … … 509 509 510 510 } 511 volatile const struct __anonymous10 _X3x31KVS13__anonymous10_1;511 static volatile const struct __anonymous10 _X3x32KVS13__anonymous10_1; 512 512 struct __anonymous11 { 513 513 signed short int _X1is_1; … … 554 554 555 555 } 556 static volatile const struct __anonymous11 _X3x3 2KVS13__anonymous11_1;556 static volatile const struct __anonymous11 _X3x33KVS13__anonymous11_1; 557 557 struct __anonymous12 { 558 558 signed short int _X1is_1; … … 599 599 600 600 } 601 static volatile const struct __anonymous12 _X3x3 3KVS13__anonymous12_1;601 static volatile const struct __anonymous12 _X3x34KVS13__anonymous12_1; 602 602 struct __anonymous13 { 603 603 signed short int _X1is_1; … … 644 644 645 645 } 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; 646 static volatile const struct __anonymous13 _X3x35KVS13__anonymous13_1; 737 647 _Thread_local signed int _X3x37i_1; 738 648 __thread signed int _X3x38i_1; … … 753 663 static inline volatile const signed short int _X3f27Fs___1(); 754 664 static inline volatile const signed short int _X3f28Fs___1(); 665 struct __anonymous14 { 666 signed int _X1ii_1; 667 }; 668 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1); 669 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1); 670 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1); 671 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1); 672 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1); 673 static inline void _X12_constructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){ 674 { 675 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ?{} */); 676 } 677 678 } 679 static inline void _X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){ 680 { 681 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1) /* ?{} */); 682 } 683 684 } 685 static inline void _X11_destructorFv_S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1){ 686 { 687 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1) /* ^?{} */); 688 } 689 690 } 691 static inline struct __anonymous14 _X16_operator_assignFS13__anonymous14_S13__anonymous14S13__anonymous14_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, struct __anonymous14 _X4_srcS13__anonymous14_1){ 692 struct __anonymous14 _X4_retS13__anonymous14_1; 693 { 694 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X4_srcS13__anonymous14_1._X1ii_1)); 695 } 696 697 { 698 ((void)_X12_constructorFv_S13__anonymous14S13__anonymous14_autogen___1((&_X4_retS13__anonymous14_1), (*_X4_dstS13__anonymous14_1))); 699 } 700 701 return _X4_retS13__anonymous14_1; 702 } 703 static inline void _X12_constructorFv_S13__anonymous14i_autogen___1(struct __anonymous14 *_X4_dstS13__anonymous14_1, signed int _X1ii_1){ 704 { 705 ((void)((*_X4_dstS13__anonymous14_1)._X1ii_1=_X1ii_1) /* ?{} */); 706 } 707 708 } 709 static inline volatile const struct __anonymous14 _X3f31FS13__anonymous14___1(); 710 struct __anonymous15 { 711 signed int _X1ii_1; 712 }; 713 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1); 714 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1); 715 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1); 716 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1); 717 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1); 718 static inline void _X12_constructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){ 719 { 720 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ?{} */); 721 } 722 723 } 724 static inline void _X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){ 725 { 726 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1) /* ?{} */); 727 } 728 729 } 730 static inline void _X11_destructorFv_S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1){ 731 { 732 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1) /* ^?{} */); 733 } 734 735 } 736 static inline struct __anonymous15 _X16_operator_assignFS13__anonymous15_S13__anonymous15S13__anonymous15_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, struct __anonymous15 _X4_srcS13__anonymous15_1){ 737 struct __anonymous15 _X4_retS13__anonymous15_1; 738 { 739 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X4_srcS13__anonymous15_1._X1ii_1)); 740 } 741 742 { 743 ((void)_X12_constructorFv_S13__anonymous15S13__anonymous15_autogen___1((&_X4_retS13__anonymous15_1), (*_X4_dstS13__anonymous15_1))); 744 } 745 746 return _X4_retS13__anonymous15_1; 747 } 748 static inline void _X12_constructorFv_S13__anonymous15i_autogen___1(struct __anonymous15 *_X4_dstS13__anonymous15_1, signed int _X1ii_1){ 749 { 750 ((void)((*_X4_dstS13__anonymous15_1)._X1ii_1=_X1ii_1) /* ?{} */); 751 } 752 753 } 754 static inline volatile const struct __anonymous15 _X3f32FS13__anonymous15___1(); 755 755 struct __anonymous16 { 756 756 signed int _X1ii_1; … … 797 797 798 798 } 799 static inline volatile const struct __anonymous16 _X3f3 1FS13__anonymous16___1();799 static inline volatile const struct __anonymous16 _X3f33FS13__anonymous16___1(); 800 800 struct __anonymous17 { 801 801 signed int _X1ii_1; … … 842 842 843 843 } 844 static inline volatile const struct __anonymous17 _X3f3 2FS13__anonymous17___1();844 static inline volatile const struct __anonymous17 _X3f34FS13__anonymous17___1(); 845 845 struct __anonymous18 { 846 846 signed int _X1ii_1; … … 887 887 888 888 } 889 static inline volatile const struct __anonymous18 _X3f3 3FS13__anonymous18___1();889 static inline volatile const struct __anonymous18 _X3f35FS13__anonymous18___1(); 890 890 struct __anonymous19 { 891 891 signed int _X1ii_1; … … 932 932 933 933 } 934 static inline volatile const struct __anonymous19 _X3f3 4FS13__anonymous19___1();934 static inline volatile const struct __anonymous19 _X3f36FS13__anonymous19___1(); 935 935 struct __anonymous20 { 936 936 signed int _X1ii_1; … … 977 977 978 978 } 979 static inline volatile const struct __anonymous20 _X3f3 5FS13__anonymous20___1();979 static inline volatile const struct __anonymous20 _X3f37FS13__anonymous20___1(); 980 980 struct __anonymous21 { 981 981 signed int _X1ii_1; … … 1022 1022 1023 1023 } 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(); 1024 static inline volatile const struct __anonymous21 _X3f38FS13__anonymous21___1(); 1115 1025 static inline volatile const signed short int _X3f41Fs___1(); 1116 1026 static inline volatile const signed short int _X3f42Fs___1(); -
tests/.expect/nested_function.x64.txt
r2ed94a9 rb110bcc 1 total 1 551 total 145 -
tests/.expect/nested_function.x86.txt
r2ed94a9 rb110bcc 1 total 1051 total 245 -
tests/Makefile.am
r2ed94a9 rb110bcc 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Fri Feb 3 23:06:44202314 ## Update Count : 9 413 ## Last Modified On : Mon Apr 10 23:24:02 2023 14 ## Update Count : 96 15 15 ############################################################################### 16 16 … … 184 184 185 185 SYNTAX_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 187 187 $(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN) 188 188 $(CFACOMPILE_SYNTAX) -
tests/PRNG.cfa
r2ed94a9 rb110bcc 8 8 // Created On : Wed Dec 29 09:38:12 2021 9 9 // Last Modified By : Peter A. Buhr 10 // Last Modified On : Wed Dec 21 20:39:59 202211 // Update Count : 4 0610 // Last Modified On : Sat Apr 15 16:44:31 2023 11 // Update Count : 419 12 12 // 13 13 … … 15 15 #include <stdlib.hfa> // PRNG 16 16 #include <clock.hfa> 17 #include <thread.hfa>18 17 #include <limits.hfa> // MAX 19 18 #include <math.hfa> // sqrt 20 19 #include <malloc.h> // malloc_stats 21 20 #include <locale.h> // setlocale 21 #include <thread.hfa> 22 22 #include <mutex_stmt.hfa> 23 23 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 25 28 #define PRNG PRNG64 26 29 #else // 32-bit architecture 27 30 #define PRNG PRNG32 28 31 #endif // __x86_64__ 32 33 //#define TIME 29 34 30 35 #ifdef TIME // use -O2 -nodebug … … 38 43 #endif // TIME 39 44 40 void avgstd( unsigned int buckets[] ) {41 unsigned int min = MAX, max = 0;45 static void avgstd( size_t trials, size_t buckets[] ) { 46 size_t min = MAX, max = 0; 42 47 double sum = 0.0, diff; 43 48 for ( i; BUCKETS ) { … … 54 59 } // for 55 60 double std = sqrt( sum / BUCKETS ); 56 mutex( sout ) sout | "trials" | TRIALS| "buckets" | BUCKETS61 mutex( sout ) sout | "trials" | trials | "buckets" | BUCKETS 57 62 | "min" | min | "max" | max 58 63 | "avg" | wd(0,1, avg) | "std" | wd(0,1, std) | "rstd" | wd(0,1, (avg == 0 ? 0.0 : std / avg * 100)) | "%"; … … 64 69 thread T1 {}; 65 70 void main( T1 & ) { 66 unsigned int * buckets = calloc( BUCKETS );// too big for task stack67 for ( TRIALS / 100 ) {71 size_t * buckets = calloc( BUCKETS ); // too big for task stack 72 for ( TRIALS / 50 ) { 68 73 buckets[rand() % BUCKETS] += 1; // concurrent 69 74 } // for 70 avgstd( buckets );75 avgstd( TRIALS / 50, buckets ); 71 76 free( buckets ); 72 77 } // main … … 76 81 PRNG prng; 77 82 if ( seed != 0 ) set_seed( prng, seed ); 78 unsigned int * buckets = calloc( BUCKETS );// too big for task stack83 size_t * buckets = calloc( BUCKETS ); // too big for task stack 79 84 for ( TRIALS ) { 80 85 buckets[prng( prng ) % BUCKETS] += 1; // concurrent 81 86 } // for 82 avgstd( buckets );87 avgstd( TRIALS, buckets ); 83 88 free( buckets ); 84 89 } // main … … 86 91 thread T3 {}; 87 92 void main( T3 & th ) { 88 unsigned int * buckets = calloc( BUCKETS );// too big for task stack89 for ( TRIALS ) {93 size_t * buckets = calloc( BUCKETS ); // too big for task stack 94 for ( TRIALS / 5 ) { 90 95 buckets[prng() % BUCKETS] += 1; // concurrent 91 96 } // for 92 avgstd( buckets );97 avgstd( TRIALS / 5, buckets ); 93 98 free( buckets ); 94 99 } // main … … 96 101 thread T4 {}; 97 102 void main( T4 & th ) { 98 unsigned int * buckets = calloc( BUCKETS );// too big for task stack103 size_t * buckets = calloc( BUCKETS ); // too big for task stack 99 104 for ( TRIALS ) { 100 buckets[prng( th ) % BUCKETS] += 1; // concurrent101 } // for 102 avgstd( buckets );105 buckets[prng( th ) % BUCKETS] += 1; // concurrent 106 } // for 107 avgstd( TRIALS, buckets ); 103 108 free( buckets ); 104 109 } // main … … 108 113 static void dummy( thread$ & th ) __attribute__(( noinline )); 109 114 static void dummy( thread$ & th ) { 110 unsigned int * buckets = (unsigned int *)calloc( BUCKETS, sizeof(unsigned int) ); // too big for task stack111 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 ) { 112 117 buckets[prng( th ) % BUCKETS] += 1; // sequential 113 118 } // for 114 avgstd( buckets );119 avgstd( TRIALS, buckets ); 115 120 free( buckets ); 116 121 } // dummy … … 126 131 enum { TASKS = 4 }; 127 132 Time start; 133 128 134 #ifdef TIME // too slow for test and generates non-repeatable results 129 135 #if 1 130 unsigned int rseed; 136 sout | "glib rand" | nl | nl; 137 138 size_t rseed; 131 139 if ( seed != 0 ) rseed = seed; 132 140 else rseed = rdtscl(); … … 134 142 135 143 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)" ); 137 145 for ( 20 ) { 138 146 sout | wd(26, rand()) | nonl; … … 146 154 STARTTIME; 147 155 { 148 unsigned int * buckets = calloc( BUCKETS );// too big for task stack149 for ( i; TRIALS / 10) {156 size_t * buckets = calloc( BUCKETS ); // too big for task stack 157 for ( i; TRIALS / 5 ) { 150 158 buckets[rand() % BUCKETS] += 1; // sequential 151 159 } // for 152 avgstd( buckets );160 avgstd( TRIALS / 5, buckets ); 153 161 free( buckets ); 154 162 } 155 ENDTIME( " x 10" );163 ENDTIME( " x 5 " ); 156 164 157 165 sout | nl | "Concurrent"; … … 163 171 } // wait for threads to complete 164 172 } 165 ENDTIME( " x 100 " );173 ENDTIME( " x 50 " ); 166 174 #endif // 0 167 175 #endif // TIME 176 177 sout | nl | "CFA " xstr(PRNG_NAME); 178 168 179 #if 1 169 180 PRNG prng; … … 184 195 STARTTIME; 185 196 { 186 unsigned int * buckets = calloc( BUCKETS );// too big for task stack197 size_t * buckets = calloc( BUCKETS ); // too big for task stack 187 198 for ( TRIALS ) { 188 199 buckets[prng( prng ) % BUCKETS] += 1; // sequential 189 200 } // for 190 avgstd( buckets );201 avgstd( TRIALS, buckets ); 191 202 free( buckets ); 192 203 } … … 219 230 STARTTIME; 220 231 { 221 unsigned int * buckets = calloc( BUCKETS );// too big for task stack222 for ( TRIALS ) {232 size_t * buckets = calloc( BUCKETS ); // too big for task stack 233 for ( TRIALS / 5 ) { 223 234 buckets[prng() % BUCKETS] += 1; 224 235 } // for 225 avgstd( buckets );236 avgstd( TRIALS / 5, buckets ); 226 237 free( buckets ); 227 238 } 228 ENDTIME( );239 ENDTIME( " x 5 " ); 229 240 230 241 sout | nl | "Concurrent"; … … 236 247 } // wait for threads to complete 237 248 } 238 ENDTIME( );249 ENDTIME( " x 5 " ); 239 250 #endif // 0 240 251 #if 1 -
tests/attributes.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Mon Feb 6 16:07:02 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 15 13:53:31 202113 // Update Count : 3 812 // Last Modified On : Thu Feb 23 20:33:07 2023 13 // Update Count : 39 14 14 // 15 15 … … 22 22 23 23 // aggregate_name 24 st ruct __attribute__(( unused )) {} Dummy;24 static struct __attribute__(( unused )) {} Dummy; 25 25 struct __attribute__(( unused )) Agn1; 26 26 struct __attribute__(( unused )) Agn2 {}; -
tests/avltree/avl.h
r2ed94a9 rb110bcc 9 9 // #include <lib.h> 10 10 11 trait Comparable(T) { 11 forall(T) 12 trait Comparable { 12 13 int ?<?(T, T); 13 14 }; -
tests/concurrent/actors/.expect/types.txt
r2ed94a9 rb110bcc 12 12 -1 13 13 5 14 nested inheritance actor test 15 -1 16 5 14 17 end -
tests/concurrent/actors/dynamic.cfa
r2ed94a9 rb110bcc 7 7 int Times = 1000000; // default values 8 8 9 struct derived_actor { 10 inline actor; 11 }; 12 void ?{}( derived_actor & this ) { ((actor &)this){}; } 13 9 struct derived_actor { inline actor; }; 14 10 struct derived_msg { 15 11 inline message; … … 23 19 void ?{}( derived_msg & this ) { ((derived_msg &)this){ 0 }; } 24 20 25 26 21 Allocation receive( derived_actor & receiver, derived_msg & msg ) { 27 22 if ( msg.cnt >= Times ) { … … 33 28 derived_actor * d_actor = alloc(); 34 29 (*d_actor){}; 35 *d_actor |*d_msg;30 *d_actor << *d_msg; 36 31 return Delete; 37 32 } … … 63 58 derived_actor * d_actor = alloc(); 64 59 (*d_actor){}; 65 *d_actor |*d_msg;60 *d_actor << *d_msg; 66 61 67 62 printf("stopping\n"); -
tests/concurrent/actors/executor.cfa
r2ed94a9 rb110bcc 15 15 }; 16 16 void ?{}( d_actor & this ) with(this) { 17 ((actor &)this){};18 17 id = ids++; 19 18 gstart = (&this + (id / Set * Set - id)); // remember group-start array-element … … 24 23 25 24 struct d_msg { inline message; } shared_msg; 26 void ?{}( d_msg & this ) { ((message &) this){ Nodelete }; }27 25 28 26 Allocation receive( d_actor & this, d_msg & msg ) with( this ) { … … 30 28 if ( recs % Batch == 0 ) { 31 29 for ( i; Batch ) { 32 gstart[sends % Set] |shared_msg;30 gstart[sends % Set] << shared_msg; 33 31 sends += 1; 34 32 } … … 85 83 } // switch 86 84 87 88 85 executor e{ Processors, Processors, Processors == 1 ? 1 : Processors * 512, true }; 89 86 … … 97 94 98 95 for ( i; Actors ) { 99 actors[i] |shared_msg;96 actors[i] << shared_msg; 100 97 } // for 101 98 -
tests/concurrent/actors/matrix.cfa
r2ed94a9 rb110bcc 7 7 unsigned int xr = 500, xc = 500, yc = 500, Processors = 1; // default values 8 8 9 struct derived_actor { 10 inline actor; 11 }; 12 void ?{}( derived_actor & this ) { ((actor &)this){}; } 9 struct derived_actor { inline actor; }; 13 10 14 11 struct derived_msg { … … 21 18 void ?{}( derived_msg & this ) {} 22 19 void ?{}( derived_msg & this, int * Z, int * X, int ** Y ) { 23 ((message &) this){ Finished};20 ((message &) this){ Nodelete }; 24 21 this.Z = Z; 25 22 this.X = X; … … 108 105 109 106 for ( unsigned int r = 0; r < xr; r += 1 ) { 110 actors[r] |messages[r];107 actors[r] << messages[r]; 111 108 } // for 112 109 -
tests/concurrent/actors/pingpong.cfa
r2ed94a9 rb110bcc 6 6 #include <actor.hfa> 7 7 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){}; } 8 struct ping { inline actor; }; 9 struct pong { inline actor; }; 17 10 18 11 struct p_msg { … … 32 25 Allocation retval = Nodelete; 33 26 if ( msg.count == times ) retval = Finished; 34 *po |msg;27 *po << msg; 35 28 return retval; 36 29 } … … 42 35 Allocation retval = Nodelete; 43 36 if ( msg.count == times ) retval = Finished; 44 *pi |msg;37 *pi << msg; 45 38 return retval; 46 39 } … … 60 53 pi = &pi_actor; 61 54 p_msg m; 62 pi_actor |m;55 pi_actor << m; 63 56 stop_actor_system(); 64 57 -
tests/concurrent/actors/static.cfa
r2ed94a9 rb110bcc 7 7 int Times = 1000000; // default values 8 8 9 struct derived_actor { 10 inline actor; 11 }; 12 void ?{}( derived_actor & this ) { ((actor &)this){}; } 13 9 struct derived_actor { inline actor; }; 14 10 struct derived_msg { 15 11 inline message; … … 23 19 void ?{}( derived_msg & this ) { ((derived_msg &)this){ 0 }; } 24 20 25 26 21 Allocation receive( derived_actor & receiver, derived_msg & msg ) { 27 22 if ( msg.cnt >= Times ) { … … 30 25 } 31 26 msg.cnt++; 32 receiver |msg;27 receiver << msg; 33 28 return Nodelete; 34 29 } … … 60 55 derived_actor actor; 61 56 62 actor |msg;57 actor << msg; 63 58 64 59 printf("stopping\n"); -
tests/concurrent/actors/types.cfa
r2ed94a9 rb110bcc 18 18 int num; 19 19 }; 20 static inline void ?{}( d_msg & this ) { ((message &)this){}; }21 20 22 21 // this isn't a valid receive routine since int is not a message type … … 36 35 inline actor; 37 36 }; 38 static inline void ?{}( derived_actor2 & this ) { ((actor &)this){}; }39 37 40 38 Allocation receive( derived_actor2 & receiver, d_msg & msg ) { … … 43 41 } 44 42 45 struct derived_actor3 { 46 inline actor; 47 }; 48 static inline void ?{}( derived_actor3 & this ) { ((actor &)this){}; } 49 43 struct derived_actor3 { inline actor; }; 44 struct derived_actor4 { inline derived_actor3; }; 50 45 struct d_msg2 { 51 46 inline message; 52 47 int num; 53 48 }; 54 static inline void ?{}( d_msg2 & this ) { ((message &)this){}; }55 49 56 50 Allocation receive( derived_actor3 & receiver, d_msg & msg ) { … … 78 72 b.num = 1; 79 73 c.num = 2; 80 a | b |c;74 a << b << c; 81 75 stop_actor_system(); 82 76 … … 86 80 d_msg d_ac2_msg; 87 81 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; 90 84 stop_actor_system(); 91 85 … … 99 93 d_msg d_ac23_msg; 100 94 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; 103 97 stop_actor_system(); 104 98 } // RAII to clean up executor … … 113 107 b1.num = -1; 114 108 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; 116 123 stop_actor_system(); 117 124 } // RAII to clean up executor -
tests/concurrent/channels/parallel_harness.hfa
r2ed94a9 rb110bcc 100 100 101 101 int 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; 103 103 // create a cluster 104 104 cluster clus[Clusters]; … … 108 108 } 109 109 110 channels = a new( Channels );110 channels = aalloc( Channels ); 111 111 112 112 // sout | "Processors: " | Processors | " ProdsPerChan: " | Producers | " ConsPerChan: " | Consumers | "Channels: " | Channels | " Channel Size: " | ChannelSize; … … 139 139 while( cons_done_count != Consumers * Channels ) { 140 140 for ( i; Channels ) { 141 if ( has_wait ing_consumers( channels[i] ) ){141 if ( has_waiters( channels[i] ) ){ 142 142 #ifdef BIG 143 143 bigObject b{0}; … … 150 150 151 151 } 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 167 153 sout | "cons"; 168 154 for ( i; Consumers * Channels ) { -
tests/concurrent/pthread/.expect/bounded_buffer.x64.txt
r2ed94a9 rb110bcc 1 producer total value is 442802 consumer total value is 442801 producer total value is 39780 2 consumer total value is 39780 -
tests/concurrent/pthread/.expect/bounded_buffer.x86.txt
r2ed94a9 rb110bcc 1 producer total value is 450602 consumer total value is 450601 producer total value is 1770 2 consumer total value is 1770 -
tests/concurrent/signal/disjoint.cfa
r2ed94a9 rb110bcc 38 38 39 39 // Use a global struct because the order needs to match with Signaller thread 40 st ruct {40 static struct { 41 41 global_t mut; 42 42 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 3 3 // 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 // 9 15 10 16 #include <monitor.hfa> … … 12 18 monitor M {}; 13 19 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 } 20 void notcalled( M & mutex m1, M & mutex m2 ) { 21 abort(); 22 } 23 void or( M & mutex m ) { 24 abort(); 25 } 26 void timeout( M & mutex m ) { 27 abort(); 28 } 29 30 void fred( M & mutex m, M & mutex or, M & mutex timeout ) { 31 // test waitfor and when 32 33 waitfor( notcalled : m, m ); 34 35 waitfor( notcalled : m, m ) { 36 } 37 38 waitfor( notcalled : m, m ) { 39 } 40 41 when( true ) waitfor( notcalled : m, m ); 42 43 when( true ) waitfor( notcalled : m, m ) { 44 } 45 46 waitfor( notcalled : m, m ); 47 or waitfor( notcalled : m, m ); 48 49 when( true ) waitfor( notcalled : m, m ); 50 or when( true ) waitfor( notcalled : m, m ); 51 52 waitfor( notcalled : m, m ) { 53 } or waitfor( notcalled : m, m ) { 54 } 55 56 waitfor( notcalled : m, m ) { 57 } or waitfor( notcalled : m, m ) { 58 } 59 60 when( true ) waitfor( notcalled : m, m ) { 61 } or when( true ) waitfor( notcalled : m, m ) { 62 } 63 64 waitfor( notcalled : m, m ); 65 or waitfor( notcalled : m, m ) { 66 } 67 68 when( true ) waitfor( notcalled : m, m ); 69 or when( true ) waitfor( notcalled : m, m ) { 70 } 71 72 waitfor( notcalled : m, m ) { 73 } or waitfor( notcalled : m, m ); 74 75 when( true ) waitfor( notcalled : m, m ) { 76 } or when( true ) waitfor( notcalled : m, m ); 77 78 // test when, waitfor and else 79 80 waitfor( notcalled : m, m ); 81 or else; 82 83 when( true ) waitfor( notcalled : m, m ); 84 or else; 85 86 when( true ) waitfor( notcalled : m, m ); 87 or else; 88 89 waitfor( notcalled : m, m ) { 90 } or else { 91 } 92 93 when( true ) waitfor( notcalled : m, m ) { 94 } or else { 95 } 96 97 waitfor( notcalled : m, m ); 50 98 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 ); 72 102 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 254 int main( int argc, char const * argv[] ) { 255 #pragma GCC warning "Compiled" // force non-empty .expect file, NO TABS!!! 256 } 257 258 // Local Variables: // 259 // tab-width: 4 // 260 // compile-command: "cfa waitfor.cfa" // 261 // End: // -
tests/declarationSpecifier.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed Aug 17 08:21:04 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Apr 30 18:20:36 201913 // Update Count : 412 // Last Modified On : Thu Feb 23 20:53:31 2023 13 // Update Count : 8 14 14 // 15 15 … … 25 25 short int volatile static const x8; 26 26 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; 27 static const volatile struct { int i; } x10; 28 static const struct { int i; } volatile x11; 29 static struct { int i; } const volatile x12; 30 const static struct { int i; } volatile x13; 31 struct { int i; } static const volatile x14; 32 struct { int i; } const static volatile x15; 33 struct { int i; } const volatile static x16; 35 34 36 35 const Int volatile x20; … … 43 42 Int volatile static const x27; 44 43 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; 44 static const volatile struct { Int i; } x29; 45 static const struct { Int i; } volatile x30; 46 static struct { Int i; } const volatile x31; 47 const static struct { Int i; } volatile x32; 48 struct { Int i; } static const volatile x33; 49 struct { Int i; } const static volatile x34; 50 struct { Int i; } const volatile static x35; 53 51 54 52 _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 int1 errors/declaration.cfa:16:1 error: duplicate static storage class(es) in declaration of x1: static const volatile short int 2 2 3 errors/declaration.cfa:17:1 error: conflicting extern & static in declaration of x2: extern const volatile short int3 errors/declaration.cfa:17:1 error: conflicting extern & static storage classes in declaration of x2: extern const volatile short int 4 4 5 errors/declaration.cfa:18:1 error: conflicting extern & auto , conflicting extern & static, conflicting extern & static, duplicate externin declaration of x3: extern const volatile short int5 errors/declaration.cfa:18:1 error: conflicting extern & auto storage classes, conflicting extern & static storage classes, conflicting extern & static storage classes, duplicate extern storage class(es) in declaration of x3: extern const volatile short int 6 6 7 errors/declaration.cfa:19:1 error: duplicate static in declaration of x4: static const volatile instance of const volatile struct __anonymous07 errors/declaration.cfa:19:1 error: duplicate static storage class(es) in declaration of x4: static const volatile instance of const volatile struct __anonymous0 8 8 with members 9 9 i: int … … 11 11 12 12 13 errors/declaration.cfa:20:1 error: duplicate const , duplicate static, duplicate volatilein declaration of x5: static const volatile instance of const volatile struct __anonymous113 errors/declaration.cfa:20:1 error: duplicate const qualifier(s), duplicate static storage class(es), duplicate volatile qualifier(s) in declaration of x5: static const volatile instance of const volatile struct __anonymous1 14 14 with members 15 15 i: int … … 17 17 18 18 19 errors/declaration.cfa:22:1 error: duplicate static in declaration of x6: static const volatile Int19 errors/declaration.cfa:22:1 error: duplicate static storage class(es) in declaration of x6: static const volatile Int 20 20 21 errors/declaration.cfa:24:1 error: duplicate const in declaration of f01: static inline function21 errors/declaration.cfa:24:1 error: duplicate const qualifier(s) in declaration of f01: static inline function 22 22 with no parameters 23 23 returning const volatile int 24 24 25 25 26 errors/declaration.cfa:25:1 error: duplicate volatile in declaration of f02: static inline function26 errors/declaration.cfa:25:1 error: duplicate volatile qualifier(s) in declaration of f02: static inline function 27 27 with no parameters 28 28 returning const volatile int 29 29 30 30 31 errors/declaration.cfa:26:1 error: duplicate const in declaration of f03: static inline function31 errors/declaration.cfa:26:1 error: duplicate const qualifier(s) in declaration of f03: static inline function 32 32 with no parameters 33 33 returning const volatile int 34 34 35 35 36 errors/declaration.cfa:27:1 error: duplicate volatile in declaration of f04: static inline function36 errors/declaration.cfa:27:1 error: duplicate volatile qualifier(s) in declaration of f04: static inline function 37 37 with no parameters 38 38 returning const volatile int 39 39 40 40 41 errors/declaration.cfa:28:1 error: duplicate const in declaration of f05: static inline function41 errors/declaration.cfa:28:1 error: duplicate const qualifier(s) in declaration of f05: static inline function 42 42 with no parameters 43 43 returning const volatile int 44 44 45 45 46 errors/declaration.cfa:29:1 error: duplicate volatile in declaration of f06: static inline function46 errors/declaration.cfa:29:1 error: duplicate volatile qualifier(s) in declaration of f06: static inline function 47 47 with no parameters 48 48 returning const volatile int 49 49 50 50 51 errors/declaration.cfa:30:1 error: duplicate const in declaration of f07: static inline function51 errors/declaration.cfa:30:1 error: duplicate const qualifier(s) in declaration of f07: static inline function 52 52 with no parameters 53 53 returning const volatile int 54 54 55 55 56 errors/declaration.cfa:31:1 error: duplicate const , duplicate volatilein declaration of f08: static inline function56 errors/declaration.cfa:31:1 error: duplicate const volatile qualifier(s) in declaration of f08: static inline function 57 57 with no parameters 58 58 returning const volatile int 59 59 60 60 61 errors/declaration.cfa:33:1 error: duplicate const , duplicate volatilein declaration of f09: static inline function61 errors/declaration.cfa:33:1 error: duplicate const volatile qualifier(s) in declaration of f09: static inline function 62 62 with no parameters 63 63 returning const volatile int 64 64 65 65 66 errors/declaration.cfa:34:1 error: duplicate const , duplicate _Atomic, duplicate _Atomic, duplicate const, duplicate restrict, duplicate volatilein declaration of f09: static inline function66 errors/declaration.cfa:34:1 error: duplicate const qualifier(s), duplicate _Atomic qualifier(s), duplicate _Atomic qualifier(s), duplicate const restrict volatile qualifier(s) in declaration of f09: static inline function 67 67 with no parameters 68 68 returning const restrict volatile _Atomic int -
tests/forall.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed May 9 08:48:15 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 5 07:54:43202313 // Update Count : 9 012 // Last Modified On : Thu Feb 23 20:29:59 2023 13 // Update Count : 91 14 14 // 15 15 … … 195 195 196 196 forall( T ) struct S { T t; } (int) x, y, z; 197 forall( T ) struct { T t; } (int) a, b, c;197 static forall( T ) struct { T t; } (int) a, b, c; 198 198 199 199 forall( T ) static forall( S ) { -
tests/function-operator.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Fri Aug 25 15:21:11 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 11 18:27:45 201913 // Update Count : 1 012 // Last Modified On : Sat Feb 25 07:26:10 2023 13 // Update Count : 12 14 14 // 15 15 … … 22 22 23 23 // STL-like Algorithms 24 trait Assignable(T &, U &) { T ?=?(T &, U); }; 25 trait Copyable(T &) { void ?{}(T &, T); }; 26 trait Destructable(T &) { void ^?{}(T &); }; 24 forall(T &, U &) 25 trait Assignable { T ?=?(T &, U); }; 26 forall(T &) 27 trait Copyable { void ?{}(T &, T); }; 28 forall(T &) 29 trait Destructable { void ^?{}(T &); }; 27 30 28 31 trait Iterator(iter & | sized(iter) | Copyable(iter) | Destructable(iter), T) { -
tests/include/includes.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun May 22 08:27:20 202213 // Update Count : 77912 // Last Modified On : Wed Feb 22 10:16:58 2023 13 // Update Count : 811 14 14 // 15 15 … … 72 72 #include <gshadow.h> 73 73 #include <iconv.h> 74 #include <ifaddrs.h> 74 //#include <ifaddrs.h> // causes warning messages that break the build 75 75 #include <inttypes.h> 76 76 #include <langinfo.h> … … 97 97 #include <ncurses_dll.h> // may not be installed, comes with ncurses 98 98 #endif 99 #include <netdb.h>99 //#include <netdb.h> 100 100 #include <nl_types.h> 101 101 #include <nss.h> … … 111 111 #include <pwd.h> 112 112 #include <regex.h> 113 #include <resolv.h>113 //#include <resolv.h> 114 114 #include <re_comp.h> 115 115 #include <sched.h> … … 170 170 #endif // __CFA__ 171 171 172 int main( int argc, char const * argv[]) {172 int main() { 173 173 #pragma GCC warning "Compiled" // force non-empty .expect file, NO TABS!!! 174 174 } -
tests/io/comp_basic.cfa
r2ed94a9 rb110bcc 26 26 #include <unistd.h> 27 27 28 st ruct {28 static struct { 29 29 barrier & bar; 30 30 int pipe[2]; 31 32 31 } globals; 33 32 -
tests/io/comp_fair.cfa
r2ed94a9 rb110bcc 26 26 #include <unistd.h> 27 27 28 st ruct {28 static struct { 29 29 barrier & bar; 30 30 int pipe[2]; 31 32 31 } globals; 33 32 -
tests/linking/mangling/header.hfa
r2ed94a9 rb110bcc 8 8 extern name_but_a_typedefed_t a_typedefed_global; 9 9 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. 11 extern "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 3 3 name_but_a_typedefed_t a_typedefed_global; 4 4 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. 6 extern "C" { 7 // This declaration is necessary to create an instance of a_global_with_no_type. 8 // typeof is a trick to get a_global_with_no_type's type because its type is anonymous. 9 // Otherwise C generates conflicting types for a_global_with_no_type in .h and .c 10 // because C uses name equivalence and the two anonymous types cannot have the same name. 11 typeof(a_global_with_no_type) a_global_with_no_type; 12 } -
tests/linking/mangling/main.cfa
r2ed94a9 rb110bcc 1 1 #include <fstream.hfa> 2 2 3 st ruct { int a; } test; //purposefully before the include3 static struct { int a; } test; // purposefully before the include to force anonymous name numbering 4 4 5 5 #include "header.hfa" … … 13 13 14 14 sout | "Done!"; 15 16 return 0;17 15 } -
tests/pybin/settings.py
r2ed94a9 rb110bcc 126 126 global archive 127 127 global install 128 global invariant 128 129 129 130 global continue_ … … 140 141 all_install = [Install(o) for o in list(dict.fromkeys(options.install))] 141 142 archive = os.path.abspath(os.path.join(original_path, options.archive_errors)) if options.archive_errors else None 143 invariant = options.invariant 142 144 continue_ = options.continue_ 143 145 dry_run = options.dry_run # must be called before tools.config_hash() -
tests/quotedKeyword.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Feb 7 19:07:07 202013 // Update Count : 2 512 // Last Modified On : Thu Feb 23 20:31:05 2023 13 // Update Count : 26 14 14 // 15 15 16 16 #include <fstream.hfa> 17 17 18 st ruct {18 static struct { 19 19 int ``otype; 20 20 int ``struct; -
tests/sum.cfa
r2ed94a9 rb110bcc 11 11 // Created On : Wed May 27 17:56:53 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Thu Aug 5 21:27:25 202114 // Update Count : 34 613 // Last Modified On : Fri Feb 24 22:52:12 2023 14 // Update Count : 347 15 15 // 16 16 … … 18 18 #include <stdlib.hfa> 19 19 20 trait sumable( T ) { 20 forall( T ) 21 trait sumable { 21 22 void ?{}( T &, zero_t ); // 0 literal constructor 22 23 void ?{}( T &, one_t ); // 1 literal constructor -
tests/test.py
r2ed94a9 rb110bcc 114 114 parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no') 115 115 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') 116 117 parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180) 117 118 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) … … 172 173 test.prepare() 173 174 175 # extra flags for cfa to pass through make. 176 cfa_flags = 'CFAFLAGS=--invariant' if settings.invariant else None 177 174 178 # ---------- 175 179 # MAKE … … 177 181 # build, skipping to next test on error 178 182 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) 180 184 181 185 # ----------
Note:
See TracChangeset
for help on using the changeset viewer.