Changeset f7e4f8e8


Ignore:
Timestamp:
Oct 30, 2020, 12:36:16 PM (12 months ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
arm-eh, jacob/cs343-translation, master, new-ast-unique-expr
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.
Message:

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

Files:
10 added
71 edited

Legend:

Unmodified
Added
Removed
  • Jenkinsfile

    rb9537e6 rf7e4f8e8  
    127127                        }
    128128
    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}"
    130132
    131133                        // Configure libcfa
     
    359361        public final CC_Desc Compiler
    360362        public final Arch_Desc Architecture
     363        public final Boolean NewAST
    361364        public final Boolean RunAllTests
    362365        public final Boolean RunBenchmark
     
    410413
    411414                this.IsSandbox          = (branch == "jenkins-sandbox")
     415                this.NewAST             = param.NewAST
    412416                this.RunAllTests        = param.RunAllTests
    413417                this.RunBenchmark       = param.RunBenchmark
     
    470474                                ],                                                                                              \
    471475                                [$class: 'BooleanParameterDefinition',                                                  \
     476                                        description: 'If true, build compiler using new AST',           \
     477                                        name: 'NewAST',                                                                         \
     478                                        defaultValue: false,                                                            \
     479                                ],                                                                                              \
     480                                [$class: 'BooleanParameterDefinition',                                                  \
    472481                                        description: 'If false, only the quick test suite is ran',              \
    473482                                        name: 'RunAllTests',                                                            \
    474483                                        defaultValue: false,                                                            \
    475                                 ],                                                                                              \
     484                                ],
    476485                                [$class: 'BooleanParameterDefinition',                                                  \
    477486                                        description: 'If true, jenkins also runs benchmarks',           \
  • doc/papers/concurrency/mail2

    rb9537e6 rf7e4f8e8  
     1
    12Date: Wed, 26 Jun 2019 20:12:38 +0000
    23From: Aaron Thomas <onbehalfof@manuscriptcentral.com>
     
    10741075Software: Practice and Experience Editorial Office
    10751076
     1077
     1078
     1079Date: Thu, 15 Oct 2020 13:48:52 +0000
     1080From: Richard Jones <onbehalfof@manuscriptcentral.com>
     1081Reply-To: R.E.Jones@kent.ac.uk
     1082To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
     1083Subject: Software: Practice and Experience - Decision on Manuscript ID
     1084 SPE-19-0219.R3
     1085
     108615-Oct-2020
     1087
     1088Dear Dr Buhr,
     1089
     1090It 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
     1092Please 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
     1094Your 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
     1096Thank you for your fine contribution.
     1097
     1098Sincerely,
     1099Richard
     1100
     1101Prof. Richard Jones
     1102Editor, Software: Practice and Experience
     1103R.E.Jones@kent.ac.uk
     1104
     1105P.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
     1107This 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
     1111Date: Fri, 16 Oct 2020 12:44:42 +0000
     1112From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com>
     1113Reply-To: speoffice@wiley.com
     1114To: pabuhr@uwaterloo.ca
     1115Subject: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
     1116
     111716-Oct-2020
     1118
     1119Dear Dr. Buhr,
     1120
     1121Manuscript id: SPE-19-0219.R3
     1122Manuscript title: Advanced Control-flow and Concurrency in Cforall
     1123
     1124Although 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
     1126Any special instructions will be listed below:
     11271) Funding Information added in ScholorOne but missing in main document, Kindly add the Funding information in main document.
     11282) Please provide the clean version of the manuscript without any highlights or tracked changes.
     11293) Kindly check and make sure citations for all figures and Tables are present in the main document
     1130
     1131Please 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
     1133On 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
     1135Instructions for uploading replacement files:
     11361. On the "File Upload" step, click on the "edit" button for the file you wish to replace.
     11372. In the "Upload a later version" section, browse to locate the replacement final version.
     11383. Add any comments concerning the replacement (e.g. "high res image").
     11394. Select whether the new file is a minor or major version (we suggest you select minor version)
     11405. Click upload.
     11416. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful.
     1142
     1143Please submit your updates within the next 7 days to ensure there are no unnecessary delays in production.
     1144
     1145Sincerely,
     1146Software: Practice and Experience Editorial Office
     1147
     1148
     1149
     1150From: SPE Office <speoffice@wiley.com>
     1151To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
     1152Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
     1153Date: Mon, 19 Oct 2020 17:04:24 +0000
     1154
     1155Dear Dr. Buhr,
     1156
     1157Thank you very much for contacting the Editorial Office.
     1158
     1159I would like to let you know that the files has been found in order and moved to production.
     1160
     1161Plesae let me know for further assistance in this regard.
     1162
     1163Best Regards
     1164
     1165Mayank Roy Chowdhury
     1166Editorial Assistant
     1167Software practice and Experience
     1168________________________________
     1169From: Peter A. Buhr <pabuhr@uwaterloo.ca>
     1170Sent: Sunday, October 18, 2020 2:00 PM
     1171To: SPE Office <speoffice@wiley.com>
     1172Cc: Thierry Delisle <tdelisle@uwaterloo.ca>
     1173Subject: 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
     1187There was no "edit" button on the "File Upload" page, so I just upload the
     1188final version of the PDF and source files using the mechanism on the "File
     1189Upload" page and submitted that.
     1190
     1191
     1192
     1193Date: Tue, 20 Oct 2020 13:28:37 +0530
     1194To: "Dr. Peter Buhr" <pabuhr@uwaterloo.ca>
     1195From: jpcms@spi-global.com
     1196Subject: Information: Production Editor Contact Software:Practice and Experience  | Advanced Control-flow and Concurrency in C A
     1197
     1198Dear Dr. Peter Buhr,
     1199
     1200We 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
     1202Please get in touch with your Production Editor at SPEproofs@wiley.com;EllaMae.Navor@spi-global.com if you have any questions.
     1203               
     1204Sincerely,
     1205Booking-in Team,
     1206On behalf of Wiley
     1207
     1208Article ID: SPE_2925
     1209Article DOI: 10.1002/SPE.2925
     1210
     1211
     1212
     1213Date: Tue, 20 Oct 2020 10:33:04 +0000
     1214From: <cs-author@wiley.com>
     1215To: <pabuhr@uwaterloo.ca>
     1216Subject: In Production: Your article accepted in Software: Practice and Experience
     1217
     1218Dear Peter Buhr,
     1219
     1220Article ID: SPE2925
     1221Article DOI: 10.1002/spe.2925
     1222Internal Article ID: 16922213
     1223Article: Advanced Control-flow and Concurrency in C A
     1224Journal: Software: Practice and Experience
     1225
     1226Congratulations on the acceptance of your article for publication in Software: Practice and Experience.
     1227
     1228Your 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
     1230Please 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
     1232https://authorservices.wiley.com/index.html#login?campaign=email_invitation-new
     1233
     1234If applicable, a list of available actions will appear below - check out your Author Services Dashboard for all actions related to your articles.
     1235
     1236Sign 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
     1237If 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
     1239Sincerely,
     1240Wiley Author Services
     1241
     1242P.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
     1246Date: Thu, 22 Oct 2020 20:21:49 +0000
     1247From: <cs-author@wiley.com>
     1248To: <pabuhr@uwaterloo.ca>
     1249Subject: You have actions to complete in Author Services
     1250
     1251Dear Peter Buhr,
     1252
     1253Article ID: SPE2925
     1254Article DOI: 10.1002/spe.2925
     1255Internal Article ID: 16922213
     1256Article: Advanced Control-flow and Concurrency in C A
     1257Journal: Software: Practice and Experience
     1258
     1259For the above article, you have the following open tasks:
     1260
     1261Sign 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
     1263Need any help? Please visit our https://authorsupport.wiley.com/s/">Author Support Center.
     1264
     1265Sincerely,
     1266Wiley Author Services
     1267
     1268
     1269
     1270Date: Thu, 22 Oct 2020 23:13:07 +0000
     1271From: <cs-author@wiley.com>
     1272To: <pabuhr@uwaterloo.ca>
     1273Subject: License was successfully submitted! Thank you!
     1274
     1275Dear Peter Buhr,                                                                 
     1276
     1277Article ID: SPE2925
     1278Article DOI: 10.1002/spe.2925
     1279Internal Article ID: 16922213
     1280Article: Advanced Control-flow and Concurrency in C A 
     1281Journal: Software: Practice and Experience                                                                     
     1282                                                                         
     1283You'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
     1285Sincerely,                                                                                 
     1286
     1287Wiley Author Services
  • doc/proposals/vtable.md

    rb9537e6 rf7e4f8e8  
    512512possibly like the one used to create the assertion.
    513513
     514### Extension: Associated Types Use
     515If the `associated_types.md` proposal is accepted the following trait could
     516be added:
     517
     518    trait is_virtual(dtype T) {
     519        dtype table;
     520        // An example assertion:
     521        const table & get_virtual_table(T &);
     522    }
     523
     524There may be more assertions but there has to be at least one way to find
     525the (possibly default) virtual table. It is required to construct instances
     526of the type.
     527
     528Without 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
     534Which is just a little bit longer to use but becomes more problematic if the
     535user has to explicately provide the table's name as it doesn't really have its
     536own type name. If it does it is probably mangled.
     537
    514538### Virtual Tables as Types
    515539Here we consider encoding plus the implementation of functions on it to be a
  • doc/theses/andrew_beach_MMath/thesis-frontpgs.tex

    rb9537e6 rf7e4f8e8  
    55% TITLE PAGE
    66%----------------------------------------------------------------------
     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}
    715
    816\pagestyle{empty}
     
    1523        \vspace*{1.0cm}
    1624
    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
    2329        by \\
    2430
    2531        \vspace*{1.0cm}
    2632
    27         \Large
    28         Pat Neugraad \\
     33        {\Large \eprint{author}} \\
    2934
    3035        \vspace*{3.0cm}
    3136
    32         \normalsize
    3337        A thesis \\
    3438        presented to the University of Waterloo \\
    3539        in fulfillment of the \\
    3640        thesis requirement for the degree of \\
    37         Doctor of Philosophy \\
     41        \eprint{degree} \\
    3842        in \\
    39         Zoology \\
     43        \eprint{program} \\
    4044
    4145        \vspace*{2.0cm}
     
    4549        \vspace*{1.0cm}
    4650
    47         \copyright\ Pat Neugraad 2017 \\
     51        \copyright{} \eprint{author} 2017 \\
    4852        \end{center}
    4953\end{titlepage}
  • doc/theses/andrew_beach_MMath/uw-ethesis.cls

    rb9537e6 rf7e4f8e8  
    1919%
    2020% 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%
    2126%   \ifformat{<format>}{<true>}{<false>}
    2227%     If the document's format is <format> than expands to <true> otherwise
     
    2732%     initial setup depends on the document format but they can be overriden
    2833%     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
    2947\NeedsTeXFormat{LaTeX2e}
    30 \ProvidesClass{uw-ethesis}[2020/03/24 v0.1 UW-eThesis Template Document Class]
     48\ProvidesClass{uw-ethesis}[2020/10/25 v0.2 UW-eThesis Template Document Class]
    3149
    3250\RequirePackage{etoolbox}
     51\RequirePackage{xkeyval}
    3352
    3453% 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}}
    3857
    3958\ProcessOptions\relax
     
    81100% a recto page. This will often require an empty verso (left-hand side) page
    82101% that should not have the page number printed on it.
    83 \let\origdoublepage\cleardoublepage
     102\let\ethesis@origdoublepage\cleardoublepage
    84103\newcommand{\clearemptydoublepage}{%
    85   \clearpage{\pagestyle{empty}\origdoublepage}}
     104  \clearpage{\pagestyle{empty}\ethesis@origdoublepage}}
    86105\let\cleardoublepage\clearemptydoublepage
    87106
     
    89108\renewcommand*{\bibname}{References}
    90109
    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}}
    96130
    97131% Includes the hyperref package loading a number of defaults.
     
    106140    pdfstartview={FitH},    % Fits the width of the page to the window.
    107141  }
    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}}}{}
    112146  \ifformat{print}{
    113147    \hypersetup{
  • libcfa/prelude/builtins.c

    rb9537e6 rf7e4f8e8  
    99// Author           : Peter A. Buhr
    1010// Created On       : Fri Jul 21 16:21:03 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct  9 18:26:19 2020
    13 // Update Count     : 110
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct 27 14:42:00 2020
     13// Update Count     : 111
    1414//
     15
     16#define __cforall_builtins__
    1517
    1618// 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  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue May 26 22:06:09 2020
    13 // Update Count     : 21
     12// Last Modified On : Fri Oct 23 23:05:24 2020
     13// Update Count     : 22
    1414//
    1515
     
    2424#include <unistd.h>
    2525#include <sys/mman.h>                                                                   // mprotect
    26 extern "C" {
    27 // use this define to make unwind.h play nice, definitely a hack
    28 #define HIDE_EXPORTS
    2926#include <unwind.h>
    30 #undef HIDE_EXPORTS
    31 }
    3227
    3328#include "kernel_private.hfa"
     29#include "exception.hfa"
    3430
    3531#define __CFA_INVOKE_PRIVATE__
     
    4945FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t))
    5046
    51 struct __cfaehm_node {
    52         struct _Unwind_Exception unwind_exception;
    53         struct __cfaehm_node * next;
    54         int handler_index;
    55 };
    56 
    5747forall(dtype T)
    5848void mark_exception(CoroutineCancelled(T) *) {}
     
    6050forall(dtype T)
    6151void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
     52        dst->virtual_table = src->virtual_table;
    6253        dst->the_coroutine = src->the_coroutine;
    6354        dst->the_exception = src->the_exception;
     
    7465        verify( desc->cancellation );
    7566        desc->state = Cancelled;
    76         exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation);
     67        exception_t * except = __cfaehm_cancellation_exception( desc->cancellation );
    7768
    7869        // TODO: Remove explitate vtable set once trac#186 is fixed.
     
    217208                size = libFloor(create_size - stack_data_size - diff, libAlign());
    218209        } // 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 );
    220211
    221212        this->storage = (__stack_t *)((intptr_t)storage + size);
  • libcfa/src/concurrency/exception.cfa

    rb9537e6 rf7e4f8e8  
    1010// Created On       : Mon Aug 17 10:41:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Aug 25 14:41:00 2020
    13 // Update Count     : 0
     12// Last Modified On : Wed Oct 28 14:34:00 2020
     13// Update Count     : 1
    1414//
    1515
    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__
    2217
    23 #include "invoke.h"
    2418#include "exception.hfa"
     19
    2520#include "coroutine.hfa"
    2621
    2722extern struct $thread * mainThread;
     23extern "C" {
     24extern void __cfactx_thrd_leave();
     25}
    2826
    2927// Common pattern for all the stop functions, wait until the end then act.
     
    5250
    5351STOP_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" );
    5654)
    5755
     
    8583                stop_param = (void *)0x22;
    8684        } else {
     85                this_thread->self_cor.cancellation = unwind_exception;
     86
    8787                stop_func = thread_cancelstop;
    8888                stop_param = this_thread;
  • libcfa/src/concurrency/exception.hfa

    rb9537e6 rf7e4f8e8  
    1616#pragma once
    1717
     18// This is an internal bridge between the two modes and must be C compatable.
     19
     20#include <unwind.h>
    1821#include "bits/defs.hfa"
    1922#include "invoke.h"
     23#include "exception.h"
    2024
    2125#ifdef __cforall
    2226extern "C" {
    23 
    24 #define HIDE_EXPORTS
    2527#endif
    26 #include "unwind.h"
    2728
    2829struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD;
     
    3233
    3334#ifdef __cforall
    34 #undef HIDE_EXPORTS
    3535}
    3636#endif
  • libcfa/src/concurrency/invoke.h

    rb9537e6 rf7e4f8e8  
    157157
    158158                // 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
    159163                volatile int ticket;
    160164                enum __Coroutine_State state:8;
  • libcfa/src/concurrency/io/setup.cfa

    rb9537e6 rf7e4f8e8  
    250250                                        // Fixup the thread state
    251251                                        thrd.state = Blocked;
    252                                         thrd.ticket = 0;
     252                                        thrd.ticket = TICKET_BLOCKED;
    253253                                        thrd.preempted = __NO_PREEMPTION;
    254254
  • libcfa/src/concurrency/kernel.cfa

    rb9537e6 rf7e4f8e8  
    252252                /* paranoid */ verify( kernelTLS.this_thread == thrd_dst );
    253253                /* paranoid */ verify( thrd_dst->context.SP );
     254                /* paranoid */ verify( thrd_dst->state != Halted );
    254255                /* 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
    255256                /* 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
     
    287288                if(unlikely(thrd_dst->state == Halted)) {
    288289                        // 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 );
    292292                        break RUNNING;
    293293                }
     
    299299                int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST);
    300300                switch(old_ticket) {
    301                         case 1:
     301                        case TICKET_RUNNING:
    302302                                // This is case 1, the regular case, nothing more is needed
    303303                                break RUNNING;
    304                         case 2:
     304                        case TICKET_UNBLOCK:
    305305                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    306306                                // In this case, just run it again.
     
    410410        int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST);
    411411        switch(old_ticket) {
    412                 case 1:
     412                case TICKET_RUNNING:
    413413                        // Wake won the race, the thread will reschedule/rerun itself
    414414                        break;
    415                 case 0:
     415                case TICKET_BLOCKED:
    416416                        /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION );
    417417                        /* paranoid */ verify( thrd->state == Blocked );
     
    422422                default:
    423423                        // 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);
    425425        }
    426426}
     
    448448}
    449449
    450 // KERNEL ONLY
    451 void __leave_thread() {
    452         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    453         returnToKernel();
    454         abort();
     450extern "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        }
    455474}
    456475
  • libcfa/src/concurrency/kernel.hfa

    rb9537e6 rf7e4f8e8  
    7979        // Handle to pthreads
    8080        pthread_t kernel_thread;
    81 
    82         // RunThread data
    83         // Action to do after a thread is ran
    84         $thread * destroyer;
    8581
    8682        // Preemption data
  • libcfa/src/concurrency/kernel/startup.cfa

    rb9537e6 rf7e4f8e8  
    441441
    442442static void ?{}( $thread & this, current_stack_info_t * info) with( this ) {
    443         ticket = 1;
     443        ticket = TICKET_RUNNING;
    444444        state = Start;
    445445        self_cor{ info };
     
    474474        this.cltr = &_cltr;
    475475        full_proc = true;
    476         destroyer = 0p;
    477476        do_terminate = false;
    478477        preemption_alarm = 0p;
  • libcfa/src/concurrency/kernel_private.hfa

    rb9537e6 rf7e4f8e8  
    3939;
    4040
    41 //Block current thread and release/wake-up the following resources
    42 void __leave_thread() __attribute__((noreturn));
     41//release/wake-up the following resources
     42void __thread_finish( $thread * thrd );
    4343
    4444//-----------------------------------------------------------------------------
     
    6565// KERNEL ONLY unpark with out disabling interrupts
    6666void __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
    6771
    6872static inline bool __post(single_sem & this, struct __processor_id_t * id) {
  • libcfa/src/concurrency/monitor.cfa

    rb9537e6 rf7e4f8e8  
    281281}
    282282
    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         }
     283void __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 );
    337308}
    338309
  • libcfa/src/concurrency/thread.cfa

    rb9537e6 rf7e4f8e8  
    1919
    2020#include "kernel_private.hfa"
     21#include "exception.hfa"
    2122
    2223#define __CFA_INVOKE_PRIVATE__
     
    2829        context{ 0p, 0p };
    2930        self_cor{ name, storage, storageSize };
    30         ticket = 1;
     31        ticket = TICKET_RUNNING;
    3132        state = Start;
    3233        preempted = __NO_PREEMPTION;
     
    5657        unregister(curr_cluster, this);
    5758        ^self_cor{};
     59}
     60
     61FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t))
     62
     63forall(dtype T)
     64void 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
     70forall(dtype T)
     71const char * msg(ThreadCancelled(T) *) {
     72        return "ThreadCancelled";
     73}
     74
     75forall(dtype T)
     76static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
     77        abort( "Unhandled thread cancellation.\n" );
     78}
     79
     80forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
     81void ?{}( 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
     113void ^?{}( thread_dtor_guard_t & this ) {
     114        ^(this.mg){};
    58115}
    59116
     
    93150}
    94151
     152//-----------------------------------------------------------------------------
     153forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
     154T & join( T & this ) {
     155        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
     156        return this;
     157}
     158
    95159// Local Variables: //
    96160// mode: c //
  • libcfa/src/concurrency/thread.hfa

    rb9537e6 rf7e4f8e8  
    2222#include "kernel.hfa"
    2323#include "monitor.hfa"
     24#include "exception.hfa"
    2425
    2526//-----------------------------------------------------------------------------
    2627// thread trait
    2728trait is_thread(dtype T) {
    28       void ^?{}(T& mutex this);
    29       void main(T& this);
    30       $thread* get_thread(T& this);
     29        void ^?{}(T& mutex this);
     30        void main(T& this);
     31        $thread* get_thread(T& this);
    3132};
     33
     34FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) (
     35        thread_t * the_thread;
     36        exception_t * the_exception;
     37);
     38
     39forall(dtype T)
     40void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src);
     41
     42forall(dtype T)
     43const char * msg(ThreadCancelled(T) *);
    3244
    3345// define that satisfies the trait without using the thread keyword
     
    6577static inline void ?{}($thread & this, const char * const name, struct cluster & cl )                   { this{ name, cl, 0p, 65000 }; }
    6678static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; }
     79
     80struct thread_dtor_guard_t {
     81        monitor_dtor_guard_t mg;
     82};
     83
     84forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
     85void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
     86void ^?{}( thread_dtor_guard_t & this );
    6787
    6888//-----------------------------------------------------------------------------
     
    108128//----------
    109129// join
    110 forall( dtype T | is_thread(T) )
     130forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
    111131T & join( T & this );
    112132
  • libcfa/src/exception.c

    rb9537e6 rf7e4f8e8  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:13:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 29 15:52:22 2020
    13 // Update Count     : 34
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct 27 16:27:00 2020
     13// Update Count     : 35
    1414//
    1515
     
    1717#include <stddef.h> // for size_t
    1818
     19#include <unwind.h> // for struct _Unwind_Exception {...};
     20
    1921#include "exception.h"
    2022
    2123#include <stdlib.h>
    2224#include <stdio.h>
    23 #include <unwind.h>
    2425#include <bits/debug.hfa>
    2526#include "concurrency/invoke.h"
     
    113114
    114115// MEMORY MANAGEMENT =========================================================
    115 
    116 struct __cfaehm_node {
    117         struct _Unwind_Exception unwind_exception;
    118         struct __cfaehm_node * next;
    119         int handler_index;
    120 };
    121116
    122117#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
  • libcfa/src/exception.h

    rb9537e6 rf7e4f8e8  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // exception.h -- Builtins for exception handling.
     7// exception.h -- Internal exception handling definitions.
    88//
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:11:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue May 19 14:17:00 2020
    13 // Update Count     : 10
     12// Last Modified On : Tue Oct 27 14:45:00 2020
     13// Update Count     : 11
    1414//
    1515
    1616#pragma once
    1717
     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.
    1821
    1922#ifdef __cforall
    2023extern "C" {
    2124#endif
     25
     26// Included in C code or the built-ins.
     27#if !defined(__cforall) || defined(__cforall_builtins__)
    2228
    2329struct __cfaehm_base_exception_t;
     
    4753// Function catches termination exceptions.
    4854void __cfaehm_try_terminate(
    49     void (*try_block)(),
    50     void (*catch_block)(int index, exception_t * except),
    51     int (*match_block)(exception_t * except));
     55        void (*try_block)(),
     56        void (*catch_block)(int index, exception_t * except),
     57        int (*match_block)(exception_t * except));
    5258
    5359// Clean-up the exception in catch blocks.
     
    5662// Data structure creates a list of resume handlers.
    5763struct __cfaehm_try_resume_node {
    58     struct __cfaehm_try_resume_node * next;
    59     _Bool (*handler)(exception_t * except);
     64        struct __cfaehm_try_resume_node * next;
     65        _Bool (*handler)(exception_t * except);
    6066};
    6167
    6268// These act as constructor and destructor for the resume node.
    6369void __cfaehm_try_resume_setup(
    64     struct __cfaehm_try_resume_node * node,
    65     _Bool (*handler)(exception_t * except));
     70        struct __cfaehm_try_resume_node * node,
     71        _Bool (*handler)(exception_t * except));
    6672void __cfaehm_try_resume_cleanup(
    67     struct __cfaehm_try_resume_node * node);
     73        struct __cfaehm_try_resume_node * node);
    6874
    6975// Check for a standard way to call fake deconstructors.
    7076struct __cfaehm_cleanup_hook {};
    7177
     78#endif
     79
     80// Included in C code and the library.
     81#if !defined(__cforall) || !defined(__cforall_builtins__)
     82struct __cfaehm_node {
     83        struct _Unwind_Exception unwind_exception;
     84        struct __cfaehm_node * next;
     85        int handler_index;
     86};
     87
     88static 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
    7294#ifdef __cforall
    7395}
     96
     97// Built-ins not visible in C.
     98#if defined(__cforall_builtins__)
    7499
    75100// Not all the built-ins can be expressed in C. These can't be
     
    124149
    125150#endif
     151
     152#endif
  • src/AST/Convert.cpp

    rb9537e6 rf7e4f8e8  
    4747
    4848//================================================================================================
    49 namespace {
     49namespace ast {
    5050
    5151// This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not)
    5252// 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
    5356ast::Type * sizeType = nullptr;
    5457ast::FunctionDecl * dereferenceOperator = nullptr;
     
    6366        using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >;
    6467        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;
    6573
    6674        template<typename T>
     
    154162        }
    155163
    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 {       
    161165                if ( inCache( node ) ) {
    162166                        return nullptr;
    163167                }
     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
    164172                auto decl = new ObjectDecl(
    165173                        node->name,
     
    168176                        bfwd,
    169177                        type->clone(),
    170                         init,
     178                        nullptr, // prevent infinite loop
    171179                        attr,
    172180                        Type::FuncSpecifiers( node->funcSpec.val )
    173181                );
    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;
    175191        }
    176192
     
    205221                decl->statements = get<CompoundStmt>().accept1( node->stmts );
    206222                decl->withExprs = get<Expression>().acceptL( node->withExprs );
    207                 if ( dereferenceOperator == node ) {
     223                if ( ast::dereferenceOperator == node ) {
    208224                        Validate::dereferenceOperator = decl;
    209225                }
    210                 if ( dtorStructDestroy == node ) {
     226                if ( ast::dtorStructDestroy == node ) {
    211227                        Validate::dtorStructDestroy = decl;
    212228                }
     
    267283                );
    268284
    269                 if ( dtorStruct == node ) {
     285                if ( ast::dtorStruct == node ) {
    270286                        Validate::dtorStruct = decl;
    271287                }
     
    320336
    321337        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 );
    323341                stmt->location = node->location;
    324342                stmt->labels = makeLabelL( stmt, node->labels );
     
    337355                if ( inCache( node ) ) return nullptr;
    338356                auto stmt = new ExprStmt( nullptr );
    339                 cache.emplace( node, stmt );
    340357                stmt->expr = get<Expression>().accept1( node->expr );
    341358                return stmtPostamble( stmt, node );
     
    10111028                auto stmts = node->stmts;
    10121029                // 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
    10161032                auto rslt = new StmtExpr(
    10171033                        get<CompoundStmt>().accept1(stmts)
     
    10201036                rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
    10211037                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                }
    10221042
    10231043                auto expr = visitBaseExpr( node, rslt );
     
    10361056
    10371057                auto expr = visitBaseExpr( node, rslt );
    1038                 this->node = expr;
     1058                this->node = expr->clone();
    10391059                return nullptr;
    10401060        }
     
    11261146                auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind };
    11271147                // I believe this should always be a BasicType.
    1128                 if ( sizeType == node ) {
     1148                if ( ast::sizeType == node ) {
    11291149                        Validate::SizeType = type;
    11301150                }
     
    15291549
    15301550                // function type is now derived from parameter decls instead of storing them
     1551
     1552                /*
    15311553                auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type));
    15321554                ftype->params.reserve(paramVars.size());
     
    15401562                }
    15411563                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);
    15431568
    15441569                auto decl = new ast::FunctionDecl{
     
    15461571                        old->name,
    15471572                        // GET_ACCEPT_1(type, FunctionType),
     1573                        std::move(forall),
    15481574                        std::move(paramVars),
    15491575                        std::move(returnVars),
     
    15521578                        { old->linkage.val },
    15531579                        GET_ACCEPT_V(attributes, Attribute),
    1554                         { old->get_funcSpec().val }
     1580                        { old->get_funcSpec().val },
     1581                        old->type->isVarArgs
    15551582                };
    15561583
    1557                 decl->type = ftype;
     1584                // decl->type = ftype;
    15581585                cache.emplace( old, decl );
    15591586
     
    15701597
    15711598                if ( Validate::dereferenceOperator == old ) {
    1572                         dereferenceOperator = decl;
     1599                        ast::dereferenceOperator = decl;
    15731600                }
    15741601
    15751602                if ( Validate::dtorStructDestroy == old ) {
    1576                         dtorStructDestroy = decl;
     1603                        ast::dtorStructDestroy = decl;
    15771604                }
    15781605        }
     
    15991626
    16001627                if ( Validate::dtorStruct == old ) {
    1601                         dtorStruct = decl;
     1628                        ast::dtorStruct = decl;
    16021629                }
    16031630        }
     
    25312558                // I believe this should always be a BasicType.
    25322559                if ( Validate::SizeType == old ) {
    2533                         sizeType = type;
     2560                        ast::sizeType = type;
    25342561                }
    25352562                visitType( old, type );
  • src/AST/Decl.cpp

    rb9537e6 rf7e4f8e8  
    4848
    4949// --- FunctionDecl
     50
     51FunctionDecl::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
    5069
    5170const Type * FunctionDecl::get_type() const { return type.get(); }
  • src/AST/Decl.hpp

    rb9537e6 rf7e4f8e8  
    131131        std::vector< ptr<Expr> > withExprs;
    132132
    133         FunctionDecl( const CodeLocation & loc, const std::string & name,
     133        FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
    134134                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    135135                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 ) {}
    139139
    140140        const Type * get_type() const override;
  • src/AST/DeclReplacer.cpp

    rb9537e6 rf7e4f8e8  
    3838                        const ast::TypeInstType * previsit( const ast::TypeInstType * );
    3939                };
     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                };
    4050        }
    4151
     
    5464                DeclMap declMap;
    5565                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 );
    5671        }
    5772
     
    88103                        return ninst;
    89104                }
     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
    90112        }
    91113}
  • src/AST/DeclReplacer.hpp

    rb9537e6 rf7e4f8e8  
    2323        class DeclWithType;
    2424        class TypeDecl;
     25        class Expr;
    2526
    2627        namespace DeclReplacer {
    2728                using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
    2829                using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
     30                using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
    2931
    3032                const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
    3133                const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
    3234                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);
    3336        }
    3437}
  • src/AST/Expr.cpp

    rb9537e6 rf7e4f8e8  
    6767// --- UntypedExpr
    6868
    69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {
     69UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
    7070        assert( arg );
    7171
     
    9292}
    9393
    94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) {
     94UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
    9595        assert( lhs && rhs );
    9696
     
    102102        }
    103103        return ret;
     104}
     105
     106// --- VariableExpr
     107
     108VariableExpr::VariableExpr( const CodeLocation & loc )
     109: Expr( loc ), var( nullptr ) {}
     110
     111VariableExpr::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
     118bool VariableExpr::get_lvalue() const {
     119        // It isn't always an lvalue, but it is never an rvalue.
     120        return true;
     121}
     122
     123VariableExpr * 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;
    104129}
    105130
     
    238263}
    239264
    240 // --- VariableExpr
    241 
    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 pointer
    260         VariableExpr * funcExpr = new VariableExpr{ loc, decl };
    261         funcExpr->result = new PointerType{ funcExpr->result };
    262         return funcExpr;
    263 }
    264 
    265265// --- ConstantExpr
    266266
  • src/AST/Expr.hpp

    rb9537e6 rf7e4f8e8  
    226226
    227227        /// Creates a new dereference expression
    228         static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );
     228        static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg );
    229229        /// 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 );
    231231
    232232        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    247247private:
    248248        NameExpr * clone() const override { return new NameExpr{ *this }; }
     249        MUTATE_FRIEND
     250};
     251
     252/// A reference to a named variable.
     253class VariableExpr final : public Expr {
     254public:
     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 ); }
     266private:
     267        VariableExpr * clone() const override { return new VariableExpr{ *this }; }
    249268        MUTATE_FRIEND
    250269};
     
    392411};
    393412
    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 function
    405         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_FRIEND
    411 };
    412 
    413413/// A compile-time constant.
    414414/// Mostly carries C-source text from parse to code-gen, without interpretation.  E.g. strings keep their outer quotes and never have backslashes interpreted.
     
    422422                const CodeLocation & loc, const Type * ty, const std::string & r,
    423423                        std::optional<unsigned long long> i )
    424         : Expr( loc, ty ), rep( r ), ival( i ) {}
     424        : Expr( loc, ty ), rep( r ), ival( i ), underlyer(ty) {}
    425425
    426426        /// Gets the integer value of this constant, if one is appropriate to its type.
     
    617617
    618618        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); }
    620620
    621621        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    742742        std::vector<ptr<Expr>> dtors;              ///< destructor(s) for return variable(s)
    743743
     744        readonly<ExprStmt> resultExpr;
     745
    744746        StmtExpr( const CodeLocation & loc, const CompoundStmt * ss );
    745747
  • src/AST/Fwd.hpp

    rb9537e6 rf7e4f8e8  
    137137typedef unsigned int UniqueId;
    138138
     139extern Type * sizeType;
     140extern FunctionDecl * dereferenceOperator;
     141extern StructDecl   * dtorStruct;
     142extern FunctionDecl * dtorStructDestroy;
     143
    139144}
  • src/AST/Node.hpp

    rb9537e6 rf7e4f8e8  
    4949
    5050        bool unique() const { return strong_count == 1; }
     51        bool isManaged() const {return strong_count > 0; }
    5152
    5253private:
  • src/AST/Pass.hpp

    rb9537e6 rf7e4f8e8  
    228228        template<typename core_type>
    229229        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
     230
     231        bool isInFunction() const {
     232                return inFunction;
     233        }
     234
    230235private:
    231236
     
    235240        const ast::Stmt * call_accept( const ast::Stmt * );
    236241        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 *);
    237246
    238247        template< typename node_t >
     
    257266        template<typename node_t, typename parent_t, typename child_t>
    258267        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);
    259271
    260272private:
     
    284296private:
    285297        bool inFunction = false;
     298        bool atFunctionTop = false;
    286299};
    287300
     
    371384struct WithVisitorRef {
    372385        Pass<core_t> * const visitor = nullptr;
     386
     387        bool isInFunction() const {
     388                return visitor->isInFunction();
     389        }
    373390};
    374391
  • src/AST/Pass.impl.hpp

    rb9537e6 rf7e4f8e8  
    167167                __pedantic_pass_assert( stmt );
    168168
     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
    169177                // add a few useful symbols to the scope
    170178                using __pass::empty;
     
    324332
    325333                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 );
    326358
    327359                static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
     
    470502                                // foralls are still in function type
    471503                                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.
    474505                                ValueGuard< bool > oldInFunction( inFunction );
    475506                                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;
    476511                                maybe_accept( node, &FunctionDecl::stmts );
    477512                                maybe_accept( node, &FunctionDecl::attributes );
     
    640675        VISIT_START( node );
    641676        VISIT({
    642                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    643                 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);
    647682                });
    648683                ValueGuard< bool > guard2( inFunction );
     
    703738                maybe_accept( node, &IfStmt::inits    );
    704739                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 );
    707742        })
    708743
     
    721756                maybe_accept( node, &WhileStmt::inits );
    722757                maybe_accept( node, &WhileStmt::cond  );
    723                 maybe_accept( node, &WhileStmt::body  );
     758                maybe_accept_as_compound( node, &WhileStmt::body  );
    724759        })
    725760
     
    736771                // for statements introduce a level of scope (for the initialization)
    737772                guard_symtab guard { *this };
     773                // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.
    738774                maybe_accept( node, &ForStmt::inits );
    739775                maybe_accept( node, &ForStmt::cond  );
    740776                maybe_accept( node, &ForStmt::inc   );
    741                 maybe_accept( node, &ForStmt::body  );
     777                maybe_accept_as_compound( node, &ForStmt::body  );
    742778        })
    743779
     
    834870                maybe_accept( node, &CatchStmt::decl );
    835871                maybe_accept( node, &CatchStmt::cond );
    836                 maybe_accept( node, &CatchStmt::body );
     872                maybe_accept_as_compound( node, &CatchStmt::body );
    837873        })
    838874
  • src/AST/SymbolTable.cpp

    rb9537e6 rf7e4f8e8  
    335335}
    336336
    337 /*
    338 void SymbolTable::addFunctionType( const FunctionType * ftype ) {
    339         addTypes( ftype->forall );
    340         addIds( ftype->returns );
    341         addIds( ftype->params );
    342 }
    343 */
     337
     338void SymbolTable::addFunction( const FunctionDecl * func ) {
     339        addTypes( func->type->forall );
     340        addIds( func->returns );
     341        addIds( func->params );
     342}
     343
    344344
    345345void SymbolTable::lazyInitScope() {
  • src/AST/SymbolTable.hpp

    rb9537e6 rf7e4f8e8  
    145145
    146146        /// 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 * );
    148148
    149149private:
  • src/AST/Type.cpp

    rb9537e6 rf7e4f8e8  
    157157
    158158template<typename decl_t>
     159SueInstType<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
     164template<typename decl_t>
    159165bool SueInstType<decl_t>::isComplete() const {
    160166        return base ? base->body : false;
  • src/AST/Type.hpp

    rb9537e6 rf7e4f8e8  
    302302class FunctionType final : public ParameterizedType {
    303303public:
    304 //      std::vector<ptr<DeclWithType>> returns;
    305 //      std::vector<ptr<DeclWithType>> params;
    306 
    307304        std::vector<ptr<Type>> returns;
    308305        std::vector<ptr<Type>> params;
     
    345342        : ParameterizedType(q, std::move(as)), params(), name(n) {}
    346343
     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
    347349        BaseInstType( const BaseInstType & o );
    348350
     
    369371
    370372        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 = {} );
    372378
    373379        bool isComplete() const override;
  • src/AST/porting.md

    rb9537e6 rf7e4f8e8  
    3030  * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0`
    3131* `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`
    3236
    3337## Structural Changes ##
     
    146150  * allows `newObject` as just default settings
    147151
     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
    148157`NamedTypeDecl`
    149158* `parameters` => `params`
     
    154163`AggregateDecl`
    155164* `parameters` => `params`
     165
     166`StructDecl`
     167* `makeInst` replaced by better constructor on `StructInstType`.
    156168
    157169`Expr`
     
    245257* **TODO** move `kind`, `typeNames` into code generator
    246258
    247 `ReferenceToType`
     259`ReferenceToType` => `BaseInstType`
    248260* deleted `get_baseParameters()` from children
    249261  * replace with `aggr() ? aggr()->params : nullptr`
     
    261273* `returnVals` => `returns`
    262274* `parameters` => `params`
     275  * Both now just point at types.
    263276* `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`
    264281
    265282`TypeInstType`
  • src/Common/PassVisitor.h

    rb9537e6 rf7e4f8e8  
    354354        virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final;
    355355
     356        bool isInFunction() const {
     357                return inFunction;
     358        }
     359
    356360private:
    357361        bool inFunction = false;
     362        bool atFunctionTop = false;
    358363
    359364        template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor );
     
    526531public:
    527532        PassVisitor<pass_type> * const visitor = nullptr;
     533
     534        bool isInFunction() const {
     535                return visitor->isInFunction();
     536        }
    528537};
    529538
  • src/Common/PassVisitor.impl.h

    rb9537e6 rf7e4f8e8  
    532532                        indexerAddId( &func );
    533533                        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.
    536535                        ValueGuard< bool > oldInFunction( inFunction );
    537536                        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;
    538541                        maybeAccept_impl( node->statements, *this );
    539542                        maybeAccept_impl( node->attributes, *this );
     
    567570                        indexerAddId( &func );
    568571                        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.
    571573                        ValueGuard< bool > oldInFunction( inFunction );
    572574                        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;
    573579                        maybeAccept_impl( node->statements, *this );
    574580                        maybeAccept_impl( node->attributes, *this );
     
    601607                        indexerAddId( &func );
    602608                        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.
    605610                        ValueGuard< bool > oldInFunction( inFunction );
    606611                        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;
    607616                        maybeMutate_impl( node->statements, *this );
    608617                        maybeMutate_impl( node->attributes, *this );
     
    10071016        VISIT_START( node );
    10081017        {
    1009                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    1010                 ValueGuard< bool > oldInFunction( 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(); } );
    10121021                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1013                 inFunction = false;
     1022                atFunctionTop = false;
    10141023                visitStatementList( node->kids );
    10151024        }
     
    10211030        VISIT_START( node );
    10221031        {
    1023                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    1024                 ValueGuard< bool > oldInFunction( 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(); } );
    10261035                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1027                 inFunction = false;
     1036                atFunctionTop = false;
    10281037                visitStatementList( node->kids );
    10291038        }
     
    10351044        MUTATE_START( node );
    10361045        {
    1037                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    1038                 ValueGuard< bool > oldInFunction( 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(); } );
    10401049                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1041                 inFunction = false;
     1050                atFunctionTop = false;
    10421051                mutateStatementList( node->kids );
    10431052        }
  • src/Common/utility.h

    rb9537e6 rf7e4f8e8  
    360360        reverse_iterate_t( T & ref ) : ref(ref) {}
    361361
    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(); }
    365366};
    366367
  • src/Concurrency/Keywords.cc

    rb9537e6 rf7e4f8e8  
    4646        }
    4747
     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
    4856        //=============================================================================================
    4957        // Pass declarations
     
    119127                        "get_thread",
    120128                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
    121                         "",
     129                        "ThreadCancelled",
    122130                        true,
    123131                        AggregateDecl::Thread
     
    290298                std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
    291299                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 );
    294303
    295304                static void implement( std::list< Declaration * > & translationUnit ) {
     
    302311                StructDecl* guard_decl = nullptr;
    303312                StructDecl* dtor_guard_decl = nullptr;
     313                StructDecl* thread_guard_decl = nullptr;
    304314
    305315                static std::unique_ptr< Type > generic_func;
     
    801811                bool first = false;
    802812                std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
    803                 bool isDtor = CodeGen::isDestructor( decl->name );
     813                bool const isDtor = CodeGen::isDestructor( decl->name );
    804814
    805815                // Is this function relevant to monitors
     
    849859
    850860                // 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 );
    853869                }
    854870                else {
    855                         addStatments( decl, body, mutexArgs );
     871                        addStatements( decl, body, mutexArgs );
    856872                }
    857873        }
     
    870886                        assert( !dtor_guard_decl );
    871887                        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;
    872892                }
    873893        }
     
    908928        }
    909929
    910         void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     930        void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    911931                Type * arg_type = args.front()->get_type()->clone();
    912932                arg_type->set_mutex( false );
     
    957977
    958978                //$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 ) {
    9631019                ObjectDecl * monitors = new ObjectDecl(
    9641020                        "__monitors",
  • src/GenPoly/GenPoly.cc

    rb9537e6 rf7e4f8e8  
    4646                }
    4747
     48                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) {
     49                        for (auto &param : params) {
     50                                auto paramType = param.strict_as<ast::TypeExpr>();
     51                                if (isPolyType(paramType->type, env)) return true;
     52                        }
     53                        return false;
     54                }
     55
    4856                /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present
    4957                bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    5664                }
    5765
     66                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
     67                        for (auto &param : params) {
     68                                auto paramType = param.strict_as<ast::TypeExpr>();
     69                                if (isPolyType(paramType->type, tyVars, env)) return true;
     70                        }
     71                        return false;
     72                }
     73
    5874                /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
    5975                bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    92108                        Type *newType = env->lookup( typeInst->get_name() );
    93109                        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;
    94119                }
    95120                return type;
     
    111136        }
    112137
     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
    113153        Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    114154                type = replaceTypeInst( type, env );
     
    126166                }
    127167                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;
    128183        }
    129184
     
    449504        }
    450505
     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
    451514        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
    452515                // is parameter is not polymorphic, don't need to box
     
    459522        }
    460523
     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
    461533        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
    462534                FunctionType * function = getFunctionType( appExpr->function->result );
     
    467539        }
    468540
     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
    469550        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    470551                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}));
    471556        }
    472557
     
    478563                if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
    479564                        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);
    480577                }
    481578        }
  • src/GenPoly/GenPoly.h

    rb9537e6 rf7e4f8e8  
    2626
    2727namespace GenPoly {
     28
    2829        typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    29 
    3030        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    3131        Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
     
    3333        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
    3434        Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );
     35        const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);
    3536
    3637        /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    3738        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);
    3840
    3941        /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
     
    8486        /// true if arg requires boxing given exprTyVars
    8587        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);
    8689
    8790        /// true if arg requires boxing in the call to appExpr
    8891        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);
    8993
    9094        /// Adds the type variable `tyVar` to `tyVarMap`
     
    9397        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    9498        void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
     99        void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap);
    95100
    96101        /// Prints type variable map
  • src/GenPoly/Specialize.cc

    rb9537e6 rf7e4f8e8  
    218218                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
    219219
     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
    220224                // thread thunk parameters into call to actual function, naming thunk parameters as we go
    221225                UniqueName paramNamer( paramPrefix );
  • src/InitTweak/FixGlobalInit.cc

    rb9537e6 rf7e4f8e8  
    3434#include "SynTree/Visitor.h"       // for acceptAll, Visitor
    3535
     36#include "AST/Expr.hpp"
     37#include "AST/Node.hpp"
     38#include "AST/Pass.hpp"
     39
    3640namespace InitTweak {
    3741        class GlobalFixer : public WithShortCircuiting {
     
    5054                FunctionDecl * initFunction;
    5155                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;
    5270        };
    5371
     
    91109        }
    92110
     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
    93134        void GlobalFixer::previsit( ObjectDecl *objDecl ) {
    94135                std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();
     
    112153                        } // if
    113154                        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 );
    130156                                initStatements.push_back( ctor );
    131157                                objDecl->init = nullptr;
     
    142168        }
    143169
     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
    144199        // only modify global variables
    145200        void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }
  • src/InitTweak/FixGlobalInit.h

    rb9537e6 rf7e4f8e8  
    1919#include <string>  // for string
    2020
     21#include <AST/Fwd.hpp>
     22
     23
    2124class Declaration;
    2225
     
    2629        /// function is for library code.
    2730        void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary );
     31        void fixGlobalInit( std::list< ast::ptr<ast::Decl> > & translationUnit, bool inLibrary );
    2832} // namespace
    2933
  • src/InitTweak/FixInit.cc

    rb9537e6 rf7e4f8e8  
    219219                };
    220220
    221                 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
     221                struct SplitExpressions : public WithShortCircuiting, /*public WithTypeSubstitution, */public WithStmtsToAdd {
    222222                        /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
    223223                        static void split( std::list< Declaration * > &translationUnit );
     
    802802                                if ( Statement * ctor = ctorInit->get_ctor() ) {
    803803                                        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
    804810                                                // originally wanted to take advantage of gcc nested functions, but
    805811                                                // we get memory errors with this approach. To remedy this, the static
  • src/InitTweak/FixInit.h

    rb9537e6 rf7e4f8e8  
    1919#include <string>  // for string
    2020
     21#include <AST/Fwd.hpp>
     22
    2123class Declaration;
    2224
     
    2426        /// replace constructor initializers with expression statements and unwrap basic C-style initializers
    2527        void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
     28
     29        void fix( std::list<ast::ptr<ast::Decl>> & translationUnit, bool inLibrary);
    2630} // namespace
    2731
  • src/InitTweak/GenInit.cc

    rb9537e6 rf7e4f8e8  
    283283                assert( stmts.size() <= 1 );
    284284                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);
    285292        }
    286293
  • src/InitTweak/GenInit.h

    rb9537e6 rf7e4f8e8  
    3333        /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    3434        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);
    3536
    3637        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
  • src/InitTweak/InitTweak.cc

    rb9537e6 rf7e4f8e8  
    498498        }
    499499
     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
    500507        bool tryConstruct( DeclarationWithType * dwt ) {
    501508                ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
     
    511518        }
    512519
     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
    513534        struct CallFinder_old {
    514535                CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
     
    536557
    537558        struct CallFinder_new final {
    538                 std::vector< ast::ptr< ast::Expr > > matches;
     559                std::vector< const ast::Expr * > matches;
    539560                const std::vector< std::string > names;
    540561
     
    558579        }
    559580
    560         std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) {
     581        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    561582                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    562583                maybe_accept( stmt, finder );
     
    696717                template <typename Predicate>
    697718                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 );
    699720                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    700721                }
     
    939960        }
    940961
     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
    941989        struct ConstExprChecker : public WithShortCircuiting {
    942990                // most expressions are not const expr
     
    10551103                return isCopyFunction( decl, "?{}" );
    10561104        }
     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
    10571115}
  • src/InitTweak/InitTweak.h

    rb9537e6 rf7e4f8e8  
    3838        /// returns the first parameter of a constructor/destructor/assignment function
    3939        ObjectDecl * getParamThis( FunctionType * ftype );
     40        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4041
    4142        /// generate a bitwise assignment operation.
    4243        ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
     44
     45        ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    4346
    4447        /// transform Initializer into an argument list that can be passed to a call expression
     
    4851        /// True if the resolver should try to construct dwt
    4952        bool tryConstruct( DeclarationWithType * dwt );
     53        bool tryConstruct( const ast::DeclWithType * dwt );
    5054
    5155        /// True if the type can have a user-defined constructor
    5256        bool isConstructable( Type * t );
     57        bool isConstructable( const ast::Type * t );
    5358
    5459        /// True if the Initializer contains designations
     
    7984        /// get all Ctor/Dtor call expressions from a Statement
    8085        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 );
    8287
    8388        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
     
    102107        bool isConstExpr( Expression * expr );
    103108        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 );
    104120
    105121        class InitExpander_old {
  • src/InitTweak/module.mk

    rb9537e6 rf7e4f8e8  
    2323        InitTweak/GenInit.h \
    2424        InitTweak/InitTweak.cc \
    25         InitTweak/InitTweak.h
     25        InitTweak/InitTweak.h \
     26        InitTweak/FixInitNew.cpp
    2627
    2728SRCDEMANGLE += \
  • src/Parser/ParseNode.h

    rb9537e6 rf7e4f8e8  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jul  6 09:33:32 2020
    13 // Update Count     : 892
     12// Last Modified On : Sat Oct 24 03:53:54 2020
     13// Update Count     : 895
    1414//
    1515
     
    205205struct TypeData;
    206206
    207 class DeclarationNode : public ParseNode {
    208   public:
     207struct DeclarationNode : public ParseNode {
    209208        // These enumerations must harmonize with their names in DeclarationNode.cc.
    210209        enum BasicType { Void, Bool, Char, Int, Int128,
     
    304303        bool get_inLine() const { return inLine; }
    305304        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    306   public:
     305
    307306        DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    308307
     
    360359//##############################################################################
    361360
    362 class StatementNode final : public ParseNode {
    363   public:
     361struct StatementNode final : public ParseNode {
    364362        StatementNode() { stmt = nullptr; }
    365363        StatementNode( Statement * stmt ) : stmt( stmt ) {}
     
    382380                os << stmt.get() << std::endl;
    383381        }
    384   private:
     382
    385383        std::unique_ptr<Statement> stmt;
    386384}; // StatementNode
     
    426424Statement * build_finally( StatementNode * stmt );
    427425Statement * build_compound( StatementNode * first );
     426StatementNode * maybe_build_compound( StatementNode * first );
    428427Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    429428Statement * build_directive( std::string * directive );
  • src/Parser/StatementNode.cc

    rb9537e6 rf7e4f8e8  
    1010// Created On       : Sat May 16 14:59:41 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug  4 09:39:25 2018
    13 // Update Count     : 363
     12// Last Modified On : Sat Oct 24 04:20:55 2020
     13// Update Count     : 383
    1414//
    1515
     
    345345} // build_compound
    346346
     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.
     351StatementNode * 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
    347362Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    348363        std::list< Expression * > out, in;
  • src/Parser/parser.yy

    rb9537e6 rf7e4f8e8  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct  9 18:09:09 2020
    13 // Update Count     : 4614
     12// Last Modified On : Sat Oct 24 08:21:14 2020
     13// Update Count     : 4624
    1414//
    1515
     
    10801080        IF '(' if_control_expression ')' statement                      %prec THEN
    10811081                // 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 ) ); }
    10831083        | 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 ) ) ); }
    10851085        ;
    10861086
     
    11301130
    11311131case_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 ) ); }
    11331133        ;
    11341134
     
    11481148iteration_statement:
    11491149        WHILE '(' push if_control_expression ')' statement pop
    1150                 { $$ = new StatementNode( build_while( $4, $6 ) ); }
     1150                { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
    11511151        | 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 ) ) ); }
    11531153        | DO statement WHILE '(' comma_expression ')' ';'
    1154                 { $$ = new StatementNode( build_do_while( $5, $2 ) ); }
     1154                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    11551155        | 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 ) ) ); }
    11571157        | 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 ) ) ); }
    11591159        | 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 ) ) ); }
    11611161        ;
    11621162
     
    13411341waitfor_clause:
    13421342        when_clause_opt waitfor statement                                       %prec THEN
    1343                 { $$ = build_waitfor( $2, $3, $1 ); }
     1343                { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }
    13441344        | 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 ); }
    13461346        | when_clause_opt timeout statement                                     %prec THEN
    1347                 { $$ = build_waitfor_timeout( $2, $3, $1 ); }
     1347                { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }
    13481348        | when_clause_opt ELSE statement
    1349                 { $$ = build_waitfor_timeout( nullptr, $3, $1 ); }
     1349                { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
    13501350                // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    13511351        | when_clause_opt timeout statement WOR ELSE statement
    13521352                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    13531353        | 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 ); }
    13551355        ;
    13561356
  • src/ResolvExpr/Resolver.cc

    rb9537e6 rf7e4f8e8  
    11051105                }
    11061106
    1107                 /// Establish post-resolver invariants for expressions
     1107               
     1108        } // anonymous namespace
     1109/// Establish post-resolver invariants for expressions
    11081110                void finishExpr(
    11091111                        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
     
    11181120                        StripCasts_new::strip( expr );
    11191121                }
    1120         } // anonymous namespace
    1121 
    11221122
    11231123        ast::ptr< ast::Expr > resolveInVoidContext(
     
    11391139        }
    11401140
    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`
    11431142                /// context.
    11441143                ast::ptr< ast::Expr > findVoidExpression(
     
    11511150                        return newExpr;
    11521151                }
     1152
     1153        namespace {
     1154               
    11531155
    11541156                /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
     
    11621164                        CandidateRef choice =
    11631165                                findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
    1164                         finishExpr( choice->expr, choice->env, untyped->env );
     1166                        ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
    11651167                        return std::move( choice->expr );
    11661168                }
  • src/ResolvExpr/Resolver.h

    rb9537e6 rf7e4f8e8  
    6666        ast::ptr< ast::Expr > findSingleExpression(
    6767                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);
    6870        /// Resolves a constructor init expression
    6971        ast::ptr< ast::Init > resolveCtorInit(
  • src/SymTab/Autogen.cc

    rb9537e6 rf7e4f8e8  
    233233        }
    234234
     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
    235246        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    236247        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    244255                ftype->parameters.push_back( dstParam );
    245256                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));
    246265        }
    247266
  • src/SymTab/Autogen.h

    rb9537e6 rf7e4f8e8  
    5555        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
    5656        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);
    5759
    5860        /// generate the type of a copy constructor for paramType.
  • src/SynTree/Expression.h

    rb9537e6 rf7e4f8e8  
    163163};
    164164
     165/// VariableExpr represents an expression that simply refers to the value of a named variable.
     166/// Does not take ownership of var.
     167class 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
    165190// The following classes are used to represent expression types that cannot be converted into
    166191// function-call format.
     
    329354};
    330355
    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 
    356356/// ConstantExpr represents an expression that simply refers to the value of a constant
    357357class ConstantExpr : public Expression {
  • src/main.cc

    rb9537e6 rf7e4f8e8  
    343343                        auto transUnit = convert( move( translationUnit ) );
    344344                        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()));
    345352                        translationUnit = convert( move( transUnit ) );
    346353                } else {
    347354                        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() ) );
    348361                }
    349362
    350                 if ( exprp ) {
    351                         dump( translationUnit );
    352                         return EXIT_SUCCESS;
    353                 } // if
    354 
    355363                // fix ObjectDecl - replaces ConstructorInit nodes
    356                 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    357364                if ( ctorinitp ) {
    358365                        dump ( translationUnit );
  • tests/.expect/const-init.txt

    rb9537e6 rf7e4f8e8  
    1 done
     1almost done
     2dtor
  • tests/complex.cfa

    rb9537e6 rf7e4f8e8  
    1414//
    1515
    16 #include <stdio.h>
    1716#include <complex.h>
    1817#ifdef __CFA__
  • tests/const-init.cfa

    rb9537e6 rf7e4f8e8  
    1616/*
    1717
    18 This test shows non-crashing of generated code for constants with interesting initizers.
     18These tests show non-crashing of generated code for constants with interesting initializers.
    1919The potential for these to crash is compiler dependent.
    2020
    2121There are two cases:
    22 1. static constants in one compilation unit (tested here)
     221. static constants in one compilation unit (tested here, in a few sub-cases)
    23232. extern constants across compilation units (tested by libcfa being loadable, specifically
    24    the constant declarations in libcfa/src/limits.cfa, which almost every test exercises,
     24   the constant definitions in libcfa/src/limits.cfa, which almost every test exercises,
    2525   including "hello;" but notably, the "limits" test does not exercise it because that test
    2626   is compile-only)
     
    3737GCC-10 on Ubuntu 20.04    Has crashed      Has crashed
    3838
    39 For this test case to fail, with most other tests passing, would be a situation only ever
     39For this test to fail, with most other tests passing, would be a situation only ever
    4040observed with GCC-8.
    4141
    4242*/
    4343
     44// initailized by generated function, called before main
    4445static const char foo = -1;
    4546
     47struct thing{};
     48void ^?{}( thing & ) { printf("dtor\n"); }
     49
    4650int 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");
    4860}
  • tests/exceptions/cancel/coroutine.cfa

    rb9537e6 rf7e4f8e8  
    11// Try cancelling a coroutine.
    22
    3 #include <stdio.h>
    43#include <coroutine.hfa>
    54#include <exception.hfa>
  • tests/exceptions/conditional.cfa

    rb9537e6 rf7e4f8e8  
    55
    66#include <exception.hfa>
    7 #include <stdio.h>
    87
    98VTABLE_DECLARATION(num_error)(
  • tests/exceptions/except-io.hfa

    rb9537e6 rf7e4f8e8  
    11// Common tools for the exception tests.
    2 
    3 #include <stdio.h>
    42
    53// Echo when a destructor is run and an area/block is left.
  • tests/exceptions/trash.cfa

    rb9537e6 rf7e4f8e8  
    22
    33#include <exception.hfa>
    4 #include <stdio.h>
    54
    65TRIVIAL_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.
    52
    63forall(dtype T)
  • tests/poly-d-cycle.cfa

    rb9537e6 rf7e4f8e8  
    11// Check that a cycle of polymorphic dtype structures can be instancated.
    2 
    3 #include <stdio.h>
    42
    53forall(dtype T)
  • tests/poly-o-cycle.cfa

    rb9537e6 rf7e4f8e8  
    11// Check that a cycle of polymorphic otype structures can be instancated.
    2 
    3 #include <stdio.h>
    42
    53forall(otype T)
Note: See TracChangeset for help on using the changeset viewer.