Changeset f7e4f8e8
- Timestamp:
- Oct 30, 2020, 12:36:16 PM (2 years ago)
- Branches:
- arm-eh, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 0ab3b73, 36d0a80
- Parents:
- b9537e6 (diff), 4ae78c1 (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:
-
- 10 added
- 71 edited
Legend:
- Unmodified
- Added
- Removed
-
Jenkinsfile
rb9537e6 rf7e4f8e8 127 127 } 128 128 129 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} --quiet --prefix=${BuildDir}" 129 ast = Settings.NewAST ? "--enable-new-ast" : "--disable-new-ast" 130 131 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} ${ast} --quiet --prefix=${BuildDir}" 130 132 131 133 // Configure libcfa … … 359 361 public final CC_Desc Compiler 360 362 public final Arch_Desc Architecture 363 public final Boolean NewAST 361 364 public final Boolean RunAllTests 362 365 public final Boolean RunBenchmark … … 410 413 411 414 this.IsSandbox = (branch == "jenkins-sandbox") 415 this.NewAST = param.NewAST 412 416 this.RunAllTests = param.RunAllTests 413 417 this.RunBenchmark = param.RunBenchmark … … 470 474 ], \ 471 475 [$class: 'BooleanParameterDefinition', \ 476 description: 'If true, build compiler using new AST', \ 477 name: 'NewAST', \ 478 defaultValue: false, \ 479 ], \ 480 [$class: 'BooleanParameterDefinition', \ 472 481 description: 'If false, only the quick test suite is ran', \ 473 482 name: 'RunAllTests', \ 474 483 defaultValue: false, \ 475 ], \484 ], 476 485 [$class: 'BooleanParameterDefinition', \ 477 486 description: 'If true, jenkins also runs benchmarks', \ -
doc/papers/concurrency/mail2
rb9537e6 rf7e4f8e8 1 1 2 Date: Wed, 26 Jun 2019 20:12:38 +0000 2 3 From: Aaron Thomas <onbehalfof@manuscriptcentral.com> … … 1074 1075 Software: Practice and Experience Editorial Office 1075 1076 1077 1078 1079 Date: Thu, 15 Oct 2020 13:48:52 +0000 1080 From: Richard Jones <onbehalfof@manuscriptcentral.com> 1081 Reply-To: R.E.Jones@kent.ac.uk 1082 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca 1083 Subject: Software: Practice and Experience - Decision on Manuscript ID 1084 SPE-19-0219.R3 1085 1086 15-Oct-2020 1087 1088 Dear Dr Buhr, 1089 1090 It is a pleasure to accept your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" in its current form for publication in Software: Practice and Experience. 1091 1092 Please note although the manuscript is accepted the files will now be checked to ensure that everything is ready for publication, and you may be contacted if final versions of files for publication are required. 1093 1094 Your article cannot be published until the publisher has received the appropriate signed license agreement. Within the next few days the corresponding author will receive an email from Wiley's Author Services system which will ask them to log in and will present them with the appropriate license for completion. 1095 1096 Thank you for your fine contribution. 1097 1098 Sincerely, 1099 Richard 1100 1101 Prof. Richard Jones 1102 Editor, Software: Practice and Experience 1103 R.E.Jones@kent.ac.uk 1104 1105 P.S. - You can help your research get the attention it deserves! Check out Wiley's free Promotion Guide for best-practice recommendations for promoting your work at www.wileyauthors.com/eeo/guide. And learn more about Wiley Editing Services which offers professional video, design, and writing services to create shareable video abstracts, infographics, conference posters, lay summaries, and research news stories for your research at www.wileyauthors.com/eeo/promotion. 1106 1107 This journal accepts artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. For more information, including artwork guidelines, pricing, and submission details, please visit the Journal Cover Image page at www.wileyauthors.com/eeo/covers. If you want help creating an image, Wiley Editing Services offers a professional cover image design service that creates eye-catching images, ready to be showcased on the journal cover at www.wileyauthors.com/eeo/design. 1108 1109 1110 1111 Date: Fri, 16 Oct 2020 12:44:42 +0000 1112 From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com> 1113 Reply-To: speoffice@wiley.com 1114 To: pabuhr@uwaterloo.ca 1115 Subject: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c] 1116 1117 16-Oct-2020 1118 1119 Dear Dr. Buhr, 1120 1121 Manuscript id: SPE-19-0219.R3 1122 Manuscript title: Advanced Control-flow and Concurrency in Cforall 1123 1124 Although your manuscript has been accepted for publication it is now being returned to your author center for you to review and make any final adjustments or corrections prior to production and publication. 1125 1126 Any special instructions will be listed below: 1127 1) Funding Information added in ScholorOne but missing in main document, Kindly add the Funding information in main document. 1128 2) Please provide the clean version of the manuscript without any highlights or tracked changes. 1129 3) Kindly check and make sure citations for all figures and Tables are present in the main document 1130 1131 Please now log back into your Scholar One Author Center and click on the "Manuscripts Accepted for First Look" queue. In order to update the submission, click on the "submit updated manuscript" link in the "Actions" column and follow the steps as you would during a manuscript submission process. 1132 1133 On the File Upload screen please upload the FINAL versions of all the files, including print quality image files. For information about image quality requirements, please refer to the guidelines at https://authorservices.wiley.com/asset/photos/electronic_artwork_guidelines.pdf. 1134 1135 Instructions for uploading replacement files: 1136 1. On the "File Upload" step, click on the "edit" button for the file you wish to replace. 1137 2. In the "Upload a later version" section, browse to locate the replacement final version. 1138 3. Add any comments concerning the replacement (e.g. "high res image"). 1139 4. Select whether the new file is a minor or major version (we suggest you select minor version) 1140 5. Click upload. 1141 6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful. 1142 1143 Please submit your updates within the next 7 days to ensure there are no unnecessary delays in production. 1144 1145 Sincerely, 1146 Software: Practice and Experience Editorial Office 1147 1148 1149 1150 From: SPE Office <speoffice@wiley.com> 1151 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca> 1152 Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c] 1153 Date: Mon, 19 Oct 2020 17:04:24 +0000 1154 1155 Dear Dr. Buhr, 1156 1157 Thank you very much for contacting the Editorial Office. 1158 1159 I would like to let you know that the files has been found in order and moved to production. 1160 1161 Plesae let me know for further assistance in this regard. 1162 1163 Best Regards 1164 1165 Mayank Roy Chowdhury 1166 Editorial Assistant 1167 Software practice and Experience 1168 ________________________________ 1169 From: Peter A. Buhr <pabuhr@uwaterloo.ca> 1170 Sent: Sunday, October 18, 2020 2:00 PM 1171 To: SPE Office <speoffice@wiley.com> 1172 Cc: Thierry Delisle <tdelisle@uwaterloo.ca> 1173 Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c] 1174 1175 This is an external email. 1176 1177 Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com> writes: 1178 1179 Instructions for uploading replacement files: 1180 1. On the "File Upload" step, click on the "edit" button for the file you wish to replace. 1181 2. In the "Upload a later version" section, browse to locate the replacement final version. 1182 3. Add any comments concerning the replacement (e.g. "high res image"). 1183 4. Select whether the new file is a minor or major version (we suggest you select minor version) 1184 5. Click upload. 1185 6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful. 1186 1187 There was no "edit" button on the "File Upload" page, so I just upload the 1188 final version of the PDF and source files using the mechanism on the "File 1189 Upload" page and submitted that. 1190 1191 1192 1193 Date: Tue, 20 Oct 2020 13:28:37 +0530 1194 To: "Dr. Peter Buhr" <pabuhr@uwaterloo.ca> 1195 From: jpcms@spi-global.com 1196 Subject: Information: Production Editor Contact Software:Practice and Experience | Advanced Control-flow and Concurrency in C A 1197 1198 Dear Dr. Peter Buhr, 1199 1200 We are in the process of preparing "Advanced Control-flow and Concurrency in C A" for publication. Your production editor, Joel Pacaanas, will support you and your article throughout the process. 1201 1202 Please get in touch with your Production Editor at SPEproofs@wiley.com;EllaMae.Navor@spi-global.com if you have any questions. 1203 1204 Sincerely, 1205 Booking-in Team, 1206 On behalf of Wiley 1207 1208 Article ID: SPE_2925 1209 Article DOI: 10.1002/SPE.2925 1210 1211 1212 1213 Date: Tue, 20 Oct 2020 10:33:04 +0000 1214 From: <cs-author@wiley.com> 1215 To: <pabuhr@uwaterloo.ca> 1216 Subject: In Production: Your article accepted in Software: Practice and Experience 1217 1218 Dear Peter Buhr, 1219 1220 Article ID: SPE2925 1221 Article DOI: 10.1002/spe.2925 1222 Internal Article ID: 16922213 1223 Article: Advanced Control-flow and Concurrency in C A 1224 Journal: Software: Practice and Experience 1225 1226 Congratulations on the acceptance of your article for publication in Software: Practice and Experience. 1227 1228 Your article has been received and the production process is now underway. We look forward to working with you and publishing your article. Using Wiley Author Services, you can track your article's progress. 1229 1230 Please click below to login - if you are using a different email address than this one, you will need to manually assign this article to your Dashboard (see https://hub.wiley.com/docs/support/assigning-a-missing-article-to-my-dashboard-DOC-11871?utm_source=new%20user%20invitation&utm_medium=email How do I assign a missing article to My Dashboard?): 1231 1232 https://authorservices.wiley.com/index.html#login?campaign=email_invitation-new 1233 1234 If applicable, a list of available actions will appear below - check out your Author Services Dashboard for all actions related to your articles. 1235 1236 Sign your license agreement (REQUIRED) -- you will receive an email when this task is ready on your dashboard. Track your article's progress to publicationAccess your published articleInvite colleagues to view your published article 1237 If you need any assistance, please click http://www.wileyauthors.com/help?utm_source=new%20user%20invitation&utm_medium=email here to view our Help section. 1238 1239 Sincerely, 1240 Wiley Author Services 1241 1242 P.S. - Some journals accept artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. Pricing and placement options vary by journal. For more information, including artwork guidelines, pricing, and submission details, please visit the https://authorservices.wiley.com/author-resources/Journal-Authors/Promotion/journal-cover-image.html?utm_source=as&utm_medium=email&utm_term=invitation_msg&utm_content=covers&utm_campaign=2019feb?campaign=email_invitation-new" target=_blank">Journal Cover Image page. If you want help creating an image, Wiley Editing Services offers a professional https://wileyeditingservices.com/en/article-promotion/cover-image-design.html?utm_source=as&utm_medium=email&utm_term=ie&utm_content=cid&utm_campaign=prodops" target=_blank">Cover Image Design service that creates eye-catching images, ready to be showcased on the journal cover. 1243 1244 1245 1246 Date: Thu, 22 Oct 2020 20:21:49 +0000 1247 From: <cs-author@wiley.com> 1248 To: <pabuhr@uwaterloo.ca> 1249 Subject: You have actions to complete in Author Services 1250 1251 Dear Peter Buhr, 1252 1253 Article ID: SPE2925 1254 Article DOI: 10.1002/spe.2925 1255 Internal Article ID: 16922213 1256 Article: Advanced Control-flow and Concurrency in C A 1257 Journal: Software: Practice and Experience 1258 1259 For the above article, you have the following open tasks: 1260 1261 Sign your license agreement in order to publish your article. Simply click the Sign License button on your https://authorservices.wiley.com?campaign=email_license-notice1">Wiley Author Services Dashboard. 1262 1263 Need any help? Please visit our https://authorsupport.wiley.com/s/">Author Support Center. 1264 1265 Sincerely, 1266 Wiley Author Services 1267 1268 1269 1270 Date: Thu, 22 Oct 2020 23:13:07 +0000 1271 From: <cs-author@wiley.com> 1272 To: <pabuhr@uwaterloo.ca> 1273 Subject: License was successfully submitted! Thank you! 1274 1275 Dear Peter Buhr, 1276 1277 Article ID: SPE2925 1278 Article DOI: 10.1002/spe.2925 1279 Internal Article ID: 16922213 1280 Article: Advanced Control-flow and Concurrency in C A 1281 Journal: Software: Practice and Experience 1282 1283 You've successfully completed license signing for your article - thank you! You can view your signed agreement at any time by visiting your https://authorservices.wiley.com?campaign=email_license-confirm">Wiley Author Services Dashboard. 1284 1285 Sincerely, 1286 1287 Wiley Author Services -
doc/proposals/vtable.md
rb9537e6 rf7e4f8e8 512 512 possibly like the one used to create the assertion. 513 513 514 ### Extension: Associated Types Use 515 If the `associated_types.md` proposal is accepted the following trait could 516 be added: 517 518 trait is_virtual(dtype T) { 519 dtype table; 520 // An example assertion: 521 const table & get_virtual_table(T &); 522 } 523 524 There may be more assertions but there has to be at least one way to find 525 the (possibly default) virtual table. It is required to construct instances 526 of the type. 527 528 Without the assotiated type it would look like this: 529 530 trait is_virtual(dtype T, dtype table) { 531 const table & get_virtual_table(T &); 532 } 533 534 Which is just a little bit longer to use but becomes more problematic if the 535 user has to explicately provide the table's name as it doesn't really have its 536 own type name. If it does it is probably mangled. 537 514 538 ### Virtual Tables as Types 515 539 Here we consider encoding plus the implementation of functions on it to be a -
doc/theses/andrew_beach_MMath/thesis-frontpgs.tex
rb9537e6 rf7e4f8e8 5 5 % TITLE PAGE 6 6 %---------------------------------------------------------------------- 7 8 % Slowly generalizing. 9 \ethesissetup{ 10 author=Pat Neugraad,% 11 title={University of Waterloo E-Thesis Template for \LaTeX}, 12 degree=phd,% 13 program=Zoology,% 14 } 7 15 8 16 \pagestyle{empty} … … 15 23 \vspace*{1.0cm} 16 24 17 \Huge 18 {\bf University of Waterloo E-Thesis Template for \LaTeX } 19 20 \vspace*{1.0cm} 21 22 \normalsize 25 {\Huge\bf \eprint{title}} 26 27 \vspace*{1.0cm} 28 23 29 by \\ 24 30 25 31 \vspace*{1.0cm} 26 32 27 \Large 28 Pat Neugraad \\ 33 {\Large \eprint{author}} \\ 29 34 30 35 \vspace*{3.0cm} 31 36 32 \normalsize33 37 A thesis \\ 34 38 presented to the University of Waterloo \\ 35 39 in fulfillment of the \\ 36 40 thesis requirement for the degree of \\ 37 Doctor of Philosophy\\41 \eprint{degree} \\ 38 42 in \\ 39 Zoology\\43 \eprint{program} \\ 40 44 41 45 \vspace*{2.0cm} … … 45 49 \vspace*{1.0cm} 46 50 47 \copyright \ Pat Neugraad2017 \\51 \copyright{} \eprint{author} 2017 \\ 48 52 \end{center} 49 53 \end{titlepage} -
doc/theses/andrew_beach_MMath/uw-ethesis.cls
rb9537e6 rf7e4f8e8 19 19 % 20 20 % Exported Names: 21 % \ethesissetup{<key-value-pairs>} 22 % Preforms set-up (or a reconfiguration) of the document class. See the 23 % Set-Up Keys section for the keys that may be passed in. Use commas to 24 % seperate key-value-pairs. 25 % 21 26 % \ifformat{<format>}{<true>}{<false>} 22 27 % If the document's format is <format> than expands to <true> otherwise … … 27 32 % initial setup depends on the document format but they can be overriden 28 33 % with options in <setup> (set hyperref's \hypersetup for details). 34 % 35 % \eprint{<key>} 36 % Expands to a human readable value tracked by the ethesis class. This 37 % can be used to retreave and format values set during set up. 38 % 39 % Set-Up Keys: 40 % author=<text> 41 % title=<text> 42 % program=<text> 43 % subject=<text> 44 % keywords=<text> 45 % degree=masters|phd 46 % faculty=ahs|arts|eng|env|math|sci 29 47 \NeedsTeXFormat{LaTeX2e} 30 \ProvidesClass{uw-ethesis}[2020/ 03/24 v0.1UW-eThesis Template Document Class]48 \ProvidesClass{uw-ethesis}[2020/10/25 v0.2 UW-eThesis Template Document Class] 31 49 32 50 \RequirePackage{etoolbox} 51 \RequirePackage{xkeyval} 33 52 34 53 % Requested Format: 35 \newrobustcmd*{\ethesis@ format}{digital}36 \DeclareOption{print}{\renewrobustcmd*{\ethesis@ format}{print}}37 \DeclareOption{digital}{\renewrobustcmd*{\ethesis@ format}{digital}}54 \newrobustcmd*{\ethesis@@format}{digital} 55 \DeclareOption{print}{\renewrobustcmd*{\ethesis@@format}{print}} 56 \DeclareOption{digital}{\renewrobustcmd*{\ethesis@@format}{digital}} 38 57 39 58 \ProcessOptions\relax … … 81 100 % a recto page. This will often require an empty verso (left-hand side) page 82 101 % that should not have the page number printed on it. 83 \let\ origdoublepage\cleardoublepage102 \let\ethesis@origdoublepage\cleardoublepage 84 103 \newcommand{\clearemptydoublepage}{% 85 \clearpage{\pagestyle{empty}\ origdoublepage}}104 \clearpage{\pagestyle{empty}\ethesis@origdoublepage}} 86 105 \let\cleardoublepage\clearemptydoublepage 87 106 … … 89 108 \renewcommand*{\bibname}{References} 90 109 91 % Configurations 92 \def\setThesisTitle#1{\newrobustcmd*{\ethesis@title}{#1}} 93 \def\setThesisAuthor#1{\newrobustcmd*{\ethesis@author}{#1}} 94 \def\setThesisSubject#1{\newrobustcmd*{\ethesis@subject}{#1}} 95 \def\setThesisKeywords#1{\newrobustcmd*{\ethesis@keywords}{#1}} 110 \newrobustcmd*\ethesissetup[1]{\setkeys{ethesis}{#1}} 111 112 \define@cmdkeys{ethesis}[ethesis@@]{% 113 author,title,program,subject,keywords} 114 115 \define@choicekey{ethesis}{degree}{masters,phd}{\def\ethesis@@degree{#1}} 116 \define@choicekey{ethesis}{faculty}{ahs,arts,eng,env,math,sci}% 117 {\def\ethesis@@faculty{#1}} 118 119 \newrobustcmd*\eprint[1]{ 120 \ifcsdef{ethesis@long#1}{\csuse{ethesis@long#1}}{% 121 \ifcsdef{ethesis@@#1}{\csuse{ethesis@@#1}}{% 122 % ERROR: (Check for a way to emit an actual error.) 123 [UW-eThesis doesn't know how to print: #1 ] 124 } 125 } 126 } 127 128 \newrobustcmd*\ethesis@longdegree{% 129 \ifdefstring{\ethesis@@degree}{phd}{Doctor of Philosophy}{Masters}} 96 130 97 131 % Includes the hyperref package loading a number of defaults. … … 106 140 pdfstartview={FitH}, % Fits the width of the page to the window. 107 141 } 108 \ifdef{\ethesis@ title}{\hypersetup{pdftitle={\ethesis@title}}}{}109 \ifdef{\ethesis@ author}{\hypersetup{pdfauthor={\ethesis@author}}}{}110 \ifdef{\ethesis@ subject}{\hypersetup{pdfsubject={\ethesis@subject}}}{}111 \ifdef{\ethesis@ keywords}{\hypersetup{pdfkeywords={\ethesis@keywords}}}{}142 \ifdef{\ethesis@@title}{\hypersetup{pdftitle={\ethesis@@title}}}{} 143 \ifdef{\ethesis@@author}{\hypersetup{pdfauthor={\ethesis@@author}}}{} 144 \ifdef{\ethesis@@subject}{\hypersetup{pdfsubject={\ethesis@@subject}}}{} 145 \ifdef{\ethesis@@keywords}{\hypersetup{pdfkeywords={\ethesis@@keywords}}}{} 112 146 \ifformat{print}{ 113 147 \hypersetup{ -
libcfa/prelude/builtins.c
rb9537e6 rf7e4f8e8 9 9 // Author : Peter A. Buhr 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Oct 9 18:26:19202013 // Update Count : 11 011 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 14:42:00 2020 13 // Update Count : 111 14 14 // 15 16 #define __cforall_builtins__ 15 17 16 18 // type that wraps a pointer and a destructor-like function - used in generating implicit destructor calls for struct members in user-defined functions -
libcfa/src/concurrency/coroutine.cfa
rb9537e6 rf7e4f8e8 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue May 26 22:06:09202013 // Update Count : 2 112 // Last Modified On : Fri Oct 23 23:05:24 2020 13 // Update Count : 22 14 14 // 15 15 … … 24 24 #include <unistd.h> 25 25 #include <sys/mman.h> // mprotect 26 extern "C" {27 // use this define to make unwind.h play nice, definitely a hack28 #define HIDE_EXPORTS29 26 #include <unwind.h> 30 #undef HIDE_EXPORTS31 }32 27 33 28 #include "kernel_private.hfa" 29 #include "exception.hfa" 34 30 35 31 #define __CFA_INVOKE_PRIVATE__ … … 49 45 FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) 50 46 51 struct __cfaehm_node {52 struct _Unwind_Exception unwind_exception;53 struct __cfaehm_node * next;54 int handler_index;55 };56 57 47 forall(dtype T) 58 48 void mark_exception(CoroutineCancelled(T) *) {} … … 60 50 forall(dtype T) 61 51 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) { 52 dst->virtual_table = src->virtual_table; 62 53 dst->the_coroutine = src->the_coroutine; 63 54 dst->the_exception = src->the_exception; … … 74 65 verify( desc->cancellation ); 75 66 desc->state = Cancelled; 76 exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation);67 exception_t * except = __cfaehm_cancellation_exception( desc->cancellation ); 77 68 78 69 // TODO: Remove explitate vtable set once trac#186 is fixed. … … 217 208 size = libFloor(create_size - stack_data_size - diff, libAlign()); 218 209 } // if 219 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of % d bytes for a stack.", size, MinStackSize );210 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %zd bytes for a stack.", size, MinStackSize ); 220 211 221 212 this->storage = (__stack_t *)((intptr_t)storage + size); -
libcfa/src/concurrency/exception.cfa
rb9537e6 rf7e4f8e8 10 10 // Created On : Mon Aug 17 10:41:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Aug 25 14:41:00 202013 // Update Count : 012 // Last Modified On : Wed Oct 28 14:34:00 2020 13 // Update Count : 1 14 14 // 15 15 16 extern "C" { 17 // use this define to make unwind.h play nice, definitely a hack 18 #define HIDE_EXPORTS 19 #include <unwind.h> 20 #undef HIDE_EXPORTS 21 } 16 #define __cforall_thread__ 22 17 23 #include "invoke.h"24 18 #include "exception.hfa" 19 25 20 #include "coroutine.hfa" 26 21 27 22 extern struct $thread * mainThread; 23 extern "C" { 24 extern void __cfactx_thrd_leave(); 25 } 28 26 29 27 // Common pattern for all the stop functions, wait until the end then act. … … 52 50 53 51 STOP_AT_END_FUNCTION(thread_cancelstop, 54 // TODO: Instead pass information to the joiner.55 abort();52 __cfactx_thrd_leave(); 53 __cabi_abort( "Resumed cancelled thread" ); 56 54 ) 57 55 … … 85 83 stop_param = (void *)0x22; 86 84 } else { 85 this_thread->self_cor.cancellation = unwind_exception; 86 87 87 stop_func = thread_cancelstop; 88 88 stop_param = this_thread; -
libcfa/src/concurrency/exception.hfa
rb9537e6 rf7e4f8e8 16 16 #pragma once 17 17 18 // This is an internal bridge between the two modes and must be C compatable. 19 20 #include <unwind.h> 18 21 #include "bits/defs.hfa" 19 22 #include "invoke.h" 23 #include "exception.h" 20 24 21 25 #ifdef __cforall 22 26 extern "C" { 23 24 #define HIDE_EXPORTS25 27 #endif 26 #include "unwind.h"27 28 28 29 struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD; … … 32 33 33 34 #ifdef __cforall 34 #undef HIDE_EXPORTS35 35 } 36 36 #endif -
libcfa/src/concurrency/invoke.h
rb9537e6 rf7e4f8e8 157 157 158 158 // current execution status for coroutine 159 // Possible values are: 160 // - TICKET_BLOCKED (-1) thread is blocked 161 // - TICKET_RUNNING ( 0) thread is running 162 // - TICKET_UNBLOCK ( 1) thread should ignore next block 159 163 volatile int ticket; 160 164 enum __Coroutine_State state:8; -
libcfa/src/concurrency/io/setup.cfa
rb9537e6 rf7e4f8e8 250 250 // Fixup the thread state 251 251 thrd.state = Blocked; 252 thrd.ticket = 0;252 thrd.ticket = TICKET_BLOCKED; 253 253 thrd.preempted = __NO_PREEMPTION; 254 254 -
libcfa/src/concurrency/kernel.cfa
rb9537e6 rf7e4f8e8 252 252 /* paranoid */ verify( kernelTLS.this_thread == thrd_dst ); 253 253 /* paranoid */ verify( thrd_dst->context.SP ); 254 /* paranoid */ verify( thrd_dst->state != Halted ); 254 255 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor 255 256 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor … … 287 288 if(unlikely(thrd_dst->state == Halted)) { 288 289 // The thread has halted, it should never be scheduled/run again 289 // We may need to wake someone up here since 290 unpark( this->destroyer ); 291 this->destroyer = 0p; 290 // finish the thread 291 __thread_finish( thrd_dst ); 292 292 break RUNNING; 293 293 } … … 299 299 int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST); 300 300 switch(old_ticket) { 301 case 1:301 case TICKET_RUNNING: 302 302 // This is case 1, the regular case, nothing more is needed 303 303 break RUNNING; 304 case 2:304 case TICKET_UNBLOCK: 305 305 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 306 306 // In this case, just run it again. … … 410 410 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 411 411 switch(old_ticket) { 412 case 1:412 case TICKET_RUNNING: 413 413 // Wake won the race, the thread will reschedule/rerun itself 414 414 break; 415 case 0:415 case TICKET_BLOCKED: 416 416 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 417 417 /* paranoid */ verify( thrd->state == Blocked ); … … 422 422 default: 423 423 // This makes no sense, something is wrong abort 424 abort( );424 abort("Thread %p (%s) has mismatch park/unpark\n", thrd, thrd->self_cor.name); 425 425 } 426 426 } … … 448 448 } 449 449 450 // KERNEL ONLY 451 void __leave_thread() { 452 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 453 returnToKernel(); 454 abort(); 450 extern "C" { 451 // Leave the thread monitor 452 // last routine called by a thread. 453 // Should never return 454 void __cfactx_thrd_leave() { 455 $thread * thrd = TL_GET( this_thread ); 456 $monitor * this = &thrd->self_mon; 457 458 // Lock the monitor now 459 lock( this->lock __cfaabi_dbg_ctx2 ); 460 461 disable_interrupts(); 462 463 thrd->state = Halted; 464 465 if( thrd != this->owner || this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); } 466 467 // Leave the thread 468 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 469 returnToKernel(); 470 abort(); 471 472 // Control flow should never reach here! 473 } 455 474 } 456 475 -
libcfa/src/concurrency/kernel.hfa
rb9537e6 rf7e4f8e8 79 79 // Handle to pthreads 80 80 pthread_t kernel_thread; 81 82 // RunThread data83 // Action to do after a thread is ran84 $thread * destroyer;85 81 86 82 // Preemption data -
libcfa/src/concurrency/kernel/startup.cfa
rb9537e6 rf7e4f8e8 441 441 442 442 static void ?{}( $thread & this, current_stack_info_t * info) with( this ) { 443 ticket = 1;443 ticket = TICKET_RUNNING; 444 444 state = Start; 445 445 self_cor{ info }; … … 474 474 this.cltr = &_cltr; 475 475 full_proc = true; 476 destroyer = 0p;477 476 do_terminate = false; 478 477 preemption_alarm = 0p; -
libcfa/src/concurrency/kernel_private.hfa
rb9537e6 rf7e4f8e8 39 39 ; 40 40 41 // Block current thread andrelease/wake-up the following resources42 void __ leave_thread() __attribute__((noreturn));41 //release/wake-up the following resources 42 void __thread_finish( $thread * thrd ); 43 43 44 44 //----------------------------------------------------------------------------- … … 65 65 // KERNEL ONLY unpark with out disabling interrupts 66 66 void __unpark( struct __processor_id_t *, $thread * thrd ); 67 68 #define TICKET_BLOCKED (-1) // thread is blocked 69 #define TICKET_RUNNING ( 0) // thread is running 70 #define TICKET_UNBLOCK ( 1) // thread should ignore next block 67 71 68 72 static inline bool __post(single_sem & this, struct __processor_id_t * id) { -
libcfa/src/concurrency/monitor.cfa
rb9537e6 rf7e4f8e8 281 281 } 282 282 283 extern "C" { 284 // Leave the thread monitor 285 // last routine called by a thread. 286 // Should never return 287 void __cfactx_thrd_leave() { 288 $thread * thrd = TL_GET( this_thread ); 289 $monitor * this = &thrd->self_mon; 290 291 // Lock the monitor now 292 lock( this->lock __cfaabi_dbg_ctx2 ); 293 294 disable_interrupts(); 295 296 thrd->state = Halted; 297 298 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 299 300 // Leaving a recursion level, decrement the counter 301 this->recursion -= 1; 302 303 // If we haven't left the last level of recursion 304 // it must mean there is an error 305 if( this->recursion != 0) { abort( "Thread internal monitor has unbalanced recursion" ); } 306 307 // Fetch the next thread, can be null 308 $thread * new_owner = next_thread( this ); 309 310 // Release the monitor lock 311 unlock( this->lock ); 312 313 // Unpark the next owner if needed 314 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 315 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 316 /* paranoid */ verify( ! kernelTLS.this_processor->destroyer ); 317 /* paranoid */ verify( thrd->state == Halted ); 318 319 kernelTLS.this_processor->destroyer = new_owner; 320 321 // Leave the thread 322 __leave_thread(); 323 324 // Control flow should never reach here! 325 } 326 } 327 328 // Join a thread 329 forall( dtype T | is_thread(T) ) 330 T & join( T & this ) { 331 $monitor * m = get_monitor(this); 332 void (*dtor)(T& mutex this) = ^?{}; 333 monitor_dtor_guard_t __guard = { &m, (fptr_t)dtor, true }; 334 { 335 return this; 336 } 283 void __thread_finish( $thread * thrd ) { 284 $monitor * this = &thrd->self_mon; 285 286 // Lock the monitor now 287 /* paranoid */ verify( this->lock.lock ); 288 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 289 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 290 /* paranoid */ verify( thrd->state == Halted ); 291 /* paranoid */ verify( this->recursion == 1 ); 292 293 // Leaving a recursion level, decrement the counter 294 this->recursion -= 1; 295 this->owner = 0p; 296 297 // Fetch the next thread, can be null 298 $thread * new_owner = next_thread( this ); 299 300 // Release the monitor lock 301 unlock( this->lock ); 302 303 // Unpark the next owner if needed 304 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 305 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 306 /* paranoid */ verify( thrd->state == Halted ); 307 unpark( new_owner ); 337 308 } 338 309 -
libcfa/src/concurrency/thread.cfa
rb9537e6 rf7e4f8e8 19 19 20 20 #include "kernel_private.hfa" 21 #include "exception.hfa" 21 22 22 23 #define __CFA_INVOKE_PRIVATE__ … … 28 29 context{ 0p, 0p }; 29 30 self_cor{ name, storage, storageSize }; 30 ticket = 1;31 ticket = TICKET_RUNNING; 31 32 state = Start; 32 33 preempted = __NO_PREEMPTION; … … 56 57 unregister(curr_cluster, this); 57 58 ^self_cor{}; 59 } 60 61 FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t)) 62 63 forall(dtype T) 64 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) { 65 dst->virtual_table = src->virtual_table; 66 dst->the_thread = src->the_thread; 67 dst->the_exception = src->the_exception; 68 } 69 70 forall(dtype T) 71 const char * msg(ThreadCancelled(T) *) { 72 return "ThreadCancelled"; 73 } 74 75 forall(dtype T) 76 static void default_thread_cancel_handler(ThreadCancelled(T) & ) { 77 abort( "Unhandled thread cancellation.\n" ); 78 } 79 80 forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))) 81 void ?{}( thread_dtor_guard_t & this, 82 T & thrd, void(*defaultResumptionHandler)(ThreadCancelled(T) &)) { 83 $monitor * m = get_monitor(thrd); 84 void (*dtor)(T& mutex this) = ^?{}; 85 bool join = defaultResumptionHandler != (void(*)(ThreadCancelled(T)&))0; 86 (this.mg){&m, (void(*)())dtor, join}; 87 88 // After the guard set-up and any wait, check for cancellation. 89 $thread * desc = get_thread(thrd); 90 struct _Unwind_Exception * cancellation = desc->self_cor.cancellation; 91 if ( likely( 0p == cancellation ) ) { 92 return; 93 } else if ( Cancelled == desc->state ) { 94 return; 95 } 96 desc->state = Cancelled; 97 if (!join) { 98 defaultResumptionHandler = default_thread_cancel_handler; 99 } 100 101 ThreadCancelled(T) except; 102 // TODO: Remove explitate vtable set once trac#186 is fixed. 103 except.virtual_table = &get_exception_vtable(&except); 104 except.the_thread = &thrd; 105 except.the_exception = __cfaehm_cancellation_exception( cancellation ); 106 throwResume except; 107 108 except.the_exception->virtual_table->free( except.the_exception ); 109 free( cancellation ); 110 desc->self_cor.cancellation = 0p; 111 } 112 113 void ^?{}( thread_dtor_guard_t & this ) { 114 ^(this.mg){}; 58 115 } 59 116 … … 93 150 } 94 151 152 //----------------------------------------------------------------------------- 153 forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))) 154 T & join( T & this ) { 155 thread_dtor_guard_t guard = { this, defaultResumptionHandler }; 156 return this; 157 } 158 95 159 // Local Variables: // 96 160 // mode: c // -
libcfa/src/concurrency/thread.hfa
rb9537e6 rf7e4f8e8 22 22 #include "kernel.hfa" 23 23 #include "monitor.hfa" 24 #include "exception.hfa" 24 25 25 26 //----------------------------------------------------------------------------- 26 27 // thread trait 27 28 trait is_thread(dtype T) { 28 29 30 29 void ^?{}(T& mutex this); 30 void main(T& this); 31 $thread* get_thread(T& this); 31 32 }; 33 34 FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) ( 35 thread_t * the_thread; 36 exception_t * the_exception; 37 ); 38 39 forall(dtype T) 40 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src); 41 42 forall(dtype T) 43 const char * msg(ThreadCancelled(T) *); 32 44 33 45 // define that satisfies the trait without using the thread keyword … … 65 77 static inline void ?{}($thread & this, const char * const name, struct cluster & cl ) { this{ name, cl, 0p, 65000 }; } 66 78 static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; } 79 80 struct thread_dtor_guard_t { 81 monitor_dtor_guard_t mg; 82 }; 83 84 forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) ) 85 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) ); 86 void ^?{}( thread_dtor_guard_t & this ); 67 87 68 88 //----------------------------------------------------------------------------- … … 108 128 //---------- 109 129 // join 110 forall( dtype T | is_thread(T) )130 forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) ) 111 131 T & join( T & this ); 112 132 -
libcfa/src/exception.c
rb9537e6 rf7e4f8e8 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Aug 29 15:52:22202013 // Update Count : 3 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 16:27:00 2020 13 // Update Count : 35 14 14 // 15 15 … … 17 17 #include <stddef.h> // for size_t 18 18 19 #include <unwind.h> // for struct _Unwind_Exception {...}; 20 19 21 #include "exception.h" 20 22 21 23 #include <stdlib.h> 22 24 #include <stdio.h> 23 #include <unwind.h>24 25 #include <bits/debug.hfa> 25 26 #include "concurrency/invoke.h" … … 113 114 114 115 // MEMORY MANAGEMENT ========================================================= 115 116 struct __cfaehm_node {117 struct _Unwind_Exception unwind_exception;118 struct __cfaehm_node * next;119 int handler_index;120 };121 116 122 117 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node))) -
libcfa/src/exception.h
rb9537e6 rf7e4f8e8 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // exception.h -- Builtins for exception handling.7 // exception.h -- Internal exception handling definitions. 8 8 // 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue May 19 14:17:00 202013 // Update Count : 1 012 // Last Modified On : Tue Oct 27 14:45:00 2020 13 // Update Count : 11 14 14 // 15 15 16 16 #pragma once 17 17 18 // This could be considered several headers. All are internal to the exception 19 // system but needed to depending on whether they are C/Cforall code and 20 // whether or not they are part of the builtins. 18 21 19 22 #ifdef __cforall 20 23 extern "C" { 21 24 #endif 25 26 // Included in C code or the built-ins. 27 #if !defined(__cforall) || defined(__cforall_builtins__) 22 28 23 29 struct __cfaehm_base_exception_t; … … 47 53 // Function catches termination exceptions. 48 54 void __cfaehm_try_terminate( 49 50 51 55 void (*try_block)(), 56 void (*catch_block)(int index, exception_t * except), 57 int (*match_block)(exception_t * except)); 52 58 53 59 // Clean-up the exception in catch blocks. … … 56 62 // Data structure creates a list of resume handlers. 57 63 struct __cfaehm_try_resume_node { 58 59 64 struct __cfaehm_try_resume_node * next; 65 _Bool (*handler)(exception_t * except); 60 66 }; 61 67 62 68 // These act as constructor and destructor for the resume node. 63 69 void __cfaehm_try_resume_setup( 64 65 70 struct __cfaehm_try_resume_node * node, 71 _Bool (*handler)(exception_t * except)); 66 72 void __cfaehm_try_resume_cleanup( 67 73 struct __cfaehm_try_resume_node * node); 68 74 69 75 // Check for a standard way to call fake deconstructors. 70 76 struct __cfaehm_cleanup_hook {}; 71 77 78 #endif 79 80 // Included in C code and the library. 81 #if !defined(__cforall) || !defined(__cforall_builtins__) 82 struct __cfaehm_node { 83 struct _Unwind_Exception unwind_exception; 84 struct __cfaehm_node * next; 85 int handler_index; 86 }; 87 88 static inline exception_t * __cfaehm_cancellation_exception( 89 struct _Unwind_Exception * unwind_exception ) { 90 return (exception_t *)(1 + (struct __cfaehm_node *)unwind_exception); 91 } 92 #endif 93 72 94 #ifdef __cforall 73 95 } 96 97 // Built-ins not visible in C. 98 #if defined(__cforall_builtins__) 74 99 75 100 // Not all the built-ins can be expressed in C. These can't be … … 124 149 125 150 #endif 151 152 #endif -
src/AST/Convert.cpp
rb9537e6 rf7e4f8e8 47 47 48 48 //================================================================================================ 49 namespace {49 namespace ast { 50 50 51 51 // This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not) 52 52 // allow us to use the same stratagy in the new ast. 53 // xxx - since convert back pass works, this concern seems to be unnecessary. 54 55 // these need to be accessed in new FixInit now 53 56 ast::Type * sizeType = nullptr; 54 57 ast::FunctionDecl * dereferenceOperator = nullptr; … … 63 66 using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >; 64 67 Cache cache; 68 69 // Statements can no longer be shared. 70 // however, since StmtExprResult is now implemented, need to still maintain 71 // readonly references. 72 Cache readonlyCache; 65 73 66 74 template<typename T> … … 154 162 } 155 163 156 const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final { 157 auto&& bfwd = get<Expression>().accept1( node->bitfieldWidth ); 158 auto&& type = get<Type>().accept1( node->type ); 159 auto&& init = get<Initializer>().accept1( node->init ); 160 auto&& attr = get<Attribute>().acceptL( node->attributes ); 164 const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final { 161 165 if ( inCache( node ) ) { 162 166 return nullptr; 163 167 } 168 auto bfwd = get<Expression>().accept1( node->bitfieldWidth ); 169 auto type = get<Type>().accept1( node->type ); 170 auto attr = get<Attribute>().acceptL( node->attributes ); 171 164 172 auto decl = new ObjectDecl( 165 173 node->name, … … 168 176 bfwd, 169 177 type->clone(), 170 init,178 nullptr, // prevent infinite loop 171 179 attr, 172 180 Type::FuncSpecifiers( node->funcSpec.val ) 173 181 ); 174 return declWithTypePostamble( decl, node ); 182 183 // handles the case where node->init references itself 184 // xxx - does it really happen? 185 declWithTypePostamble(decl, node); 186 auto init = get<Initializer>().accept1( node->init ); 187 decl->init = init; 188 189 this->node = decl; 190 return nullptr; 175 191 } 176 192 … … 205 221 decl->statements = get<CompoundStmt>().accept1( node->stmts ); 206 222 decl->withExprs = get<Expression>().acceptL( node->withExprs ); 207 if ( dereferenceOperator == node ) {223 if ( ast::dereferenceOperator == node ) { 208 224 Validate::dereferenceOperator = decl; 209 225 } 210 if ( dtorStructDestroy == node ) {226 if ( ast::dtorStructDestroy == node ) { 211 227 Validate::dtorStructDestroy = decl; 212 228 } … … 267 283 ); 268 284 269 if ( dtorStruct == node ) {285 if ( ast::dtorStruct == node ) { 270 286 Validate::dtorStruct = decl; 271 287 } … … 320 336 321 337 const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) { 322 cache.emplace( node, stmt ); 338 // force statements in old tree to be unique. 339 // cache.emplace( node, stmt ); 340 readonlyCache.emplace( node, stmt ); 323 341 stmt->location = node->location; 324 342 stmt->labels = makeLabelL( stmt, node->labels ); … … 337 355 if ( inCache( node ) ) return nullptr; 338 356 auto stmt = new ExprStmt( nullptr ); 339 cache.emplace( node, stmt );340 357 stmt->expr = get<Expression>().accept1( node->expr ); 341 358 return stmtPostamble( stmt, node ); … … 1011 1028 auto stmts = node->stmts; 1012 1029 // disable sharing between multiple StmtExprs explicitly. 1013 if (inCache(stmts)) { 1014 stmts = ast::deepCopy(stmts.get()); 1015 } 1030 // this should no longer be true. 1031 1016 1032 auto rslt = new StmtExpr( 1017 1033 get<CompoundStmt>().accept1(stmts) … … 1020 1036 rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls); 1021 1037 rslt->dtors = get<Expression>().acceptL(node->dtors); 1038 if (node->resultExpr) { 1039 // this MUST be found by children visit 1040 rslt->resultExpr = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr)); 1041 } 1022 1042 1023 1043 auto expr = visitBaseExpr( node, rslt ); … … 1036 1056 1037 1057 auto expr = visitBaseExpr( node, rslt ); 1038 this->node = expr ;1058 this->node = expr->clone(); 1039 1059 return nullptr; 1040 1060 } … … 1126 1146 auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind }; 1127 1147 // I believe this should always be a BasicType. 1128 if ( sizeType == node ) {1148 if ( ast::sizeType == node ) { 1129 1149 Validate::SizeType = type; 1130 1150 } … … 1529 1549 1530 1550 // function type is now derived from parameter decls instead of storing them 1551 1552 /* 1531 1553 auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type)); 1532 1554 ftype->params.reserve(paramVars.size()); … … 1540 1562 } 1541 1563 ftype->forall = std::move(forall); 1542 visitType(old->type, ftype); 1564 */ 1565 1566 // can function type have attributes? seems not to be the case. 1567 // visitType(old->type, ftype); 1543 1568 1544 1569 auto decl = new ast::FunctionDecl{ … … 1546 1571 old->name, 1547 1572 // GET_ACCEPT_1(type, FunctionType), 1573 std::move(forall), 1548 1574 std::move(paramVars), 1549 1575 std::move(returnVars), … … 1552 1578 { old->linkage.val }, 1553 1579 GET_ACCEPT_V(attributes, Attribute), 1554 { old->get_funcSpec().val } 1580 { old->get_funcSpec().val }, 1581 old->type->isVarArgs 1555 1582 }; 1556 1583 1557 decl->type = ftype;1584 // decl->type = ftype; 1558 1585 cache.emplace( old, decl ); 1559 1586 … … 1570 1597 1571 1598 if ( Validate::dereferenceOperator == old ) { 1572 dereferenceOperator = decl;1599 ast::dereferenceOperator = decl; 1573 1600 } 1574 1601 1575 1602 if ( Validate::dtorStructDestroy == old ) { 1576 dtorStructDestroy = decl;1603 ast::dtorStructDestroy = decl; 1577 1604 } 1578 1605 } … … 1599 1626 1600 1627 if ( Validate::dtorStruct == old ) { 1601 dtorStruct = decl;1628 ast::dtorStruct = decl; 1602 1629 } 1603 1630 } … … 2531 2558 // I believe this should always be a BasicType. 2532 2559 if ( Validate::SizeType == old ) { 2533 sizeType = type;2560 ast::sizeType = type; 2534 2561 } 2535 2562 visitType( old, type ); -
src/AST/Decl.cpp
rb9537e6 rf7e4f8e8 48 48 49 49 // --- FunctionDecl 50 51 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 52 std::vector<ptr<TypeDecl>>&& forall, 53 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 54 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage, 55 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs) 56 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)), 57 stmts( stmts ) { 58 FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs)); 59 for (auto & param : this->params) { 60 ftype->params.emplace_back(param->get_type()); 61 } 62 for (auto & ret : this->returns) { 63 ftype->returns.emplace_back(ret->get_type()); 64 } 65 ftype->forall = std::move(forall); 66 this->type = ftype; 67 } 68 50 69 51 70 const Type * FunctionDecl::get_type() const { return type.get(); } -
src/AST/Decl.hpp
rb9537e6 rf7e4f8e8 131 131 std::vector< ptr<Expr> > withExprs; 132 132 133 FunctionDecl( const CodeLocation & loc, const std::string & name, 133 FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall, 134 134 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 135 135 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, 136 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {} )137 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),138 stmts( stmts ) {}136 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false); 137 // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)), 138 // stmts( stmts ) {} 139 139 140 140 const Type * get_type() const override; -
src/AST/DeclReplacer.cpp
rb9537e6 rf7e4f8e8 38 38 const ast::TypeInstType * previsit( const ast::TypeInstType * ); 39 39 }; 40 41 struct VarExprReplacer { 42 private: 43 const ExprMap & exprMap; 44 45 public: 46 VarExprReplacer(const ExprMap & exprMap): exprMap (exprMap) {} 47 48 const Expr * postvisit (const VariableExpr *); 49 }; 40 50 } 41 51 … … 54 64 DeclMap declMap; 55 65 return replace( node, declMap, typeMap, debug ); 66 } 67 68 const ast::Node * replace( const ast::Node * node, const ExprMap & exprMap) { 69 Pass<VarExprReplacer> replacer = {exprMap}; 70 return node->accept( replacer ); 56 71 } 57 72 … … 88 103 return ninst; 89 104 } 105 106 const Expr * VarExprReplacer::postvisit( const VariableExpr * expr ) { 107 if (!exprMap.count(expr->var)) return expr; 108 109 return exprMap.at(expr->var); 110 } 111 90 112 } 91 113 } -
src/AST/DeclReplacer.hpp
rb9537e6 rf7e4f8e8 23 23 class DeclWithType; 24 24 class TypeDecl; 25 class Expr; 25 26 26 27 namespace DeclReplacer { 27 28 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 28 29 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 30 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >; 29 31 30 32 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 31 33 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 32 34 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false ); 35 const Node * replace( const Node * node, const ExprMap & exprMap); 33 36 } 34 37 } -
src/AST/Expr.cpp
rb9537e6 rf7e4f8e8 67 67 // --- UntypedExpr 68 68 69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) { 70 70 assert( arg ); 71 71 … … 92 92 } 93 93 94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs,Expr * rhs ) {94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) { 95 95 assert( lhs && rhs ); 96 96 … … 102 102 } 103 103 return ret; 104 } 105 106 // --- VariableExpr 107 108 VariableExpr::VariableExpr( const CodeLocation & loc ) 109 : Expr( loc ), var( nullptr ) {} 110 111 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v ) 112 : Expr( loc ), var( v ) { 113 assert( var ); 114 assert( var->get_type() ); 115 result = shallowCopy( var->get_type() ); 116 } 117 118 bool VariableExpr::get_lvalue() const { 119 // It isn't always an lvalue, but it is never an rvalue. 120 return true; 121 } 122 123 VariableExpr * VariableExpr::functionPointer( 124 const CodeLocation & loc, const FunctionDecl * decl ) { 125 // wrap usually-determined result type in a pointer 126 VariableExpr * funcExpr = new VariableExpr{ loc, decl }; 127 funcExpr->result = new PointerType{ funcExpr->result }; 128 return funcExpr; 104 129 } 105 130 … … 238 263 } 239 264 240 // --- VariableExpr241 242 VariableExpr::VariableExpr( const CodeLocation & loc )243 : Expr( loc ), var( nullptr ) {}244 245 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )246 : Expr( loc ), var( v ) {247 assert( var );248 assert( var->get_type() );249 result = shallowCopy( var->get_type() );250 }251 252 bool VariableExpr::get_lvalue() const {253 // It isn't always an lvalue, but it is never an rvalue.254 return true;255 }256 257 VariableExpr * VariableExpr::functionPointer(258 const CodeLocation & loc, const FunctionDecl * decl ) {259 // wrap usually-determined result type in a pointer260 VariableExpr * funcExpr = new VariableExpr{ loc, decl };261 funcExpr->result = new PointerType{ funcExpr->result };262 return funcExpr;263 }264 265 265 // --- ConstantExpr 266 266 -
src/AST/Expr.hpp
rb9537e6 rf7e4f8e8 226 226 227 227 /// Creates a new dereference expression 228 static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );228 static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg ); 229 229 /// Creates a new assignment expression 230 static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs,Expr * rhs );230 static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ); 231 231 232 232 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 247 247 private: 248 248 NameExpr * clone() const override { return new NameExpr{ *this }; } 249 MUTATE_FRIEND 250 }; 251 252 /// A reference to a named variable. 253 class VariableExpr final : public Expr { 254 public: 255 readonly<DeclWithType> var; 256 257 VariableExpr( const CodeLocation & loc ); 258 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 259 260 bool get_lvalue() const final; 261 262 /// generates a function pointer for a given function 263 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl ); 264 265 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 266 private: 267 VariableExpr * clone() const override { return new VariableExpr{ *this }; } 249 268 MUTATE_FRIEND 250 269 }; … … 392 411 }; 393 412 394 /// A reference to a named variable.395 class VariableExpr final : public Expr {396 public:397 readonly<DeclWithType> var;398 399 VariableExpr( const CodeLocation & loc );400 VariableExpr( const CodeLocation & loc, const DeclWithType * v );401 402 bool get_lvalue() const final;403 404 /// generates a function pointer for a given function405 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );406 407 const Expr * accept( Visitor & v ) const override { return v.visit( this ); }408 private:409 VariableExpr * clone() const override { return new VariableExpr{ *this }; }410 MUTATE_FRIEND411 };412 413 413 /// A compile-time constant. 414 414 /// Mostly carries C-source text from parse to code-gen, without interpretation. E.g. strings keep their outer quotes and never have backslashes interpreted. … … 422 422 const CodeLocation & loc, const Type * ty, const std::string & r, 423 423 std::optional<unsigned long long> i ) 424 : Expr( loc, ty ), rep( r ), ival( i ) {}424 : Expr( loc, ty ), rep( r ), ival( i ), underlyer(ty) {} 425 425 426 426 /// Gets the integer value of this constant, if one is appropriate to its type. … … 617 617 618 618 ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call ) 619 : Expr( loc, call->result ) { assert( call); }619 : Expr( loc, call->result ), callExpr(call) { assert( call ); assert(call->result); } 620 620 621 621 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 742 742 std::vector<ptr<Expr>> dtors; ///< destructor(s) for return variable(s) 743 743 744 readonly<ExprStmt> resultExpr; 745 744 746 StmtExpr( const CodeLocation & loc, const CompoundStmt * ss ); 745 747 -
src/AST/Fwd.hpp
rb9537e6 rf7e4f8e8 137 137 typedef unsigned int UniqueId; 138 138 139 extern Type * sizeType; 140 extern FunctionDecl * dereferenceOperator; 141 extern StructDecl * dtorStruct; 142 extern FunctionDecl * dtorStructDestroy; 143 139 144 } -
src/AST/Node.hpp
rb9537e6 rf7e4f8e8 49 49 50 50 bool unique() const { return strong_count == 1; } 51 bool isManaged() const {return strong_count > 0; } 51 52 52 53 private: -
src/AST/Pass.hpp
rb9537e6 rf7e4f8e8 228 228 template<typename core_type> 229 229 friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor ); 230 231 bool isInFunction() const { 232 return inFunction; 233 } 234 230 235 private: 231 236 … … 235 240 const ast::Stmt * call_accept( const ast::Stmt * ); 236 241 const ast::Expr * call_accept( const ast::Expr * ); 242 243 // requests WithStmtsToAdd directly add to this statement, as if it is a compound. 244 245 const ast::Stmt * call_accept_as_compound(const ast::Stmt *); 237 246 238 247 template< typename node_t > … … 257 266 template<typename node_t, typename parent_t, typename child_t> 258 267 void maybe_accept(const node_t * &, child_t parent_t::* child); 268 269 template<typename node_t, typename parent_t, typename child_t> 270 void maybe_accept_as_compound(const node_t * &, child_t parent_t::* child); 259 271 260 272 private: … … 284 296 private: 285 297 bool inFunction = false; 298 bool atFunctionTop = false; 286 299 }; 287 300 … … 371 384 struct WithVisitorRef { 372 385 Pass<core_t> * const visitor = nullptr; 386 387 bool isInFunction() const { 388 return visitor->isInFunction(); 389 } 373 390 }; 374 391 -
src/AST/Pass.impl.hpp
rb9537e6 rf7e4f8e8 167 167 __pedantic_pass_assert( stmt ); 168 168 169 return stmt->accept( *this ); 170 } 171 172 template< typename core_t > 173 const ast::Stmt * ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) { 174 __pedantic_pass_assert( __visit_children() ); 175 __pedantic_pass_assert( stmt ); 176 169 177 // add a few useful symbols to the scope 170 178 using __pass::empty; … … 324 332 325 333 auto new_val = call_accept( old_val ); 334 335 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR"); 336 337 if( __pass::differs(old_val, new_val) ) { 338 auto new_parent = __pass::mutate<core_t>(parent); 339 new_parent->*child = new_val; 340 parent = new_parent; 341 } 342 } 343 344 template< typename core_t > 345 template<typename node_t, typename parent_t, typename child_t> 346 void ast::Pass< core_t >::maybe_accept_as_compound( 347 const node_t * & parent, 348 child_t parent_t::*child 349 ) { 350 static_assert( std::is_base_of<parent_t, node_t>::value, "Error deducing member object" ); 351 352 if(__pass::skip(parent->*child)) return; 353 const auto & old_val = __pass::get(parent->*child, 0); 354 355 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 356 357 auto new_val = call_accept_as_compound( old_val ); 326 358 327 359 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR"); … … 470 502 // foralls are still in function type 471 503 maybe_accept( node, &FunctionDecl::type ); 472 // function body needs to have the same scope as parameters - CompoundStmt will not enter 473 // a new scope if inFunction is true 504 // First remember that we are now within a function. 474 505 ValueGuard< bool > oldInFunction( inFunction ); 475 506 inFunction = true; 507 // The function body needs to have the same scope as parameters. 508 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 509 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 510 atFunctionTop = true; 476 511 maybe_accept( node, &FunctionDecl::stmts ); 477 512 maybe_accept( node, &FunctionDecl::attributes ); … … 640 675 VISIT_START( node ); 641 676 VISIT({ 642 // do not enter a new scope if inFunction is true - needs to check old state before the assignment643 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {644 if ( ! inFunctionCpy) __pass::symtab::enter(core, 0);645 }, [this, inFunctionCpy = this->inFunction]() {646 if ( ! inFunctionCpy) __pass::symtab::leave(core, 0);677 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result. 678 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() { 679 if ( enterScope ) __pass::symtab::enter(core, 0); 680 }, [this, leaveScope = !this->atFunctionTop]() { 681 if ( leaveScope ) __pass::symtab::leave(core, 0); 647 682 }); 648 683 ValueGuard< bool > guard2( inFunction ); … … 703 738 maybe_accept( node, &IfStmt::inits ); 704 739 maybe_accept( node, &IfStmt::cond ); 705 maybe_accept ( node, &IfStmt::thenPart );706 maybe_accept ( node, &IfStmt::elsePart );740 maybe_accept_as_compound( node, &IfStmt::thenPart ); 741 maybe_accept_as_compound( node, &IfStmt::elsePart ); 707 742 }) 708 743 … … 721 756 maybe_accept( node, &WhileStmt::inits ); 722 757 maybe_accept( node, &WhileStmt::cond ); 723 maybe_accept ( node, &WhileStmt::body );758 maybe_accept_as_compound( node, &WhileStmt::body ); 724 759 }) 725 760 … … 736 771 // for statements introduce a level of scope (for the initialization) 737 772 guard_symtab guard { *this }; 773 // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later. 738 774 maybe_accept( node, &ForStmt::inits ); 739 775 maybe_accept( node, &ForStmt::cond ); 740 776 maybe_accept( node, &ForStmt::inc ); 741 maybe_accept ( node, &ForStmt::body );777 maybe_accept_as_compound( node, &ForStmt::body ); 742 778 }) 743 779 … … 834 870 maybe_accept( node, &CatchStmt::decl ); 835 871 maybe_accept( node, &CatchStmt::cond ); 836 maybe_accept ( node, &CatchStmt::body );872 maybe_accept_as_compound( node, &CatchStmt::body ); 837 873 }) 838 874 -
src/AST/SymbolTable.cpp
rb9537e6 rf7e4f8e8 335 335 } 336 336 337 /* 338 void SymbolTable::addFunction Type( const FunctionType * ftype) {339 addTypes( f type->forall );340 addIds( f type->returns );341 addIds( f type->params );342 } 343 */ 337 338 void SymbolTable::addFunction( const FunctionDecl * func ) { 339 addTypes( func->type->forall ); 340 addIds( func->returns ); 341 addIds( func->params ); 342 } 343 344 344 345 345 void SymbolTable::lazyInitScope() { -
src/AST/SymbolTable.hpp
rb9537e6 rf7e4f8e8 145 145 146 146 /// convenience function for adding all of the declarations in a function type to the indexer 147 // void addFunctionType( const FunctionType * ftype);147 void addFunction( const FunctionDecl * ); 148 148 149 149 private: -
src/AST/Type.cpp
rb9537e6 rf7e4f8e8 157 157 158 158 template<typename decl_t> 159 SueInstType<decl_t>::SueInstType( 160 const base_type * b, std::vector<ptr<Expr>> && params, 161 CV::Qualifiers q, std::vector<ptr<Attribute>> && as ) 162 : BaseInstType( b->name, std::move(params), q, std::move(as) ), base( b ) {} 163 164 template<typename decl_t> 159 165 bool SueInstType<decl_t>::isComplete() const { 160 166 return base ? base->body : false; -
src/AST/Type.hpp
rb9537e6 rf7e4f8e8 302 302 class FunctionType final : public ParameterizedType { 303 303 public: 304 // std::vector<ptr<DeclWithType>> returns;305 // std::vector<ptr<DeclWithType>> params;306 307 304 std::vector<ptr<Type>> returns; 308 305 std::vector<ptr<Type>> params; … … 345 342 : ParameterizedType(q, std::move(as)), params(), name(n) {} 346 343 344 BaseInstType( 345 const std::string& n, std::vector<ptr<Expr>> && params, 346 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 347 : ParameterizedType(q, std::move(as)), params(std::move(params)), name(n) {} 348 347 349 BaseInstType( const BaseInstType & o ); 348 350 … … 369 371 370 372 SueInstType( 371 const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 373 const base_type * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 374 375 SueInstType( 376 const base_type * b, std::vector<ptr<Expr>> && params, 377 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 372 378 373 379 bool isComplete() const override; -
src/AST/porting.md
rb9537e6 rf7e4f8e8 30 30 * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0` 31 31 * `PassVisitor` is replaced with `ast::Pass` 32 * Most one shot uses can use `ast::Pass::run` and `ast::Pass::read`. 33 34 `WithConstTypeSubstitution` 35 * `env` => `typeSubs` 32 36 33 37 ## Structural Changes ## … … 146 150 * allows `newObject` as just default settings 147 151 152 `FunctionDecl` 153 * `params` and `returns` added. 154 * Contain the declarations of the parameters and return variables. 155 * Types should match (even be shared with) the fields of `type`. 156 148 157 `NamedTypeDecl` 149 158 * `parameters` => `params` … … 154 163 `AggregateDecl` 155 164 * `parameters` => `params` 165 166 `StructDecl` 167 * `makeInst` replaced by better constructor on `StructInstType`. 156 168 157 169 `Expr` … … 245 257 * **TODO** move `kind`, `typeNames` into code generator 246 258 247 `ReferenceToType` 259 `ReferenceToType` => `BaseInstType` 248 260 * deleted `get_baseParameters()` from children 249 261 * replace with `aggr() ? aggr()->params : nullptr` … … 261 273 * `returnVals` => `returns` 262 274 * `parameters` => `params` 275 * Both now just point at types. 263 276 * `bool isVarArgs;` => `enum ArgumentFlag { FixedArgs, VariableArgs }; ArgumentFlag isVarArgs;` 277 278 `SueInstType` 279 * Template class, with specializations and using to implement some other types: 280 * `StructInstType`, `UnionInstType` & `EnumInstType` 264 281 265 282 `TypeInstType` -
src/Common/PassVisitor.h
rb9537e6 rf7e4f8e8 354 354 virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final; 355 355 356 bool isInFunction() const { 357 return inFunction; 358 } 359 356 360 private: 357 361 bool inFunction = false; 362 bool atFunctionTop = false; 358 363 359 364 template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); … … 526 531 public: 527 532 PassVisitor<pass_type> * const visitor = nullptr; 533 534 bool isInFunction() const { 535 return visitor->isInFunction(); 536 } 528 537 }; 529 538 -
src/Common/PassVisitor.impl.h
rb9537e6 rf7e4f8e8 532 532 indexerAddId( &func ); 533 533 maybeAccept_impl( node->type, *this ); 534 // function body needs to have the same scope as parameters - CompoundStmt will not enter 535 // a new scope if inFunction is true 534 // First remember that we are now within a function. 536 535 ValueGuard< bool > oldInFunction( inFunction ); 537 536 inFunction = true; 537 // The function body needs to have the same scope as parameters. 538 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 539 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 540 atFunctionTop = true; 538 541 maybeAccept_impl( node->statements, *this ); 539 542 maybeAccept_impl( node->attributes, *this ); … … 567 570 indexerAddId( &func ); 568 571 maybeAccept_impl( node->type, *this ); 569 // function body needs to have the same scope as parameters - CompoundStmt will not enter 570 // a new scope if inFunction is true 572 // First remember that we are now within a function. 571 573 ValueGuard< bool > oldInFunction( inFunction ); 572 574 inFunction = true; 575 // The function body needs to have the same scope as parameters. 576 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 577 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 578 atFunctionTop = true; 573 579 maybeAccept_impl( node->statements, *this ); 574 580 maybeAccept_impl( node->attributes, *this ); … … 601 607 indexerAddId( &func ); 602 608 maybeMutate_impl( node->type, *this ); 603 // function body needs to have the same scope as parameters - CompoundStmt will not enter 604 // a new scope if inFunction is true 609 // First remember that we are now within a function. 605 610 ValueGuard< bool > oldInFunction( inFunction ); 606 611 inFunction = true; 612 // The function body needs to have the same scope as parameters. 613 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 614 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 615 atFunctionTop = true; 607 616 maybeMutate_impl( node->statements, *this ); 608 617 maybeMutate_impl( node->attributes, *this ); … … 1007 1016 VISIT_START( node ); 1008 1017 { 1009 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1010 ValueGuard< bool > old InFunction( inFunction);1011 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1018 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1019 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1020 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1012 1021 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1013 inFunction= false;1022 atFunctionTop = false; 1014 1023 visitStatementList( node->kids ); 1015 1024 } … … 1021 1030 VISIT_START( node ); 1022 1031 { 1023 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1024 ValueGuard< bool > old InFunction( inFunction);1025 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1032 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1033 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1034 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1026 1035 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1027 inFunction= false;1036 atFunctionTop = false; 1028 1037 visitStatementList( node->kids ); 1029 1038 } … … 1035 1044 MUTATE_START( node ); 1036 1045 { 1037 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1038 ValueGuard< bool > old InFunction( inFunction);1039 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1046 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1047 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1048 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1040 1049 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1041 inFunction= false;1050 atFunctionTop = false; 1042 1051 mutateStatementList( node->kids ); 1043 1052 } -
src/Common/utility.h
rb9537e6 rf7e4f8e8 360 360 reverse_iterate_t( T & ref ) : ref(ref) {} 361 361 362 typedef typename T::reverse_iterator iterator; 363 iterator begin() { return ref.rbegin(); } 364 iterator end() { return ref.rend(); } 362 // this does NOT work on const T!!! 363 // typedef typename T::reverse_iterator iterator; 364 auto begin() { return ref.rbegin(); } 365 auto end() { return ref.rend(); } 365 366 }; 366 367 -
src/Concurrency/Keywords.cc
rb9537e6 rf7e4f8e8 46 46 } 47 47 48 // Only detects threads constructed with the keyword thread. 49 inline static bool isThread( DeclarationWithType * decl ) { 50 Type * baseType = decl->get_type()->stripDeclarator(); 51 StructInstType * instType = dynamic_cast<StructInstType *>( baseType ); 52 if ( nullptr == instType ) { return false; } 53 return instType->baseStruct->is_thread(); 54 } 55 48 56 //============================================================================================= 49 57 // Pass declarations … … 119 127 "get_thread", 120 128 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n", 121 " ",129 "ThreadCancelled", 122 130 true, 123 131 AggregateDecl::Thread … … 290 298 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first ); 291 299 void validate( DeclarationWithType * ); 292 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 293 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 300 void addDtorStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 301 void addStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 302 void addThreadDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ); 294 303 295 304 static void implement( std::list< Declaration * > & translationUnit ) { … … 302 311 StructDecl* guard_decl = nullptr; 303 312 StructDecl* dtor_guard_decl = nullptr; 313 StructDecl* thread_guard_decl = nullptr; 304 314 305 315 static std::unique_ptr< Type > generic_func; … … 801 811 bool first = false; 802 812 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first ); 803 bool isDtor = CodeGen::isDestructor( decl->name );813 bool const isDtor = CodeGen::isDestructor( decl->name ); 804 814 805 815 // Is this function relevant to monitors … … 849 859 850 860 // Instrument the body 851 if( isDtor ) { 852 addDtorStatments( decl, body, mutexArgs ); 861 if ( isDtor && isThread( mutexArgs.front() ) ) { 862 if( !thread_guard_decl ) { 863 SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" ); 864 } 865 addThreadDtorStatements( decl, body, mutexArgs ); 866 } 867 else if ( isDtor ) { 868 addDtorStatements( decl, body, mutexArgs ); 853 869 } 854 870 else { 855 addStat ments( decl, body, mutexArgs );871 addStatements( decl, body, mutexArgs ); 856 872 } 857 873 } … … 870 886 assert( !dtor_guard_decl ); 871 887 dtor_guard_decl = decl; 888 } 889 else if( decl->name == "thread_dtor_guard_t" && decl->body ) { 890 assert( !thread_guard_decl ); 891 thread_guard_decl = decl; 872 892 } 873 893 } … … 908 928 } 909 929 910 void MutexKeyword::addDtorStat ments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {930 void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 911 931 Type * arg_type = args.front()->get_type()->clone(); 912 932 arg_type->set_mutex( false ); … … 957 977 958 978 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) }; 959 body->push_front( new DeclStmt( monitors) ); 960 } 961 962 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 979 body->push_front( new DeclStmt( monitors ) ); 980 } 981 982 void MutexKeyword::addThreadDtorStatements( 983 FunctionDecl*, CompoundStmt * body, 984 const std::list<DeclarationWithType * > & args ) { 985 assert( args.size() == 1 ); 986 DeclarationWithType * arg = args.front(); 987 Type * arg_type = arg->get_type()->clone(); 988 assert( arg_type->get_mutex() ); 989 arg_type->set_mutex( false ); 990 991 // thread_dtor_guard_t __guard = { this, intptr( 0 ) }; 992 body->push_front( 993 new DeclStmt( new ObjectDecl( 994 "__guard", 995 noStorageClasses, 996 LinkageSpec::Cforall, 997 nullptr, 998 new StructInstType( 999 noQualifiers, 1000 thread_guard_decl 1001 ), 1002 new ListInit( 1003 { 1004 new SingleInit( new CastExpr( new VariableExpr( arg ), arg_type ) ), 1005 new SingleInit( new UntypedExpr( 1006 new NameExpr( "intptr" ), { 1007 new ConstantExpr( Constant::from_int( 0 ) ), 1008 } 1009 ) ), 1010 }, 1011 noDesignators, 1012 true 1013 ) 1014 )) 1015 ); 1016 } 1017 1018 void MutexKeyword::addStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 963 1019 ObjectDecl * monitors = new ObjectDecl( 964 1020 "__monitors", -
src/GenPoly/GenPoly.cc
rb9537e6 rf7e4f8e8 46 46 } 47 47 48 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) { 49 for (auto ¶m : params) { 50 auto paramType = param.strict_as<ast::TypeExpr>(); 51 if (isPolyType(paramType->type, env)) return true; 52 } 53 return false; 54 } 55 48 56 /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present 49 57 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 56 64 } 57 65 66 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) { 67 for (auto ¶m : params) { 68 auto paramType = param.strict_as<ast::TypeExpr>(); 69 if (isPolyType(paramType->type, tyVars, env)) return true; 70 } 71 return false; 72 } 73 58 74 /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present 59 75 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 92 108 Type *newType = env->lookup( typeInst->get_name() ); 93 109 if ( newType ) return newType; 110 } 111 return type; 112 } 113 114 const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) { 115 if (!env) return type; 116 if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) { 117 auto newType = env->lookup(typeInst->name); 118 if (newType) return newType; 94 119 } 95 120 return type; … … 111 136 } 112 137 138 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env) { 139 type = replaceTypeInst( type, env ); 140 141 if ( dynamic_cast< const ast::TypeInstType * >( type ) ) { 142 return type; 143 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 144 return isPolyType( arrayType->base, env ); 145 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { 146 if ( hasPolyParams( structType->params, env ) ) return type; 147 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { 148 if ( hasPolyParams( unionType->params, env ) ) return type; 149 } 150 return 0; 151 } 152 113 153 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 114 154 type = replaceTypeInst( type, env ); … … 126 166 } 127 167 return 0; 168 } 169 170 const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env) { 171 type = replaceTypeInst( type, env ); 172 173 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) { 174 return tyVars.find(typeInst->name) != tyVars.end() ? type : nullptr; 175 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 176 return isPolyType( arrayType->base, env ); 177 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { 178 if ( hasPolyParams( structType->params, env ) ) return type; 179 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { 180 if ( hasPolyParams( unionType->params, env ) ) return type; 181 } 182 return nullptr; 128 183 } 129 184 … … 449 504 } 450 505 506 namespace { 507 // temporary hack to avoid re-implementing anything related to TyVarMap 508 // does this work? these two structs have identical definitions. 509 inline TypeDecl::Data convData(const ast::TypeDecl::Data & data) { 510 return *reinterpret_cast<const TypeDecl::Data *>(&data); 511 } 512 } 513 451 514 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) { 452 515 // is parameter is not polymorphic, don't need to box … … 459 522 } 460 523 524 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env) { 525 // is parameter is not polymorphic, don't need to box 526 if ( ! isPolyType( param, exprTyVars ) ) return false; 527 ast::ptr<ast::Type> newType = arg; 528 if ( env ) env->apply( newType ); 529 // if the argument's type is polymorphic, we don't need to box again! 530 return ! isPolyType( newType ); 531 } 532 461 533 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) { 462 534 FunctionType * function = getFunctionType( appExpr->function->result ); … … 467 539 } 468 540 541 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env) { 542 const ast::FunctionType * function = getFunctionType(appExpr->func->result); 543 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->func->result ).c_str() ); 544 TyVarMap exprTyVars(TypeDecl::Data{}); 545 makeTyVarMap(function, exprTyVars); 546 return needsBoxing(param, arg, exprTyVars, env); 547 548 } 549 469 550 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) { 470 551 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } ); 552 } 553 554 void addToTyVarMap( const ast::TypeDecl * tyVar, TyVarMap & tyVarMap) { 555 tyVarMap.insert(tyVar->name, convData(ast::TypeDecl::Data{tyVar})); 471 556 } 472 557 … … 478 563 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) { 479 564 makeTyVarMap( pointer->get_base(), tyVarMap ); 565 } 566 } 567 568 void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) { 569 if (auto ptype = dynamic_cast<const ast::ParameterizedType *>(type)) { 570 for (auto & tyVar : ptype->forall) { 571 assert (tyVar); 572 addToTyVarMap(tyVar, tyVarMap); 573 } 574 } 575 if (auto pointer = dynamic_cast<const ast::PointerType *>(type)) { 576 makeTyVarMap(pointer->base, tyVarMap); 480 577 } 481 578 } -
src/GenPoly/GenPoly.h
rb9537e6 rf7e4f8e8 26 26 27 27 namespace GenPoly { 28 28 29 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap; 29 30 30 /// Replaces a TypeInstType by its referrent in the environment, if applicable 31 31 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ); … … 33 33 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided 34 34 Type *isPolyType( Type *type, const TypeSubstitution *env = 0 ); 35 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr); 35 36 36 37 /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 37 38 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 ); 39 const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env = nullptr); 38 40 39 41 /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided … … 84 86 /// true if arg requires boxing given exprTyVars 85 87 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ); 88 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env); 86 89 87 90 /// true if arg requires boxing in the call to appExpr 88 91 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ); 92 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env); 89 93 90 94 /// Adds the type variable `tyVar` to `tyVarMap` … … 93 97 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 94 98 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ); 99 void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap); 95 100 96 101 /// Prints type variable map -
src/GenPoly/Specialize.cc
rb9537e6 rf7e4f8e8 218 218 thunkFunc->get_attributes().push_back( new Attribute( "unused" ) ); 219 219 220 // Thunks at the global level must be static to avoid collisions between files. 221 // (Conversly thunks inside a function must be unique and not static.) 222 thunkFunc->storageClasses.is_static = !isInFunction(); 223 220 224 // thread thunk parameters into call to actual function, naming thunk parameters as we go 221 225 UniqueName paramNamer( paramPrefix ); -
src/InitTweak/FixGlobalInit.cc
rb9537e6 rf7e4f8e8 34 34 #include "SynTree/Visitor.h" // for acceptAll, Visitor 35 35 36 #include "AST/Expr.hpp" 37 #include "AST/Node.hpp" 38 #include "AST/Pass.hpp" 39 36 40 namespace InitTweak { 37 41 class GlobalFixer : public WithShortCircuiting { … … 50 54 FunctionDecl * initFunction; 51 55 FunctionDecl * destroyFunction; 56 }; 57 58 class GlobalFixer_new : public ast::WithShortCircuiting { 59 public: 60 void previsit (const ast::ObjectDecl *); 61 void previsit (const ast::FunctionDecl *) { visit_children = false; } 62 void previsit (const ast::StructDecl *) { visit_children = false; } 63 void previsit (const ast::UnionDecl *) { visit_children = false; } 64 void previsit (const ast::EnumDecl *) { visit_children = false; } 65 void previsit (const ast::TraitDecl *) { visit_children = false; } 66 void previsit (const ast::TypeDecl *) { visit_children = false; } 67 68 std::list< ast::ptr<ast::Stmt> > initStmts; 69 std::list< ast::ptr<ast::Stmt> > destroyStmts; 52 70 }; 53 71 … … 91 109 } 92 110 111 void fixGlobalInit(std::list<ast::ptr<ast::Decl>> & translationUnit, bool inLibrary) { 112 ast::Pass<GlobalFixer_new> fixer; 113 accept_all(translationUnit, fixer); 114 115 if ( !fixer.core.initStmts.empty() ) { 116 std::vector<ast::ptr<ast::Expr>> ctorParams; 117 if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int({}, 200)); 118 auto initFunction = new ast::FunctionDecl({}, "__global_init__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.initStmts)), 119 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("constructor", std::move(ctorParams))}); 120 121 translationUnit.emplace_back( initFunction ); 122 } // if 123 124 if ( !fixer.core.destroyStmts.empty() ) { 125 std::vector<ast::ptr<ast::Expr>> dtorParams; 126 if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int({}, 200)); 127 auto destroyFunction = new ast::FunctionDecl({}, "__global_destroy__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.destroyStmts)), 128 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("destructor", std::move(dtorParams))}); 129 130 translationUnit.emplace_back(destroyFunction); 131 } // if 132 } 133 93 134 void GlobalFixer::previsit( ObjectDecl *objDecl ) { 94 135 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids(); … … 112 153 } // if 113 154 if ( Statement * ctor = ctorInit->ctor ) { 114 // Translation 1: Add this attribute on the global declaration: 115 // __attribute__((section (".data#"))) 116 // which makes gcc put the global in the data section, 117 // so that the global is writeable (via a const cast) in the init function. 118 // The trailing # is an injected assembly comment, to suppress the "a" in 119 // .section .data,"a" 120 // .section .data#,"a" 121 // to avoid assembler warning "ignoring changed section attributes for .data" 122 Type *strLitT = new PointerType( Type::Qualifiers( ), 123 new BasicType( Type::Qualifiers( ), BasicType::Char ) ); 124 std::list< Expression * > attr_params; 125 attr_params.push_back( 126 new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) ); 127 objDecl->attributes.push_back(new Attribute("section", attr_params)); 128 // Translation 2: Move the initizliation off the global declaration, 129 // into the startup function. 155 addDataSectonAttribute( objDecl ); 130 156 initStatements.push_back( ctor ); 131 157 objDecl->init = nullptr; … … 142 168 } 143 169 170 void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) { 171 auto mutDecl = mutate(objDecl); 172 assertf(mutDecl == objDecl, "Global object decl must be unique"); 173 if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) { 174 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 175 assert( ! ctorInit->ctor || ! ctorInit->init ); 176 177 const ast::Stmt * dtor = ctorInit->dtor; 178 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 179 // don't need to call intrinsic dtor, because it does nothing, but 180 // non-intrinsic dtors must be called 181 destroyStmts.push_front( dtor ); 182 // ctorInit->dtor = nullptr; 183 } // if 184 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 185 initStmts.push_back( ctor ); 186 mutDecl->init = nullptr; 187 // ctorInit->ctor = nullptr; 188 } else if ( const ast::Init * init = ctorInit->init ) { 189 mutDecl->init = init; 190 // ctorInit->init = nullptr; 191 } else { 192 // no constructor and no initializer, which is okay 193 mutDecl->init = nullptr; 194 } // if 195 // delete ctorInit; 196 } // if 197 } 198 144 199 // only modify global variables 145 200 void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; } -
src/InitTweak/FixGlobalInit.h
rb9537e6 rf7e4f8e8 19 19 #include <string> // for string 20 20 21 #include <AST/Fwd.hpp> 22 23 21 24 class Declaration; 22 25 … … 26 29 /// function is for library code. 27 30 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ); 31 void fixGlobalInit( std::list< ast::ptr<ast::Decl> > & translationUnit, bool inLibrary ); 28 32 } // namespace 29 33 -
src/InitTweak/FixInit.cc
rb9537e6 rf7e4f8e8 219 219 }; 220 220 221 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution,public WithStmtsToAdd {221 struct SplitExpressions : public WithShortCircuiting, /*public WithTypeSubstitution, */public WithStmtsToAdd { 222 222 /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places. 223 223 static void split( std::list< Declaration * > &translationUnit ); … … 802 802 if ( Statement * ctor = ctorInit->get_ctor() ) { 803 803 if ( objDecl->get_storageClasses().is_static ) { 804 805 // The ojbect needs to go in the data section, regardless of dtor complexity below. 806 // The attribute works, and is meant to apply, both for leaving the static local alone, 807 // and for hoisting it out as a static global. 808 addDataSectonAttribute( objDecl ); 809 804 810 // originally wanted to take advantage of gcc nested functions, but 805 811 // we get memory errors with this approach. To remedy this, the static -
src/InitTweak/FixInit.h
rb9537e6 rf7e4f8e8 19 19 #include <string> // for string 20 20 21 #include <AST/Fwd.hpp> 22 21 23 class Declaration; 22 24 … … 24 26 /// replace constructor initializers with expression statements and unwrap basic C-style initializers 25 27 void fix( std::list< Declaration * > & translationUnit, bool inLibrary ); 28 29 void fix( std::list<ast::ptr<ast::Decl>> & translationUnit, bool inLibrary); 26 30 } // namespace 27 31 -
src/InitTweak/GenInit.cc
rb9537e6 rf7e4f8e8 283 283 assert( stmts.size() <= 1 ); 284 284 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr; 285 286 } 287 288 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 289 assertf(objDecl, "genCtorDtor passed null objDecl"); 290 InitExpander_new srcParam(arg); 291 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 285 292 } 286 293 -
src/InitTweak/GenInit.h
rb9537e6 rf7e4f8e8 33 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 34 34 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr ); 35 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 35 36 36 37 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer -
src/InitTweak/InitTweak.cc
rb9537e6 rf7e4f8e8 498 498 } 499 499 500 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 501 assertf( func, "getParamThis: nullptr ftype" ); 502 auto & params = func->params; 503 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 504 return params.front().strict_as<ast::ObjectDecl>(); 505 } 506 500 507 bool tryConstruct( DeclarationWithType * dwt ) { 501 508 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt ); … … 511 518 } 512 519 520 bool tryConstruct( const ast::DeclWithType * dwt ) { 521 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt ); 522 if ( ! objDecl ) return false; 523 return (objDecl->init == nullptr || 524 ( objDecl->init != nullptr && objDecl->init->maybeConstructed )) 525 && ! objDecl->storage.is_extern 526 && isConstructable( objDecl->type ); 527 } 528 529 bool isConstructable( const ast::Type * type ) { 530 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type ) 531 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type ); 532 } 533 513 534 struct CallFinder_old { 514 535 CallFinder_old( const std::list< std::string > & names ) : names( names ) {} … … 536 557 537 558 struct CallFinder_new final { 538 std::vector< ast::ptr< ast::Expr >> matches;559 std::vector< const ast::Expr * > matches; 539 560 const std::vector< std::string > names; 540 561 … … 558 579 } 559 580 560 std::vector< ast::ptr< ast::Expr >> collectCtorDtorCalls( const ast::Stmt * stmt ) {581 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 561 582 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 562 583 maybe_accept( stmt, finder ); … … 696 717 template <typename Predicate> 697 718 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { 698 std::vector< ast::ptr< ast::Expr >> callExprs = collectCtorDtorCalls( stmt );719 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt ); 699 720 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 700 721 } … … 939 960 } 940 961 962 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards 963 // following passes may accidentally resolve this expression if returned as untyped... 964 ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) { 965 static ast::ptr<ast::FunctionDecl> assign = nullptr; 966 if (!assign) { 967 auto td = new ast::TypeDecl({}, "T", {}, nullptr, ast::TypeDecl::Dtype, true); 968 assign = new ast::FunctionDecl({}, "?=?", {}, 969 { new ast::ObjectDecl({}, "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 970 new ast::ObjectDecl({}, "_src", new ast::TypeInstType("T", td))}, 971 { new ast::ObjectDecl({}, "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic); 972 } 973 if (dst->result.as<ast::ReferenceType>()) { 974 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 975 dst = new ast::AddressExpr(dst); 976 } 977 } 978 else { 979 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 980 } 981 if (src->result.as<ast::ReferenceType>()) { 982 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 983 src = new ast::AddressExpr(src); 984 } 985 } 986 return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src}); 987 } 988 941 989 struct ConstExprChecker : public WithShortCircuiting { 942 990 // most expressions are not const expr … … 1055 1103 return isCopyFunction( decl, "?{}" ); 1056 1104 } 1105 1106 void addDataSectonAttribute( ObjectDecl * objDecl ) { 1107 Type *strLitT = new PointerType( Type::Qualifiers( ), 1108 new BasicType( Type::Qualifiers( ), BasicType::Char ) ); 1109 std::list< Expression * > attr_params; 1110 attr_params.push_back( 1111 new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) ); 1112 objDecl->attributes.push_back(new Attribute("section", attr_params)); 1113 } 1114 1057 1115 } -
src/InitTweak/InitTweak.h
rb9537e6 rf7e4f8e8 38 38 /// returns the first parameter of a constructor/destructor/assignment function 39 39 ObjectDecl * getParamThis( FunctionType * ftype ); 40 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 40 41 41 42 /// generate a bitwise assignment operation. 42 43 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ); 44 45 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 43 46 44 47 /// transform Initializer into an argument list that can be passed to a call expression … … 48 51 /// True if the resolver should try to construct dwt 49 52 bool tryConstruct( DeclarationWithType * dwt ); 53 bool tryConstruct( const ast::DeclWithType * dwt ); 50 54 51 55 /// True if the type can have a user-defined constructor 52 56 bool isConstructable( Type * t ); 57 bool isConstructable( const ast::Type * t ); 53 58 54 59 /// True if the Initializer contains designations … … 79 84 /// get all Ctor/Dtor call expressions from a Statement 80 85 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ); 81 std::vector< ast::ptr< ast::Expr >> collectCtorDtorCalls( const ast::Stmt * stmt );86 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 82 87 83 88 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call … … 102 107 bool isConstExpr( Expression * expr ); 103 108 bool isConstExpr( Initializer * init ); 109 110 /// Modifies objDecl to have: 111 /// __attribute__((section (".data#"))) 112 /// which makes gcc put the declared variable in the data section, 113 /// which is helpful for global constants on newer gcc versions, 114 /// so that CFA's generated initialization won't segfault when writing it via a const cast. 115 /// The trailing # is an injected assembly comment, to suppress the "a" in 116 /// .section .data,"a" 117 /// .section .data#,"a" 118 /// to avoid assembler warning "ignoring changed section attributes for .data" 119 void addDataSectonAttribute( ObjectDecl * objDecl ); 104 120 105 121 class InitExpander_old { -
src/InitTweak/module.mk
rb9537e6 rf7e4f8e8 23 23 InitTweak/GenInit.h \ 24 24 InitTweak/InitTweak.cc \ 25 InitTweak/InitTweak.h 25 InitTweak/InitTweak.h \ 26 InitTweak/FixInitNew.cpp 26 27 27 28 SRCDEMANGLE += \ -
src/Parser/ParseNode.h
rb9537e6 rf7e4f8e8 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jul 6 09:33:32202013 // Update Count : 89 212 // Last Modified On : Sat Oct 24 03:53:54 2020 13 // Update Count : 895 14 14 // 15 15 … … 205 205 struct TypeData; 206 206 207 class DeclarationNode : public ParseNode { 208 public: 207 struct DeclarationNode : public ParseNode { 209 208 // These enumerations must harmonize with their names in DeclarationNode.cc. 210 209 enum BasicType { Void, Bool, Char, Int, Int128, … … 304 303 bool get_inLine() const { return inLine; } 305 304 DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; } 306 public: 305 307 306 DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); } 308 307 … … 360 359 //############################################################################## 361 360 362 class StatementNode final : public ParseNode { 363 public: 361 struct StatementNode final : public ParseNode { 364 362 StatementNode() { stmt = nullptr; } 365 363 StatementNode( Statement * stmt ) : stmt( stmt ) {} … … 382 380 os << stmt.get() << std::endl; 383 381 } 384 private: 382 385 383 std::unique_ptr<Statement> stmt; 386 384 }; // StatementNode … … 426 424 Statement * build_finally( StatementNode * stmt ); 427 425 Statement * build_compound( StatementNode * first ); 426 StatementNode * maybe_build_compound( StatementNode * first ); 428 427 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr ); 429 428 Statement * build_directive( std::string * directive ); -
src/Parser/StatementNode.cc
rb9537e6 rf7e4f8e8 10 10 // Created On : Sat May 16 14:59:41 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 4 09:39:25 201813 // Update Count : 3 6312 // Last Modified On : Sat Oct 24 04:20:55 2020 13 // Update Count : 383 14 14 // 15 15 … … 345 345 } // build_compound 346 346 347 // A single statement in a control structure is always converted to a compound statement so subsequent generated code 348 // can be placed within this compound statement. Otherwise, code generation has to constantly check for a single 349 // statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a 350 // conical form for code generation. 351 StatementNode * maybe_build_compound( StatementNode * first ) { 352 // Optimization: if the control-structure statement is a compound statement, do not wrap it. 353 // e.g., if (...) {...} do not wrap the existing compound statement. 354 if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr 355 CompoundStmt * cs = new CompoundStmt(); 356 buildMoveList( first, cs->get_kids() ); 357 return new StatementNode( cs ); 358 } // if 359 return first; 360 } // maybe_build_compound 361 347 362 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { 348 363 std::list< Expression * > out, in; -
src/Parser/parser.yy
rb9537e6 rf7e4f8e8 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Oct 9 18:09:09202013 // Update Count : 46 1412 // Last Modified On : Sat Oct 24 08:21:14 2020 13 // Update Count : 4624 14 14 // 15 15 … … 1080 1080 IF '(' if_control_expression ')' statement %prec THEN 1081 1081 // explicitly deal with the shift/reduce conflict on if/else 1082 { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }1082 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); } 1083 1083 | IF '(' if_control_expression ')' statement ELSE statement 1084 { $$ = new StatementNode( build_if( $3, $5, $7) ); }1084 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); } 1085 1085 ; 1086 1086 … … 1130 1130 1131 1131 case_clause: // CFA 1132 case_label_list statement { $$ = $1->append_last_case( new StatementNode( build_compound( $2 )) ); }1132 case_label_list statement { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); } 1133 1133 ; 1134 1134 … … 1148 1148 iteration_statement: 1149 1149 WHILE '(' push if_control_expression ')' statement pop 1150 { $$ = new StatementNode( build_while( $4, $6) ); }1150 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); } 1151 1151 | WHILE '(' ')' statement // CFA => while ( 1 ) 1152 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), $4) ); }1152 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1153 1153 | DO statement WHILE '(' comma_expression ')' ';' 1154 { $$ = new StatementNode( build_do_while( $5, $2) ); }1154 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1155 1155 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1156 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2) ); }1156 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); } 1157 1157 | FOR '(' push for_control_expression_list ')' statement pop 1158 { $$ = new StatementNode( build_for( $4, $6) ); }1158 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); } 1159 1159 | FOR '(' ')' statement // CFA => for ( ;; ) 1160 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), $4) ); }1160 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); } 1161 1161 ; 1162 1162 … … 1341 1341 waitfor_clause: 1342 1342 when_clause_opt waitfor statement %prec THEN 1343 { $$ = build_waitfor( $2, $3, $1 ); }1343 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); } 1344 1344 | when_clause_opt waitfor statement WOR waitfor_clause 1345 { $$ = build_waitfor( $2, $3, $1, $5 ); }1345 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); } 1346 1346 | when_clause_opt timeout statement %prec THEN 1347 { $$ = build_waitfor_timeout( $2, $3, $1 ); }1347 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); } 1348 1348 | when_clause_opt ELSE statement 1349 { $$ = build_waitfor_timeout( nullptr, $3, $1 ); }1349 { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); } 1350 1350 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1351 1351 | when_clause_opt timeout statement WOR ELSE statement 1352 1352 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1353 1353 | when_clause_opt timeout statement WOR when_clause ELSE statement 1354 { $$ = build_waitfor_timeout( $2, $3, $1, $7, $5 ); }1354 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); } 1355 1355 ; 1356 1356 -
src/ResolvExpr/Resolver.cc
rb9537e6 rf7e4f8e8 1105 1105 } 1106 1106 1107 /// Establish post-resolver invariants for expressions 1107 1108 } // anonymous namespace 1109 /// Establish post-resolver invariants for expressions 1108 1110 void finishExpr( 1109 1111 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, … … 1118 1120 StripCasts_new::strip( expr ); 1119 1121 } 1120 } // anonymous namespace1121 1122 1122 1123 1123 ast::ptr< ast::Expr > resolveInVoidContext( … … 1139 1139 } 1140 1140 1141 namespace { 1142 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1141 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1143 1142 /// context. 1144 1143 ast::ptr< ast::Expr > findVoidExpression( … … 1151 1150 return newExpr; 1152 1151 } 1152 1153 namespace { 1154 1153 1155 1154 1156 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the … … 1162 1164 CandidateRef choice = 1163 1165 findUnfinishedKindExpression( untyped, symtab, kind, pred, mode ); 1164 finishExpr( choice->expr, choice->env, untyped->env );1166 ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env ); 1165 1167 return std::move( choice->expr ); 1166 1168 } -
src/ResolvExpr/Resolver.h
rb9537e6 rf7e4f8e8 66 66 ast::ptr< ast::Expr > findSingleExpression( 67 67 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab ); 68 ast::ptr< ast::Expr > findVoidExpression( 69 const ast::Expr * untyped, const ast::SymbolTable & symtab); 68 70 /// Resolves a constructor init expression 69 71 ast::ptr< ast::Init > resolveCtorInit( -
src/SymTab/Autogen.cc
rb9537e6 rf7e4f8e8 233 233 } 234 234 235 // shallow copy the pointer list for return 236 std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) { 237 if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) { 238 return structInst->base->params; 239 } 240 if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) { 241 return unionInst->base->params; 242 } 243 return {}; 244 } 245 235 246 /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *) 236 247 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) { … … 244 255 ftype->parameters.push_back( dstParam ); 245 256 return ftype; 257 } 258 259 /// 260 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) { 261 std::vector<ast::ptr<ast::TypeDecl>> typeParams; 262 if (maybePolymorphic) typeParams = getGenericParams(paramType); 263 auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall); 264 return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc)); 246 265 } 247 266 -
src/SymTab/Autogen.h
rb9537e6 rf7e4f8e8 55 55 /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic 56 56 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true ); 57 58 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true); 57 59 58 60 /// generate the type of a copy constructor for paramType. -
src/SynTree/Expression.h
rb9537e6 rf7e4f8e8 163 163 }; 164 164 165 /// VariableExpr represents an expression that simply refers to the value of a named variable. 166 /// Does not take ownership of var. 167 class VariableExpr : public Expression { 168 public: 169 DeclarationWithType * var; 170 171 VariableExpr(); 172 VariableExpr( DeclarationWithType * var ); 173 VariableExpr( const VariableExpr & other ); 174 virtual ~VariableExpr(); 175 176 bool get_lvalue() const final; 177 178 DeclarationWithType * get_var() const { return var; } 179 void set_var( DeclarationWithType * newValue ) { var = newValue; } 180 181 static VariableExpr * functionPointer( FunctionDecl * decl ); 182 183 virtual VariableExpr * clone() const override { return new VariableExpr( * this ); } 184 virtual void accept( Visitor & v ) override { v.visit( this ); } 185 virtual void accept( Visitor & v ) const override { v.visit( this ); } 186 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 187 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 188 }; 189 165 190 // The following classes are used to represent expression types that cannot be converted into 166 191 // function-call format. … … 329 354 }; 330 355 331 /// VariableExpr represents an expression that simply refers to the value of a named variable.332 /// Does not take ownership of var.333 class VariableExpr : public Expression {334 public:335 DeclarationWithType * var;336 337 VariableExpr();338 VariableExpr( DeclarationWithType * var );339 VariableExpr( const VariableExpr & other );340 virtual ~VariableExpr();341 342 bool get_lvalue() const final;343 344 DeclarationWithType * get_var() const { return var; }345 void set_var( DeclarationWithType * newValue ) { var = newValue; }346 347 static VariableExpr * functionPointer( FunctionDecl * decl );348 349 virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }350 virtual void accept( Visitor & v ) override { v.visit( this ); }351 virtual void accept( Visitor & v ) const override { v.visit( this ); }352 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }353 virtual void print( std::ostream & os, Indenter indent = {} ) const override;354 };355 356 356 /// ConstantExpr represents an expression that simply refers to the value of a constant 357 357 class ConstantExpr : public Expression { -
src/main.cc
rb9537e6 rf7e4f8e8 343 343 auto transUnit = convert( move( translationUnit ) ); 344 344 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 345 if ( exprp ) { 346 translationUnit = convert( move( transUnit ) ); 347 dump( translationUnit ); 348 return EXIT_SUCCESS; 349 } // if 350 351 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary())); 345 352 translationUnit = convert( move( transUnit ) ); 346 353 } else { 347 354 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 355 if ( exprp ) { 356 dump( translationUnit ); 357 return EXIT_SUCCESS; 358 } 359 360 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) ); 348 361 } 349 362 350 if ( exprp ) {351 dump( translationUnit );352 return EXIT_SUCCESS;353 } // if354 355 363 // fix ObjectDecl - replaces ConstructorInit nodes 356 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );357 364 if ( ctorinitp ) { 358 365 dump ( translationUnit ); -
tests/.expect/const-init.txt
rb9537e6 rf7e4f8e8 1 done 1 almost done 2 dtor -
tests/complex.cfa
rb9537e6 rf7e4f8e8 14 14 // 15 15 16 #include <stdio.h>17 16 #include <complex.h> 18 17 #ifdef __CFA__ -
tests/const-init.cfa
rb9537e6 rf7e4f8e8 16 16 /* 17 17 18 Th is test shows non-crashing of generated code for constants with interesting initizers.18 These tests show non-crashing of generated code for constants with interesting initializers. 19 19 The potential for these to crash is compiler dependent. 20 20 21 21 There are two cases: 22 1. static constants in one compilation unit (tested here )22 1. static constants in one compilation unit (tested here, in a few sub-cases) 23 23 2. extern constants across compilation units (tested by libcfa being loadable, specifically 24 the constant de clarations in libcfa/src/limits.cfa, which almost every test exercises,24 the constant definitions in libcfa/src/limits.cfa, which almost every test exercises, 25 25 including "hello;" but notably, the "limits" test does not exercise it because that test 26 26 is compile-only) … … 37 37 GCC-10 on Ubuntu 20.04 Has crashed Has crashed 38 38 39 For this test caseto fail, with most other tests passing, would be a situation only ever39 For this test to fail, with most other tests passing, would be a situation only ever 40 40 observed with GCC-8. 41 41 42 42 */ 43 43 44 // initailized by generated function, called before main 44 45 static const char foo = -1; 45 46 47 struct thing{}; 48 void ^?{}( thing & ) { printf("dtor\n"); } 49 46 50 int main() { 47 printf("done\n"); 51 // foo is already initialized 52 53 // no dtor => stays a (static) local, initialized here 54 static const char bar = -1; 55 56 // has dtor => becomes a global, ctor called here, dtor called at exit 57 static const thing it; 58 59 printf("almost done\n"); 48 60 } -
tests/exceptions/cancel/coroutine.cfa
rb9537e6 rf7e4f8e8 1 1 // Try cancelling a coroutine. 2 2 3 #include <stdio.h>4 3 #include <coroutine.hfa> 5 4 #include <exception.hfa> -
tests/exceptions/conditional.cfa
rb9537e6 rf7e4f8e8 5 5 6 6 #include <exception.hfa> 7 #include <stdio.h>8 7 9 8 VTABLE_DECLARATION(num_error)( -
tests/exceptions/except-io.hfa
rb9537e6 rf7e4f8e8 1 1 // Common tools for the exception tests. 2 3 #include <stdio.h>4 2 5 3 // Echo when a destructor is run and an area/block is left. -
tests/exceptions/trash.cfa
rb9537e6 rf7e4f8e8 2 2 3 3 #include <exception.hfa> 4 #include <stdio.h>5 4 6 5 TRIVIAL_EXCEPTION(yin); -
tests/global-monomorph.cfa
rb9537e6 rf7e4f8e8 1 // Crea 2 3 #include <stdlib.hfa> 4 #include <stdio.h> 1 // Create monomorphic instances of polymorphic types at global scope. 5 2 6 3 forall(dtype T) -
tests/poly-d-cycle.cfa
rb9537e6 rf7e4f8e8 1 1 // Check that a cycle of polymorphic dtype structures can be instancated. 2 3 #include <stdio.h>4 2 5 3 forall(dtype T) -
tests/poly-o-cycle.cfa
rb9537e6 rf7e4f8e8 1 1 // Check that a cycle of polymorphic otype structures can be instancated. 2 3 #include <stdio.h>4 2 5 3 forall(otype T)
Note: See TracChangeset
for help on using the changeset viewer.