Changes in / [34b4268:24d6572]


Ignore:
Files:
744 added
156 deleted
239 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    r34b4268 r24d6572  
    2020                                        gcc_08_x86_new: { trigger_build( 'gcc-10',  'x86', false ) },
    2121                                        gcc_07_x86_new: { trigger_build( 'gcc-9',   'x86', false ) },
     22                                        gcc_11_x64_new: { trigger_build( 'gcc-11',  'x64', false ) },
    2223                                        gcc_10_x64_new: { trigger_build( 'gcc-10',  'x64', false ) },
    2324                                        gcc_09_x64_new: { trigger_build( 'gcc-9',   'x64', false ) },
    2425                                        gcc_08_x64_new: { trigger_build( 'gcc-8',   'x64', false ) },
    2526                                        gcc_07_x64_new: { trigger_build( 'gcc-7',   'x64', false ) },
    26                                         gcc_06_x64_new: { trigger_build( 'gcc-6',   'x64', false ) },
     27                                        // gcc_06_x64_new: { trigger_build( 'gcc-6',   'x64', false ) },
    2728                                        clang_x64_new:  { trigger_build( 'clang',   'x64', true  ) },
    2829                                )
     
    4142        }
    4243
    43         //If an exception is caught we need to change the status and remember to
    44         //attach the build log to the email
     44        // If an exception is caught we need to change the status and remember to
     45        // attach the build log to the email
    4546        catch (Exception caughtError) {
    4647                echo('error caught')
     
    7374        // Run the build
    7475        // Don't propagate, it doesn't play nice with our email setup
    75         def result = build job: 'Cforall/master',               \
     76        def result = build job: 'Cforall/master',                       \
    7677                parameters: [                                           \
    7778                        [$class: 'StringParameterValue',                \
     
    8384                        [$class: 'BooleanParameterValue',               \
    8485                          name: 'NewAST',                               \
    85                           value: true],                                         \
     86                          value: true],                                 \
    8687                        [$class: 'BooleanParameterValue',               \
    8788                          name: 'RunAllTests',                          \
    88                           value: true],                                         \
     89                          value: true],                                 \
    8990                        [$class: 'BooleanParameterValue',               \
    9091                          name: 'RunBenchmark',                         \
    91                           value: true],                                         \
     92                          value: true],                                 \
    9293                        [$class: 'BooleanParameterValue',               \
    93                           name: 'BuildDocumentation',           \
     94                          name: 'BuildDocumentation',                   \
    9495                          value: doc],                                  \
    9596                        [$class: 'BooleanParameterValue',               \
    9697                          name: 'Publish',                              \
    97                           value: true],                                         \
     98                          value: true],                                 \
    9899                        [$class: 'BooleanParameterValue',               \
    99100                          name: 'Silent',                               \
    100                           value: true],                                         \
    101                 ],                                                              \
     101                          value: true],                                 \
     102                ],                                                      \
    102103                propagate: false
    103104
     
    111112
    112113def trigger_dist(String commitId, String buildNum) {
    113         def result = build job: 'Cforall_Distribute_Ref',       \
     114        def result = build job: 'Cforall_Distribute_Ref',               \
    114115                parameters: [                                           \
    115116                        string(name: 'GitRef', value: commitId),        \
    116                         string(name: 'Build' , value: buildNum) \
    117                 ],                                                              \
     117                        string(name: 'Build' , value: buildNum)         \
     118                ],                                                      \
    118119                propagate: false
    119120
  • Jenkins/Promote

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

    r34b4268 r24d6572  
    155155                        dir (BuildDir) {
    156156                                //Run the tests from the tests directory
    157                                 sh """make ${jopt} --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=yes archiveerrors=${BuildDir}/tests/crashes/full-debug"""
     157                                sh """make ${jopt} --no-print-directory -C tests timeout=600 global-timeout=14400 tests debug=yes archive-errors=${BuildDir}/tests/crashes/full-debug"""
    158158                        }
    159159                }
     
    162162                        dir (BuildDir) {
    163163                                //Run the tests from the tests directory
    164                                 sh """make ${jopt} --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=no  archiveerrors=${BuildDir}/tests/crashes/full-nodebug"""
     164                                sh """make ${jopt} --no-print-directory -C tests timeout=600 global-timeout=14400 tests debug=no archive-errors=${BuildDir}/tests/crashes/full-nodebug"""
    165165                        }
    166166                }
     
    305305                                this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
    306306                        break
    307                         case 'gcc-6':
    308                                 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
    309                         break
    310                         case 'gcc-5':
    311                                 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
    312                         break
    313                         case 'gcc-4.9':
    314                                 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
    315                         break
     307                        // case 'gcc-6':
     308                        //      this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
     309                        // break
     310                        // case 'gcc-5':
     311                        //      this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
     312                        // break
     313                        // case 'gcc-4.9':
     314                        //      this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
     315                        // break
    316316                        case 'clang':
    317317                                this.Compiler = new CC_Desc('clang', 'clang++-10', 'gcc-10', '-flto=thin -flto-jobs=0')
     
    359359def prepare_build() {
    360360        // prepare the properties
    361         properties ([                                                                                                   \
    362                 buildDiscarder(logRotator(                                                                              \
    363                         artifactDaysToKeepStr: '',                                                                      \
    364                         artifactNumToKeepStr: '',                                                                       \
    365                         daysToKeepStr: '730',                                                                           \
    366                         numToKeepStr: '1000'                                                                            \
    367                 )),                                                                                                             \
    368                 [$class: 'ParametersDefinitionProperty',                                                                \
    369                         parameterDefinitions: [                                                                         \
    370                                 [$class: 'ChoiceParameterDefinition',                                           \
    371                                         description: 'Which compiler to use',                                   \
    372                                         name: 'Compiler',                                                                       \
    373                                         choices: 'gcc-11\ngcc-10\ngcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang',   \
    374                                         defaultValue: 'gcc-8',                                                          \
    375                                 ],                                                                                              \
    376                                 [$class: 'ChoiceParameterDefinition',                                           \
    377                                         description: 'The target architecture',                                 \
    378                                         name: 'Architecture',                                                           \
    379                                         choices: 'x64\nx86',                                                            \
    380                                         defaultValue: 'x64',                                                            \
    381                                 ],                                                                                              \
    382                                 [$class: 'BooleanParameterDefinition',                                                  \
     361        properties ([                                                                           \
     362                buildDiscarder(logRotator(                                                      \
     363                        artifactDaysToKeepStr: '',                                              \
     364                        artifactNumToKeepStr: '',                                               \
     365                        daysToKeepStr: '730',                                                   \
     366                        numToKeepStr: '1000'                                                    \
     367                )),                                                                             \
     368                [$class: 'ParametersDefinitionProperty',                                        \
     369                        parameterDefinitions: [                                                 \
     370                                [$class: 'ChoiceParameterDefinition',                           \
     371                                        description: 'Which compiler to use',                   \
     372                                        name: 'Compiler',                                       \
     373                                        choices: 'gcc-11\ngcc-10\ngcc-9\ngcc-8\ngcc-7\nclang',  \
     374                                        defaultValue: 'gcc-9',                                  \
     375                                ],                                                              \
     376                                [$class: 'ChoiceParameterDefinition',                           \
     377                                        description: 'The target architecture',                 \
     378                                        name: 'Architecture',                                   \
     379                                        choices: 'x64\nx86',                                    \
     380                                        defaultValue: 'x64',                                    \
     381                                ],                                                              \
     382                                [$class: 'BooleanParameterDefinition',                          \
    383383                                        description: 'If false, the test suite is only ran in debug',   \
    384                                         name: 'RunAllTests',                                                            \
    385                                         defaultValue: false,                                                            \
    386                                 ],                                                                                              \
    387                                 [$class: 'BooleanParameterDefinition',                                                  \
    388                                         description: 'If true, jenkins also runs benchmarks',           \
    389                                         name: 'RunBenchmark',                                                           \
    390                                         defaultValue: false,                                                            \
    391                                 ],                                                                                              \
    392                                 [$class: 'BooleanParameterDefinition',                                                  \
    393                                         description: 'If true, jenkins also builds documentation',              \
    394                                         name: 'BuildDocumentation',                                                     \
    395                                         defaultValue: true,                                                             \
    396                                 ],                                                                                              \
    397                                 [$class: 'BooleanParameterDefinition',                                                  \
    398                                         description: 'If true, jenkins also publishes results',                 \
    399                                         name: 'Publish',                                                                        \
    400                                         defaultValue: false,                                                            \
    401                                 ],                                                                                              \
    402                                 [$class: 'BooleanParameterDefinition',                                                  \
    403                                         description: 'If true, jenkins will not send emails',           \
    404                                         name: 'Silent',                                                                         \
    405                                         defaultValue: false,                                                            \
    406                                 ],                                                                                              \
     384                                        name: 'RunAllTests',                                    \
     385                                        defaultValue: false,                                    \
     386                                ],                                                              \
     387                                [$class: 'BooleanParameterDefinition',                          \
     388                                        description: 'If true, jenkins also runs benchmarks',   \
     389                                        name: 'RunBenchmark',                                   \
     390                                        defaultValue: false,                                    \
     391                                ],                                                              \
     392                                [$class: 'BooleanParameterDefinition',                          \
     393                                        description: 'If true, jenkins also builds documentation', \
     394                                        name: 'BuildDocumentation',                             \
     395                                        defaultValue: true,                                     \
     396                                ],                                                              \
     397                                [$class: 'BooleanParameterDefinition',                          \
     398                                        description: 'If true, jenkins also publishes results', \
     399                                        name: 'Publish',                                        \
     400                                        defaultValue: false,                                    \
     401                                ],                                                              \
     402                                [$class: 'BooleanParameterDefinition',                          \
     403                                        description: 'If true, jenkins will not send emails',   \
     404                                        name: 'Silent',                                         \
     405                                        defaultValue: false,                                    \
     406                                ],                                                              \
    407407                        ],
    408408                ]])
     409                                        // choices: 'gcc-11\ngcc-10\ngcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang',
     410                                        // defaultValue: 'gcc-8',
    409411
    410412        // It's unfortunate but it looks like we need to checkout the entire repo just to get
  • Makefile.am

    r34b4268 r24d6572  
    1111## Created On       : Sun May 31 22:14:18 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Feb  2 16:54:42 2019
    14 ## Update Count     : 21
     13## Last Modified On : Wed May 17 11:02:34 2023
     14## Update Count     : 56
    1515###############################################################################
    1616
     
    2424DIST_SUBDIRS = driver src . libcfa tests
    2525
    26 @LIBCFA_TARGET_MAKEFILES@ : Makefile $(srcdir)/libcfa/configure
    27         @$(eval config_file = $(dir $@)config.data)
    28         @ls $(config_file) || (echo "Missing config.data, re-run configure script again" && false)
    29         @$(eval config_data = $(shell cat $(config_file)))
    30         @echo "Configuring libcfa ($(abs_top_srcdir)/libcfa/configure) with '$(config_data)' from $(shell pwd) / $(dir $@)"
    31         @cd $(dir $@) && $(abs_top_srcdir)/libcfa/configure $(config_data)
     26@LIBCFA_TARGET_MAKEFILES@ : Makefile ${srcdir}/libcfa/configure
     27        @${eval config_file = ${dir ${@}}config.data}
     28        @ls ${config_file} || (echo "Missing config.data, re-run configure script again" && false)
     29        @${eval config_data = ${shell cat ${config_file}}}
     30        @echo "Configuring libcfa (${abs_top_srcdir}/libcfa/configure) with '${config_data}' from ${shell pwd} / ${dir ${@}}"
     31        @cd ${dir ${@}} && ${abs_top_srcdir}/libcfa/configure ${config_data}
    3232
    3333noinst_DATA = @LIBCFA_TARGET_MAKEFILES@
     
    3737EXTRA_DIST = LICENSE doc/man/cfa.1 libcfa/configure libcfa/Makefile.dist.am libcfa/Makefile.dist.in tools/build/distcc_hash tools/build/push2dist.sh
    3838
    39 debug=yes
    40 check:
    41         $(MAKE) -C tests all-tests installed=no debug=${debug}
     39debug ?= yes
     40installed ?= no
     41ARCH = ${if ${arch},"arch=${arch}"}
     42arch_support = "x86/x64/arm"
    4243
    43 installcheck:
    44         $(MAKE) -C tests all-tests installed=yes debug=${debug}
     44# target "all" created by automake
    4545
    46 configure-libcfa: @LIBCFA_TARGET_MAKEFILES@
    47         @true
     46check :
     47        ${MAKE} -C tests tests installed=${installed} debug=${debug} ${ARCH}
    4848
    49 status: @LIBCFA_TARGET_MAKEFILES@
     49tests : check # synonym
     50
     51installcheck :
     52        ${MAKE} -C tests tests installed=yes debug=${debug} ${ARCH}
     53
     54installtest : installcheck # synonym
     55
     56status : @LIBCFA_TARGET_MAKEFILES@
    5057        @echo -ne "translator\n\t"
    5158        @./config.status --config | sed "s/ /\n\t/g; s/\t'/\t/g; s/'\n/\n/g; s/^'//g; s/'$$//g"
    5259        @find libcfa -name config.status -printf "\n%h\n\t" -exec {} --config \; | sed "s/ /\n\t/g; s/\t'/\t/g; s/'\n/\n/g; s/^'//g; s/'$$//g"
    5360
    54 @LIBCFA_TARGET_DIRS@::
    55         $(MAKE) -C $@ $(MAKECMDGOALS)
     61help :
     62        @echo "user targets:"
     63        @echo "    Compile compiler/runtime."
     64        @echo "    $$ make (null) / all"
     65        @echo ""
     66        @echo "    Compile compiler/runtime and run test suite."
     67        @echo "    $$ make check / tests [debug=yes/no] [installed=yes/no] [arch=${arch_support}]"
     68        @echo ""
     69        @echo "    Compile compiler/runtime, install, and run test suite on installed system."
     70        @echo "    $$ make installcheck / installtests [debug=yes/no] installed=yes [arch=${arch_support}]"
     71        @echo ""
     72        @echo "    Print configuration parameters and system build information."
     73        @echo "    $$ make status"
    5674
    57 mostlyclean clean distclean maintainer-clean: @LIBCFA_TARGET_DIRS@
     75configure-libcfa : @LIBCFA_TARGET_MAKEFILES@
     76        @true
     77
     78@LIBCFA_TARGET_DIRS@ ::
     79        ${MAKE} -C ${@} ${MAKECMDGOALS}
     80
     81mostlyclean clean distclean maintainer-clean : @LIBCFA_TARGET_DIRS@
  • benchmark/Makefile.am

    r34b4268 r24d6572  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Tue Mar 10 11:41:18 2020
    14 ## Update Count     : 258
     13## Last Modified On : Fri May 26 12:13:48 2023
     14## Update Count     : 260
    1515###############################################################################
    1616
     
    374374## =========================================================================================================
    375375
    376 mutexStmt$(EXEEXT) :                \
    377         mutexStmt-cpp1.run                      \
    378         mutexStmt-cpp2.run                      \
    379         mutexStmt-cpp4.run                      \
    380         mutexStmt-cpp8.run                      \
    381         mutexStmt-java.run                      \
    382         mutexStmt-lock1.run                 \
    383         mutexStmt-lock2.run                 \
    384         mutexStmt-lock4.run                 \
    385         mutexStmt-lock8.run                 \
    386         mutexStmt-no-stmt-lock1.run \
    387         mutexStmt-no-stmt-lock2.run \
    388         mutexStmt-no-stmt-lock4.run \
    389         mutexStmt-no-stmt-lock8.run \
    390         mutexStmt-monitor1.run      \
    391         mutexStmt-monitor2.run      \
     376mutexStmt$(EXEEXT) :                    \
     377        mutexStmt-cpp1.run              \
     378        mutexStmt-cpp2.run              \
     379        mutexStmt-cpp4.run              \
     380        mutexStmt-cpp8.run              \
     381        mutexStmt-java.run              \
     382        mutexStmt-lock1.run             \
     383        mutexStmt-lock2.run             \
     384        mutexStmt-lock4.run             \
     385        mutexStmt-lock8.run             \
     386        mutexStmt-no-stmt-lock1.run     \
     387        mutexStmt-no-stmt-lock2.run     \
     388        mutexStmt-no-stmt-lock4.run     \
     389        mutexStmt-no-stmt-lock8.run     \
     390        mutexStmt-monitor1.run          \
     391        mutexStmt-monitor2.run          \
    392392        mutexStmt-monitor4.run
    393393
     
    567567        compile-array.make      \
    568568        compile-attributes.make \
    569         compile-empty.make      \
     569        compile-empty.make      \
    570570        compile-expression.make \
    571571        compile-io.make         \
     
    592592
    593593compile-monitor$(EXEEXT):
    594         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     594        $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/concurrency/monitor.cfa
    595595
    596596compile-operators$(EXEEXT):
     
    598598
    599599compile-thread$(EXEEXT):
    600         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     600        $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/concurrency/thread.cfa
    601601
    602602compile-typeof$(EXEEXT):
  • configure.ac

    r34b4268 r24d6572  
    4747
    4848#==============================================================================
    49 # HACK to be able to use conditionnals inside makefiles
     49# HACK to be able to use conditionals inside makefiles
    5050DOifskipcompile='ifeq ($(skipcompile),yes)
    5151else'
     
    226226AC_PROG_YACC
    227227if test "${YACC}" = "yacc" ; then echo "Error: bison required." ; exit 1 ; fi
    228 AC_PROG_LEX
     228AC_PROG_LEX(yywrap)
    229229if test "${LEX}" = "lex" ; then echo "Error: flex required." ; exit 1 ; fi
    230 AC_PROG_LIBTOOL
     230LT_INIT
    231231AC_PROG_INSTALL
    232232
     
    284284                tools/Makefile
    285285                tools/prettyprinter/Makefile
     286                benchmark/Cargo.toml
    286287        ])
    287 
    288         AC_OUTPUT(benchmark/Cargo.toml)
    289288])
    290289
    291290AC_CONFIG_LINKS([tests/test.py:tests/test.py])
    292 
    293 AC_OUTPUT(tests/config.py)
     291AC_CONFIG_FILES([tests/config.py])
     292
     293AC_OUTPUT
    294294
    295295# Final text
  • doc/LaTeXmacros/common.sty

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

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

    r34b4268 r24d6572  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Mon May 31 08:20:41 2021
    11 %% Update Count     : 28
     10%% Last Modified On : Tue May  2 08:52:35 2023
     11%% Update Count     : 30
    1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1313
     
    112112\lstdefinelanguage{CFA}[ANSI]{C}{
    113113        morekeywords={
    114                 _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__,
    115                 auto, basetypeof, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
    116                 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, fixup,
    117                 __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
    118                 inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
    119                 otype, restrict, __restrict, __restrict__, recover, report, __signed, __signed__, _Static_assert, suspend,
    120                 thread, __thread, _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    121                 virtual, __volatile, __volatile__, waitfor, when, with, zero_t,
     114                _Alignas, _Alignof, __alignof, __alignof__, and, asm, __asm, __asm__, _Atomic, __attribute, __attribute__,
     115                __auto_type, basetypeof, _Bool, catch, catchResume, choose, coerce, _Complex, __complex, __complex__, __const, __const__,
     116                coroutine, _Decimal32, _Decimal64, _Decimal128, disable, enable, exception, __extension__, fallthrough, fallthru, finally, fixup,
     117                __float80, float80, __float128, float128, _Float16, _Float32, _Float32x, _Float64, _Float64x, _Float128, _Float128x,
     118                forall, fortran, generator, _Generic, _Imaginary, __imag, __imag__, inline, __inline, __inline__, int128, __int128, __int128_t,
     119                __label__, monitor, mutex, _Noreturn, __builtin_offsetof, one_t, or, recover, report, restrict, __restrict, __restrict__,
     120                __signed, __signed__, _Static_assert, suspend, thread, __thread, _Thread_local, throw, throwResume, timeout, trait, try,
     121                typeof, __typeof, __typeof__, typeid, __uint128_t, __builtin_va_arg, __builtin_va_list, virtual, __volatile, __volatile__,
     122                vtable, waitfor, waituntil, when, with, zero_t,
    122123    },
    123124        moredirectives={defined,include_next}%
  • doc/bibliography/pl.bib

    r34b4268 r24d6572  
    147147    author      = {Zhang, Yizhou and Salvaneschi, Guido and Beightol, Quinn and Liskov, Barbara and Myers, Andrew C.},
    148148    title       = {Accepting Blame for Safe Tunneled Exceptions},
    149     booktitle   = {Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation},
     149    organization= {Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation},
    150150    series      = {PLDI'16},
    151151    year        = {2016},
     
    198198}
    199199
     200@inproceedings{Koster16,
     201    keywords    = {Actor Model, Concurrency},
     202    contributer = {pabuhr@plg},
     203    author      = {De Koster, Joeri and Van Cutsem, Tom and De Meuter, Wolfgang},
     204    title       = {43 Years of Actors: A Taxonomy of Actor Models and Their Key Properties},
     205    publisher   = {ACM},
     206    address     = {New York, NY, USA},
     207    organization= {Proceedings of the 6th International Workshop on Programming Based on Actors, Agents, and Decentralized Control},
     208    pages       = {31-40},
     209    numpages    = {10},
     210    year        = {2016},
     211    location    = {Amsterdam, Netherlands},
     212    series      = {AGERE 2016}
     213}
     214
     215@misc{ActorBenchmarks,
     216    keywords    = {Actors, microbenchmarks, uC++. CAF, ProtoActor, AkkaC, AkkaT},
     217    contributer = {pabuhr@plg},
     218    key         = {ActorBenchmarks},
     219    title       = {Actor Benchmarks},
     220    author      = {Peter A. Buhr and Colby A. Parsons},
     221    howpublished= {\href{https://github.com/pabuhr/ActorExperiments}{https://\-github.com/\-pabuhr/\-ActorExperiments}},
     222    year        = 2022,
     223}
     224
    200225@book{Actors,
    201226    keywords    = {actors, concurrency},
     
    205230    publisher   = {MIT Press, Cambridge},
    206231    year        = 1986
     232}
     233
     234@inproceedings{Srinivasan08,
     235    author      = {Srinivasan, Sriram and Mycroft, Alan},
     236    editor      = {Vitek, Jan},
     237    title       = {Kilim: Isolation-Typed Actors for Java},
     238    organization= {ECOOP 2008 -- Object-Oriented Programming},
     239    year        = {2008},
     240    publisher   = {Springer Berlin Heidelberg},
     241    address     = {Berlin, Heidelberg},
     242    pages       = {104--128},
     243}
     244
     245@inproceedings{Haller07,
     246    author      = {Haller, Philipp and Odersky, Martin},
     247    editor      = {Murphy, Amy L. and Vitek, Jan},
     248    title       = {Actors That Unify Threads and Events},
     249    organization= {Coordination Models and Languages},
     250    year        = 2007,
     251    publisher   = {Springer Berlin Heidelberg},
     252    address     = {Berlin, Heidelberg},
     253    pages       = {171-190},
    207254}
    208255
     
    245292}
    246293
     294@manual{Ada95,
     295    keywords    = {Ada},
     296    contributer = {pabuhr@plg},
     297    title       = {{A}da Reference Manual},
     298    edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
     299    organization= {Intermetrics, Inc.},
     300    month       = dec,
     301    year        = 1995,
     302    note        = {Language and Standards Libraries}
     303}
     304
     305@manual{Ada12,
     306    keywords    = {ISO/IEC Ada},
     307    contributer = {pabuhr@plg},
     308    author      = {Ada12},
     309    title       = {Programming languages -- {Ada} ISO/IEC 8652:2012},
     310    edition     = {3rd},
     311    organization= {International Standard Organization},
     312    address     = {Geneva, Switzerland},
     313    year        = 2012,
     314    note        = {\href{https://www.iso.org/standard/61507.html}{https://\-www.iso.org/\-standard/\-61507.html}},
     315}
     316
     317@manual{Ada95:annotated,
     318    keywords    = {Ada},
     319    contributer = {pabuhr@plg},
     320    title       = {Annotated {A}da Reference Manual},
     321    edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
     322    organization= {Intermetrics, Inc.},
     323    month       = dec,
     324    year        = 1995,
     325    note        = {Language and Standards Libraries}
     326}
     327
    247328@article{dim:ada,
    248329    keywords    = {Dimensional Analysis, Ada},
     
    256337    number      = 2,
    257338    pages       = {189-203},
     339}
     340
     341@article{Agrawal08,
     342    keywords    = {Adaptive scheduling, multiprocessing, processor allocation, randomized algorithm, space sharing, thread scheduling, two-level scheduling, work-stealing},
     343    author      = {Agrawal, Kunal and Leiserson, Charles E. and He, Yuxiong and Hsu, Wen Jing},
     344    title       = {Adaptive Work-stealing with Parallelism Feedback},
     345    journal     = {ACM Trans. Comput. Syst.},
     346    issue_date  = {September 2008},
     347    volume      = {26},
     348    number      = {3},
     349    month       = sep,
     350    year        = {2008},
     351    pages       = {7:1-7:32},
     352    publisher   = {ACM},
     353    address     = {New York, NY, USA},
    258354}
    259355
     
    376472    month       = sep,
    377473    year        = 2016,
    378     note        = {\href{http://doc.akka.io/docs/akka/2.4/AkkaScala.pdf}{http://\-doc.akka.io/\-docs/\-akka/\-2.4/\-AkkaScala.pdf}},
     474    note        = {\url{http://doc.akka.io/docs/akka/2.4/AkkaScala.pdf}},
     475}
     476
     477@misc{AkkaClassic,
     478    contributer = {pabuhr@plg},
     479    key         = {AkkaClassic},
     480    title       = {Akka Classic Actors},
     481    author      = {{Lightbend}},
     482    howpublished= {\url{https://doc.akka.io/docs/akka/current/index-classic.html}},
     483    year        = 2023,
     484}
     485
     486@misc{AkkaFuture,
     487    contributer = {pabuhr@plg},
     488    key         = {AkkaFuture},
     489    title       = {Akka Futures},
     490    author      = {{Lightbend}},
     491    howpublished= {\url{https://doc.akka.io/docs/akka/2.5/futures.html}},
     492    year        = 2022,
     493}
     494
     495@misc{AkkaTyped,
     496    contributer = {pabuhr@plg},
     497    key         = {AkkaTyped},
     498    title       = {Akka Typed Actors},
     499    author      = {{Lightbend}},
     500    howpublished= {\url{https://doc.akka.io/docs/akka/2.5/typed-actors.html}},
     501    year        = 2022,
    379502}
    380503
     
    548671}
    549672
     673@inproceedings{Mitzenmacher98,
     674    author      = {Mitzenmacher, Michael},
     675    title       = {Analyses of Load Stealing Models Based on Differential Equations},
     676    organization= {Proceedings of the Tenth Annual ACM Symposium on Parallel Algorithms and Architectures},
     677    series      = {SPAA '98},
     678    year        = {1998},
     679    isbn        = {0-89791-989-0},
     680    location    = {Puerto Vallarta, Mexico},
     681    pages       = {212-221},
     682    publisher   = {ACM},
     683    address     = {New York, NY, USA},
     684}
     685
     686@inproceedings{Squillante91,
     687    author      = {Squillante, Mark S. and Nelson, Randolph D.},
     688    title       = {Analysis of Task Migration in Shared-memory Multiprocessor Scheduling},
     689    organization= {Proceedings of the 1991 ACM SIGMETRICS Conference on Measurement and Modeling of Computer Systems},
     690    series      = {SIGMETRICS '91},
     691    year        = {1991},
     692    isbn        = {0-89791-392-2},
     693    location    = {San Diego, California, USA},
     694    pages       = {143-155},
     695    publisher   = {ACM},
     696    address     = {New York, NY, USA},
     697}
     698
    550699@article{Sinha00,
    551700    author      = {Saurabh Sinha and Mary Jean Harrold},
     
    562711    author      = {Martin P. Robillard and Gail C. Murphy},
    563712    title       = {Analyzing Exception Flow in {J}ava Programs},
    564     booktitle   = {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly
     713    organization= {ESEC/FSE-7: Proceedings of the 7th European Software Engineering Conference held jointly
    565714                   with the 7th ACM SIGSOFT International Symposium on Foundations of Software Engineering},
    566715    year        = 1999,
     
    604753    author      = {Henry Qin and Qian Li and Jacqueline Speiser and Peter Kraft and John Ousterhout},
    605754    title       = {Arachne: Core-Aware Thread Management},
    606     booktitle   = {13th {USENIX} Symp. on Oper. Sys. Design and Impl. ({OSDI} 18)},
     755    organization= {13th {USENIX} Symp. on Oper. Sys. Design and Impl. ({OSDI} 18)},
    607756    year        = {2018},
    608757    address     = {Carlsbad, CA},
     
    661810    author      = {Jaewoong Chung and Luke Yen and Stephan Diestelhorst and Martin Pohlack and Michael Hohmuth and David Christie and Dan Grossman},
    662811    title       = {ASF: AMD64 Extension for Lock-Free Data Structures and Transactional Memory},
    663     booktitle   = {Proceedings of the 2010 43rd Annual IEEE/ACM International Symposium on Microarchitecture},
     812    organization= {Proceedings of the 2010 43rd Annual IEEE/ACM International Symposium on Microarchitecture},
    664813    series      = {MICRO '43},
    665814    year        = 2010,
     
    682831}
    683832
     833@misc{AsyncAwait,
     834    contributer = {pabuhr@plg},
     835    key         = {AsyncAwait},
     836    title       = {Async Await},
     837    author      = {{WikipediA}},
     838    howpublished= {\href{https://en.wikipedia.org/wiki/Async/await}{https://\-en.wikipedia.org/\-wiki/\-Async/\-await}},
     839    year        = 2022,
     840}
     841
    684842@inproceedings{Krischer08,
    685843    keywords    = {exception handling, asynchronous, blocked tasks},
     
    687845    author      = {Roy Krischer and Peter A. Buhr},
    688846    title       = {Asynchronous Exception Propagation in Blocked Tasks},
    689     booktitle   = {4th International Workshop on Exception Handling (WEH.08)},
     847    organization= {4th International Workshop on Exception Handling (WEH.08)},
    690848    optorganization= {16th International Symposium on the Foundations of Software Engineering (FSE 16)},
    691849    address     = {Atlanta, U.S.A},
     
    696854
    697855@article{Joung00,
     856    keywords    = {group mutual exclusion, congenial talking philosophers, resource allocation, shared-memory algorithms},
    698857    author      = {Joung, Yuh-Jzer},
    699858    title       = {Asynchronous group mutual exclusion},
     
    759918    publisher   = {ACM},
    760919    address     = {New York, NY, USA},
     920}
     921
     922@techreport{Neill09,
     923    author      = {Daniel Neill and Adam Wierman},
     924    title       = {On the Benefits of Work Stealing in Shared-Memory Multiprocessors},
     925    institution = {Carnegie Mellon University},
     926    address     = {California Institute of Technology, Pasadena, CA, USA},
     927    note        = {\href{http://www.cs.cmu.edu/~acw/15740/paper.pdf}{http://\-www.cs.cmu.edu/\-$\sim$acw/\-15740/\-paper.pdf}, Accessed May 2014},
     928    year        = 2009,
    761929}
    762930
     
    9161084}
    9171085
     1086@inproceedings{Ding12,
     1087    keywords    = {fairness, multicore, time sharing, work stealing},
     1088    author      = {Ding, Xiaoning and Wang, Kaibo and Gibbons, Phillip B. and Zhang, Xiaodong},
     1089    title       = {BWS: Balanced Work Stealing for Time-sharing Multicores},
     1090    organization= {Proceedings of the 7th ACM European Conference on Computer Systems},
     1091    series      = {EuroSys '12},
     1092    year        = {2012},
     1093    location    = {Bern, Switzerland},
     1094    pages       = {365-378},
     1095    publisher   = {ACM},
     1096    address     = {New York, NY, USA},
     1097}
     1098
    9181099% C
    9191100
     
    9901171}
    9911172
     1173@inproceedings{CAF,
     1174    keywords    = {performance measurement, actor model, c++, message-oriented middleware, distributed debugging},
     1175    contributer = {pabuhr@plg},
     1176    author      = {Charousset, Dominik and Hiesgen, Raphael and Schmidt, Thomas C.},
     1177    title       = {{CAF} -- the {C}++ Actor Framework for Scalable and Resource-Efficient Applications},
     1178    publisher   = {ACM},
     1179    address     = {New York, NY, USA},
     1180    organization= {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
     1181    pages       = {15-28},
     1182    numpages    = 14,
     1183    location    = {Portland, Oregon, USA},
     1184    series      = {AGERE'14},
     1185    year        = 2014,
     1186}
     1187
    9921188@techreport{cfa-cc,
    9931189    keywords    = {Cforall, cfa-cc, transpiler},
     
    10131209    year        = 2018,
    10141210    pages       = {2111-2146},
    1015     note        = {\href{http://dx.doi.org/10.1002/spe.2624}{http://\-dx.doi.org/\-10.1002/\-spe.2624}},
     1211    optnote     = {\href{http://dx.doi.org/10.1002/spe.2624}{http://\-dx.doi.org/\-10.1002/\-spe.2624}},
    10161212}
    10171213
     
    11721368@techreport{Prokopec11,
    11731369    keywords    = {ctrie, concurrent map},
    1174     contributer = {a3moss@uwaterloo.ca},
     1370    contributer = {a3moss@uwaterloo.ca},
    11751371    title       = {Cache-aware lock-free concurrent hash tries},
    11761372    author      = {Prokopec, Aleksandar and Bagwell, Phil and Odersky, Martin},
     
    14961692    author      = {Emery D. Berger and Benjamin G. Zorn and Kathryn S. McKinley},
    14971693    title       = {Composing High-Performance Memory Allocators},
    1498     booktitle   = {{SIGPLAN} Conference on Programming Language Design and Implementation},
     1694    organization= {{SIGPLAN} Conference on Programming Language Design and Implementation},
    14991695    pages       = {114-124},
    15001696    year        = 2001,
     
    16741870    month       = sep,
    16751871    year        = 2020,
    1676     note        = {\href{https://plg.uwaterloo.ca/~usystem/pub/uSystem/uC++.pdf}{https://\-plg.uwaterloo.ca/\-$\sim$usystem/\-pub/\-uSystem/uC++.pdf}},
     1872    note        = {\url{https://plg.uwaterloo.ca/~usystem/pub/uSystem/uC++.pdf}},
    16771873}
    16781874
     
    18082004    number      = 5,
    18092005    pages       = {1005-1042},
    1810     note        = {\href{https://onlinelibrary.wiley.com/doi/10.1002/spe.2925}{https://\-onlinelibrary.wiley.com/\-doi/\-10.1002/\-spe.2925}},
     2006    optnote     = {\href{https://onlinelibrary.wiley.com/doi/10.1002/spe.2925}{https://\-onlinelibrary.wiley.com/\-doi/\-10.1002/\-spe.2925}},
    18112007}
    18122008
     
    19962192    address     = {Eindhoven, Neth.},
    19972193    year        = 1965,
    1998     note        = {Reprinted in \cite{Genuys68} pp. 43--112.}
     2194    optnote     = {Reprinted in \cite{Genuys68} pp. 43--112.},
     2195    note        = {\url{https://pure.tue.nl/ws/files/4279816/344354178746665.pdf}},
    19992196}
    20002197
     
    20032200    author      = {Adya, Atul and Howell, Jon and Theimer, Marvin and Bolosky, William J. and Douceur, John R.},
    20042201    title       = {Cooperative Task Management Without Manual Stack Management},
    2005     booktitle   = {Proc. of the General Track USENIX Tech. Conf.},
     2202    organization= {Proc. of the General Track USENIX Tech. Conf.},
    20062203    series      = {ATEC '02},
    20072204    year        = {2002},
     
    21112308    year        = 2016,
    21122309    note        = {\href{http://dlang.org/spec/spec.html}{http://\-dlang.org/\-spec/\-spec.html}},
     2310}
     2311
     2312@article{Acar02,
     2313    author      = {Acar, Umut A. and Blelloch, Guy E. and Blumofe, Robert D.},
     2314    title       = {The Data Locality of Work Stealing},
     2315    journal     = {Theory of Computing Systems},
     2316    volume      = {35},
     2317    number      = {3},
     2318    year        = {2002},
     2319    publisher   = {Springer-Verlag},
     2320    pages       = {321-347},
    21132321}
    21142322
     
    23702578    editor      = {R. E. A. Mason},
    23712579    organization= {IFIP},
    2372     publisher = {North-Holland},
    2373     summary = {
     2580    publisher   = {North-Holland},
     2581    summary     = {
    23742582        Packages group related declarations or subprograms, and encapsulate
    23752583        data types.  Separate interfaces and bodies promotes information
     
    25982806    address     = {Waterview Corporate Center, 20 Waterview Boulevard, Parsippany, NJ 07054},
    25992807    year        = {1993}
     2808}
     2809
     2810@inproceedings{Chen14,
     2811    keywords    = {Core allocation, Multi-programmed, Work-stealing},
     2812    author      = {Chen, Quan and Zheng, Long and Guo, Minyi},
     2813    title       = {DWS: Demand-aware Work-Stealing in Multi-programmed Multi-core Architectures},
     2814    organization= {Proceedings of Programming Models and Applications on Multicores and Manycores},
     2815    series      = {PMAM'14},
     2816    year        = {2007},
     2817    location    = {Orlando, FL, USA},
     2818    pages       = {131:131-131:139},
     2819    articleno   = {131},
     2820    numpages    = {9},
     2821    publisher   = {ACM},
     2822    address     = {New York, NY, USA},
    26002823}
    26012824
     
    26312854    year        = 2003,
    26322855    pages       = {29-35},
     2856}
     2857
     2858@inproceedings{Hamidzadeh96,
     2859    keywords    = {processor scheduling, resource allocation, shared memory systems, average memory referencing delay},
     2860    author      = {Hamidzadeh, B. and Lilja, D.J.},
     2861    booktitle   = {Distributed Computing Systems, 1996., Proceedings of the 16th International Conference on},
     2862    title       = {Dynamic scheduling strategies for shared-memory multiprocessors},
     2863    year        = {1996},
     2864    month       = {May},
     2865    pages       = {208-215},
     2866}
     2867
     2868@article{Hendler06,
     2869    keywords    = {Concurrent programming; Load balancing; Work stealing; Lock-free; Data structures},
     2870    author      = {Hendler, Danny and Lev, Yossi and Moir, Mark and Shavit, Nir},
     2871    title       = {A dynamic-sized nonblocking work stealing deque},
     2872    journal     = {Distributed Computing},
     2873    volume      = {18},
     2874    number      = {3},
     2875    year        = {2006},
     2876    publisher   = {Springer-Verlag},
     2877    pages       = {189-207},
    26332878}
    26342879
     
    27342979}
    27352980
     2981@inproceedings{Blelloch04,
     2982    keywords    = {chip multiprocessors, multithreaded architectures, scheduling algorithms, shared cache},
     2983    author      = {Blelloch, Guy E. and Gibbons, Phillip B.},
     2984    title       = {Effectively Sharing a Cache Among Threads},
     2985    organization= {Proceedings of the Sixteenth Annual ACM Symposium on Parallelism in Algorithms and Architectures},
     2986    series      = {SPAA '04},
     2987    year        = {2004},
     2988    location    = {Barcelona, Spain},
     2989    pages       = {235-244},
     2990    publisher   = {ACM},
     2991    address     = {New York, NY, USA},
     2992}
     2993
    27362994@techreport{Habermann80,
    27372995    keywords    = {Ada, threads},
     
    28083066    title       = {Encapsulation and Inheritance in Object-Oriented Programming Languages},
    28093067    journal     = sigplan,
    2810     volume      = {21},    number = {11},
     3068    volume      = {21},
     3069    number      = {11},
    28113070    pages       = {38-45},
    2812     month       = nov, year = 1986,
     3071    month       = nov,
     3072    year        = 1986,
    28133073    comment     = {
    28143074        Client, child interfaces should be distinct.  Child interface
     
    28663126}
    28673127
     3128@inproceedings{Ribic14,
     3129    keywords    = {dvfs, energy efficiency, language runtimes, thread management, work stealing},
     3130    author      = {Ribic, Haris and Liu, Yu David},
     3131    title       = {Energy-efficient Work-stealing Language Runtimes},
     3132    organization= {Proceedings of the 19th International Conference on Architectural Support for Programming Languages and Operating Systems},
     3133    series      = {ASPLOS '14},
     3134    year        = {2014},
     3135    location    = {Salt Lake City, Utah, USA},
     3136    pages       = {513-528},
     3137    publisher   = {ACM},
     3138    address     = {New York, NY, USA},
     3139}
     3140
    28683141@manual{EPT,
    28693142    keywords    = {concurrency, light-weight threads},
     
    28873160}
    28883161
     3162@misc{Soleimani16,
     3163    keywords    = {Erlang, scheduler, history},
     3164    contributer = {pabuhr@plg},
     3165    author      = {Hamidreza Soleimani},
     3166    title       = {Erlang Scheduler Details and Why It Matters},
     3167    month       = feb,
     3168    year        = 2016,
     3169    howpublished= {\url{https://hamidreza-s.github.io/erlang/scheduling/real-time/preemptive/migration/2016/02/09/erlang-scheduler-details.html}},
     3170}
     3171
    28893172@inproceedings{MH88,
    28903173    keywords    = {modules, general sums, general products},
     
    29033186    publisher   = {North Oxford Academic},
    29043187    year        = 1985
     3188}
     3189
     3190@article{Torrellas95,
     3191    author      = {J. Torrellas and A. Tucker and A. Gupta},
     3192    title       = {Evaluating the Performance of Cache-Affinity Scheduling in Shared-Memory Multiprocessors},
     3193    journal     = {Journal of Parallel and Distributed Computing},
     3194    volume      = {24},
     3195    number      = {2},
     3196    pages       = {139-151},
     3197    year        = {1995},
    29053198}
    29063199
     
    36143907    author      = {Robert Griesemer and Rob Pike and Ken Thompson},
    36153908    title       = {{Go} Programming Language},
     3909    address     = {Mountain View, CA, USA},
    36163910    organization= {Google},
    36173911    year        = 2009,
     
    37254019@article{Michael04a,
    37264020    keywords    = {Lock-free, synchronization, concurrent programming, memory management, multiprogramming, dynamic data structures},
     4021    contributer = {pabuhr@plg},
    37274022    author      = {Maged M. Michael},
    37284023    title       = {Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects},
     
    37354030    publisher   = {IEEE Press},
    37364031    address     = {Piscataway, NJ, USA},
     4032}
     4033
     4034@inproceedings{Johansson02,
     4035    keywords    = {concurrent languages, erlang, garbage collection, message passing, runtime systems},
     4036    contributer = {pabuhr@plg},
     4037    author      = {Erik Johansson and Konstantinos Sagonas and Jesper Wilhelmsson},
     4038    title       = {Heap Architectures for Concurrent Languages Using Message Passing},
     4039    year        = {2002},
     4040    isbn        = {1581135394},
     4041    publisher   = {ACM},
     4042    address     = {New York, NY, USA},
     4043    organization= {Proceedings of the 3rd International Symposium on Memory Management},
     4044    pages       = {88-99},
     4045    location    = {Berlin, Germany},
    37374046}
    37384047
     
    39144223    title       = {Implementing Lock-Free Queues},
    39154224    booktitle   = {Seventh International Conference on Parallel and Distributed Computing Systems},
     4225    organization= {International Society for Computers and Their Applications},
    39164226    address     = {Las Vegas, Nevada, U.S.A.},
    39174227    year        = {1994},
    39184228    pages       = {64-69},
     4229}
     4230
     4231@inproceedings{Halstead84,
     4232    author      = {Halstead,Jr., Robert H.},
     4233    title       = {Implementation of Multilisp: Lisp on a Multiprocessor},
     4234    organization= {Proceedings of the 1984 ACM Symposium on LISP and Functional Programming},
     4235    series      = {LFP '84},
     4236    year        = {1984},
     4237    location    = {Austin, Texas, USA},
     4238    pages       = {9-17},
     4239    publisher   = {ACM},
     4240    address     = {New York, NY, USA},
    39194241}
    39204242
     
    46955017    contributer = {pabuhr@plg},
    46965018    author      = {Lua},
    4697     title       = {Lua 5.3 Reference Manual},
    4698     address     = {\href{https://www.lua.org/manual/5.3}{https://\-www.lua.org/\-manual/\-5.3}},
    4699     year        = 2018,
     5019    title       = {Lua 5.4 Reference Manual},
     5020    organization= {Pontifical Catholic University},
     5021    address     = {\href{https://www.lua.org/manual/5.4}{https://\-www.lua.org/\-manual/\-5.4}},
     5022    year        = 2020,
    47005023}
    47015024
     
    47645087}
    47655088
    4766 @manual{MMTk,
     5089@misc{MMTk,
    47675090    keywords    = {Java memory management},
    47685091    contributer = {pabuhr@plg},
     
    47715094    month       = sep,
    47725095    year        = 2006,
    4773     note        = {\href{http://cs.anu.edu.au/~Robin.Garner/mmtk-guide.pdf}
    4774                   {http://cs.anu.edu.au/\-$\sim$Robin.Garner/\-mmtk-guide.pdf}},
     5096    howpublished= {\url{http://cs.anu.edu.au/~Robin.Garner/mmtk-guide.pdf}},
    47755097}
    47765098
     
    50785400    year        = 2015,
    50795401    note        = {\href{http://www.mpi-forum.org/docs/mpi-3.1/mpi31-report.pdf}{http://www.mpi-forum.org/\-docs/\-mpi-3.1/\-mpi31-report.pdf}},
     5402}
     5403
     5404@article{Lombardo19,
     5405    contributer = {pabuhr@plg},
     5406    author      = {Lombardo, Gianfranco and Fornacciari, Paolo and Mordonini, Monica and Tomaiuolo, Michele and Poggi, Agostino},
     5407    title       = {A Multi-Agent Architecture for Data Analysis},
     5408    journal     = {Future Internet},
     5409    volume      = 11,
     5410    year        = 2019,
     5411    number      = 2,
    50805412}
    50815413
     
    52775609        Programming Language},
    52785610    year        = 1980,
    5279     month       = dec, pages = {139-145},
     5611    month       = dec,
     5612    pages       = {139-145},
    52805613    note        = {SIGPLAN Notices, v. 15, n. 11},
    52815614    abstract    = {
     
    53985731    year        = 2005,
    53995732    pages       = {146-196},
     5733    publisher   = {ACM},
     5734    address     = {New York, NY, USA},
     5735}
     5736
     5737@inproceedings{Hendler02,
     5738    author      = {Hendler, Danny and Shavit, Nir},
     5739    title       = {Non-blocking Steal-half Work Queues},
     5740    organization= {Proceedings of the Twenty-first Annual Symposium on Principles of Distributed Computing},
     5741    series      = {PODC '02},
     5742    year        = {2002},
     5743    location    = {Monterey, California},
     5744    pages       = {280-289},
    54005745    publisher   = {ACM},
    54015746    address     = {New York, NY, USA},
     
    56465991}
    56475992
     5993@misc{OpenTelemetry,
     5994    contributer = {pabuhr@plg},
     5995    key         = {OpenTelemetry},
     5996    title       = {OpenTelemetry},
     5997    author      = {{Asynkron AB}},
     5998    howpublished= {\href{https://proto.actor/docs/tracing}{https://\-proto.actor/\-docs/\-tracing}},
     5999    year        = 2022,
     6000}
     6001
    56486002@inproceedings{Krebbers14,
    56496003    keywords    = {c formalization},
     
    58836237}
    58846238
     6239@article{Nigro21,
     6240    keywords    = {Actors, Asynchronous messages, Reflective control on message passing, Lock-free parallel computing, Java, Scalable multi-agent systems, Parallel matrix multiplication, Iterated Prisoner's Dilemma},
     6241    contributer = {pabuhr@plg},
     6242    author      = {Libero Nigro},
     6243    title       = {Parallel Theatre: An actor framework in {Java} for high performance computing},
     6244    journal     = {Simulation Modelling Practice and Theory},
     6245    volume      = {106},
     6246    number      = {102189},
     6247    year        = {2021},
     6248}
     6249
    58856250@incollection{Stroustrup96,
    58866251    keywords    = {concurrency, C++},
     
    59176282    journal     = ieeese,
    59186283    year        = 1984,
    5919     month       = sep, volume = "SE-10", number = 5, pages = {528-543},
     6284    month       = sep,
     6285    volume      = "SE-10",
     6286    number      = 5,
     6287    pages       = {528-543},
    59206288    abstract    = {
    59216289        Parameterized programming is a powerful technique for the reliable
     
    59496317    booktitle   = {USENIX {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Conference},
    59506318    organization= {USENIX Association},
    5951     year        = 1988, pages = {1-18}
     6319    year        = 1988,
     6320    pages       = {1-18},
    59526321}
    59536322
     
    60376406}
    60386407
     6408@incollection{Kazempour08,
     6409    keywords    = {multicore processors; cache affinity; performance evaluation; scheduling},
     6410    author      = {Kazempour, Vahid and Fedorova, Alexandra and Alagheband, Pouya},
     6411    title       = {Performance Implications of Cache Affinity on Multicore Processors},
     6412    organization= {Euro-Par 2008 -- Parallel Processing},
     6413    series      = {Lecture Notes in Computer Science},
     6414    editor      = {Luque, Emilio and Margalef, Tomas and Benitez, Domingo},
     6415    year        = {2008},
     6416    volume      = {5168},
     6417    pages       = {151-161},
     6418    publisher   = {Springer Berlin Heidelberg},
     6419}
     6420
     6421@article{Anderson89,
     6422    keywords    = {data structures, multiprocessing systems, operating systems (computers), performance evaluation, critical resource waiting},
     6423    author      = {Anderson, T.E. and Lazowska, E.D. and Levy, H.M.},
     6424    journal     = {Computers, IEEE Transactions on},
     6425    title       = {The Performance Implications of Thread Management Alternatives for Shared-Memory Multiprocessors},
     6426    year        = {1989},
     6427    month       = {Dec},
     6428    volume      = {38},
     6429    number      = {12},
     6430    pages       = {1631-1644},
     6431}
     6432
    60396433@article{Anderson90,
    60406434    keywords    = {spin locks, back off, performance},
     
    60486442    number      = 1,
    60496443    pages       = {6-16},
     6444}
     6445
     6446@article{Blumofe98,
     6447    author      = {Blumofe, Robert D. and Papadopoulos, Dionisios},
     6448    title       = {The Performance of Work Stealing in Multiprogrammed Environments (Extended Abstract)},
     6449    journal     = {SIGMETRICS Perform. Eval. Rev.},
     6450    volume      = {26},
     6451    number      = {1},
     6452    month       = jun,
     6453    year        = {1998},
     6454    issn        = {0163-5999},
     6455    pages       = {266-267},
     6456    publisher   = {ACM},
     6457    address     = {New York, NY, USA},
    60506458}
    60516459
     
    62866694}
    62876695
     6696@article{Varela01,
     6697    keywords    = {programming languages, SALSA, continuations, actors, java, internet, network computing, open systems, mobile computing},
     6698    contributer = {pabuhr@plg},
     6699    author      = {Varela, Carlos and Agha, Gul},
     6700    title       = {Programming Dynamically Reconfigurable Open Systems with SALSA},
     6701    issue_date  = {December 2001},
     6702    publisher   = {Association for Computing Machinery},
     6703    address     = {New York, NY, USA},
     6704    volume      = 36,
     6705    number      = 12,
     6706    journal     = {SIGPLAN Not.},
     6707    year        = 2001,
     6708    month       = dec,
     6709    pages       = {20-34},
     6710}
     6711
    62886712@book{PowerPC,
    62896713    key         = {PowerPC processor},
     
    63476771    title       = {Programming Languages -- {C}},
    63486772    organization= {International Standard ISO/IEC 9899:1999 (E)},
    6349     publisher   = {American National Standards Institute},
     6773    publisher   = {American National Standards Institute},
    63506774    address     = {www.ansi.org},
    63516775    year        = 1999,
     
    63586782    title       = {{C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Programming Language ISO/IEC 14882:1998},
    63596783    edition     = {1st},
    6360     organization  = {International Standard Organization},
     6784    organization= {International Standard Organization},
    63616785    address     = {Geneva, Switzerland},
    63626786    year        = 1998,
     
    66497073}
    66507074
     7075@misc{protoactor,
     7076    contributer = {pabuhr@plg},
     7077    key         = {Protoactor},
     7078    author      = {{proto.actor}},
     7079    title       = {Asynkron AB},
     7080    year        = 2023,
     7081    howpublished= {\url{https://proto.actor}},
     7082}
     7083
    66517084@misc{Pthreads,
    66527085    keywords    = {pthreads, C concurrency},
     
    67607193}
    67617194
    6762 @manual{Ada95,
    6763     keywords    = {Ada},
    6764     contributer = {pabuhr@plg},
    6765     title       = {{A}da Reference Manual},
    6766     edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
    6767     organization= {Intermetrics, Inc.},
    6768     month       = dec,
    6769     year        = 1995,
    6770     note        = {Language and Standards Libraries}
    6771 }
    6772 
    6773 @manual{Ada12,
    6774     keywords    = {ISO/IEC Ada},
    6775     contributer = {pabuhr@plg},
    6776     author      = {Ada12},
    6777     title       = {Programming languages -- {Ada} ISO/IEC 8652:2012},
    6778     edition     = {3rd},
    6779     organization= {International Standard Organization},
    6780     address     = {Geneva, Switzerland},
    6781     year        = 2012,
    6782     note        = {\href{https://www.iso.org/standard/61507.html}{https://\-www.iso.org/\-standard/\-61507.html}},
    6783 }
    6784 
    6785 @manual{Ada95:annotated,
    6786     keywords    = {Ada},
    6787     contributer = {pabuhr@plg},
    6788     title       = {Annotated {A}da Reference Manual},
    6789     edition     = {International Standard {ISO}/{IEC} {8652:1995(E)} with {COR.1:2000}},
    6790     organization = {Intermetrics, Inc.},
    6791     month       = dec,
    6792     year        = 1995,
    6793     note        = {Language and Standards Libraries}
     7195@inproceedings{Bacon03,
     7196    keywords    = {utilization, real-time scheduling, read barrier, defragmentation},
     7197    contributer = {pabuhr@plg},
     7198    author      = {David F. Bacon and Perry Cheng and V. T. Rajan},
     7199    title       = {A Real-Time Garbage Collector with Low Overhead and Consistent Utilization},
     7200    year        = {2003},
     7201    organization= {Proceedings of the 30th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages},
     7202    publisher   = {ACM},
     7203    address     = {New York, NY, USA},
     7204    pages       = {285-298},
     7205    location    = {New Orleans, Louisiana, USA},
    67947206}
    67957207
     
    69277339    journal     = sigplan,
    69287340    year        = 1991,
    6929     month       = oct, volume = 26, number = 10, pages = {29-43},
     7341    month       = oct,
     7342    volume      = 26,
     7343    number      = 10,
     7344    pages       = {29-43},
    69307345    abstract    = {
    69317346        {\tt lcc} is a new retargetable compiler for ANSI C.  Versions for
     
    69877402}
    69887403
     7404@misc{rpmalloc,
     7405    author      = {Mattias Jansson},
     7406    title       = {rpmalloc version 1.4.1},
     7407    month       = apr,
     7408    year        = 2022,
     7409    howpublished= {\href{https://github.com/mjansson/rpmalloc}{https://\-github.com/\-mjansson/\-rpmalloc}},
     7410}
     7411
    69897412@manual{Rust,
    69907413    keywords    = {Rust programming language},
     
    70177440    publisher   = {ACM},
    70187441    address     = {New York, NY, USA},
    7019     booktitle   = {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
     7442    organization= {Proceedings of the 4th International Workshop on Programming Based on Actors Agents \& Decentralized Control},
    70207443    pages       = {67-80},
    70217444    numpages    = {14},
     
    70417464    booktitle   = {PLDI '04: Proceedings of the ACM SIGPLAN 2004 Conference on Programming Language Design and Implementation},
    70427465    location    = {Washington DC, USA},
    7043     publisher   = {ACM},
     7466    organization= {ACM},
    70447467    address     = {New York, NY, USA},
    70457468    volume      = 39,
     
    70477470    month       = jun,
    70487471    pages       = {35-46},
     7472}
     7473
     7474@article{Nickolls08,
     7475    author      = {Nickolls, John and Buck, Ian and Garland, Michael and Skadron, Kevin},
     7476    title       = {Scalable Parallel Programming with CUDA},
     7477    journal     = {Queue},
     7478    volume      = {6},
     7479    number      = {2},
     7480    month       = mar,
     7481    year        = 2008,
     7482    pages       = {40-53},
     7483    publisher   = {ACM},
     7484    address     = {New York, NY, USA},
    70497485}
    70507486
     
    70627498}
    70637499
     7500@article{Blumofe99,
     7501    keywords    = {critical-path length, multiprocessor, multithreading, randomized algorithm, thread scheduling, work stealing},
     7502    author      = {Blumofe, Robert D. and Leiserson, Charles E.},
     7503    title       = {Scheduling Multithreaded Computations by Work Stealing},
     7504    journal     = {Journal of the ACM},
     7505    volume      = {46},
     7506    number      = {5},
     7507    month       = sep,
     7508    year        = {1999},
     7509    pages       = {720-748},
     7510    publisher   = {ACM},
     7511    address     = {New York, NY, USA},
     7512}
     7513
     7514@inproceedings{Acar13,
     7515    keywords    = {dynamic load balancing, nested parallelism, work stealing},
     7516    author      = {Acar, Umut A. and Chargueraud, Arthur and Rainey, Mike},
     7517    title       = {Scheduling Parallel Programs by Work Stealing with Private Deques},
     7518    organization= {Proceedings of the 18th ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming},
     7519    series      = {PPoPP '13},
     7520    year        = {2013},
     7521    location    = {Shenzhen, China},
     7522    pages       = {219-228},
     7523    publisher   = {ACM},
     7524    address     = {New York, NY, USA},
     7525}
     7526
     7527@inproceedings{Chen07,
     7528    keywords    = {chip multiprocessors, constructive cache sharing, parallel depth first, scheduling algorithms, thread granularity, work stealing, working set profiling},
     7529    author      = {Chen, Shimin and Gibbons, Phillip B. and Kozuch, Michael and Liaskovitis, Vasileios and Ailamaki, Anastassia and Blelloch, Guy E. and Falsafi, Babak and Fix, Limor and Hardavellas, Nikos and Mowry, Todd C. and Wilkerson, Chris},
     7530    title       = {Scheduling Threads for Constructive Cache Sharing on CMPs},
     7531    organization= {Proceedings of the Nineteenth Annual ACM Symposium on Parallel Algorithms and Architectures},
     7532    series      = {SPAA '07},
     7533    year        = {2007},
     7534    location    = {San Diego, California, USA},
     7535    pages       = {105-115},
     7536    numpages    = {11},
     7537    publisher   = {ACM},
     7538    address     = {New York, NY, USA},
     7539}
     7540
    70647541@manual{SELF,
    70657542    keywords    = {programming language, obect-oriented, polymorphism},
     
    70837560    publisher   = {Springer},
    70847561    note        = {Lecture Notes in Computer Science v. 173},
     7562}
     7563
     7564@inproceedings{Kahn74,
     7565    keywords    = {programming language, obect-oriented, polymorphism},
     7566    contributer = {pabuhr@plg},
     7567    title       = {The Semantics of a Simple Language for Parallel Programming},
     7568    author      = {Gilles Kahn},
     7569    organization= {IFIP Congress},
     7570    year        = 1974,
    70857571}
    70867572
     
    71437629    number      = 12,
    71447630    pages       = {66-76},
     7631}
     7632
     7633@book{Scott13,
     7634    author      = {Michael L. Scott},
     7635    title       = {Shared-Memory Synchronization},
     7636    publisher   = {Morgan \& Claypool},
     7637    year        = 2013,
     7638}
     7639
     7640@inproceedings{Leissa14,
     7641    title       = {{S}ierra: a {SIMD} extension for {C}++},
     7642    author      = {Lei{\ss}a, Roland and Haffner, Immanuel and Hack, Sebastian},
     7643    booktitle   = {Proceedings of the 2014 Workshop on Workshop on programming models for SIMD/Vector processing},
     7644    pages       = {17-24},
     7645    year        = {2014},
     7646    organization= {ACM}
    71457647}
    71467648
     
    77808282
    77818283@article{SysVABI,
    7782     keywords    =  {System V ABI},
    7783     contributer =  {a3moss@uwaterloo.ca},
     8284    keywords    = {System V ABI},
     8285    contributer = {a3moss@uwaterloo.ca},
    77848286    title       = {System {V} application binary interface},
    77858287    author      = {Matz, Michael and Hubicka, Jan and Jaeger, Andreas and Mitchell, Mark},
     
    77878289    volume      = {99},
    77888290    year        = {2013}
     8291}
     8292
     8293@article{Albert18,
     8294    keywords    = {actor-based concurrency, partial order reduction, systematic testing, synchronization, task independence},
     8295    contributer = {pabuhr@plg},
     8296    author      = {Albert, Elvira and Arenas, Puri and G\'{o}mez-Zamalloa, Miguel},
     8297    title       = {Systematic testing of actor systems},
     8298    journal     = {Software Testing, Verification and Reliability},
     8299    volume      = {28},
     8300    number      = {3},
     8301    pages       = {e1661},
     8302    year        = {2018}
    77898303}
    77908304
     
    78138327    journal     = jcss,
    78148328    year        = 1978,
    7815     volume      = 17, pages = {348-375}
     8329    volume      = 17,
     8330    pages       = {348-375},
    78168331}
    78178332
     
    78248339    address     = {New York, New York, U.S.A.},
    78258340    year        = 1982
     8341}
     8342
     8343@article{Arora01,
     8344    author      = {Arora, N. S. and Blumofe, R. D. and Plaxton, C. G.},
     8345    title       = {Thread Scheduling for Multiprogrammed Multiprocessors},
     8346    journal     = {Theory of Computing Systems},
     8347    year        = {2001},
     8348    volume      = {34},
     8349    number      = {2},
     8350    pages       = {115-144},
     8351    publisher   = {Springer-Verlag},
    78268352}
    78278353
     
    80538579}
    80548580
     8581@misc{AkkaBecome,
     8582    contributer = {pabuhr@plg},
     8583    key         = {AkkaBecome},
     8584    title       = {Typed Actors},
     8585    author      = {{Lightbend}},
     8586    howpublished= {\href{https://doc.akka.io/docs/akka/2.5/typed-actors.html}{https://\-doc.akka.io/\-docs/\-akka/\-2.5/\-typed-actors.html}},
     8587    year        = 2022,
     8588}
     8589
    80558590@article{concatenation,
    80568591    keywords    = {record concatenation, isa},
     
    81178652    author      = {Paul R. Wilson},
    81188653    title       = {Uniprocessor Garbage Collection Techniques},
    8119     booktitle   = {Proceedings of the International Workshop on Memory Management},
     8654    organization= {Proceedings of the International Workshop on Memory Management},
    81208655    location    = {St. Malo, France},
    81218656    publisher   = {Springer},
     
    81308665    author      = {Carl Hewitt and Peter Bishop and Richard Steiger},
    81318666    title       = {A Universal Modular {ACTOR} Formalism for Artificial Intelligence},
    8132     booktitle   = {Proceedings of the 3rd International Joint Conference on Artificial Intelligence},
     8667    organization= {Proceedings of the 3rd International Joint Conference on Artificial Intelligence},
    81338668    address     = {Standford, California, U.S.A.},
    81348669    pages       = {235-245},
     8670    location    = {Stanford, USA},
     8671    series      = {IJCAI'73},
    81358672    month       = aug,
    81368673    year        = 1973,
     
    81648701@article{Karsten20,
    81658702    author      = {Karsten, Martin and Barghi, Saman},
    8166     title       = {{User-level Threading: Have Your Cake and Eat It Too}},
     8703    title       = {User-level Threading: Have Your Cake and Eat It Too},
    81678704    year        = {2020},
    81688705    issue_date  = {March 2020},
     
    81898726}
    81908727
     8728@article{Squillante93,
     8729    keywords    = {buffer storage, performance evaluation, queueing theory, scheduling, shared memory systems, processor-cache affinity},
     8730    author      = {Squillante, M.S. and Lazowska, E.D.},
     8731    title       = {Using Processor-Cache Affinity Information in Shared-Memory Multiprocessor Scheduling},
     8732    journal     = {Parallel and Distributed Systems, IEEE Transactions on},
     8733    year        = {1993},
     8734    month       = {Feb},
     8735    volume      = {4},
     8736    number      = {2},
     8737    pages       = {131-143},
     8738}
     8739
    81918740@article{delegation,
    81928741    keywords    = {delegation, inheritance, actors},
     
    83388887    year        = 2003,
    83398888    pages       = {19-24},
     8889}
     8890
     8891@inproceedings{Saman18,
     8892    keywords    = {actors, scheduling, NUMA, locality},
     8893    contributer = {pabuhr@plg},
     8894    author      = {Saman Barghi and Martin Karsten},
     8895    organization= {2018 IEEE International Parallel and Distributed Processing Symposium (IPDPS)},
     8896    title       = {Work-Stealing, Locality-Aware Actor Scheduling},
     8897    year        = {2018},
     8898    address     = {Vancouver, BC, Canada},
     8899    pages       = {484-494},
     8900}
     8901
     8902@article{Wimmer13,
     8903    keywords    = {priorities, scheduler hints, strategies, work-stealing},
     8904    author      = {Wimmer, Martin and Cederman, Daniel and Tr\"{a}ff, Jesper Larsson and Tsigas, Philippas},
     8905    title       = {Work-stealing with Configurable Scheduling Strategies},
     8906    journal     = {SIGPLAN Not.},
     8907    issue_date  = {August 2013},
     8908    volume      = {48},
     8909    number      = {8},
     8910    month       = feb,
     8911    year        = {2013},
     8912    issn        = {0362-1340},
     8913    pages       = {315-316},
     8914    publisher   = {ACM},
     8915    address     = {New York, NY, USA},
    83408916}
    83418917
  • doc/theses/mike_brooks_MMath/Makefile

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

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

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

    r34b4268 r24d6572  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 14 21:55:12 2021
    13 // Update Count     : 467
     12// Last Modified On : Tue May 30 10:47:52 2023
     13// Update Count     : 478
    1414//
    1515
     
    4444        static int flags = 0;
    4545
     46    // This allocation 'leaks' memory from the program to the execution
     47    // environment, as putenv does not manage the storage of the string used
     48    // as an environment variable. This leak is necessary to ensure the
     49    // underlying C string is allocated long enough.
    4650        if ( putenv( (char *)( *new string( string( __CFA_FLAGPREFIX__ + to_string( flags++ ) + "__=" ) + arg ) ).c_str() ) ) {
    4751                cerr << argv[0] << " error, cannot set environment variable." << endl;
     
    198202                                } // if
    199203                        } else if ( arg == "-CFA" ) {
    200                                 CFA_flag = true;                                                // strip the -CFA flag
     204                                CFA_flag = true;                                                // strip -CFA flag
    201205                                link = false;
    202206                                args[nargs++] = "-fsyntax-only";                // stop after stage 2
    203207                        } else if ( arg == "-debug" ) {
    204                                 debug = true;                                                   // strip the debug flag
     208                                debug = true;                                                   // strip debug flag
    205209                        } else if ( arg == "-nodebug" ) {
    206                                 debug = false;                                                  // strip the nodebug flag
     210                                debug = false;                                                  // strip nodebug flag
    207211                        } else if ( arg == "-quiet" ) {
    208                                 quiet = true;                                                   // strip the quiet flag
     212                                quiet = true;                                                   // strip quiet flag
    209213                        } else if ( arg == "-noquiet" ) {
    210                                 quiet = false;                                                  // strip the noquiet flag
     214                                quiet = false;                                                  // strip noquiet flag
     215                        } else if ( arg == "-invariant" ) {
     216                                Putenv( argv, "-" + arg );
     217                        } else if ( arg == "--invariant" ) {
     218                                Putenv( argv, arg );
    211219                        } else if ( arg == "-no-include-stdhdr" ) {
    212                                 noincstd_flag = true;                                   // strip the no-include-stdhdr flag
     220                                noincstd_flag = true;                                   // strip no-include-stdhdr flag
    213221                        } else if ( arg == "-nolib" ) {
    214                                 nolib = true;                                                   // strip the nolib flag
     222                                nolib = true;                                                   // strip nolib flag
    215223                        } else if ( arg == "-help" ) {
    216                                 help = true;                                                    // strip the help flag
     224                                help = true;                                                    // strip help flag
    217225                        } else if ( arg == "-nohelp" ) {
    218                                 help = false;                                                   // strip the nohelp flag
     226                                help = false;                                                   // strip nohelp flag
    219227                        } else if ( arg == "-cfalib") {
    220228                                compiling_libs = true;
     
    274282                                } // if
    275283                        } else if ( prefix( arg, "-B" ) ) {
    276                                 bprefix = arg.substr(2);                                // strip the -B flag
     284                                bprefix = arg.substr(2);                                // strip -B flag
    277285                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    278286                                args[nargs++] = argv[i];                                // pass flag along
     
    321329        #endif // __x86_64__
    322330
     331        // ARM -mno-outline-atomics => use LL/SC instead of calls to atomic routines: __aarch64_swp_acq_rel, __aarch64_cas8_acq_rel
     332        // ARM -march=armv8.2-a+lse => generate Arm LSE extension instructions SWAP and CAS
     333        // https://community.arm.com/developer/tools-software/tools/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10
     334        #ifdef __ARM_ARCH
     335        args[nargs++] = "-mno-outline-atomics";                         // use ARM LL/SC instructions for atomics
     336        #endif // __ARM_ARCH
     337
    323338        #ifdef __DEBUG_H__
    324339        cerr << "args:";
     
    444459
    445460        args[nargs++] = "-fexceptions";                                         // add exception flags (unconditionally)
     461        args[nargs++] = "-D_GNU_SOURCE";                                        // force gnu libraries
    446462
    447463        // add flags based on the type of compile
  • libcfa/configure.ac

    r34b4268 r24d6572  
    122122AC_PROG_CC
    123123AM_PROG_AS
    124 AC_PROG_LIBTOOL
     124LT_INIT
    125125AC_PROG_INSTALL
    126126AC_PROG_MAKE_SET
     
    246246AC_CONFIG_HEADERS(prelude/defines.hfa)
    247247
    248 AC_OUTPUT()
     248AC_OUTPUT
    249249
    250250# Final text
  • libcfa/prelude/builtins.c

    r34b4268 r24d6572  
    1010// Created On       : Fri Jul 21 16:21:03 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 14 08:45:54 2021
    13 // Update Count     : 133
     12// Last Modified On : Thu Feb  2 11:33:56 2023
     13// Update Count     : 135
    1414//
    1515
     
    6464static inline void ^?{}(generator$ &) {}
    6565
    66 trait is_generator(T &) {
     66forall( T & )
     67trait is_generator {
    6768      void main(T & this);
    6869      generator$ * get_generator(T & this);
     
    148149
    149150static inline {
    150         long int ?\?( int x, unsigned int y ) { __CFA_EXP__(); }
     151        int ?\?( int x, unsigned int y ) { __CFA_EXP__(); }
    151152        long int ?\?( long int x, unsigned long int y ) { __CFA_EXP__(); }
    152153        long long int ?\?( long long int x, unsigned long long int y ) { __CFA_EXP__(); }
    153154        // unsigned computation may be faster and larger
    154         unsigned long int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); }
     155        unsigned int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); }
    155156        unsigned long int ?\?( unsigned long int x, unsigned long int y ) { __CFA_EXP__(); }
    156157        unsigned long long int ?\?( unsigned long long int x, unsigned long long int y ) { __CFA_EXP__(); }
     
    175176
    176177static inline {
    177         long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }
     178        int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }
    178179        long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
    179180        long long int ?\=?( long long int & x, unsigned long long int y ) { x = x \ y; return x; }
    180         unsigned long int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; }
     181        unsigned int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; }
    181182        unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
    182183        unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; }
  • libcfa/prelude/prelude-gen.cc

    r34b4268 r24d6572  
    1010// Created On       : Sat Feb 16 08:44:58 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr  2 17:18:24 2019
    13 // Update Count     : 37
     12// Last Modified On : Thu Feb  2 11:40:01 2023
     13// Update Count     : 38
    1414//
    1515
     
    159159int main() {
    160160        cout << "# 2 \"prelude.cfa\"  // needed for error messages from this file" << endl;
    161         cout << "trait sized(T &) {};" << endl;
     161        cout << "forall( T & ) trait sized {};" << endl;
    162162
    163163        cout << "//////////////////////////" << endl;
  • libcfa/src/Makefile.am

    r34b4268 r24d6572  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Fri Jul 16 16:00:40 2021
    14 ## Update Count     : 255
     13## Last Modified On : Thu May 25 15:20:04 2023
     14## Update Count     : 259
    1515###############################################################################
    1616
     
    4848        math.hfa \
    4949        time_t.hfa \
     50        virtual_dtor.hfa \
    5051        bits/algorithm.hfa \
    5152        bits/align.hfa \
     
    5859        bits/queue.hfa \
    5960        bits/sequence.hfa \
     61        concurrency/atomic.hfa \
    6062        concurrency/iofwd.hfa \
    6163        concurrency/barrier.hfa \
     
    113115        concurrency/once.hfa \
    114116        concurrency/kernel/fwd.hfa \
    115         concurrency/mutex_stmt.hfa
     117        concurrency/mutex_stmt.hfa \
     118        concurrency/channel.hfa \
     119        concurrency/actor.hfa
    116120
    117121inst_thread_headers_src = \
     
    124128        concurrency/monitor.hfa \
    125129        concurrency/mutex.hfa \
     130        concurrency/select.hfa \
    126131        concurrency/thread.hfa
    127132
  • libcfa/src/algorithms/range_iterator.hfa

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

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

    r34b4268 r24d6572  
    1010// Created On       : Tue Oct 31 16:38:50 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jan 15 07:42:35 2020
    13 // Update Count     : 28
     12// Last Modified On : Thu Feb  2 11:33:08 2023
     13// Update Count     : 29
    1414
    1515#pragma once
     
    6969
    7070#ifdef __cforall
    71         trait is_node(T &) {
     71        forall( T & )
     72        trait is_node {
    7273                T *& get_next( T & );
    7374        };
  • libcfa/src/bits/random.hfa

    r34b4268 r24d6572  
    1010// Created On       : Fri Jan 14 07:18:11 2022
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 11 18:43:58 2022
    13 // Update Count     : 171
     12// Last Modified On : Mon Mar 20 21:45:24 2023
     13// Update Count     : 186
    1414//
    1515
    1616#pragma once
    1717
    18 #include <stdint.h>
     18#include <stdint.h>                                                                             // uintXX_t
    1919
    2020#define GLUE2( x, y ) x##y
     
    2424#ifdef __x86_64__                                                                               // 64-bit architecture
    2525        // 64-bit generators
    26         #define LEHMER64
     26        //#define LEHMER64
    2727        //#define XORSHIFT_12_25_27
    28         //#define XOSHIRO256PP
     28        #define XOSHIRO256PP
    2929        //#define KISS_64
     30    // #define SPLITMIX_64
    3031
    3132        // 32-bit generators
    32         #define XORSHIFT_6_21_7
    33         //#define XOSHIRO128PP
     33        //#define XORSHIFT_6_21_7
     34        #define XOSHIRO128PP
     35    // #define SPLITMIX_32
    3436#else                                                                                                   // 32-bit architecture
    3537        // 64-bit generators
    36         #define XORSHIFT_13_7_17
     38        //#define XORSHIFT_13_7_17
     39        #define XOSHIRO256PP
     40    // #define SPLITMIX_64
    3741
    3842        // 32-bit generators
    39         #define XORSHIFT_6_21_7
     43        //#define XORSHIFT_6_21_7
     44        #define XOSHIRO128PP
     45    // #define SPLITMIX_32
    4046#endif // __x86_64__
    4147
    4248// Define C/CFA PRNG name and random-state.
    43 
    44 // SKULLDUGGERY: typedefs name struct and typedef with the same name to deal with CFA typedef numbering problem.
    4549
    4650#ifdef XOSHIRO256PP
    4751#define PRNG_NAME_64 xoshiro256pp
    4852#define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t)
    49 typedef struct PRNG_STATE_64_T { uint64_t s[4]; } PRNG_STATE_64_T;
     53typedef struct { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T;
    5054#endif // XOSHIRO256PP
    5155
     
    5357#define PRNG_NAME_32 xoshiro128pp
    5458#define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t)
    55 typedef struct PRNG_STATE_32_T { uint32_t s[4]; } PRNG_STATE_32_T;
     59typedef struct { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T;
    5660#endif // XOSHIRO128PP
    5761
     
    8185#endif // XORSHIFT_12_25_27
    8286
     87#ifdef SPLITMIX_64
     88#define PRNG_NAME_64 splitmix64
     89#define PRNG_STATE_64_T uint64_t
     90#endif // SPLITMIX32
     91
     92#ifdef SPLITMIX_32
     93#define PRNG_NAME_32 splitmix32
     94#define PRNG_STATE_32_T uint32_t
     95#endif // SPLITMIX32
     96
    8397#ifdef KISS_64
    8498#define PRNG_NAME_64 kiss_64
    8599#define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t)
    86 typedef struct PRNG_STATE_64_T { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;
     100typedef struct { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;
    87101#endif // KISS_^64
    88102
     
    90104#define PRNG_NAME_32 xorwow
    91105#define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t)
    92 typedef struct PRNG_STATE_32_T { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;
     106typedef struct { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;
    93107#endif // XOSHIRO128PP
    94108
     
    110124
    111125// ALL PRNG ALGORITHMS ARE OPTIMIZED SO THAT THE PRNG LOGIC CAN HAPPEN IN PARALLEL WITH THE USE OF THE RESULT.
    112 // Therefore, the set_seed routine primes the PRNG by calling it with the state so the seed is not return as the
    113 // first random value.
     126// Specifically, the current random state is copied for returning, before computing the next value.  As a consequence,
     127// the set_seed routine primes the PRNG by calling it with the state so the seed is not return as the first random
     128// value.
     129
    114130
    115131#ifdef __cforall                                                                                // don't include in C code (invoke.h)
     132
     133// https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
     134//
     135// Splitmix64 is not recommended for demanding random number requirements, but is often used to calculate initial states
     136// for other more complex pseudo-random number generators (see https://prng.di.unimi.it).
     137// Also https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64.
     138static inline uint64_t splitmix64( uint64_t & state ) {
     139    state += 0x9e3779b97f4a7c15;
     140    uint64_t z = state;
     141    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
     142    z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
     143    return z ^ (z >> 31);
     144} // splitmix64
     145
     146static inline void splitmix64_set_seed( uint64_t & state , uint64_t seed ) {
     147    state = seed;
     148    splitmix64( state );                                                                // prime
     149} // splitmix64_set_seed
     150
     151// https://github.com/bryc/code/blob/master/jshash/PRNGs.md#splitmix32
     152//
     153// Splitmix32 is not recommended for demanding random number requirements, but is often used to calculate initial states
     154// for other more complex pseudo-random number generators (see https://prng.di.unimi.it).
     155
     156static inline uint32_t splitmix32( uint32_t & state ) {
     157    state += 0x9e3779b9;
     158    uint64_t z = state;
     159    z = (z ^ (z >> 15)) * 0x85ebca6b;
     160    z = (z ^ (z >> 13)) * 0xc2b2ae35;
     161    return z ^ (z >> 16);
     162} // splitmix32
     163
     164static inline void splitmix32_set_seed( uint32_t & state, uint64_t seed ) {
     165    state = seed;
     166    splitmix32( state );                                                                // prime
     167} // splitmix32_set_seed
     168
     169#ifdef __SIZEOF_INT128__
     170//--------------------------------------------------
     171static inline uint64_t lehmer64( __uint128_t & state ) {
     172        __uint128_t ret = state;
     173        state *= 0x_da94_2042_e4dd_58b5;
     174        return ret >> 64;
     175} // lehmer64
     176
     177static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) {
     178        // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed.
     179        state = splitmix64( seed );                                                     // prime
     180} // lehmer64_set_seed
     181
     182//--------------------------------------------------
     183static inline uint64_t wyhash64( uint64_t & state ) {
     184        uint64_t ret = state;
     185        state += 0x_60be_e2be_e120_fc15;
     186        __uint128_t tmp;
     187        tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d;
     188        uint64_t m1 = (tmp >> 64) ^ tmp;
     189        tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9;
     190        uint64_t m2 = (tmp >> 64) ^ tmp;
     191        return m2;
     192} // wyhash64
     193
     194static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {
     195        state = splitmix64( seed );                                                     // prime
     196} // wyhash64_set_seed
     197#endif // __SIZEOF_INT128__
    116198
    117199// https://prng.di.unimi.it/xoshiro256starstar.c
     
    126208
    127209#ifndef XOSHIRO256PP
    128 typedef struct xoshiro256pp_t { uint64_t s[4]; } xoshiro256pp_t;
     210typedef struct { uint64_t s0, s1, s2, s3; } xoshiro256pp_t;
    129211#endif // ! XOSHIRO256PP
    130212
    131213static inline uint64_t xoshiro256pp( xoshiro256pp_t & rs ) with(rs) {
    132         inline uint64_t rotl(const uint64_t x, int k) {
     214        inline uint64_t rotl( const uint64_t x, int k ) {
    133215                return (x << k) | (x >> (64 - k));
    134216        } // rotl
    135217
    136         const uint64_t result = rotl( s[0] + s[3], 23 ) + s[0];
    137         const uint64_t t = s[1] << 17;
    138 
    139         s[2] ^= s[0];
    140         s[3] ^= s[1];
    141         s[1] ^= s[2];
    142         s[0] ^= s[3];
    143         s[2] ^= t;
    144         s[3] = rotl( s[3], 45 );
     218        const uint64_t result = rotl( s0 + s3, 23 ) + s0;
     219        const uint64_t t = s1 << 17;
     220
     221        s2 ^= s0;
     222        s3 ^= s1;
     223        s1 ^= s2;
     224        s0 ^= s3;
     225        s2 ^= t;
     226        s3 = rotl( s3, 45 );
    145227        return result;
    146228} // xoshiro256pp
    147229
    148 static inline void xoshiro256pp_set_seed( xoshiro256pp_t & state,  uint64_t seed ) {
    149         state = (xoshiro256pp_t){ {seed, seed, seed, seed} };
    150         xoshiro256pp( state );
     230static inline void xoshiro256pp_set_seed( xoshiro256pp_t & state, uint64_t seed ) {
     231    // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
     232    uint64_t seed1 = splitmix64( seed );                                // prime
     233    uint64_t seed2 = splitmix64( seed );
     234    uint64_t seed3 = splitmix64( seed );
     235    uint64_t seed4 = splitmix64( seed );
     236        state = (xoshiro256pp_t){ seed1, seed2, seed3, seed4 };
    151237} // xoshiro256pp_set_seed
    152238
     
    161247
    162248#ifndef XOSHIRO128PP
    163 typedef struct xoshiro128pp_t { uint32_t s[4]; } xoshiro128pp_t;
     249typedef struct { uint32_t s0, s1, s2, s3; } xoshiro128pp_t;
    164250#endif // ! XOSHIRO128PP
    165251
     
    169255        } // rotl
    170256
    171         const uint32_t result = rotl( s[0] + s[3], 7 ) + s[0];
    172         const uint32_t t = s[1] << 9;
    173 
    174         s[2] ^= s[0];
    175         s[3] ^= s[1];
    176         s[1] ^= s[2];
    177         s[0] ^= s[3];
    178         s[2] ^= t;
    179         s[3] = rotl( s[3], 11 );
     257        const uint32_t result = rotl( s0 + s3, 7 ) + s0;
     258        const uint32_t t = s1 << 9;
     259
     260        s2 ^= s0;
     261        s3 ^= s1;
     262        s1 ^= s2;
     263        s0 ^= s3;
     264        s2 ^= t;
     265        s3 = rotl( s3, 11 );
    180266        return result;
    181267} // xoshiro128pp
    182268
    183269static inline void xoshiro128pp_set_seed( xoshiro128pp_t & state, uint32_t seed ) {
    184         state = (xoshiro128pp_t){ {seed, seed, seed, seed} };
    185         xoshiro128pp( state );                                                          // prime
     270    // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
     271    uint32_t seed1 = splitmix32( seed );                                // prime
     272    uint32_t seed2 = splitmix32( seed );
     273    uint32_t seed3 = splitmix32( seed );
     274    uint32_t seed4 = splitmix32( seed );
     275        state = (xoshiro128pp_t){ seed1, seed2, seed3, seed4 };
    186276} // xoshiro128pp_set_seed
    187 
    188 #ifdef __SIZEOF_INT128__
    189         // Pipelined to allow out-of-order overlap with reduced dependencies. Critically, the current random state is
    190         // returned (copied), and then compute and store the next random value.
    191         //--------------------------------------------------
    192         static inline uint64_t lehmer64( __uint128_t & state ) {
    193                 __uint128_t ret = state;
    194                 state *= 0xda942042e4dd58b5;
    195                 return ret >> 64;
    196         } // lehmer64
    197 
    198         static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) {
    199                 state = seed;
    200                 lehmer64( state );
    201         } // lehmer64_set_seed
    202 
    203         //--------------------------------------------------
    204         static inline uint64_t wyhash64( uint64_t & state ) {
    205                 uint64_t ret = state;
    206                 state += 0x_60be_e2be_e120_fc15;
    207                 __uint128_t tmp;
    208                 tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d;
    209                 uint64_t m1 = (tmp >> 64) ^ tmp;
    210                 tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9;
    211                 uint64_t m2 = (tmp >> 64) ^ tmp;
    212                 return m2;
    213         } // wyhash64
    214 
    215         static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {
    216                 state = seed;
    217                 wyhash64( state );                                                              // prime
    218         } // wyhash64_set_seed
    219 #endif // __SIZEOF_INT128__
    220277
    221278//--------------------------------------------------
     
    229286
    230287static inline void xorshift_13_7_17_set_seed( uint64_t & state, uint64_t seed ) {
    231         state = seed;
    232         xorshift_13_7_17( state );                                                      // prime
     288        state = splitmix64( seed );                                                     // prime
    233289} // xorshift_13_7_17_set_seed
    234290
     
    247303
    248304static inline void xorshift_6_21_7_set_seed( uint32_t & state, uint32_t seed ) {
    249         state = seed;
    250         xorshift_6_21_7( state );                                                       // prime
     305    state = splitmix32( seed );                                                 // prime
    251306} // xorshift_6_21_7_set_seed
    252307
     
    262317
    263318static inline void xorshift_12_25_27_set_seed( uint64_t & state, uint64_t seed ) {
    264         state = seed;
    265         xorshift_12_25_27( state );                                                     // prime
     319        state = splitmix64( seed );                                                     // prime
    266320} // xorshift_12_25_27_set_seed
    267321
     
    269323// The state must be seeded with a nonzero value.
    270324#ifndef KISS_64
    271 typedef struct kiss_64_t { uint64_t z, w, jsr, jcong; } kiss_64_t;
     325typedef struct { uint64_t z, w, jsr, jcong; } kiss_64_t;
    272326#endif // ! KISS_64
    273327
    274 static inline uint64_t kiss_64( kiss_64_t & state ) with(state) {
    275         kiss_64_t ret = state;
     328static inline uint64_t kiss_64( kiss_64_t & rs ) with(rs) {
     329        kiss_64_t ret = rs;
    276330        z = 36969 * (z & 65535) + (z >> 16);
    277331        w = 18000 * (w & 65535) + (w >> 16);
    278         jsr ^= (jsr << 17);
    279332        jsr ^= (jsr << 13);
     333        jsr ^= (jsr >> 17);
    280334        jsr ^= (jsr << 5);
    281335        jcong = 69069 * jcong + 1234567;
     
    283337} // kiss_64
    284338
    285 static inline void kiss_64_set_seed( kiss_64_t & state, uint64_t seed ) with(state) {
    286         z = 1; w = 1; jsr = 4; jcong = seed;
    287         kiss_64( state );                                                                       // prime
     339static inline void kiss_64_set_seed( kiss_64_t & rs, uint64_t seed ) with(rs) {
     340        z = 1; w = 1; jsr = 4; jcong = splitmix64( seed );      // prime
    288341} // kiss_64_set_seed
    289342
     
    291344// The state array must be initialized to non-zero in the first four words.
    292345#ifndef XORWOW
    293 typedef struct xorwow_t { uint32_t a, b, c, d, counter; } xorwow_t;
     346typedef struct { uint32_t a, b, c, d, counter; } xorwow_t;
    294347#endif // ! XORWOW
    295348
    296 static inline uint32_t xorwow( xorwow_t & state ) with(state) {
     349static inline uint32_t xorwow( xorwow_t & rs ) with(rs) {
    297350        // Algorithm "xorwow" from p. 5 of Marsaglia, "Xorshift RNGs".
    298351        uint32_t ret = a + counter;
     
    312365} // xorwow
    313366
    314 static inline void xorwow_set_seed( xorwow_t & state, uint32_t seed ) {
    315         state = (xorwow_t){ seed, seed, seed, seed, 0 };
    316         xorwow( state );                                                                        // prime
     367static inline void xorwow_set_seed( xorwow_t & rs, uint32_t seed ) {
     368    // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
     369    uint32_t seed1 = splitmix32( seed );                                // prime
     370    uint32_t seed2 = splitmix32( seed );
     371    uint32_t seed3 = splitmix32( seed );
     372    uint32_t seed4 = splitmix32( seed );
     373        rs = (xorwow_t){ seed1, seed2, seed3, seed4, 0 };
    317374} // xorwow_set_seed
    318375
     
    320377// Used in __tls_rand_fwd
    321378#define M  (1_l64u << 48_l64u)
    322 #define A  (25214903917_l64u)
    323 #define AI (18446708753438544741_l64u)
     379#define A  (25_214_903_917_l64u)
     380#define AI (18_446_708_753_438_544_741_l64u)
    324381#define C  (11_l64u)
    325382#define D  (16_l64u)
    326383
    327384// Bi-directional LCG random-number generator
    328 static inline uint32_t LCGBI_fwd( uint64_t & state ) {
    329         state = (A * state + C) & (M - 1);
    330         return state >> D;
     385static inline uint32_t LCGBI_fwd( uint64_t & rs ) {
     386        rs = (A * rs + C) & (M - 1);
     387        return rs >> D;
    331388} // LCGBI_fwd
    332389
    333 static inline uint32_t LCGBI_bck( uint64_t & state ) {
    334         unsigned int r = state >> D;
    335         state = AI * (state - C) & (M - 1);
     390static inline uint32_t LCGBI_bck( uint64_t & rs ) {
     391        unsigned int r = rs >> D;
     392        rs = AI * (rs - C) & (M - 1);
    336393        return r;
    337394} // LCGBI_bck
  • libcfa/src/bits/weakso_locks.cfa

    r34b4268 r24d6572  
    1515// Update Count     :
    1616//
    17 
    1817#include "bits/weakso_locks.hfa"
    19 
    2018#pragma GCC visibility push(default)
    2119
     
    2725void unlock( blocking_lock & ) {}
    2826void on_notify( blocking_lock &, struct thread$ * ) {}
    29 size_t on_wait( blocking_lock & ) { return 0; }
     27size_t on_wait( blocking_lock &, void (*pp_fn)( void * ), void * pp_datum ) { return 0; }
    3028void on_wakeup( blocking_lock &, size_t ) {}
    3129size_t wait_count( blocking_lock & ) { return 0; }
     30bool register_select( blocking_lock & this, select_node & node ) { return false; }
     31bool unregister_select( blocking_lock & this, select_node & node ) { return false; }
     32void on_selected( blocking_lock & this, select_node & node ) {}
     33
  • libcfa/src/bits/weakso_locks.hfa

    r34b4268 r24d6572  
    2323#include "containers/list.hfa"
    2424
    25 struct thread$;
     25struct select_node;
    2626
    2727//-----------------------------------------------------------------------------
     
    3232
    3333        // List of blocked threads
    34         dlist( thread$ ) blocked_threads;
     34        dlist( select_node ) blocked_threads;
    3535
    3636        // Count of current blocked threads
     
    5757void unlock( blocking_lock & this ) OPTIONAL_THREAD;
    5858void on_notify( blocking_lock & this, struct thread$ * t ) OPTIONAL_THREAD;
    59 size_t on_wait( blocking_lock & this ) OPTIONAL_THREAD;
     59size_t on_wait( blocking_lock & this, void (*pp_fn)( void * ), void * pp_datum ) OPTIONAL_THREAD;
    6060void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD;
    6161size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD;
     62bool register_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     63bool unregister_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     64void on_selected( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    6265
    6366//----------
     
    7275static inline bool   try_lock ( multiple_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }
    7376static inline void   unlock   ( multiple_acquisition_lock & this ) { unlock  ( (blocking_lock &)this ); }
    74 static inline size_t on_wait  ( multiple_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); }
     77static inline size_t on_wait  ( multiple_acquisition_lock & this, void (*pp_fn)( void * ), void * pp_datum ) { return on_wait ( (blocking_lock &)this, pp_fn, pp_datum ); }
    7578static inline void   on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    7679static inline void   on_notify( multiple_acquisition_lock & this, struct thread$ * t ){ on_notify( (blocking_lock &)this, t ); }
     80static inline bool   register_select( multiple_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
     81static inline bool   unregister_select( multiple_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
     82static inline void   on_selected( multiple_acquisition_lock & this, select_node & node ) { on_selected( (blocking_lock &)this, node ); }
  • libcfa/src/common.hfa

    r34b4268 r24d6572  
    3232} // extern "C"
    3333static inline __attribute__((always_inline)) {
    34         unsigned char abs( signed char v ) { return abs( (int)v ); }
     34        unsigned char abs( signed char v ) { return (int)abs( (int)v ); }
    3535        // use default C routine for int
    3636        unsigned long int abs( long int v ) { return labs( v ); }
     
    7070        unsigned int min( unsigned int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; }
    7171        long int min( long int v1, long int v2 ) { return v1 < v2 ? v1 : v2; }
    72         unsigned long int min( unsigned long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; }
     72        unsigned long int min( unsigned long int v1, unsigned long int v2 ) { return v1 < v2 ? v1 : v2; }
    7373        long long int min( long long int v1, long long int v2 ) { return v1 < v2 ? v1 : v2; }
    74         unsigned long long int min( unsigned long long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; }
     74        unsigned long long int min( unsigned long long int v1, unsigned long long int v2 ) { return v1 < v2 ? v1 : v2; }
    7575        forall( T | { int ?<?( T, T ); } )                                      // generic
    7676        T min( T v1, T v2 ) { return v1 < v2 ? v1 : v2; }
  • libcfa/src/concurrency/clib/cfathread.cfa

    r34b4268 r24d6572  
    1616// #define EPOLL_FOR_SOCKETS
    1717
     18#include <string.h>
     19
    1820#include "fstream.hfa"
    1921#include "locks.hfa"
     
    2325#include "time.hfa"
    2426#include "stdlib.hfa"
    25 
     27#include "iofwd.hfa"
    2628#include "cfathread.h"
    27 
    28 extern "C" {
    29                 #include <string.h>
    30                 #include <errno.h>
    31 }
    3229
    3330extern void ?{}(processor &, const char[], cluster &, thread$ *);
    3431extern "C" {
    35       extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
    36         extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
     32        extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
    3733}
    3834
     
    439435        // Mutex
    440436        struct cfathread_mutex {
    441                 linear_backoff_then_block_lock impl;
     437                exp_backoff_then_block_lock impl;
    442438        };
    443439        int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; }
     
    454450        // Condition
    455451        struct cfathread_condition {
    456                 condition_variable(linear_backoff_then_block_lock) impl;
     452                condition_variable(exp_backoff_then_block_lock) impl;
    457453        };
    458454        int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; }
     
    472468}
    473469
    474 #include <iofwd.hfa>
    475 
    476470extern "C" {
    477         #include <unistd.h>
    478         #include <sys/types.h>
    479         #include <sys/socket.h>
    480 
    481471        //--------------------
    482472        // IO operations
     
    488478                , protocol);
    489479        }
    490         int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {
     480        int cfathread_bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) {
    491481                return bind(socket, address, address_len);
    492482        }
     
    496486        }
    497487
    498         int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
     488        int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len) {
    499489                #if defined(EPOLL_FOR_SOCKETS)
    500490                        int ret;
     
    513503        }
    514504
    515         int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {
     505        int cfathread_connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) {
    516506                #if defined(EPOLL_FOR_SOCKETS)
    517507                        int ret;
  • libcfa/src/concurrency/clib/cfathread.h

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

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

    r34b4268 r24d6572  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan  6 16:33:16 2022
    13 // Update Count     : 12
     12// Last Modified On : Thu Feb  2 11:31:42 2023
     13// Update Count     : 13
    1414//
    1515
     
    3838// Anything that implements this trait can be resumed.
    3939// Anything that is resumed is a coroutine.
    40 trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(CoroutineCancelled(T))) {
     40forall( T & | IS_RESUMPTION_EXCEPTION(CoroutineCancelled(T)) )
     41trait is_coroutine {
    4142        void main(T & this);
    4243        coroutine$ * get_coroutine(T & this);
  • libcfa/src/concurrency/future.hfa

    r34b4268 r24d6572  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // io/types.hfa --
    8 //
    9 // Author           : Thierry Delisle & Peiran Hong
     7// concurrency/future.hfa --
     8//
     9// Author           : Thierry Delisle & Peiran Hong & Colby Parsons
    1010// Created On       : Wed Jan 06 17:33:18 2021
    1111// Last Modified By :
     
    1818#include "bits/locks.hfa"
    1919#include "monitor.hfa"
    20 
     20#include "select.hfa"
     21#include "locks.hfa"
     22
     23//----------------------------------------------------------------------------
     24// future
     25// I don't use future_t here since I need to use a lock for this future
     26//  since it supports multiple consumers
     27//  future_t is lockfree and uses atomics which aren't needed given we use locks here
    2128forall( T ) {
     29    // enum { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 }; // Enums seem to be broken so feel free to add this back afterwards
     30
     31    // temporary enum replacement
     32    const int FUTURE_EMPTY = 0;
     33    const int FUTURE_FULFILLED = 1;
     34
    2235        struct future {
     36                int state;
     37                T result;
     38                dlist( select_node ) waiters;
     39        futex_mutex lock;
     40        };
     41
     42    struct future_node {
     43        inline select_node;
     44        T * my_result;
     45    };
     46
     47        static inline {
     48
     49        void ?{}( future_node(T) & this, thread$ * blocked_thread, T * my_result ) {
     50            ((select_node &)this){ blocked_thread };
     51            this.my_result = my_result;
     52        }
     53
     54        void ?{}( future(T) & this ) {
     55                        this.waiters{};
     56            this.state = FUTURE_EMPTY;
     57            this.lock{};
     58                }
     59
     60                // Reset future back to original state
     61                void reset( future(T) & this ) with(this)
     62        {
     63            lock( lock );
     64            if( ! waiters`isEmpty )
     65                abort("Attempting to reset a future with blocked waiters");
     66            state = FUTURE_EMPTY;
     67            unlock( lock );
     68        }
     69
     70                // check if the future is available
     71        // currently no mutual exclusion because I can't see when you need this call to be synchronous or protected
     72                bool available( future(T) & this ) { return __atomic_load_n( &this.state, __ATOMIC_RELAXED ); }
     73
     74
     75        // memcpy wrapper to help copy values
     76        void copy_T( T & from, T & to ) {
     77            memcpy((void *)&to, (void *)&from, sizeof(T));
     78        }
     79
     80        // internal helper to signal waiters off of the future
     81        void _internal_flush( future(T) & this ) with(this) {
     82            while( ! waiters`isEmpty ) {
     83                if ( !__handle_waituntil_OR( waiters ) ) // handle special waituntil OR case
     84                    break; // if handle_OR returns false then waiters is empty so break
     85                select_node &s = try_pop_front( waiters );
     86
     87                if ( s.clause_status == 0p ) // poke in result so that woken threads do not need to reacquire any locks
     88                    copy_T( result, *(((future_node(T) &)s).my_result) );
     89               
     90                wake_one( waiters, s );
     91            }
     92        }
     93
     94                // Fulfil the future, returns whether or not someone was unblocked
     95                bool fulfil( future(T) & this, T val ) with(this) {
     96            lock( lock );
     97            if( state != FUTURE_EMPTY )
     98                abort("Attempting to fulfil a future that has already been fulfilled");
     99
     100            copy_T( val, result );
     101
     102            bool ret_val = ! waiters`isEmpty;
     103            state = FUTURE_FULFILLED;
     104                        _internal_flush( this );
     105            unlock( lock );
     106            return ret_val;
     107                }
     108
     109                // Wait for the future to be fulfilled
     110                // Also return whether the thread had to block or not
     111                [T, bool] get( future(T) & this ) with( this ) {
     112            lock( lock );
     113            T ret_val;
     114            if( state == FUTURE_FULFILLED ) {
     115                copy_T( result, ret_val );
     116                unlock( lock );
     117                return [ret_val, false];
     118            }
     119
     120            future_node(T) node = { active_thread(), &ret_val };
     121            insert_last( waiters, ((select_node &)node) );
     122            unlock( lock );
     123            park( );
     124
     125                        return [ret_val, true];
     126                }
     127
     128                // Wait for the future to be fulfilled
     129                T get( future(T) & this ) {
     130                        [T, bool] tt;
     131                        tt = get(this);
     132                        return tt.0;
     133                }
     134
     135        // Gets value if it is available and returns [ val, true ]
     136        // otherwise returns [ default_val, false]
     137        // will not block
     138        [T, bool] try_get( future(T) & this ) with(this) {
     139            lock( lock );
     140            T ret_val;
     141            if( state == FUTURE_FULFILLED ) {
     142                copy_T( result, ret_val );
     143                unlock( lock );
     144                return [ret_val, true];
     145            }
     146            unlock( lock );
     147           
     148            return [ret_val, false];
     149        }
     150
     151        bool register_select( future(T) & this, select_node & s ) with(this) {
     152            lock( lock );
     153
     154            // check if we can complete operation. If so race to establish winner in special OR case
     155            if ( !s.park_counter && state != FUTURE_EMPTY ) {
     156                if ( !__make_select_node_available( s ) ) { // we didn't win the race so give up on registering
     157                    unlock( lock );
     158                    return false;
     159                }
     160            }
     161
     162            // future not ready -> insert select node and return
     163            if( state == FUTURE_EMPTY ) {
     164                insert_last( waiters, s );
     165                unlock( lock );
     166                return false;
     167            }
     168
     169            __make_select_node_available( s );
     170            unlock( lock );
     171            return true;
     172        }
     173
     174        bool unregister_select( future(T) & this, select_node & s ) with(this) {
     175            if ( ! s`isListed ) return false;
     176            lock( lock );
     177            if ( s`isListed ) remove( s );
     178            unlock( lock );
     179            return false;
     180        }
     181               
     182        void on_selected( future(T) & this, select_node & node ) {}
     183        }
     184}
     185
     186//--------------------------------------------------------------------------------------------------------
     187// These futures below do not support select statements so they may not have as many features as 'future'
     188//  however the 'single_future' is cheap and cheerful and is most likely more performant than 'future'
     189//  since it uses raw atomics and no locks
     190//
     191// As far as 'multi_future' goes I can't see many use cases as it will be less performant than 'future'
     192//  since it is monitor based and also is not compatible with select statements
     193//--------------------------------------------------------------------------------------------------------
     194
     195forall( T ) {
     196        struct single_future {
    23197                inline future_t;
    24198                T result;
     
    27201        static inline {
    28202                // Reset future back to original state
    29                 void reset(future(T) & this) { reset( (future_t&)this ); }
     203                void reset(single_future(T) & this) { reset( (future_t&)this ); }
    30204
    31205                // check if the future is available
    32                 bool available( future(T) & this ) { return available( (future_t&)this ); }
     206                bool available( single_future(T) & this ) { return available( (future_t&)this ); }
    33207
    34208                // Mark the future as abandoned, meaning it will be deleted by the server
    35209                // This doesn't work beause of the potential need for a destructor
    36                 void abandon( future(T) & this );
     210                void abandon( single_future(T) & this );
    37211
    38212                // Fulfil the future, returns whether or not someone was unblocked
    39                 thread$ * fulfil( future(T) & this, T result ) {
     213                thread$ * fulfil( single_future(T) & this, T result ) {
    40214                        this.result = result;
    41215                        return fulfil( (future_t&)this );
     
    44218                // Wait for the future to be fulfilled
    45219                // Also return whether the thread had to block or not
    46                 [T, bool] wait( future(T) & this ) {
     220                [T, bool] wait( single_future(T) & this ) {
    47221                        bool r = wait( (future_t&)this );
    48222                        return [this.result, r];
     
    50224
    51225                // Wait for the future to be fulfilled
    52                 T wait( future(T) & this ) {
     226                T wait( single_future(T) & this ) {
    53227                        [T, bool] tt;
    54228                        tt = wait(this);
  • libcfa/src/concurrency/invoke.h

    r34b4268 r24d6572  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov 29 20:42:21 2022
    13 // Update Count     : 56
    14 //
     12// Last Modified On : Tue Mar 14 13:39:31 2023
     13// Update Count     : 59
     14//
     15
     16// No not use #pragma once was this file is included twice in some places. It has its own guard system.
    1517
    1618#include "bits/containers.hfa"
     
    215217                struct __thread_user_link cltr_link;
    216218
    217                 // used to store state between clh lock/unlock
    218                 volatile bool * clh_prev;
    219 
    220                 // used to point to this thd's current clh node
    221                 volatile bool * clh_node;
    222 
    223219                struct processor * last_proc;
     220
     221        // ptr used during handover between blocking lists to allow for stack allocation of intrusive nodes
     222        // main use case is wait-morphing to allow a different node to be used to block on condvar vs lock
     223        void * link_node;
    224224
    225225                PRNG_STATE_T random_state;                                              // fast random numbers
  • libcfa/src/concurrency/io.cfa

    r34b4268 r24d6572  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#if defined(__CFA_DEBUG__)
     
    8584        static io_context$ * __ioarbiter_allocate( io_arbiter$ & this, __u32 idxs[], __u32 want );
    8685        static void __ioarbiter_submit( io_context$ * , __u32 idxs[], __u32 have, bool lazy );
    87         static void __ioarbiter_flush ( io_context$ & );
     86        static void __ioarbiter_flush ( io_context$ &, bool kernel );
    8887        static inline void __ioarbiter_notify( io_context$ & ctx );
    8988//=============================================================================================
     
    9493        extern void __kernel_unpark( thread$ * thrd, unpark_hint );
    9594
     95        static inline void __post(oneshot & this, bool kernel, unpark_hint hint) {
     96                thread$ * t = post( this, false );
     97                if(kernel) __kernel_unpark( t, hint );
     98                else unpark( t, hint );
     99        }
     100
     101        // actual system call of io uring
     102        // wrap so everything that needs to happen around it is always done
     103        //   i.e., stats, book keeping, sqe reclamation, etc.
    96104        static void ioring_syscsll( struct io_context$ & ctx, unsigned int min_comp, unsigned int flags ) {
    97105                __STATS__( true, io.calls.flush++; )
    98106                int ret;
    99107                for() {
     108                        // do the system call in a loop, repeat on interrupts
    100109                        ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, min_comp, flags, (sigset_t *)0p, _NSIG / 8);
    101110                        if( ret < 0 ) {
     
    120129                /* paranoid */ verify( ctx.sq.to_submit >= ret );
    121130
    122                 ctx.sq.to_submit -= ret;
     131                // keep track of how many still need submitting
     132                __atomic_fetch_sub(&ctx.sq.to_submit, ret, __ATOMIC_SEQ_CST);
    123133
    124134                /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num );
     
    129139                /* paranoid */ verify( ! __preemption_enabled() );
    130140
     141                // mark that there is no pending io left
    131142                __atomic_store_n(&ctx.proc->io.pending, false, __ATOMIC_RELAXED);
    132143        }
    133144
     145        // try to acquire an io context for draining, helping means we never *need* to drain, we can always do it later
    134146        static bool try_acquire( io_context$ * ctx ) __attribute__((nonnull(1))) {
    135147                /* paranoid */ verify( ! __preemption_enabled() );
     
    138150
    139151                {
     152                        // if there is nothing to drain there is no point in acquiring anything
    140153                        const __u32 head = *ctx->cq.head;
    141154                        const __u32 tail = *ctx->cq.tail;
     
    144157                }
    145158
    146                 // Drain the queue
    147                 if(!__atomic_try_acquire(&ctx->cq.lock)) {
     159                // try a simple spinlock acquire, it's likely there are completions to drain
     160                if(!__atomic_try_acquire(&ctx->cq.try_lock)) {
     161                        // some other processor already has it
    148162                        __STATS__( false, io.calls.locked++; )
    149163                        return false;
    150164                }
    151165
     166                // acquired!!
    152167                return true;
    153168        }
    154169
     170        // actually drain the completion
    155171        static bool __cfa_do_drain( io_context$ * ctx, cluster * cltr ) __attribute__((nonnull(1, 2))) {
    156172                /* paranoid */ verify( ! __preemption_enabled() );
    157173                /* paranoid */ verify( ready_schedule_islocked() );
    158                 /* paranoid */ verify( ctx->cq.lock == true );
    159 
     174                /* paranoid */ verify( ctx->cq.try_lock == true );
     175
     176                // get all the invariants and initial state
    160177                const __u32 mask = *ctx->cq.mask;
    161178                const __u32 num  = *ctx->cq.num;
     
    166183                for() {
    167184                        // re-read the head and tail in case it already changed.
     185                        // count the difference between the two
    168186                        const __u32 head = *ctx->cq.head;
    169187                        const __u32 tail = *ctx->cq.tail;
     
    171189                        __STATS__( false, io.calls.drain++; io.calls.completed += count; )
    172190
     191                        // for everything between head and tail, drain it
    173192                        for(i; count) {
    174193                                unsigned idx = (head + i) & mask;
     
    177196                                /* paranoid */ verify(&cqe);
    178197
     198                                // find the future in the completion
    179199                                struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data;
    180200                                // __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future );
    181201
     202                                // don't directly fulfill the future, preemption is disabled so we need to use kernel_unpark
    182203                                __kernel_unpark( fulfil( *future, cqe.res, false ), UNPARK_LOCAL );
    183204                        }
    184205
     206                        // update the timestamps accordingly
     207                        // keep a local copy so we can update the relaxed copy
    185208                        ts_next = ctx->cq.ts = rdtscl();
    186209
     
    190213                        ctx->proc->idle_wctx.drain_time = ts_next;
    191214
     215                        // we finished draining the completions... unless the ring buffer was full and there are more secret completions in the kernel.
    192216                        if(likely(count < num)) break;
    193217
     218                        // the ring buffer was full, there could be more stuff in the kernel.
    194219                        ioring_syscsll( *ctx, 0, IORING_ENTER_GETEVENTS);
    195220                }
     
    199224                /* paranoid */ verify( ! __preemption_enabled() );
    200225
    201                 __atomic_unlock(&ctx->cq.lock);
    202 
     226                // everything is drained, we can release the lock
     227                __atomic_unlock(&ctx->cq.try_lock);
     228
     229                // update the relaxed timestamp
    203230                touch_tsc( cltr->sched.io.tscs, ctx->cq.id, ts_prev, ts_next, false );
    204231
     
    206233        }
    207234
     235        // call from a processor to flush
     236        // contains all the bookkeeping a proc must do, not just the barebones flushing logic
     237        void __cfa_do_flush( io_context$ & ctx, bool kernel ) {
     238                /* paranoid */ verify( ! __preemption_enabled() );
     239
     240                // flush any external requests
     241                ctx.sq.last_external = false; // clear the external bit, the arbiter will reset it if needed
     242                __ioarbiter_flush( ctx, kernel );
     243
     244                // if submitting must be submitted, do the system call
     245                if(ctx.sq.to_submit != 0) {
     246                        ioring_syscsll(ctx, 0, 0);
     247                }
     248        }
     249
     250        // call from a processor to drain
     251        // contains all the bookkeeping a proc must do, not just the barebones draining logic
    208252        bool __cfa_io_drain( struct processor * proc ) {
    209253                bool local = false;
    210254                bool remote = false;
    211255
     256                // make sure no ones creates/destroys io contexts
    212257                ready_schedule_lock();
    213258
     
    217262                /* paranoid */ verify( ctx );
    218263
     264                // Help if needed
    219265                with(cltr->sched) {
    220266                        const size_t ctxs_count = io.count;
     
    230276                        const unsigned long long ctsc = rdtscl();
    231277
     278                        // only help once every other time
     279                        // pick a target when not helping
    232280                        if(proc->io.target == UINT_MAX) {
    233281                                uint64_t chaos = __tls_rand();
     282                                // choose who to help and whether to accept helping far processors
    234283                                unsigned ext = chaos & 0xff;
    235284                                unsigned other  = (chaos >> 8) % (ctxs_count);
    236285
     286                                // if the processor is on the same cache line or is lucky ( 3 out of 256 odds ) help it
    237287                                if(ext < 3 || __atomic_load_n(&caches[other / __shard_factor.io].id, __ATOMIC_RELAXED) == this_cache) {
    238288                                        proc->io.target = other;
     
    240290                        }
    241291                        else {
     292                                // a target was picked last time, help it
    242293                                const unsigned target = proc->io.target;
    243294                                /* paranoid */ verify( io.tscs[target].t.tv != ULLONG_MAX );
     295                                // make sure the target hasn't stopped existing since last time
    244296                                HELP: if(target < ctxs_count) {
     297                                        // calculate it's age and how young it could be before we give up on helping
    245298                                        const __readyQ_avg_t cutoff = calc_cutoff(ctsc, ctx->cq.id, ctxs_count, io.data, io.tscs, __shard_factor.io, false);
    246299                                        const __readyQ_avg_t age = moving_average(ctsc, io.tscs[target].t.tv, io.tscs[target].t.ma, false);
    247300                                        __cfadbg_print_safe(io, "Kernel I/O: Help attempt on %u from %u, age %'llu vs cutoff %'llu, %s\n", target, ctx->cq.id, age, cutoff, age > cutoff ? "yes" : "no");
     301                                        // is the target older than the cutoff, recall 0 is oldest and bigger ints are younger
    248302                                        if(age <= cutoff) break HELP;
    249303
    250                                         if(!try_acquire(io.data[target])) break HELP;
    251 
     304                                        // attempt to help the submission side
     305                                        __cfa_do_flush( *io.data[target], true );
     306
     307                                        // attempt to help the completion side
     308                                        if(!try_acquire(io.data[target])) break HELP; // already acquire no help needed
     309
     310                                        // actually help
    252311                                        if(!__cfa_do_drain( io.data[target], cltr )) break HELP;
    253312
     313                                        // track we did help someone
    254314                                        remote = true;
    255315                                        __STATS__( true, io.calls.helped++; )
    256316                                }
     317
     318                                // reset the target
    257319                                proc->io.target = UINT_MAX;
    258320                        }
    259321                }
    260 
    261322
    262323                // Drain the local queue
     
    270331
    271332                ready_schedule_unlock();
     333
     334                // return true if some completion entry, local or remote, was drained
    272335                return local || remote;
    273336        }
    274337
     338
     339
     340        // call from a processor to flush
     341        // contains all the bookkeeping a proc must do, not just the barebones flushing logic
    275342        bool __cfa_io_flush( struct processor * proc ) {
    276343                /* paranoid */ verify( ! __preemption_enabled() );
     
    278345                /* paranoid */ verify( proc->io.ctx );
    279346
    280                 io_context$ & ctx = *proc->io.ctx;
    281 
    282                 __ioarbiter_flush( ctx );
    283 
    284                 if(ctx.sq.to_submit != 0) {
    285                         ioring_syscsll(ctx, 0, 0);
    286 
    287                 }
    288 
     347                __cfa_do_flush( *proc->io.ctx, false );
     348
     349                // also drain since some stuff will immediately complete
    289350                return __cfa_io_drain( proc );
    290351        }
     
    393454        //=============================================================================================
    394455        // submission
    395         static inline void __submit_only( struct io_context$ * ctx, __u32 idxs[], __u32 have) {
     456        // barebones logic to submit a group of sqes
     457        static inline void __submit_only( struct io_context$ * ctx, __u32 idxs[], __u32 have, bool lock) {
     458                if(!lock)
     459                        lock( ctx->ext_sq.lock __cfaabi_dbg_ctx2 );
    396460                // We can proceed to the fast path
    397461                // Get the right objects
     
    408472                // Make the sqes visible to the submitter
    409473                __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE);
    410                 sq.to_submit += have;
    411 
     474                __atomic_fetch_add(&sq.to_submit, have, __ATOMIC_SEQ_CST);
     475
     476                // set the bit to mark things need to be flushed
    412477                __atomic_store_n(&ctx->proc->io.pending, true, __ATOMIC_RELAXED);
    413478                __atomic_store_n(&ctx->proc->io.dirty  , true, __ATOMIC_RELAXED);
    414         }
    415 
     479
     480                if(!lock)
     481                        unlock( ctx->ext_sq.lock );
     482        }
     483
     484        // submission logic + maybe flushing
    416485        static inline void __submit( struct io_context$ * ctx, __u32 idxs[], __u32 have, bool lazy) {
    417486                __sub_ring_t & sq = ctx->sq;
    418                 __submit_only(ctx, idxs, have);
     487                __submit_only(ctx, idxs, have, false);
    419488
    420489                if(sq.to_submit > 30) {
     
    428497        }
    429498
     499        // call from a processor to flush
     500        // might require arbitration if the thread was migrated after the allocation
    430501        void cfa_io_submit( struct io_context$ * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) libcfa_public {
    431502                // __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager");
     
    441512                if( ctx == inctx )              // We have the right instance?
    442513                {
     514                        // yes! fast submit
    443515                        __submit(ctx, idxs, have, lazy);
    444516
     
    507579                __atomic_store_n(&ctx.sq.free_ring.tail, ftail + count, __ATOMIC_SEQ_CST);
    508580
     581                // notify the allocator that new allocations can be made
    509582                __ioarbiter_notify(ctx);
    510583
     
    557630        }
    558631
     632        // notify the arbiter that new allocations are available
    559633        static void __ioarbiter_notify( io_arbiter$ & this, io_context$ * ctx ) {
    560634                /* paranoid */ verify( !empty(this.pending.queue) );
    561 
     635                /* paranoid */ verify( __preemption_enabled() );
     636
     637                // mutual exclusion is needed
    562638                lock( this.pending.lock __cfaabi_dbg_ctx2 );
    563639                {
     640                        __cfadbg_print_safe(io, "Kernel I/O : notifying\n");
     641
     642                        // as long as there are pending allocations try to satisfy them
     643                        // for simplicity do it in FIFO order
    564644                        while( !empty(this.pending.queue) ) {
    565                                 __cfadbg_print_safe(io, "Kernel I/O : notifying\n");
     645                                // get first pending allocs
    566646                                __u32 have = ctx->sq.free_ring.tail - ctx->sq.free_ring.head;
    567647                                __pending_alloc & pa = (__pending_alloc&)head( this.pending.queue );
    568648
     649                                // check if we have enough to satisfy the request
    569650                                if( have > pa.want ) goto DONE;
     651
     652                                // if there are enough allocations it means we can drop the request
    570653                                drop( this.pending.queue );
    571654
    572655                                /* paranoid */__attribute__((unused)) bool ret =
    573656
     657                                // actually do the alloc
    574658                                __alloc(ctx, pa.idxs, pa.want);
    575659
    576660                                /* paranoid */ verify( ret );
    577661
     662                                // write out which context statisfied the request and post
     663                                // this
    578664                                pa.ctx = ctx;
    579 
    580665                                post( pa.waitctx );
    581666                        }
     
    585670                }
    586671                unlock( this.pending.lock );
    587         }
    588 
     672
     673                /* paranoid */ verify( __preemption_enabled() );
     674        }
     675
     676        // short hand to avoid the mutual exclusion of the pending is empty regardless
    589677        static void __ioarbiter_notify( io_context$ & ctx ) {
    590                 if(!empty( ctx.arbiter->pending )) {
    591                         __ioarbiter_notify( *ctx.arbiter, &ctx );
    592                 }
    593         }
    594 
    595         // Simply append to the pending
     678                if(empty( ctx.arbiter->pending )) return;
     679                __ioarbiter_notify( *ctx.arbiter, &ctx );
     680        }
     681
     682        // Submit from outside the local processor: append to the outstanding list
    596683        static void __ioarbiter_submit( io_context$ * ctx, __u32 idxs[], __u32 have, bool lazy ) {
    597684                __cfadbg_print_safe(io, "Kernel I/O : submitting %u from the arbiter to context %u\n", have, ctx->fd);
     
    599686                __cfadbg_print_safe(io, "Kernel I/O : waiting to submit %u\n", have);
    600687
     688                // create the intrusive object to append
    601689                __external_io ei;
    602690                ei.idxs = idxs;
     
    604692                ei.lazy = lazy;
    605693
     694                // enqueue the io
    606695                bool we = enqueue(ctx->ext_sq, (__outstanding_io&)ei);
    607696
     697                // mark pending
    608698                __atomic_store_n(&ctx->proc->io.pending, true, __ATOMIC_SEQ_CST);
    609699
     700                // if this is the first to be enqueued, signal the processor in an attempt to speed up flushing
     701                // if it's not the first enqueue, a signal is already in transit
    610702                if( we ) {
    611703                        sigval_t value = { PREEMPT_IO };
    612704                        __cfaabi_pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);
    613                 }
    614 
     705                        __STATS__( false, io.flush.signal += 1; )
     706                }
     707                __STATS__( false, io.submit.extr += 1; )
     708
     709                // to avoid dynamic allocation/memory reclamation headaches, wait for it to have been submitted
    615710                wait( ei.waitctx );
    616711
     
    618713        }
    619714
    620         static void __ioarbiter_flush( io_context$ & ctx ) {
    621                 if(!empty( ctx.ext_sq )) {
    622                         __STATS__( false, io.flush.external += 1; )
    623 
    624                         __cfadbg_print_safe(io, "Kernel I/O : arbiter flushing\n");
    625 
    626                         lock( ctx.ext_sq.lock __cfaabi_dbg_ctx2 );
    627                         {
    628                                 while( !empty(ctx.ext_sq.queue) ) {
    629                                         __external_io & ei = (__external_io&)drop( ctx.ext_sq.queue );
    630 
    631                                         __submit_only(&ctx, ei.idxs, ei.have);
    632 
    633                                         post( ei.waitctx );
    634                                 }
    635 
    636                                 ctx.ext_sq.empty = true;
     715        // flush the io arbiter: move all external io operations to the submission ring
     716        static void __ioarbiter_flush( io_context$ & ctx, bool kernel ) {
     717                // if there are no external operations just return
     718                if(empty( ctx.ext_sq )) return;
     719
     720                // stats and logs
     721                __STATS__( false, io.flush.external += 1; )
     722                __cfadbg_print_safe(io, "Kernel I/O : arbiter flushing\n");
     723
     724                // this can happen from multiple processors, mutual exclusion is needed
     725                lock( ctx.ext_sq.lock __cfaabi_dbg_ctx2 );
     726                {
     727                        // pop each operation one at a time.
     728                        // There is no wait morphing because of the io sq ring
     729                        while( !empty(ctx.ext_sq.queue) ) {
     730                                // drop the element from the queue
     731                                __external_io & ei = (__external_io&)drop( ctx.ext_sq.queue );
     732
     733                                // submit it
     734                                __submit_only(&ctx, ei.idxs, ei.have, true);
     735
     736                                // wake the thread that was waiting on it
     737                                // since this can both be called from kernel and user, check the flag before posting
     738                                __post( ei.waitctx, kernel, UNPARK_LOCAL );
    637739                        }
    638                         unlock(ctx.ext_sq.lock );
     740
     741                        // mark the queue as empty
     742                        ctx.ext_sq.empty = true;
     743                        ctx.sq.last_external = true;
     744                }
     745                unlock(ctx.ext_sq.lock );
     746        }
     747
     748        extern "C" {
     749                // debug functions used for gdb
     750                // io_uring doesn't yet support gdb soe the kernel-shared data structures aren't viewable in gdb
     751                // these functions read the data that gdb can't and should be removed once the support is added
     752                static __u32 __cfagdb_cq_head( io_context$ * ctx ) __attribute__((nonnull(1),used,noinline)) { return *ctx->cq.head; }
     753                static __u32 __cfagdb_cq_tail( io_context$ * ctx ) __attribute__((nonnull(1),used,noinline)) { return *ctx->cq.tail; }
     754                static __u32 __cfagdb_cq_mask( io_context$ * ctx ) __attribute__((nonnull(1),used,noinline)) { return *ctx->cq.mask; }
     755                static __u32 __cfagdb_sq_head( io_context$ * ctx ) __attribute__((nonnull(1),used,noinline)) { return *ctx->sq.kring.head; }
     756                static __u32 __cfagdb_sq_tail( io_context$ * ctx ) __attribute__((nonnull(1),used,noinline)) { return *ctx->sq.kring.tail; }
     757                static __u32 __cfagdb_sq_mask( io_context$ * ctx ) __attribute__((nonnull(1),used,noinline)) { return *ctx->sq.mask; }
     758
     759                // fancier version that reads an sqe and copies it out.
     760                static struct io_uring_sqe __cfagdb_sq_at( io_context$ * ctx, __u32 at ) __attribute__((nonnull(1),used,noinline)) {
     761                        __u32 ax = at & *ctx->sq.mask;
     762                        __u32 ix = ctx->sq.kring.array[ax];
     763                        return ctx->sq.sqes[ix];
    639764                }
    640765        }
  • libcfa/src/concurrency/io/call.cfa.in

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

    r34b4268 r24d6572  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#if defined(__CFA_DEBUG__)
     
    216215
    217216                // completion queue
    218                 cq.lock      = false;
     217                cq.try_lock  = false;
    219218                cq.id        = MAX;
    220219                cq.ts        = rdtscl();
  • libcfa/src/concurrency/io/types.hfa

    r34b4268 r24d6572  
    3737        //-----------------------------------------------------------------------
    3838        // Ring Data structure
    39       struct __sub_ring_t {
     39        // represent the io_uring submission ring which contains operations that will be sent to io_uring for processing
     40        struct __sub_ring_t {
     41                // lock needed because remote processors might need to flush the instance
     42                __spinlock_t lock;
     43
    4044                struct {
    4145                        // Head and tail of the ring (associated with array)
     
    5862
    5963                // number of sqes to submit on next system call.
    60                 __u32 to_submit;
     64                volatile __u32 to_submit;
    6165
    6266                // number of entries and mask to go with it
     
    7781                void * ring_ptr;
    7882                size_t ring_sz;
    79         };
    80 
     83
     84                // for debug purposes, whether or not the last flush was due to a arbiter flush
     85                bool last_external;
     86        };
     87
     88        // represent the io_uring completion ring which contains operations that have completed
    8189        struct __cmp_ring_t {
    82                 volatile bool lock;
    83 
     90                // needed because remote processors can help drain the buffer
     91                volatile bool try_lock;
     92
     93                // id of the ring, used for the helping/topology algorithms
    8494                unsigned id;
    8595
     96                // timestamp from last time it was drained
    8697                unsigned long long ts;
    8798
     
    105116        };
    106117
     118        // struct representing an io operation that still needs processing
     119        // actual operations are expected to inherit from this
    107120        struct __outstanding_io {
     121                // intrusive link fields
    108122                inline Colable;
     123
     124                // primitive on which to block until the io is processed
    109125                oneshot waitctx;
    110126        };
    111127        static inline __outstanding_io *& Next( __outstanding_io * n ) { return (__outstanding_io *)Next( (Colable *)n ); }
    112128
     129        // queue of operations that are outstanding
    113130        struct __outstanding_io_queue {
     131                // spinlock for protection
     132                // TODO: changing to a lock that blocks, I haven't examined whether it should be a kernel or user lock
    114133                __spinlock_t lock;
     134
     135                // the actual queue
    115136                Queue(__outstanding_io) queue;
     137
     138                // volatile used to avoid the need for taking the lock if it's empty
    116139                volatile bool empty;
    117140        };
    118141
     142        // struct representing an operation that was submitted
    119143        struct __external_io {
     144                // inherits from outstanding io
    120145                inline __outstanding_io;
     146
     147                // pointer and count to an array of ids to be submitted
    121148                __u32 * idxs;
    122149                __u32 have;
     150
     151                // whether or not these can be accumulated before flushing the buffer
    123152                bool lazy;
    124153        };
    125154
    126 
     155        // complete io_context, contains all the data for io submission and completion
    127156        struct __attribute__((aligned(64))) io_context$ {
     157                // arbiter, used in cases where threads for migrated at unfortunate moments
    128158                io_arbiter$ * arbiter;
     159
     160                // which prcessor the context is tied to
    129161                struct processor * proc;
    130162
     163                // queue of io submissions that haven't beeen processed.
    131164                __outstanding_io_queue ext_sq;
    132165
     166                // io_uring ring data structures
    133167                struct __sub_ring_t sq;
    134168                struct __cmp_ring_t cq;
     169
     170                // flag the io_uring rings where created with
    135171                __u32 ring_flags;
     172
     173                // file descriptor that identifies the io_uring instance
    136174                int fd;
    137175        };
    138176
     177        // short hand to check when the io_context was last processed (io drained)
    139178        static inline unsigned long long ts(io_context$ *& this) {
    140179                const __u32 head = *this->cq.head;
    141180                const __u32 tail = *this->cq.tail;
    142181
     182                // if there is no pending completions, just pretend it's infinetely recent
    143183                if(head == tail) return ULLONG_MAX;
    144184
     
    146186        }
    147187
     188        // structure represeting allocations that couldn't succeed locally
    148189        struct __pending_alloc {
     190                // inherit from outstanding io
    149191                inline __outstanding_io;
     192
     193                // array and size of the desired allocation
    150194                __u32 * idxs;
    151195                __u32 want;
     196
     197                // output param, the context the io was allocated from
    152198                io_context$ * ctx;
    153199        };
    154200
     201        // arbiter that handles cases where the context tied to the local processor is unable to satisfy the io
    155202        monitor __attribute__((aligned(64))) io_arbiter$ {
     203                // contains a queue of io for pending allocations
    156204                __outstanding_io_queue pending;
    157205        };
  • libcfa/src/concurrency/iofwd.hfa

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

    r34b4268 r24d6572  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Nov 30 18:14:08 2022
    13 // Update Count     : 76
     12// Last Modified On : Mon Jan  9 08:42:05 2023
     13// Update Count     : 77
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
     
    258257                __cfadbg_print_safe(runtime_core, "Kernel : core %p stopping\n", this);
    259258        }
     259
     260        __cfa_io_flush( this );
     261        __cfa_io_drain( this );
    260262
    261263        post( this->terminated );
  • libcfa/src/concurrency/kernel/cluster.cfa

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

    r34b4268 r24d6572  
    4040
    4141// convert to log2 scale but using double
    42 static inline __readyQ_avg_t __to_readyQ_avg(unsigned long long intsc) { if(unlikely(0 == intsc)) return 0.0; else return log2(intsc); }
     42static inline __readyQ_avg_t __to_readyQ_avg(unsigned long long intsc) { if(unlikely(0 == intsc)) return 0.0; else return log2((__readyQ_avg_t)intsc); }
    4343
    4444#define warn_large_before warnf( !strict || old_avg < 35.0, "Suspiciously large previous average: %'lf, %'" PRId64 "ms \n", old_avg, program()`ms )
     
    146146}
    147147
    148 static struct {
    149         const unsigned readyq;
    150         const unsigned io;
     148const static struct {
     149        unsigned readyq;
     150        unsigned io;
    151151} __shard_factor = { 2, 1 };
    152152
  • libcfa/src/concurrency/kernel/private.hfa

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

    r34b4268 r24d6572  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    2019
    2120// C Includes
    22 #include <errno.h>                                      // errno
     21#include <errno.h>                                                                              // errno
    2322#include <signal.h>
    24 #include <string.h>                                     // strerror
    25 #include <unistd.h>                                     // sysconf
    26 
     23#include <string.h>                                                                             // strerror
     24#include <unistd.h>
     25#include <limits.h>                                                                             // PTHREAD_STACK_MIN
    2726extern "C" {
    28         #include <limits.h>                             // PTHREAD_STACK_MIN
    29         #include <unistd.h>                             // syscall
    30         #include <sys/eventfd.h>                        // eventfd
    31         #include <sys/mman.h>                           // mprotect
    32         #include <sys/resource.h>                       // getrlimit
     27        #include <sys/eventfd.h>                                                        // eventfd
     28        #include <sys/mman.h>                                                           // mprotect
     29        #include <sys/resource.h>                                                       // getrlimit
    3330}
    3431
     
    3633#include "kernel/private.hfa"
    3734#include "iofwd.hfa"
    38 #include "startup.hfa"                                  // STARTUP_PRIORITY_XXX
     35#include "startup.hfa"                                                                  // STARTUP_PRIORITY_XXX
    3936#include "limits.hfa"
    4037#include "math.hfa"
     
    150147__scheduler_RWLock_t __scheduler_lock @= { 0 };
    151148
    152 #if   defined(CFA_HAVE_LINUX_LIBRSEQ)
    153         // No data needed
    154 #elif defined(CFA_HAVE_LINUX_RSEQ_H)
    155         extern "Cforall" {
    156                 __attribute__((aligned(64))) __thread volatile struct rseq __cfaabi_rseq @= {
    157                         .cpu_id : RSEQ_CPU_ID_UNINITIALIZED,
    158                 };
    159         }
    160 #else
    161         // No data needed
    162 #endif
    163 
    164149//-----------------------------------------------------------------------------
    165150// Struct to steal stack
  • libcfa/src/concurrency/locks.cfa

    r34b4268 r24d6572  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // locks.hfa -- LIBCFATHREAD
     7// locks.cfa -- LIBCFATHREAD
    88// Runtime locks that used with the runtime thread system.
    99//
     
    1616
    1717#define __cforall_thread__
    18 #define _GNU_SOURCE
    1918
    2019#include "locks.hfa"
     
    8079        // lock is held by some other thread
    8180        if ( owner != 0p && owner != thrd ) {
    82                 insert_last( blocked_threads, *thrd );
     81        select_node node;
     82                insert_last( blocked_threads, node );
    8383                wait_count++;
    8484                unlock( lock );
    8585                park( );
    86         }
    87         // multi acquisition lock is held by current thread
    88         else if ( owner == thrd && multi_acquisition ) {
     86        return;
     87        } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread
    8988                recursion_count++;
    90                 unlock( lock );
    91         }
    92         // lock isn't held
    93         else {
     89        } else {  // lock isn't held
    9490                owner = thrd;
    9591                recursion_count = 1;
    96                 unlock( lock );
    97         }
     92        }
     93    unlock( lock );
    9894}
    9995
     
    118114}
    119115
    120 static void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
    121         thread$ * t = &try_pop_front( blocked_threads );
    122         owner = t;
    123         recursion_count = ( t ? 1 : 0 );
    124         if ( t ) wait_count--;
    125         unpark( t );
     116static inline void pop_node( blocking_lock & this ) with( this ) {
     117    __handle_waituntil_OR( blocked_threads );
     118    select_node * node = &try_pop_front( blocked_threads );
     119    if ( node ) {
     120        wait_count--;
     121        owner = node->blocked_thread;
     122        recursion_count = 1;
     123        // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread );
     124        wake_one( blocked_threads, *node );
     125    } else {
     126        owner = 0p;
     127        recursion_count = 0;
     128    }
    126129}
    127130
     
    135138        recursion_count--;
    136139        if ( recursion_count == 0 ) {
    137                 pop_and_set_new_owner( this );
     140                pop_node( this );
    138141        }
    139142        unlock( lock );
     
    148151        // lock held
    149152        if ( owner != 0p ) {
    150                 insert_last( blocked_threads, *t );
     153                insert_last( blocked_threads, *(select_node *)t->link_node );
    151154                wait_count++;
    152                 unlock( lock );
    153155        }
    154156        // lock not held
     
    157159                recursion_count = 1;
    158160                unpark( t );
    159                 unlock( lock );
    160         }
    161 }
    162 
    163 size_t on_wait( blocking_lock & this ) with( this ) {
     161        }
     162    unlock( lock );
     163}
     164
     165size_t on_wait( blocking_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) with( this ) {
    164166        lock( lock __cfaabi_dbg_ctx2 );
    165167        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    168170        size_t ret = recursion_count;
    169171
    170         pop_and_set_new_owner( this );
     172        pop_node( this );
     173
     174    select_node node;
     175    active_thread()->link_node = (void *)&node;
    171176        unlock( lock );
     177
     178    pre_park_then_park( pp_fn, pp_datum );
     179
    172180        return ret;
    173181}
     
    176184        recursion_count = recursion;
    177185}
     186
     187// waituntil() support
     188bool register_select( blocking_lock & this, select_node & node ) with(this) {
     189    lock( lock __cfaabi_dbg_ctx2 );
     190        thread$ * thrd = active_thread();
     191
     192        // single acquisition lock is held by current thread
     193        /* paranoid */ verifyf( owner != thrd || multi_acquisition, "Single acquisition lock holder (%p) attempted to reacquire the lock %p resulting in a deadlock.", owner, &this );
     194
     195    if ( !node.park_counter && ( (owner == thrd && multi_acquisition) || owner == 0p ) ) { // OR special case
     196        if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
     197           unlock( lock );
     198           return false;
     199        }
     200    }
     201
     202        // lock is held by some other thread
     203        if ( owner != 0p && owner != thrd ) {
     204                insert_last( blocked_threads, node );
     205                wait_count++;
     206                unlock( lock );
     207        return false;
     208        } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread
     209                recursion_count++;
     210        } else {  // lock isn't held
     211                owner = thrd;
     212                recursion_count = 1;
     213        }
     214
     215    if ( node.park_counter ) __make_select_node_available( node );
     216    unlock( lock );
     217    return true;
     218}
     219
     220bool unregister_select( blocking_lock & this, select_node & node ) with(this) {
     221    lock( lock __cfaabi_dbg_ctx2 );
     222    if ( node`isListed ) {
     223        remove( node );
     224        wait_count--;
     225        unlock( lock );
     226        return false;
     227    }
     228   
     229    if ( owner == active_thread() ) {
     230        /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to unlock owner lock %p in waituntil unregister, which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count );
     231        // if recursion count is zero release lock and set new owner if one is waiting
     232        recursion_count--;
     233        if ( recursion_count == 0 ) {
     234            pop_node( this );
     235        }
     236    }
     237        unlock( lock );
     238    return false;
     239}
     240
     241void on_selected( blocking_lock & this, select_node & node ) {}
    178242
    179243//-----------------------------------------------------------------------------
     
    312376        int counter( condition_variable(L) & this ) with(this) { return count; }
    313377
    314         static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
     378        static void enqueue_thread( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    315379                // add info_thread to waiting queue
    316380                insert_last( blocked_threads, *i );
    317381                count++;
    318                 size_t recursion_count = 0;
    319                 if (i->lock) {
    320                         // if lock was passed get recursion count to reset to after waking thread
    321                         recursion_count = on_wait( *i->lock );
    322                 }
    323                 return recursion_count;
    324         }
     382        }
     383
     384    static size_t block_and_get_recursion( info_thread(L) & i, __cfa_pre_park pp_fn, void * pp_datum ) {
     385        size_t recursion_count = 0;
     386                if ( i.lock ) // if lock was passed get recursion count to reset to after waking thread
     387                        recursion_count = on_wait( *i.lock, pp_fn, pp_datum ); // this call blocks
     388                else
     389            pre_park_then_park( pp_fn, pp_datum );
     390        return recursion_count;
     391    }
     392    static size_t block_and_get_recursion( info_thread(L) & i ) { return block_and_get_recursion( i, pre_park_noop, 0p ); }
    325393
    326394        // helper for wait()'s' with no timeout
    327395        static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
    328396                lock( lock __cfaabi_dbg_ctx2 );
    329                 size_t recursion_count = queue_and_get_recursion(this, &i);
     397        enqueue_thread( this, &i );
    330398                unlock( lock );
    331399
    332400                // blocks here
    333                 park( );
     401        size_t recursion_count = block_and_get_recursion( i );
    334402
    335403                // resets recursion count here after waking
    336                 if (i.lock) on_wakeup(*i.lock, recursion_count);
     404                if ( i.lock ) on_wakeup( *i.lock, recursion_count );
    337405        }
    338406
     
    341409                queue_info_thread( this, i );
    342410
     411    static void cond_alarm_register( void * node_ptr ) { register_self( (alarm_node_t *)node_ptr ); }
     412
    343413        // helper for wait()'s' with a timeout
    344414        static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    345415                lock( lock __cfaabi_dbg_ctx2 );
    346                 size_t recursion_count = queue_and_get_recursion(this, &info);
     416        enqueue_thread( this, &info );
    347417                alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    348418                unlock( lock );
    349419
    350                 // registers alarm outside cond lock to avoid deadlock
    351                 register_self( &node_wrap.alarm_node );
    352 
    353                 // blocks here
    354                 park();
     420                // blocks here and registers alarm node before blocking after releasing locks to avoid deadlock
     421        size_t recursion_count = block_and_get_recursion( info, cond_alarm_register, (void *)(&node_wrap.alarm_node) );
     422                // park();
    355423
    356424                // unregisters alarm so it doesn't go off if this happens first
     
    358426
    359427                // resets recursion count here after waking
    360                 if (info.lock) on_wakeup(*info.lock, recursion_count);
     428                if ( info.lock ) on_wakeup( *info.lock, recursion_count );
    361429        }
    362430
     
    418486                info_thread( L ) i = { active_thread(), info, &l };
    419487                insert_last( blocked_threads, i );
    420                 size_t recursion_count = on_wait( *i.lock );
    421                 park( );
     488                size_t recursion_count = on_wait( *i.lock, pre_park_noop, 0p ); // blocks here
     489                // park( );
    422490                on_wakeup(*i.lock, recursion_count);
    423491        }
     
    460528        bool empty ( pthread_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }
    461529
    462         static size_t queue_and_get_recursion( pthread_cond_var(L) & this, info_thread(L) * i ) with(this) {
    463                 // add info_thread to waiting queue
    464                 insert_last( blocked_threads, *i );
    465                 size_t recursion_count = 0;
    466                 recursion_count = on_wait( *i->lock );
    467                 return recursion_count;
    468         }
    469        
    470530        static void queue_info_thread_timeout( pthread_cond_var(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    471531                lock( lock __cfaabi_dbg_ctx2 );
    472                 size_t recursion_count = queue_and_get_recursion(this, &info);
     532        insert_last( blocked_threads, info );
    473533                pthread_alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    474534                unlock( lock );
    475535
    476                 // registers alarm outside cond lock to avoid deadlock
    477                 register_self( &node_wrap.alarm_node );
    478 
    479                 // blocks here
    480                 park();
    481 
    482                 // unregisters alarm so it doesn't go off if this happens first
     536                // blocks here and registers alarm node before blocking after releasing locks to avoid deadlock
     537        size_t recursion_count = block_and_get_recursion( info, cond_alarm_register, (void *)(&node_wrap.alarm_node) );
     538
     539                // unregisters alarm so it doesn't go off if signal happens first
    483540                unregister_self( &node_wrap.alarm_node );
    484541
    485542                // resets recursion count here after waking
    486                 if (info.lock) on_wakeup(*info.lock, recursion_count);
     543                if ( info.lock ) on_wakeup( *info.lock, recursion_count );
    487544        }
    488545
     
    494551                lock( lock __cfaabi_dbg_ctx2 );
    495552                info_thread( L ) i = { active_thread(), info, &l };
    496                 size_t recursion_count = queue_and_get_recursion(this, &i);
    497                 unlock( lock );
    498                 park( );
    499                 on_wakeup(*i.lock, recursion_count);
     553        insert_last( blocked_threads, i );
     554                unlock( lock );
     555
     556        // blocks here
     557                size_t recursion_count = block_and_get_recursion( i );
     558
     559                on_wakeup( *i.lock, recursion_count );
    500560        }
    501561
     
    585645        return thrd != 0p;
    586646}
     647
  • libcfa/src/concurrency/locks.hfa

    r34b4268 r24d6572  
    3030#include "time.hfa"
    3131
     32#include "select.hfa"
     33
    3234#include <fstream.hfa>
    33 
    3435
    3536// futex headers
     
    3839#include <unistd.h>
    3940
    40 // undef to make a number of the locks not reacquire upon waking from a condlock
    41 #define REACQ 1
     41typedef void (*__cfa_pre_park)( void * );
     42
     43static inline void pre_park_noop( void * ) {}
     44
     45//-----------------------------------------------------------------------------
     46// is_blocking_lock
     47forall( L & | sized(L) )
     48trait is_blocking_lock {
     49        // For synchronization locks to use when acquiring
     50        void on_notify( L &, struct thread$ * );
     51
     52        // For synchronization locks to use when releasing
     53        size_t on_wait( L &, __cfa_pre_park pp_fn, void * pp_datum );
     54
     55        // to set recursion count after getting signalled;
     56        void on_wakeup( L &, size_t recursion );
     57};
     58
     59static inline void pre_park_then_park( __cfa_pre_park pp_fn, void * pp_datum ) {
     60    pp_fn( pp_datum );
     61    park();
     62}
     63
     64// macros for default routine impls for is_blocking_lock trait that do not wait-morph
     65
     66#define DEFAULT_ON_NOTIFY( lock_type ) \
     67    static inline void on_notify( lock_type & this, thread$ * t ){ unpark(t); }
     68
     69#define DEFAULT_ON_WAIT( lock_type ) \
     70    static inline size_t on_wait( lock_type & this, __cfa_pre_park pp_fn, void * pp_datum ) { \
     71        unlock( this ); \
     72        pre_park_then_park( pp_fn, pp_datum ); \
     73        return 0; \
     74    }
     75
     76// on_wakeup impl if lock should be reacquired after waking up
     77#define DEFAULT_ON_WAKEUP_REACQ( lock_type ) \
     78    static inline void on_wakeup( lock_type & this, size_t recursion ) { lock( this ); }
     79
     80// on_wakeup impl if lock will not be reacquired after waking up
     81#define DEFAULT_ON_WAKEUP_NO_REACQ( lock_type ) \
     82    static inline void on_wakeup( lock_type & this, size_t recursion ) {}
     83
     84
    4285
    4386//-----------------------------------------------------------------------------
     
    66109static inline bool   try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }
    67110static inline void   unlock   ( single_acquisition_lock & this ) { unlock  ( (blocking_lock &)this ); }
    68 static inline size_t on_wait  ( single_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); }
     111static inline size_t on_wait  ( single_acquisition_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) { return on_wait ( (blocking_lock &)this, pp_fn, pp_datum ); }
    69112static inline void   on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    70113static inline void   on_notify( single_acquisition_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
     114static inline bool   register_select( single_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
     115static inline bool   unregister_select( single_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
     116static inline void   on_selected( single_acquisition_lock & this, select_node & node ) { on_selected( (blocking_lock &)this, node ); }
    71117
    72118//----------
     
    80126static inline bool   try_lock ( owner_lock & this ) { return try_lock( (blocking_lock &)this ); }
    81127static inline void   unlock   ( owner_lock & this ) { unlock  ( (blocking_lock &)this ); }
    82 static inline size_t on_wait  ( owner_lock & this ) { return on_wait ( (blocking_lock &)this ); }
     128static inline size_t on_wait  ( owner_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) { return on_wait ( (blocking_lock &)this, pp_fn, pp_datum ); }
    83129static inline void   on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    84130static inline void   on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
     131static inline bool   register_select( owner_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
     132static inline bool   unregister_select( owner_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
     133static inline void   on_selected( owner_lock & this, select_node & node ) { on_selected( (blocking_lock &)this, node ); }
    85134
    86135//-----------------------------------------------------------------------------
     
    127176static inline void ?{}(mcs_spin_node & this) { this.next = 0p; this.locked = true; }
    128177
    129 static inline mcs_spin_node * volatile & ?`next ( mcs_spin_node * node ) {
    130         return node->next;
    131 }
    132 
    133178struct mcs_spin_lock {
    134179        mcs_spin_queue queue;
     
    136181
    137182static inline void lock(mcs_spin_lock & l, mcs_spin_node & n) {
     183    n.locked = true;
    138184        mcs_spin_node * prev = __atomic_exchange_n(&l.queue.tail, &n, __ATOMIC_SEQ_CST);
    139         n.locked = true;
    140         if(prev == 0p) return;
     185        if( prev == 0p ) return;
    141186        prev->next = &n;
    142         while(__atomic_load_n(&n.locked, __ATOMIC_RELAXED)) Pause();
     187        while( __atomic_load_n(&n.locked, __ATOMIC_RELAXED) ) Pause();
    143188}
    144189
     
    146191        mcs_spin_node * n_ptr = &n;
    147192        if (__atomic_compare_exchange_n(&l.queue.tail, &n_ptr, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return;
    148         while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) {}
     193        while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) Pause();
    149194        n.next->locked = false;
    150195}
     
    153198// futex_mutex
    154199
    155 // - No cond var support
    156200// - Kernel thd blocking alternative to the spinlock
    157201// - No ownership (will deadlock on reacq)
     202// - no reacq on wakeup
    158203struct futex_mutex {
    159204        // lock state any state other than UNLOCKED is locked
     
    169214}
    170215
    171 static inline void  ?{}( futex_mutex & this ) with(this) { val = 0; }
    172 
    173 static inline bool internal_try_lock(futex_mutex & this, int & compare_val) with(this) {
     216static inline void ?{}( futex_mutex & this ) with(this) { val = 0; }
     217
     218static inline bool internal_try_lock( futex_mutex & this, int & compare_val) with(this) {
    174219        return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
    175220}
    176221
    177 static inline int internal_exchange(futex_mutex & this) with(this) {
     222static inline int internal_exchange( futex_mutex & this ) with(this) {
    178223        return __atomic_exchange_n((int*)&val, 2, __ATOMIC_ACQUIRE);
    179224}
    180225
    181226// if this is called recursively IT WILL DEADLOCK!!!!!
    182 static inline void lock(futex_mutex & this) with(this) {
     227static inline void lock( futex_mutex & this ) with(this) {
    183228        int state;
    184229
    185        
    186         // // linear backoff omitted for now
    187         // for( int spin = 4; spin < 1024; spin += spin) {
    188         //      state = 0;
    189         //      // if unlocked, lock and return
    190         //      if (internal_try_lock(this, state)) return;
    191         //      if (2 == state) break;
    192         //      for (int i = 0; i < spin; i++) Pause();
    193         // }
    194 
    195         // no contention try to acquire
    196         if (internal_try_lock(this, state)) return;
     230        for( int spin = 4; spin < 1024; spin += spin) {
     231                state = 0;
     232                // if unlocked, lock and return
     233                if (internal_try_lock(this, state)) return;
     234                if (2 == state) break;
     235                for (int i = 0; i < spin; i++) Pause();
     236        }
    197237       
    198238        // if not in contended state, set to be in contended state
     
    207247
    208248static inline void unlock(futex_mutex & this) with(this) {
    209         // if uncontended do atomice unlock and then return
    210         if (__atomic_fetch_sub(&val, 1, __ATOMIC_RELEASE) == 1) return; // TODO: try acq/rel
     249        // if uncontended do atomic unlock and then return
     250    if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
    211251       
    212252        // otherwise threads are blocked so we must wake one
    213         __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);
    214253        futex((int *)&val, FUTEX_WAKE, 1);
    215254}
    216255
    217 static inline void on_notify( futex_mutex & f, thread$ * t){ unpark(t); }
    218 static inline size_t on_wait( futex_mutex & f ) {unlock(f); return 0;}
    219 
    220 // to set recursion count after getting signalled;
    221 static inline void on_wakeup( futex_mutex & f, size_t recursion ) {}
    222 
    223 //-----------------------------------------------------------------------------
    224 // CLH Spinlock
    225 // - No recursive acquisition
    226 // - Needs to be released by owner
    227 
    228 struct clh_lock {
    229         volatile bool * volatile tail;
    230 };
    231 
    232 static inline void  ?{}( clh_lock & this ) { this.tail = malloc(); *this.tail = true; }
    233 static inline void ^?{}( clh_lock & this ) { free(this.tail); }
    234 
    235 static inline void lock(clh_lock & l) {
    236         thread$ * curr_thd = active_thread();
    237         *(curr_thd->clh_node) = false;
    238         volatile bool * prev = __atomic_exchange_n((bool **)(&l.tail), (bool *)(curr_thd->clh_node), __ATOMIC_SEQ_CST);
    239         while(!__atomic_load_n(prev, __ATOMIC_ACQUIRE)) Pause();
    240         curr_thd->clh_prev = prev;
    241 }
    242 
    243 static inline void unlock(clh_lock & l) {
    244         thread$ * curr_thd = active_thread();
    245         __atomic_store_n(curr_thd->clh_node, true, __ATOMIC_RELEASE);
    246         curr_thd->clh_node = curr_thd->clh_prev;
    247 }
    248 
    249 static inline void on_notify(clh_lock & this, struct thread$ * t ) { unpark(t); }
    250 static inline size_t on_wait(clh_lock & this) { unlock(this); return 0; }
    251 static inline void on_wakeup(clh_lock & this, size_t recursion ) {
    252         #ifdef REACQ
    253         lock(this);
    254         #endif
    255 }
    256 
    257 
    258 //-----------------------------------------------------------------------------
    259 // Linear backoff Spinlock
    260 struct linear_backoff_then_block_lock {
     256DEFAULT_ON_NOTIFY( futex_mutex )
     257DEFAULT_ON_WAIT( futex_mutex )
     258DEFAULT_ON_WAKEUP_NO_REACQ( futex_mutex )
     259
     260//-----------------------------------------------------------------------------
     261// go_mutex
     262
     263// - Kernel thd blocking alternative to the spinlock
     264// - No ownership (will deadlock on reacq)
     265// - Golang's flavour of mutex
     266// - Impl taken from Golang: src/runtime/lock_futex.go
     267struct go_mutex {
     268        // lock state any state other than UNLOCKED is locked
     269        // enum LockState { UNLOCKED = 0, LOCKED = 1, SLEEPING = 2 };
     270       
     271        // stores a lock state
     272        int val;
     273};
     274static inline void  ?{}( go_mutex & this ) with(this) { val = 0; }
     275// static inline void ?{}( go_mutex & this, go_mutex this2 ) = void; // these don't compile correctly at the moment so they should be omitted
     276// static inline void ?=?( go_mutex & this, go_mutex this2 ) = void;
     277
     278static inline bool internal_try_lock(go_mutex & this, int & compare_val, int new_val ) with(this) {
     279        return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, new_val, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
     280}
     281
     282static inline int internal_exchange(go_mutex & this, int swap ) with(this) {
     283        return __atomic_exchange_n((int*)&val, swap, __ATOMIC_ACQUIRE);
     284}
     285
     286// if this is called recursively IT WILL DEADLOCK!!!!!
     287static inline void lock( go_mutex & this ) with( this ) {
     288        int state, init_state;
     289
     290    // speculative grab
     291    state = internal_exchange(this, 1);
     292    if ( !state ) return; // state == 0
     293    init_state = state;
     294    for (;;) {
     295        for( int i = 0; i < 4; i++ ) {
     296            while( !val ) { // lock unlocked
     297                state = 0;
     298                if ( internal_try_lock( this, state, init_state ) ) return;
     299            }
     300            for (int i = 0; i < 30; i++) Pause();
     301        }
     302
     303        while( !val ) { // lock unlocked
     304            state = 0;
     305            if ( internal_try_lock( this, state, init_state ) ) return;
     306        }
     307        sched_yield();
     308       
     309        // if not in contended state, set to be in contended state
     310        state = internal_exchange( this, 2 );
     311        if ( !state ) return; // state == 0
     312        init_state = 2;
     313        futex( (int*)&val, FUTEX_WAIT, 2 ); // if val is not 2 this returns with EWOULDBLOCK
     314    }
     315}
     316
     317static inline void unlock( go_mutex & this ) with(this) {
     318        // if uncontended do atomic unlock and then return
     319    if ( __atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1 ) return;
     320       
     321        // otherwise threads are blocked so we must wake one
     322        futex( (int *)&val, FUTEX_WAKE, 1 );
     323}
     324
     325DEFAULT_ON_NOTIFY( go_mutex )
     326DEFAULT_ON_WAIT( go_mutex )
     327DEFAULT_ON_WAKEUP_NO_REACQ( go_mutex )
     328
     329//-----------------------------------------------------------------------------
     330// Exponential backoff then block lock
     331struct exp_backoff_then_block_lock {
    261332        // Spin lock used for mutual exclusion
    262333        __spinlock_t spinlock;
     
    269340};
    270341
    271 static inline void  ?{}( linear_backoff_then_block_lock & this ) {
     342static inline void  ?{}( exp_backoff_then_block_lock & this ) {
    272343        this.spinlock{};
    273344        this.blocked_threads{};
    274345        this.lock_value = 0;
    275346}
    276 static inline void ^?{}( linear_backoff_then_block_lock & this ) {}
    277 // static inline void ?{}( linear_backoff_then_block_lock & this, linear_backoff_then_block_lock this2 ) = void;
    278 // static inline void ?=?( linear_backoff_then_block_lock & this, linear_backoff_then_block_lock this2 ) = void;
    279 
    280 static inline bool internal_try_lock(linear_backoff_then_block_lock & this, size_t & compare_val) with(this) {
    281         if (__atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
    282                 return true;
    283         }
    284         return false;
    285 }
    286 
    287 static inline bool try_lock(linear_backoff_then_block_lock & this) { size_t compare_val = 0; return internal_try_lock(this, compare_val); }
    288 
    289 static inline bool try_lock_contention(linear_backoff_then_block_lock & this) with(this) {
    290         if (__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE) == 0) {
    291                 return true;
    292         }
    293         return false;
    294 }
    295 
    296 static inline bool block(linear_backoff_then_block_lock & this) with(this) {
    297         lock( spinlock __cfaabi_dbg_ctx2 ); // TODO change to lockfree queue (MPSC)
    298         if (lock_value != 2) {
    299                 unlock( spinlock );
    300                 return true;
    301         }
    302         insert_last( blocked_threads, *active_thread() );
    303         unlock( spinlock );
     347static inline void ?{}( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void;
     348static inline void ?=?( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void;
     349
     350static inline void  ^?{}( exp_backoff_then_block_lock & this ){}
     351
     352static inline bool internal_try_lock( exp_backoff_then_block_lock & this, size_t & compare_val ) with(this) {
     353        return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
     354}
     355
     356static inline bool try_lock( exp_backoff_then_block_lock & this ) { size_t compare_val = 0; return internal_try_lock( this, compare_val ); }
     357
     358static inline bool try_lock_contention( exp_backoff_then_block_lock & this ) with(this) {
     359        return !__atomic_exchange_n( &lock_value, 2, __ATOMIC_ACQUIRE );
     360}
     361
     362static inline bool block( exp_backoff_then_block_lock & this ) with(this) {
     363    lock( spinlock __cfaabi_dbg_ctx2 );
     364    if (__atomic_load_n( &lock_value, __ATOMIC_SEQ_CST) != 2) {
     365        unlock( spinlock );
     366        return true;
     367    }
     368    insert_last( blocked_threads, *active_thread() );
     369    unlock( spinlock );
    304370        park( );
    305371        return true;
    306372}
    307373
    308 static inline void lock(linear_backoff_then_block_lock & this) with(this) {
     374static inline void lock( exp_backoff_then_block_lock & this ) with(this) {
    309375        size_t compare_val = 0;
    310376        int spin = 4;
     377
    311378        // linear backoff
    312379        for( ;; ) {
     
    324391}
    325392
    326 static inline void unlock(linear_backoff_then_block_lock & this) with(this) {
     393static inline void unlock( exp_backoff_then_block_lock & this ) with(this) {
    327394    if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return;
    328         lock( spinlock __cfaabi_dbg_ctx2 );
    329         thread$ * t = &try_pop_front( blocked_threads );
    330         unlock( spinlock );
    331         unpark( t );
    332 }
    333 
    334 static inline void on_notify(linear_backoff_then_block_lock & this, struct thread$ * t ) { unpark(t); }
    335 static inline size_t on_wait(linear_backoff_then_block_lock & this) { unlock(this); return 0; }
    336 static inline void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) {
    337         #ifdef REACQ
    338         lock(this);
    339         #endif
    340 }
     395    lock( spinlock __cfaabi_dbg_ctx2 );
     396    thread$ * t = &try_pop_front( blocked_threads );
     397    unlock( spinlock );
     398    unpark( t );
     399}
     400
     401DEFAULT_ON_NOTIFY( exp_backoff_then_block_lock )
     402DEFAULT_ON_WAIT( exp_backoff_then_block_lock )
     403DEFAULT_ON_WAKEUP_REACQ( exp_backoff_then_block_lock )
    341404
    342405//-----------------------------------------------------------------------------
     
    368431
    369432// if this is called recursively IT WILL DEADLOCK!!!!!
    370 static inline void lock(fast_block_lock & this) with(this) {
     433static inline void lock( fast_block_lock & this ) with(this) {
    371434        lock( lock __cfaabi_dbg_ctx2 );
    372435        if ( held ) {
     
    380443}
    381444
    382 static inline void unlock(fast_block_lock & this) with(this) {
     445static inline void unlock( fast_block_lock & this ) with(this) {
    383446        lock( lock __cfaabi_dbg_ctx2 );
    384447        /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this );
     
    389452}
    390453
    391 static inline void on_notify(fast_block_lock & this, struct thread$ * t ) with(this) {
    392         #ifdef REACQ
    393                 lock( lock __cfaabi_dbg_ctx2 );
    394                 insert_last( blocked_threads, *t );
    395                 unlock( lock );
    396         #else
    397                 unpark(t);
    398         #endif
    399 }
    400 static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; }
    401 static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { }
     454static inline void on_notify( fast_block_lock & this, struct thread$ * t ) with(this) {
     455    lock( lock __cfaabi_dbg_ctx2 );
     456    insert_last( blocked_threads, *t );
     457    unlock( lock );
     458}
     459DEFAULT_ON_WAIT( fast_block_lock )
     460DEFAULT_ON_WAKEUP_NO_REACQ( fast_block_lock )
    402461
    403462//-----------------------------------------------------------------------------
     
    410469struct simple_owner_lock {
    411470        // List of blocked threads
    412         dlist( thread$ ) blocked_threads;
     471        dlist( select_node ) blocked_threads;
    413472
    414473        // Spin lock used for mutual exclusion
     
    431490static inline void ?=?( simple_owner_lock & this, simple_owner_lock this2 ) = void;
    432491
    433 static inline void lock(simple_owner_lock & this) with(this) {
    434         if (owner == active_thread()) {
     492static inline void lock( simple_owner_lock & this ) with(this) {
     493        if ( owner == active_thread() ) {
    435494                recursion_count++;
    436495                return;
     
    438497        lock( lock __cfaabi_dbg_ctx2 );
    439498
    440         if (owner != 0p) {
    441                 insert_last( blocked_threads, *active_thread() );
     499        if ( owner != 0p ) {
     500        select_node node;
     501                insert_last( blocked_threads, node );
    442502                unlock( lock );
    443503                park( );
     
    449509}
    450510
    451 // TODO: fix duplicate def issue and bring this back
    452 // void pop_and_set_new_owner( simple_owner_lock & this ) with( this ) {
    453         // thread$ * t = &try_pop_front( blocked_threads );
    454         // owner = t;
    455         // recursion_count = ( t ? 1 : 0 );
    456         // unpark( t );
    457 // }
    458 
    459 static inline void unlock(simple_owner_lock & this) with(this) {
     511static inline void pop_node( simple_owner_lock & this ) with(this) {
     512    __handle_waituntil_OR( blocked_threads );
     513    select_node * node = &try_pop_front( blocked_threads );
     514    if ( node ) {
     515        owner = node->blocked_thread;
     516        recursion_count = 1;
     517        // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread );
     518        wake_one( blocked_threads, *node );
     519    } else {
     520        owner = 0p;
     521        recursion_count = 0;
     522    }
     523}
     524
     525static inline void unlock( simple_owner_lock & this ) with(this) {
    460526        lock( lock __cfaabi_dbg_ctx2 );
    461527        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    464530        recursion_count--;
    465531        if ( recursion_count == 0 ) {
    466                 // pop_and_set_new_owner( this );
    467                 thread$ * t = &try_pop_front( blocked_threads );
    468                 owner = t;
    469                 recursion_count = ( t ? 1 : 0 );
    470                 unpark( t );
     532                pop_node( this );
    471533        }
    472534        unlock( lock );
    473535}
    474536
    475 static inline void on_notify(simple_owner_lock & this, struct thread$ * t ) with(this) {
     537static inline void on_notify( simple_owner_lock & this, thread$ * t ) with(this) {
    476538        lock( lock __cfaabi_dbg_ctx2 );
    477539        // lock held
    478540        if ( owner != 0p ) {
    479                 insert_last( blocked_threads, *t );
     541                insert_last( blocked_threads, *(select_node *)t->link_node );
    480542        }
    481543        // lock not held
     
    488550}
    489551
    490 static inline size_t on_wait(simple_owner_lock & this) with(this) {
     552static inline size_t on_wait( simple_owner_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) with(this) {
    491553        lock( lock __cfaabi_dbg_ctx2 );
    492554        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    495557        size_t ret = recursion_count;
    496558
    497         // pop_and_set_new_owner( this );
    498 
    499         thread$ * t = &try_pop_front( blocked_threads );
    500         owner = t;
    501         recursion_count = ( t ? 1 : 0 );
    502         unpark( t );
    503 
     559        pop_node( this );
     560
     561    select_node node;
     562    active_thread()->link_node = (void *)&node;
    504563        unlock( lock );
     564
     565    pre_park_then_park( pp_fn, pp_datum );
     566
    505567        return ret;
    506568}
    507569
    508 static inline void on_wakeup(simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; }
     570static inline void on_wakeup( simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; }
     571
     572// waituntil() support
     573static inline bool register_select( simple_owner_lock & this, select_node & node ) with(this) {
     574    lock( lock __cfaabi_dbg_ctx2 );
     575
     576    // check if we can complete operation. If so race to establish winner in special OR case
     577    if ( !node.park_counter && ( owner == active_thread() || owner == 0p ) ) {
     578        if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
     579           unlock( lock );
     580           return false;
     581        }
     582    }
     583
     584    if ( owner == active_thread() ) {
     585                recursion_count++;
     586        if ( node.park_counter ) __make_select_node_available( node );
     587        unlock( lock );
     588                return true;
     589        }
     590
     591    if ( owner != 0p ) {
     592                insert_last( blocked_threads, node );
     593                unlock( lock );
     594                return false;
     595        }
     596   
     597        owner = active_thread();
     598        recursion_count = 1;
     599
     600    if ( node.park_counter ) __make_select_node_available( node );
     601    unlock( lock );
     602    return true;
     603}
     604
     605static inline bool unregister_select( simple_owner_lock & this, select_node & node ) with(this) {
     606    lock( lock __cfaabi_dbg_ctx2 );
     607    if ( node`isListed ) {
     608        remove( node );
     609        unlock( lock );
     610        return false;
     611    }
     612
     613    if ( owner == active_thread() ) {
     614        recursion_count--;
     615        if ( recursion_count == 0 ) {
     616            pop_node( this );
     617        }
     618    }
     619    unlock( lock );
     620    return false;
     621}
     622
     623static inline void on_selected( simple_owner_lock & this, select_node & node ) {}
     624
    509625
    510626//-----------------------------------------------------------------------------
     
    521637        // flag showing if lock is held
    522638        volatile bool held;
    523 
    524         #ifdef __CFA_DEBUG__
    525         // for deadlock detection
    526         struct thread$ * owner;
    527         #endif
    528639};
    529640
     
    536647static inline void ?=?( spin_queue_lock & this, spin_queue_lock this2 ) = void;
    537648
    538 // if this is called recursively IT WILL DEADLOCK!!!!!
    539 static inline void lock(spin_queue_lock & this) with(this) {
     649// if this is called recursively IT WILL DEADLOCK!
     650static inline void lock( spin_queue_lock & this ) with(this) {
    540651        mcs_spin_node node;
    541652        lock( lock, node );
     
    545656}
    546657
    547 static inline void unlock(spin_queue_lock & this) with(this) {
     658static inline void unlock( spin_queue_lock & this ) with(this) {
    548659        __atomic_store_n(&held, false, __ATOMIC_RELEASE);
    549660}
    550661
    551 static inline void on_notify(spin_queue_lock & this, struct thread$ * t ) {
    552         unpark(t);
    553 }
    554 static inline size_t on_wait(spin_queue_lock & this) { unlock(this); return 0; }
    555 static inline void on_wakeup(spin_queue_lock & this, size_t recursion ) {
    556         #ifdef REACQ
    557         lock(this);
    558         #endif
    559 }
    560 
     662DEFAULT_ON_NOTIFY( spin_queue_lock )
     663DEFAULT_ON_WAIT( spin_queue_lock )
     664DEFAULT_ON_WAKEUP_REACQ( spin_queue_lock )
    561665
    562666//-----------------------------------------------------------------------------
     
    584688
    585689// if this is called recursively IT WILL DEADLOCK!!!!!
    586 static inline void lock(mcs_block_spin_lock & this) with(this) {
     690static inline void lock( mcs_block_spin_lock & this ) with(this) {
    587691        mcs_node node;
    588692        lock( lock, node );
     
    596700}
    597701
    598 static inline void on_notify(mcs_block_spin_lock & this, struct thread$ * t ) { unpark(t); }
    599 static inline size_t on_wait(mcs_block_spin_lock & this) { unlock(this); return 0; }
    600 static inline void on_wakeup(mcs_block_spin_lock & this, size_t recursion ) {
    601         #ifdef REACQ
    602         lock(this);
    603         #endif
    604 }
     702DEFAULT_ON_NOTIFY( mcs_block_spin_lock )
     703DEFAULT_ON_WAIT( mcs_block_spin_lock )
     704DEFAULT_ON_WAKEUP_REACQ( mcs_block_spin_lock )
    605705
    606706//-----------------------------------------------------------------------------
     
    628728
    629729// if this is called recursively IT WILL DEADLOCK!!!!!
    630 static inline void lock(block_spin_lock & this) with(this) {
     730static inline void lock( block_spin_lock & this ) with(this) {
    631731        lock( lock );
    632732        while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause();
     
    635735}
    636736
    637 static inline void unlock(block_spin_lock & this) with(this) {
     737static inline void unlock( block_spin_lock & this ) with(this) {
    638738        __atomic_store_n(&held, false, __ATOMIC_RELEASE);
    639739}
    640740
    641 static inline void on_notify(block_spin_lock & this, struct thread$ * t ) with(this.lock) {
    642   #ifdef REACQ
     741static inline void on_notify( block_spin_lock & this, struct thread$ * t ) with(this.lock) {
    643742        // first we acquire internal fast_block_lock
    644743        lock( lock __cfaabi_dbg_ctx2 );
     
    652751        unlock( lock );
    653752
    654   #endif
    655753        unpark(t);
    656        
    657 }
    658 static inline size_t on_wait(block_spin_lock & this) { unlock(this); return 0; }
    659 static inline void on_wakeup(block_spin_lock & this, size_t recursion ) with(this) {
    660   #ifdef REACQ
     754}
     755DEFAULT_ON_WAIT( block_spin_lock )
     756static inline void on_wakeup( block_spin_lock & this, size_t recursion ) with(this) {
    661757        // now we acquire the entire block_spin_lock upon waking up
    662758        while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause();
    663759        __atomic_store_n(&held, true, __ATOMIC_RELEASE);
    664760        unlock( lock ); // Now we release the internal fast_spin_lock
    665   #endif
    666 }
    667 
    668 //-----------------------------------------------------------------------------
    669 // is_blocking_lock
    670 trait is_blocking_lock(L & | sized(L)) {
    671         // For synchronization locks to use when acquiring
    672         void on_notify( L &, struct thread$ * );
    673 
    674         // For synchronization locks to use when releasing
    675         size_t on_wait( L & );
    676 
    677         // to set recursion count after getting signalled;
    678         void on_wakeup( L &, size_t recursion );
    679 };
     761}
    680762
    681763//-----------------------------------------------------------------------------
     
    685767forall(L & | is_blocking_lock(L)) {
    686768        struct info_thread;
    687 
    688         // // for use by sequence
    689         // info_thread(L) *& Back( info_thread(L) * this );
    690         // info_thread(L) *& Next( info_thread(L) * this );
    691769}
    692770
  • libcfa/src/concurrency/monitor.cfa

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

    r34b4268 r24d6572  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec  4 07:55:32 2019
    13 // Update Count     : 11
     12// Last Modified On : Thu Feb  2 11:29:21 2023
     13// Update Count     : 12
    1414//
    1515
     
    2222#include "stdlib.hfa"
    2323
    24 trait is_monitor(T &) {
     24forall( T & )
     25trait is_monitor {
    2526        monitor$ * get_monitor( T & );
    2627        void ^?{}( T & mutex );
  • libcfa/src/concurrency/mutex.cfa

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

    r34b4268 r24d6572  
    1212// Created On       : Fri May 25 01:24:09 2018
    1313// Last Modified By : Peter A. Buhr
    14 // Last Modified On : Wed Dec  4 09:16:53 2019
    15 // Update Count     : 1
     14// Last Modified On : Thu Feb  2 11:46:08 2023
     15// Update Count     : 2
    1616//
    1717
     
    7070void unlock(recursive_mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
    7171
    72 trait is_lock(L & | sized(L)) {
     72forall( L & | sized(L) )
     73trait is_lock {
    7374        void lock  (L &);
    7475        void unlock(L &);
  • libcfa/src/concurrency/mutex_stmt.hfa

    r34b4268 r24d6572  
     1#pragma once
     2
    13#include "bits/algorithm.hfa"
    24#include "bits/defs.hfa"
     
    46//-----------------------------------------------------------------------------
    57// is_lock
    6 trait is_lock(L & | sized(L)) {
     8forall(L & | sized(L))
     9trait is_lock {
    710        // For acquiring a lock
    811        void lock( L & );
     
    1114        void unlock( L & );
    1215};
    13 
    1416
    1517struct __mutex_stmt_lock_guard {
     
    2426    // Sort locks based on address
    2527    __libcfa_small_sort(this.lockarr, count);
    26 
    27     // acquire locks in order
    28     // for ( size_t i = 0; i < count; i++ ) {
    29     //     lock(*this.lockarr[i]);
    30     // }
    31 }
    32 
    33 static inline void ^?{}( __mutex_stmt_lock_guard & this ) with(this) {
    34     // for ( size_t i = count; i > 0; i-- ) {
    35     //     unlock(*lockarr[i - 1]);
    36     // }
    3728}
    3829
    3930forall(L & | is_lock(L)) {
    40 
    41     struct scoped_lock {
    42         L * internal_lock;
    43     };
    44 
    45     static inline void ?{}( scoped_lock(L) & this, L & internal_lock ) {
    46         this.internal_lock = &internal_lock;
    47         lock(internal_lock);
    48     }
    49    
    50     static inline void ^?{}( scoped_lock(L) & this ) with(this) {
    51         unlock(*internal_lock);
    52     }
    53 
    54     static inline void * __get_mutexstmt_lock_ptr( L & this ) {
    55         return &this;
    56     }
    57 
    58     static inline L __get_mutexstmt_lock_type( L & this );
    59 
    60     static inline L __get_mutexstmt_lock_type( L * this );
     31    static inline void * __get_mutexstmt_lock_ptr( L & this ) { return &this; }
     32    static inline L __get_mutexstmt_lock_type( L & this ) {}
     33    static inline L __get_mutexstmt_lock_type( L * this ) {}
    6134}
  • libcfa/src/concurrency/preemption.cfa

    r34b4268 r24d6572  
    1010// Created On       : Mon Jun 5 14:20:42 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 17 11:18:57 2022
    13 // Update Count     : 59
     12// Last Modified On : Mon Jan  9 08:42:59 2023
     13// Update Count     : 60
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_PREEMPTION__
     
    118117                __cfadbg_print_buffer_decl( preemption, " KERNEL: preemption tick %lu\n", currtime.tn);
    119118                Duration period = node->period;
    120                 if( period == 0) {
     119                if( period == 0 ) {
    121120                        node->set = false;                  // Node is one-shot, just mark it as not pending
    122121                }
  • libcfa/src/concurrency/pthread.cfa

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

    r34b4268 r24d6572  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_READY_QUEUE__
  • libcfa/src/concurrency/thread.cfa

    r34b4268 r24d6572  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 11 20:56:54 2022
    13 // Update Count     : 102
     12// Last Modified On : Mon Jan  9 08:42:33 2023
     13// Update Count     : 103
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include "thread.hfa"
     
    5453        preferred = ready_queue_new_preferred();
    5554        last_proc = 0p;
     55    link_node = 0p;
    5656        PRNG_SET_SEED( random_state, __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl() );
    5757        #if defined( __CFA_WITH_VERIFY__ )
     
    6060        #endif
    6161
    62         clh_node = malloc( );
    63         *clh_node = false;
    64 
    6562        doregister(curr_cluster, this);
    6663        monitors{ &self_mon_p, 1, (fptr_t)0 };
     
    7168                canary = 0xDEADDEADDEADDEADp;
    7269        #endif
    73         free(clh_node);
    7470        unregister(curr_cluster, this);
    7571        ^self_cor{};
  • libcfa/src/concurrency/thread.hfa

    r34b4268 r24d6572  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov 22 22:18:34 2022
    13 // Update Count     : 35
     12// Last Modified On : Thu Feb  2 11:27:59 2023
     13// Update Count     : 37
    1414//
    1515
     
    2727//-----------------------------------------------------------------------------
    2828// thread trait
    29 trait is_thread(T &) {
     29forall( T & )
     30trait is_thread {
    3031        void ^?{}(T& mutex this);
    3132        void main(T& this);
  • libcfa/src/containers/array.hfa

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

    r34b4268 r24d6572  
    99// Author           : Michael Brooks
    1010// Created On       : Wed Apr 22 18:00:00 2020
    11 // Last Modified By : Michael Brooks
    12 // Last Modified On : Wed Apr 22 18:00:00 2020
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb  2 11:32:26 2023
     13// Update Count     : 2
    1414//
    1515
     
    2323};
    2424
    25 trait embedded( tOuter &, tMid &, tInner & ) {
     25forall( tOuter &, tMid &, tInner & )
     26trait embedded {
    2627    tytagref( tMid, tInner ) ?`inner( tOuter & );
    2728};
     
    3132static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; }
    3233
    33 // use this on every case of plan-9 inheritance, to make embedded a closure of plan-9 inheritance
    34 #define P9_EMBEDDED( derived, immedBase ) \
    35 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \
    36     static inline tytagref(immedBase, Tbase) ?`inner( derived & this ) { \
     34
     35//
     36// P9_EMBEDDED: Use on every case of plan-9 inheritance, to make "implements embedded" be a closure of plan-9 inheritance.
     37//
     38// struct foo {
     39//    int a, b, c;
     40//    inline (bar);
     41// };
     42// P9_EMBEDDED( foo, bar )
     43//
     44
     45// usual version, for structs that are top-level declarations
     46#define P9_EMBEDDED(        derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, static ) P9_EMBEDDED_BDY_( immedBase )
     47
     48// special version, for structs that are declared in functions
     49#define P9_EMBEDDED_INFUNC( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase,        ) P9_EMBEDDED_BDY_( immedBase )
     50
     51// forward declarations of both the above; generally not needed
     52// may help you control where the P9_EMBEEDED cruft goes, in case "right after the stuct" isn't where you want it
     53#define P9_EMBEDDED_FWD(        derived, immedBase )      P9_EMBEDDED_DECL_( derived, immedBase, static ) ;
     54#define P9_EMBEDDED_FWD_INFUNC( derived, immedBase ) auto P9_EMBEDDED_DECL_( derived, immedBase,        ) ;
     55
     56// private helpers
     57#define P9_EMBEDDED_DECL_( derived, immedBase, STORAGE ) \
     58    forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \
     59    STORAGE inline tytagref(immedBase, Tbase) ?`inner( derived & this )
     60   
     61#define P9_EMBEDDED_BDY_( immedBase ) { \
    3762        immedBase & ib = this; \
    3863        Tbase & b = ib`inner; \
  • libcfa/src/containers/vector.hfa

    r34b4268 r24d6572  
    1010// Created On       : Tue Jul  5 18:00:07 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 17 11:02:46 2020
    13 // Update Count     : 4
     12// Last Modified On : Thu Feb  2 11:41:24 2023
     13// Update Count     : 5
    1414//
    1515
     
    5050//------------------------------------------------------------------------------
    5151//Declaration
    52 trait allocator_c(T, allocator_t)
    53 {
     52forall( T, allocator_t )
     53trait allocator_c {
    5454        void realloc_storage(allocator_t*, size_t);
    5555        T* data(allocator_t*);
  • libcfa/src/containers/vector2.hfa

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

    r34b4268 r24d6572  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:11:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr  8 15:20:00 2021
    13 // Update Count     : 12
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb  2 11:20:19 2023
     13// Update Count     : 13
    1414//
    1515
     
    101101// implemented in the .c file either so they all have to be inline.
    102102
    103 trait is_exception(exceptT &, virtualT &) {
     103forall( exceptT &, virtualT & )
     104trait is_exception {
    104105        /* The first field must be a pointer to a virtual table.
    105106         * That virtual table must be a decendent of the base exception virtual table.
     
    109110};
    110111
    111 trait is_termination_exception(exceptT &, virtualT & | is_exception(exceptT, virtualT)) {
     112forall( exceptT &, virtualT & | is_exception(exceptT, virtualT) )
     113trait is_termination_exception {
    112114        void defaultTerminationHandler(exceptT &);
    113115};
    114116
    115 trait is_resumption_exception(exceptT &, virtualT & | is_exception(exceptT, virtualT)) {
     117forall( exceptT &, virtualT & | is_exception(exceptT, virtualT) )
     118trait is_resumption_exception {
    116119        void defaultResumptionHandler(exceptT &);
    117120};
  • libcfa/src/heap.cfa

    r34b4268 r24d6572  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 30 20:56:20 2022
    13 // Update Count     : 1584
     12// Last Modified On : Fri Dec 30 08:37:37 2022
     13// Update Count     : 1605
    1414//
    1515
     
    1717#include <string.h>                                                                             // memset, memcpy
    1818#include <limits.h>                                                                             // ULONG_MAX
    19 #include <stdlib.h>                                                                             // EXIT_FAILURE
    2019#include <errno.h>                                                                              // errno, ENOMEM, EINVAL
    21 #include <unistd.h>                                                                             // STDERR_FILENO, sbrk, sysconf
    22 #include <malloc.h>                                                                             // memalign, malloc_usable_size
     20#include <unistd.h>                                                                             // STDERR_FILENO, sbrk, sysconf, write
    2321#include <sys/mman.h>                                                                   // mmap, munmap
    2422extern "C" {
     
    2624} // extern "C"
    2725
     26#include "heap.hfa"
    2827#include "bits/align.hfa"                                                               // libAlign
    2928#include "bits/defs.hfa"                                                                // likely, unlikely
     
    140139#endif
    141140
    142 typedef volatile uintptr_t SpinLock_t CALIGN;                   // aligned addressable word-size
     141typedef volatile uintptr_t SpinLock_t;
    143142
    144143static inline __attribute__((always_inline)) void lock( volatile SpinLock_t & slock ) {
     
    147146
    148147        for ( unsigned int i = 1;; i += 1 ) {
    149           if ( slock == 0 && __atomic_test_and_set( &slock, __ATOMIC_SEQ_CST ) == 0 ) break; // Fence
     148          if ( slock == 0 && __atomic_test_and_set( &slock, __ATOMIC_ACQUIRE ) == 0 ) break; // Fence
    150149                for ( volatile unsigned int s = 0; s < spin; s += 1 ) Pause(); // exponential spin
    151150                spin += spin;                                                                   // powers of 2
     
    156155
    157156static inline __attribute__((always_inline)) void unlock( volatile SpinLock_t & slock ) {
    158         __atomic_clear( &slock, __ATOMIC_SEQ_CST );                     // Fence
     157        __atomic_clear( &slock, __ATOMIC_RELEASE );                     // Fence
    159158} // spin_unlock
    160159
     
    261260        static_assert( libAlign() >= sizeof( Storage ), "minimum alignment < sizeof( Storage )" );
    262261
    263         struct __attribute__(( aligned (8) )) FreeHeader {
    264                 size_t blockSize __attribute__(( aligned(8) )); // size of allocations on this list
     262        struct CALIGN FreeHeader {
     263                size_t blockSize CALIGN;                                                // size of allocations on this list
    265264                #ifdef OWNERSHIP
    266265                #ifdef RETURNSPIN
     
    284283
    285284        #ifdef __CFA_DEBUG__
    286         int64_t allocUnfreed;                                                           // running total of allocations minus frees; can be negative
     285        ptrdiff_t allocUnfreed;                                                         // running total of allocations minus frees; can be negative
    287286        #endif // __CFA_DEBUG__
    288287
     
    369368// Thread-local storage is allocated lazily when the storage is accessed.
    370369static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing
    371 static __thread Heap * volatile heapManager CALIGN TLSMODEL;
     370static __thread Heap * heapManager CALIGN TLSMODEL;
    372371static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing
    373372
     
    443442                // 12K ~= 120K byte superblock.  Where 128-heap superblock handles a medium sized multi-processor server.
    444443                size_t remaining = heapManagersStorageEnd - heapManagersStorage; // remaining free heaps in superblock
    445                 if ( ! heapManagersStorage || remaining != 0 ) {
     444                if ( ! heapManagersStorage || remaining == 0 ) {
    446445                        // Each block of heaps is a multiple of the number of cores on the computer.
    447446                        int HeapDim = get_nprocs();                                     // get_nprocs_conf does not work
     
    562561                // allocUnfreed is set to 0 when a heap is created and it accumulates any unfreed storage during its multiple thread
    563562                // usages.  At the end, add up each heap allocUnfreed value across all heaps to get the total unfreed storage.
    564                 int64_t allocUnfreed = 0;
     563                ptrdiff_t allocUnfreed = 0;
    565564                for ( Heap * heap = heapMaster.heapManagersList; heap; heap = heap->nextHeapManager ) {
    566565                        allocUnfreed += heap->allocUnfreed;
     
    572571                        char helpText[512];
    573572                        __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
    574                                                                                 "CFA warning (UNIX pid:%ld) : program terminating with %ju(0x%jx) bytes of storage allocated but not freed.\n"
     573                                                                                "CFA warning (UNIX pid:%ld) : program terminating with %td(%#tx) bytes of storage allocated but not freed.\n"
    575574                                                                                "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    576575                                                                                (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
     
    806805
    807806        ptrdiff_t rem = heapRemaining - size;
    808         if ( unlikely( rem < 0 ) ) {
     807        if ( unlikely( rem < 0 ) ) {                                            // negative ?
    809808                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    810809
     
    842841        ptrdiff_t rem = heapReserve - size;
    843842
    844         if ( unlikely( rem < 0 ) ) {                                            // negative
     843        if ( unlikely( rem < 0 ) ) {                                            // negative ?
    845844                // If the size requested is bigger than the current remaining reserve, use the current reserve to populate
    846845                // smaller freeLists, and increase the reserve.
     
    848847                rem = heapReserve;                                                              // positive
    849848
    850                 if ( rem >= bucketSizes[0] ) {                                  // minimal size ? otherwise ignore
     849                if ( (unsigned int)rem >= bucketSizes[0] ) {    // minimal size ? otherwise ignore
    851850                        size_t bucket;
    852851                        #ifdef FASTLOOKUP
     
    857856                        Heap.FreeHeader * freeHead = &(freeLists[bucket]);
    858857
    859                         // The remaining storage many not be bucket size, whereas all other allocations are. Round down to previous
     858                        // The remaining storage may not be bucket size, whereas all other allocations are. Round down to previous
    860859                        // bucket size in this case.
    861860                        if ( unlikely( freeHead->blockSize > (size_t)rem ) ) freeHead -= 1;
     
    950949                block = freeHead->freeList;                                             // remove node from stack
    951950                if ( unlikely( block == 0p ) ) {                                // no free block ?
    952                         // Freelist for this size is empty, so check return list (OWNERSHIP), carve it out of the heap, if there
     951                        // Freelist for this size is empty, so check return list (OWNERSHIP), or carve it out of the heap if there
    953952                        // is enough left, or get some more heap storage and carve it off.
    954953                        #ifdef OWNERSHIP
     
    11151114                        while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, (Heap.Storage *)header,
    11161115                                                                                                   false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) );
     1116
     1117                        #ifdef __STATISTICS__
     1118                        stats.return_pushes += 1;
     1119                        stats.return_storage_request += rsize;
     1120                        stats.return_storage_alloc += size;
     1121                        #endif // __STATISTICS__
    11171122                        #endif // RETURNSPIN
    11181123                } // if
     
    11251130                freeHead->freeList = (Heap.Storage *)header;
    11261131                #endif // ! OWNERSHIP
    1127 
    1128                 #ifdef __U_STATISTICS__
    1129                 stats.return_pushes += 1;
    1130                 stats.return_storage_request += rsize;
    1131                 stats.return_storage_alloc += size;
    1132                 #endif // __U_STATISTICS__
    11331132
    11341133                // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
     
    11801179
    11811180#ifdef __STATISTICS__
    1182 static void incCalls( intptr_t statName ) libcfa_nopreempt {
     1181static void incCalls( size_t statName ) libcfa_nopreempt {
    11831182        heapManager->stats.counters[statName].calls += 1;
    11841183} // incCalls
    11851184
    1186 static void incZeroCalls( intptr_t statName ) libcfa_nopreempt {
     1185static void incZeroCalls( size_t statName ) libcfa_nopreempt {
    11871186        heapManager->stats.counters[statName].calls_0 += 1;
    11881187} // incZeroCalls
     
    14561455        // 0p, no operation is performed.
    14571456        void free( void * addr ) libcfa_public {
    1458 //              verify( heapManager );
    1459 
    14601457          if ( unlikely( addr == 0p ) ) {                                       // special case
    14611458                        #ifdef __STATISTICS__
  • libcfa/src/interpose.cfa

    r34b4268 r24d6572  
    1010// Created On       : Wed Mar 29 16:10:31 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 13 17:35:37 2020
    13 // Update Count     : 178
    14 //
    15 
    16 #include <stdarg.h>                                                                             // va_start, va_end
     12// Last Modified On : Mon Mar 27 21:09:03 2023
     13// Update Count     : 196
     14//
     15
    1716#include <stdio.h>
    18 #include <string.h>                                                                             // strlen
    1917#include <unistd.h>                                                                             // _exit, getpid
    20 #define __USE_GNU
    21 #include <signal.h>
    22 #undef __USE_GNU
    2318extern "C" {
    2419#include <dlfcn.h>                                                                              // dlopen, dlsym
     
    2621}
    2722
    28 #include "bits/debug.hfa"
    2923#include "bits/defs.hfa"
    3024#include "bits/signal.hfa"                                                              // sigHandler_?
     
    4236
    4337typedef void (* generic_fptr_t)(void);
     38
    4439static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) {
    45         const char * error;
    46 
    4740        union { generic_fptr_t fptr; void * ptr; } originalFunc;
    4841
    4942        #if defined( _GNU_SOURCE )
    50                 if ( version ) {
    51                         originalFunc.ptr = dlvsym( library, symbol, version );
    52                 } else {
    53                         originalFunc.ptr = dlsym( library, symbol );
    54                 }
     43        if ( version ) {
     44                originalFunc.ptr = dlvsym( library, symbol, version );
     45        } else {
     46                originalFunc.ptr = dlsym( library, symbol );
     47        } // if
    5548        #else
    56                 originalFunc.ptr = dlsym( library, symbol );
     49        originalFunc.ptr = dlsym( library, symbol );
    5750        #endif // _GNU_SOURCE
    5851
    59         error = dlerror();
    60         if ( error ) abort( "interpose_symbol : internal error, %s\n", error );
    61 
     52        if ( ! originalFunc.ptr ) {                                                     // == nullptr
     53                abort( "interpose_symbol : internal error, %s\n", dlerror() );
     54        } // if
    6255        return originalFunc.fptr;
    6356}
    6457
    6558static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
    66         const char * error;
    67 
    68         static void * library;
    69         static void * pthread_library;
    70         if ( ! library ) {
    71                 #if defined( RTLD_NEXT )
    72                         library = RTLD_NEXT;
    73                 #else
    74                         // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
    75                         library = dlopen( "libc.so.6", RTLD_LAZY );
    76                         error = dlerror();
    77                         if ( error ) {
    78                                 abort( "interpose_symbol : failed to open libc, %s\n", error );
    79                         }
    80                 #endif
     59        void * library;
     60
     61        #if defined( RTLD_NEXT )
     62        library = RTLD_NEXT;
     63        #else
     64        // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
     65        library = dlopen( "libc.so.6", RTLD_LAZY );
     66        if ( ! library ) {                                                                      // == nullptr
     67                abort( "interpose_symbol : failed to open libc, %s\n", dlerror() );
    8168        } // if
    82         if ( ! pthread_library ) {
    83                 #if defined( RTLD_NEXT )
    84                         pthread_library = RTLD_NEXT;
    85                 #else
    86                         // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
    87                         pthread_library = dlopen( "libpthread.so", RTLD_LAZY );
    88                         error = dlerror();
    89                         if ( error ) {
    90                                 abort( "interpose_symbol : failed to open libpthread, %s\n", error );
    91                         }
    92                 #endif
    93         } // if
    94 
    95         return do_interpose_symbol(library, symbol, version);
     69        #endif // RTLD_NEXT
     70
     71        return do_interpose_symbol( library, symbol, version );
    9672}
    9773
     
    12399                preload_libgcc();
    124100
    125 #pragma GCC diagnostic push
    126 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
     101                #pragma GCC diagnostic push
     102                #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
    127103                INTERPOSE_LIBC( abort, version );
    128104                INTERPOSE_LIBC( exit , version );
    129 #pragma GCC diagnostic pop
     105                #pragma GCC diagnostic pop
    130106
    131107                if(__cfathreadabi_interpose_startup) __cfathreadabi_interpose_startup( do_interpose_symbol );
     108
     109                // SKULLDUGGERY: In Ubuntu 22.04, someone augmented signal.h to allow SIGSTKSZ to be "sysconf(_SC_SIGSTKSZ)" in
     110                // sigstksz.h, as well as 8192 in sigstack.h. HOWEVER, they forgot to provide a mechanism to tell signal.h to
     111                // use sigstack.h rather than sigstksz.h. (I'm not happy.) By undefining _GNU_SOURCE before signal.h and
     112                // redefining it afterwards, you can get 8192, but then nothing works correctly inside of signal.h without
     113                // _GNU_SOURCE defined.  So what is needed is a way to get signal.h to use sigstack.h WITH _GNU_SOURCE defined.
     114                // Basically something is wrong with features.h and its use in signal.h.
     115
     116                #undef SIGSTKSZ
     117                #define SIGSTKSZ 8192
    132118
    133119                // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
     
    295281        va_start( args, fmt );
    296282        __abort( false, fmt, args );
    297     // CONTROL NEVER REACHES HERE!
     283        // CONTROL NEVER REACHES HERE!
    298284        va_end( args );
    299285}
    300286
    301287void abort( bool signalAbort, const char fmt[], ... ) {
    302     va_list args;
    303     va_start( args, fmt );
    304     __abort( signalAbort, fmt, args );
    305     // CONTROL NEVER REACHES HERE!
    306     va_end( args );
     288        va_list args;
     289        va_start( args, fmt );
     290        __abort( signalAbort, fmt, args );
     291        // CONTROL NEVER REACHES HERE!
     292        va_end( args );
    307293}
    308294
  • libcfa/src/interpose_thread.cfa

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

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

    r34b4268 r24d6572  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 10 10:02:07 2021
    13 // Update Count     : 407
     12// Last Modified On : Thu Feb  2 11:25:39 2023
     13// Update Count     : 410
    1414//
    1515
     
    2222
    2323
    24 trait basic_ostream( ostype & ) {
     24forall( ostype & )
     25trait basic_ostream {
    2526        // private
    2627        bool sepPrt$( ostype & );                                                       // get separator state (on/off)
     
    5152}; // basic_ostream
    5253       
    53 trait ostream( ostype & | basic_ostream( ostype ) ) {
     54forall( ostype & | basic_ostream( ostype ) )
     55trait ostream {
    5456        bool fail( ostype & );                                                          // operation failed?
    5557        void clear( ostype & );
     
    6062}; // ostream
    6163
    62 // trait writeable( T ) {
     64// forall( T )
     65// trait writeable {
    6366//      forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype &, T );
    6467// }; // writeable
    6568
    66 trait writeable( T, ostype & | ostream( ostype ) ) {
     69forall( T, ostype & | ostream( ostype ) )
     70        trait writeable {
    6771        ostype & ?|?( ostype &, T );
    6872}; // writeable
     
    290294
    291295
    292 trait basic_istream( istype & ) {
     296forall( istype & )
     297trait basic_istream {
    293298        // private
    294299        bool getANL$( istype & );                                                       // get scan newline (on/off)
     
    302307}; // basic_istream
    303308
    304 trait istream( istype & | basic_istream( istype ) ) {
     309forall( istype & | basic_istream( istype ) )
     310trait istream {
    305311        bool fail( istype & );
    306312        void clear( istype & );
     
    310316}; // istream
    311317
    312 trait readable( T ) {
     318forall( T )
     319trait readable {
    313320        forall( istype & | istream( istype ) ) istype & ?|?( istype &, T );
    314321}; // readable
  • libcfa/src/iterator.hfa

    r34b4268 r24d6572  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul  7 08:37:25 2017
    13 // Update Count     : 10
     12// Last Modified On : Thu Feb  2 11:21:50 2023
     13// Update Count     : 11
    1414//
    1515
     
    1717
    1818// An iterator can be used to traverse a data structure.
    19 trait iterator( iterator_type, elt_type ) {
     19forall( iterator_type, elt_type )
     20trait iterator {
    2021        // point to the next element
    2122//      iterator_type ?++( iterator_type & );
     
    3132};
    3233
    33 trait iterator_for( iterator_type, collection_type, elt_type | iterator( iterator_type, elt_type ) ) {
     34forall( iterator_type, collection_type, elt_type | iterator( iterator_type, elt_type ) )
     35        trait iterator_for {
    3436//      [ iterator_type begin, iterator_type end ] get_iterators( collection_type );
    3537        iterator_type begin( collection_type );
  • libcfa/src/limits.cfa

    r34b4268 r24d6572  
    1010// Created On       : Wed Apr  6 18:06:52 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar  1 16:22:51 2018
    13 // Update Count     : 74
     12// Last Modified On : Fri Feb 17 12:25:39 2023
     13// Update Count     : 87
    1414//
    1515
    1616#include <limits.h>
    1717#include <float.h>
    18 #define __USE_GNU                                                                               // get M_* constants
    1918#include <math.h>
    2019#include <complex.h>
  • libcfa/src/math.trait.hfa

    r34b4268 r24d6572  
    1010// Created On       : Fri Jul 16 15:40:52 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jul 20 17:47:19 2021
    13 // Update Count     : 19
     12// Last Modified On : Thu Feb  2 11:36:56 2023
     13// Update Count     : 20
    1414//
    1515
    1616#pragma once
    1717
    18 trait Not( U ) {
     18forall( U )
     19trait Not {
    1920        void ?{}( U &, zero_t );
    2021        int !?( U );
    2122}; // Not
    2223
    23 trait Equality( T | Not( T ) ) {
     24forall( T | Not( T ) )
     25trait Equality {
    2426        int ?==?( T, T );
    2527        int ?!=?( T, T );
    2628}; // Equality
    2729
    28 trait Relational( U | Equality( U ) ) {
     30forall( U | Equality( U ) )
     31trait Relational {
    2932        int ?<?( U, U );
    3033        int ?<=?( U, U );
     
    3336}; // Relational
    3437
    35 trait Signed( T ) {
     38forall ( T )
     39trait Signed {
    3640        T +?( T );
    3741        T -?( T );
     
    3943}; // Signed
    4044
    41 trait Additive( U | Signed( U ) ) {
     45forall( U | Signed( U ) )
     46trait Additive {
    4247        U ?+?( U, U );
    4348        U ?-?( U, U );
     
    4651}; // Additive
    4752
    48 trait Incdec( T | Additive( T ) ) {
     53forall( T | Additive( T ) )
     54trait Incdec {
    4955        void ?{}( T &, one_t );
    5056        // T ?++( T & );
     
    5460}; // Incdec
    5561
    56 trait Multiplicative( U | Incdec( U ) ) {
     62forall( U | Incdec( U ) )
     63trait Multiplicative {
    5764        U ?*?( U, U );
    5865        U ?/?( U, U );
     
    6168}; // Multiplicative
    6269
    63 trait Arithmetic( T | Relational( T ) | Multiplicative( T ) ) {
     70forall( T | Relational( T ) | Multiplicative( T ) )
     71trait Arithmetic {
    6472}; // Arithmetic
    6573
  • libcfa/src/stdlib.cfa

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

    r34b4268 r24d6572  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 11 18:25:53 2022
    13 // Update Count     : 765
     12// Last Modified On : Thu Feb  2 11:30:04 2023
     13// Update Count     : 766
    1414//
    1515
     
    367367
    368368        char random( void ) { return (unsigned long int)random(); }
    369         char random( char u ) { return random( (unsigned long int)u ); } // [0,u)
     369        char random( char u ) { return (unsigned long int)random( (unsigned long int)u ); } // [0,u)
    370370        char random( char l, char u ) { return random( (unsigned long int)l, (unsigned long int)u ); } // [l,u)
    371371        int random( void ) { return (long int)random(); }
    372         int random( int u ) { return random( (long int)u ); } // [0,u]
     372        int random( int u ) { return (long int)random( (long int)u ); } // [0,u]
    373373        int random( int l, int u ) { return random( (long int)l, (long int)u ); } // [l,u)
    374374        unsigned int random( void ) { return (unsigned long int)random(); }
    375         unsigned int random( unsigned int u ) { return random( (unsigned long int)u ); } // [0,u]
     375        unsigned int random( unsigned int u ) { return (unsigned long int)random( (unsigned long int)u ); } // [0,u]
    376376        unsigned int random( unsigned int l, unsigned int u ) { return random( (unsigned long int)l, (unsigned long int)u ); } // [l,u)
    377377} // distribution
     
    404404//   calls( sprng );
    405405
    406 trait basic_prng( PRNG &, R ) {
     406forall( PRNG &, R )
     407trait basic_prng {
    407408        void set_seed( PRNG & prng, R seed );                           // set seed
    408409        R get_seed( PRNG & prng );                                                      // get seed
  • libcfa/src/vec/vec.hfa

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

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

    r34b4268 r24d6572  
    559559                auto stmt = new SuspendStmt();
    560560                stmt->then   = get<CompoundStmt>().accept1( node->then   );
    561                 switch(node->type) {
     561                switch (node->kind) {
    562562                        case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
    563563                        case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
     
    565565                }
    566566                return stmtPostamble( stmt, node );
     567        }
     568
     569    const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
     570                // There is no old-AST WhenClause, so this should never be called.
     571                assert( !node );
     572                return nullptr;
    567573        }
    568574
     
    573579                for ( auto clause : node->clauses ) {
    574580                        stmt->clauses.push_back({{
    575                                         get<Expression>().accept1( clause->target_func ),
     581                                        get<Expression>().accept1( clause->target ),
    576582                                        get<Expression>().acceptL( clause->target_args ),
    577583                                },
    578584                                get<Statement>().accept1( clause->stmt ),
    579                                 get<Expression>().accept1( clause->cond ),
     585                                get<Expression>().accept1( clause->when_cond ),
    580586                        });
    581587                }
     
    594600        const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
    595601                // There is no old-AST WaitForClause, so this should never be called.
     602                assert( !node );
     603                return nullptr;
     604        }
     605
     606    const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
     607        // There is no old-AST WaitUntilStmt, so this should never be called.
    596608                assert( !node );
    597609                return nullptr;
     
    16831695                        GET_ACCEPT_V(attributes, Attribute),
    16841696                        { old->get_funcSpec().val },
    1685                         old->type->isVarArgs
     1697                        (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs
    16861698                };
    16871699
     
    19892001                        GET_ACCEPT_1(else_, Stmt),
    19902002                        GET_ACCEPT_V(initialization, Stmt),
    1991                         old->isDoWhile,
     2003                        (old->isDoWhile) ? ast::DoWhile : ast::While,
    19922004                        GET_LABELS_V(old->labels)
    19932005                );
     
    21312143        virtual void visit( const SuspendStmt * old ) override final {
    21322144                if ( inCache( old ) ) return;
    2133                 ast::SuspendStmt::Type type;
     2145                ast::SuspendStmt::Kind type;
    21342146                switch (old->type) {
    21352147                        case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
     
    21582170                        auto clause = new ast::WaitForClause( old->location );
    21592171
    2160                         clause->target_func = GET_ACCEPT_1(clauses[i].target.function, Expr);
     2172                        clause->target = GET_ACCEPT_1(clauses[i].target.function, Expr);
    21612173                        clause->target_args = GET_ACCEPT_V(clauses[i].target.arguments, Expr);
    21622174                        clause->stmt = GET_ACCEPT_1(clauses[i].statement, Stmt);
    2163                         clause->cond = GET_ACCEPT_1(clauses[i].condition, Expr);
     2175                        clause->when_cond = GET_ACCEPT_1(clauses[i].condition, Expr);
    21642176
    21652177                        stmt->clauses.push_back( clause );
  • src/AST/Create.cpp

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

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

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

    r34b4268 r24d6572  
    3030#include "Common/SemanticError.h"
    3131#include "GenPoly/Lvalue.h"        // for referencesPermissable
    32 #include "ResolvExpr/typeops.h"    // for extractResultType
     32#include "ResolvExpr/Unify.h"      // for extractResultType
    3333#include "Tuples/Tuples.h"         // for makeTupleType
    3434
  • src/AST/Expr.hpp

    r34b4268 r24d6572  
    256256};
    257257
     258/// A name qualified by a namespace or type.
    258259class QualifiedNameExpr final : public Expr {
    259260public:
     
    261262        std::string name;
    262263
    263         QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 
     264        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
    264265        : Expr( loc ), type_decl( d ), name( n ) {}
    265266
     
    631632};
    632633
     634/// A name that refers to a generic dimension parameter.
    633635class DimensionExpr final : public Expr {
    634636public:
     
    920922};
    921923
    922 
    923924}
    924925
  • src/AST/Fwd.hpp

    r34b4268 r24d6572  
    1515
    1616#pragma once
     17
     18template<typename> struct bitfield;
    1719
    1820#include "AST/Node.hpp"
     
    5658class FinallyClause;
    5759class SuspendStmt;
     60class WhenClause;
    5861class WaitForStmt;
    5962class WaitForClause;
     63class WaitUntilStmt;
    6064class WithStmt;
    6165class DeclStmt;
     
    147151class TranslationGlobal;
    148152
     153// For the following types, only use the using type.
     154namespace CV {
     155        struct qualifier_flags;
     156        using Qualifiers = bitfield<qualifier_flags>;
    149157}
     158namespace Function {
     159        struct spec_flags;
     160        using Specs = bitfield<spec_flags>;
     161}
     162namespace Storage {
     163        struct class_flags;
     164        using Classes = bitfield<class_flags>;
     165}
     166namespace Linkage {
     167        struct spec_flags;
     168        using Spec = bitfield<spec_flags>;
     169}
     170
     171}
  • src/AST/Init.hpp

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

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

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

    r34b4268 r24d6572  
    174174template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::weak >;
    175175template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::strong >;
     176template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::weak >;
     177template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::strong >;
    176178template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::weak >;
    177179template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::strong >;
    178180template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::weak >;
    179181template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::strong >;
     182template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::weak >;
     183template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::strong >;
    180184template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::weak >;
    181185template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::strong >;
  • src/AST/Node.hpp

    r34b4268 r24d6572  
    1919#include <cstddef>     // for nullptr_t
    2020#include <iosfwd>
    21 #include <type_traits> // for remove_reference
    2221
    2322#include "Common/ErrorObjects.h"  // for SemanticErrorException
     
    3635        Node(const Node&) : strong_count(0), weak_count(0) {}
    3736        Node(Node&&) : strong_count(0), weak_count(0) {}
    38         Node& operator= (const Node&) = delete;
    39         Node& operator= (Node&&) = delete;
     37        Node& operator=(const Node&) = delete;
     38        Node& operator=(Node&&) = delete;
    4039        virtual ~Node() {}
    4140
  • src/AST/ParseNode.hpp

    r34b4268 r24d6572  
    4040        template<typename node_t>
    4141        friend node_t * mutate(const node_t * node);
     42        template<typename node_t>
     43        friend node_t * shallowCopy(const node_t * node);
    4244};
    4345
  • src/AST/Pass.hpp

    r34b4268 r24d6572  
    6666//
    6767// Other Special Members:
     68// | beginScope            - A method with no parameters or return value, called each time the
     69//                           visitor enters a block.
     70// | endScope              - A method with no parameters or return value, called each time the
     71//                           visitor leaves a block.
    6872// | result                - Either a method that takes no parameters or a field. If a method (or
    6973//                           callable field) get_result calls it, otherwise the value is returned.
     
    8286        {
    8387                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    84                 type * const * visitor = __pass::visitor(core, 0);
    85                 if(visitor) {
     88                type * const * visitor = __pass::visitor( core, 0 );
     89                if ( visitor ) {
    8690                        *const_cast<type **>( visitor ) = this;
    8791                }
     
    9498
    9599        /// If the core defines a result, call it if possible, otherwise return it.
    96         inline auto get_result() -> decltype( __pass::get_result( core, '0' ) ) {
    97                 return __pass::get_result( core, '0' );
     100        inline auto get_result() -> decltype( __pass::result::get( core, '0' ) ) {
     101                return __pass::result::get( core, '0' );
    98102        }
    99103
     
    158162        const ast::FinallyClause *    visit( const ast::FinallyClause        * ) override final;
    159163        const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
     164    const ast::WhenClause *       visit( const ast::WhenClause           * ) override final;
    160165        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    161166        const ast::WaitForClause *    visit( const ast::WaitForClause        * ) override final;
     167    const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) override final;
    162168        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
    163169        const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    r34b4268 r24d6572  
    2020#include <unordered_map>
    2121
     22#include "AST/Copy.hpp"
    2223#include "AST/TranslationUnit.hpp"
    2324#include "AST/TypeSubstitution.hpp"
     
    4546
    4647#ifdef PEDANTIC_PASS_ASSERT
    47 #define __pedantic_pass_assert(...) assert (__VA_ARGS__)
     48#define __pedantic_pass_assert(...) assert(__VA_ARGS__)
    4849#define __pedantic_pass_assertf(...) assertf(__VA_ARGS__)
    4950#else
     
    124125                        return !new_val.empty();
    125126                }
    126         }
    127 
    128         template< typename node_t >
    129         template< typename object_t, typename super_t, typename field_t >
    130         void __pass::result1< node_t >::apply( object_t * object, field_t super_t::* field ) {
    131                 object->*field = value;
    132127        }
    133128
     
    233228
    234229                return {true, compound};
    235         }
    236 
    237         template< template <class...> class container_t >
    238         template< typename object_t, typename super_t, typename field_t >
    239         void __pass::resultNstmt<container_t>::apply(object_t * object, field_t super_t::* field) {
    240                 auto & container = object->*field;
    241                 __pedantic_pass_assert( container.size() <= values.size() );
    242 
    243                 auto cit = enumerate(container).begin();
    244 
    245                 container_t<ptr<Stmt>> nvals;
    246                 for (delta & d : values) {
    247                         if ( d.is_old ) {
    248                                 __pedantic_pass_assert( cit.idx <= d.old_idx );
    249                                 std::advance( cit, d.old_idx - cit.idx );
    250                                 nvals.push_back( std::move( (*cit).val) );
    251                         } else {
    252                                 nvals.push_back( std::move(d.new_val) );
    253                         }
    254                 }
    255 
    256                 container = std::move(nvals);
    257         }
    258 
    259         template< template <class...> class container_t >
    260         template< template <class...> class incontainer_t >
    261         void __pass::resultNstmt< container_t >::take_all( incontainer_t<ptr<Stmt>> * stmts ) {
    262                 if (!stmts || stmts->empty()) return;
    263 
    264                 std::transform(stmts->begin(), stmts->end(), std::back_inserter( values ),
    265                         [](ast::ptr<ast::Stmt>& stmt) -> delta {
    266                                 return delta( stmt.release(), -1, false );
    267                         });
    268                 stmts->clear();
    269                 differs = true;
    270         }
    271 
    272         template< template<class...> class container_t >
    273         template< template<class...> class incontainer_t >
    274         void __pass::resultNstmt< container_t >::take_all( incontainer_t<ptr<Decl>> * decls ) {
    275                 if (!decls || decls->empty()) return;
    276 
    277                 std::transform(decls->begin(), decls->end(), std::back_inserter( values ),
    278                         [](ast::ptr<ast::Decl>& decl) -> delta {
    279                                 auto loc = decl->location;
    280                                 auto stmt = new DeclStmt( loc, decl.release() );
    281                                 return delta( stmt, -1, false );
    282                         });
    283                 decls->clear();
    284                 differs = true;
    285230        }
    286231
     
    352297
    353298                return new_kids;
    354         }
    355 
    356         template< template <class...> class container_t, typename node_t >
    357         template< typename object_t, typename super_t, typename field_t >
    358         void __pass::resultN<container_t, node_t>::apply(object_t * object, field_t super_t::* field) {
    359                 auto & container = object->*field;
    360                 __pedantic_pass_assert( container.size() == values.size() );
    361 
    362                 for(size_t i = 0; i < container.size(); i++) {
    363                         // Take all the elements that are different in 'values'
    364                         // and swap them into 'container'
    365                         if( values[i] != nullptr ) swap(container[i], values[i]);
    366                 }
    367 
    368                 // Now the original containers should still have the unchanged values
    369                 // but also contain the new values
    370299        }
    371300
     
    836765                        if ( enterScope ) {
    837766                                __pass::symtab::enter(core, 0);
    838                                 __pass::scope::enter(core, 0);
    839767                        }
    840768                }, [this, leaveScope = !this->atFunctionTop]() {
    841769                        if ( leaveScope ) {
    842770                                __pass::symtab::leave(core, 0);
    843                                 __pass::scope::leave(core, 0);
    844771                        }
    845772                });
     
    1067994
    1068995//--------------------------------------------------------------------------
     996// WhenClause
     997template< typename core_t >
     998const ast::WhenClause * ast::Pass< core_t >::visit( const ast::WhenClause * node ) {
     999        VISIT_START( node );
     1000
     1001        if ( __visit_children() ) {
     1002                maybe_accept( node, &WhenClause::target );
     1003                maybe_accept( node, &WhenClause::stmt );
     1004                maybe_accept( node, &WhenClause::when_cond );
     1005        }
     1006
     1007        VISIT_END( WhenClause, node );
     1008}
     1009
     1010//--------------------------------------------------------------------------
    10691011// WaitForStmt
    10701012template< typename core_t >
     
    10911033
    10921034        if ( __visit_children() ) {
    1093                 maybe_accept( node, &WaitForClause::target_func );
     1035                maybe_accept( node, &WaitForClause::target );
    10941036                maybe_accept( node, &WaitForClause::target_args );
    10951037                maybe_accept( node, &WaitForClause::stmt );
    1096                 maybe_accept( node, &WaitForClause::cond );
     1038                maybe_accept( node, &WaitForClause::when_cond );
    10971039        }
    10981040
    10991041        VISIT_END( WaitForClause, node );
     1042}
     1043
     1044//--------------------------------------------------------------------------
     1045// WaitUntilStmt
     1046template< typename core_t >
     1047const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitUntilStmt * node ) {
     1048        VISIT_START( node );
     1049
     1050        if ( __visit_children() ) {
     1051                maybe_accept( node, &WaitUntilStmt::clauses );
     1052                maybe_accept( node, &WaitUntilStmt::timeout_time );
     1053                maybe_accept( node, &WaitUntilStmt::timeout_stmt );
     1054                maybe_accept( node, &WaitUntilStmt::timeout_cond );
     1055                maybe_accept( node, &WaitUntilStmt::else_stmt );
     1056                maybe_accept( node, &WaitUntilStmt::else_cond );
     1057        }
     1058
     1059        VISIT_END( Stmt, node );
    11001060}
    11011061
     
    20432003        if ( __visit_children() ) {
    20442004                maybe_accept( node, &TupleType::types );
    2045                 maybe_accept( node, &TupleType::members );
    20462005        }
    20472006
     
    22052164}
    22062165
     2166#undef __pedantic_pass_assertf
     2167#undef __pedantic_pass_assert
    22072168#undef VISIT_START
    22082169#undef VISIT_END
  • src/AST/Pass.proto.hpp

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

    r34b4268 r24d6572  
    1616#include "Print.hpp"
    1717
     18#include "Attribute.hpp"
    1819#include "Decl.hpp"
    1920#include "Expr.hpp"
     21#include "Init.hpp"
    2022#include "Stmt.hpp"
    2123#include "Type.hpp"
    2224#include "TypeSubstitution.hpp"
    2325#include "CompilationState.h"
    24 
    25 #include "Common/utility.h" // for group_iterate
     26#include "Common/Iterate.hpp"
    2627
    2728using namespace std;
     
    2930namespace ast {
    3031
    31 template <typename C, typename... T>
    32 constexpr array<C,sizeof...(T)> make_array(T&&... values)
    33 {
    34         return array<C,sizeof...(T)>{
    35                 std::forward<T>(values)...
    36         };
     32namespace {
     33
     34template<typename C, typename... T>
     35constexpr array<C, sizeof...(T)> make_array( T&&... values ) {
     36        return array<C, sizeof...(T)>{ std::forward<T>( values )... };
     37}
     38
     39namespace Names {
     40        static constexpr auto FuncSpecifiers = make_array<const char*>(
     41                "inline", "_Noreturn", "fortran"
     42        );
     43
     44        static constexpr auto StorageClasses = make_array<const char*>(
     45                "extern", "static", "auto", "register", "__thread", "_Thread_local"
     46        );
     47
     48        static constexpr auto Qualifiers = make_array<const char*>(
     49                "const", "restrict", "volatile", "mutex", "_Atomic"
     50        );
     51}
     52
     53template<typename bits_t, size_t N>
     54void print( ostream & os, const bits_t & bits,
     55                const array<const char *, N> & names ) {
     56        if ( !bits.any() ) return;
     57        for ( size_t i = 0 ; i < N ; i += 1 ) {
     58                if ( bits[i] ) {
     59                        os << names[i] << ' ';
     60                }
     61        }
    3762}
    3863
     
    80105        static const char* Names[];
    81106
    82         struct Names {
    83                 static constexpr auto FuncSpecifiers = make_array<const char*>(
    84                         "inline", "_Noreturn", "fortran"
    85                 );
    86 
    87                 static constexpr auto StorageClasses = make_array<const char*>(
    88                         "extern", "static", "auto", "register", "__thread", "_Thread_local"
    89                 );
    90 
    91                 static constexpr auto Qualifiers = make_array<const char*>(
    92                         "const", "restrict", "volatile", "mutex", "_Atomic"
    93                 );
    94         };
    95 
    96         template<typename storage_t, size_t N>
    97         void print(const storage_t & storage, const array<const char *, N> & Names ) {
    98                 if ( storage.any() ) {
    99                         for ( size_t i = 0; i < Names.size(); i += 1 ) {
    100                                 if ( storage[i] ) {
    101                                         os << Names[i] << ' ';
    102                                 }
    103                         }
    104                 }
    105         }
    106 
    107         void print( const ast::Function::Specs & specs ) {
    108                 print(specs, Names::FuncSpecifiers);
    109         }
    110 
    111         void print( const ast::Storage::Classes & storage ) {
    112                 print(storage, Names::StorageClasses);
    113         }
    114 
    115         void print( const ast::CV::Qualifiers & qualifiers ) {
    116                 print(qualifiers, Names::Qualifiers);
    117         }
    118 
    119107        void print( const std::vector<ast::Label> & labels ) {
    120108                if ( labels.empty() ) return;
     
    221209        }
    222210
     211    void print( const ast::WaitStmt * node ) {
     212                if ( node->timeout_time ) {
     213                        os << indent-1 << "timeout of:" << endl;
     214                        node->timeout_time->accept( *this );
     215
     216                        if ( node->timeout_stmt ) {
     217                                os << indent-1 << "... with statment:" << endl;
     218                                node->timeout_stmt->accept( *this );
     219                        }
     220
     221                        if ( node->timeout_cond ) {
     222                                os << indent-1 << "... with condition:" << endl;
     223                                node->timeout_cond->accept( *this );
     224                        }
     225                }
     226
     227                if ( node->else_stmt ) {
     228                        os << indent-1 << "else:" << endl;
     229                        node->else_stmt->accept( *this );
     230
     231                        if ( node->else_cond ) {
     232                                os << indent-1 << "... with condition:" << endl;
     233                                node->else_cond->accept( *this );
     234                        }
     235                }
     236        }
     237
    223238        void preprint( const ast::NamedTypeDecl * node ) {
    224239                if ( ! node->name.empty() ) {
     
    230245                }
    231246
    232                 print( node->storage );
     247                ast::print( os, node->storage );
    233248                os << node->typeString();
    234249
     
    272287
    273288        void preprint( const ast::Type * node ) {
    274                 print( node->qualifiers );
     289                ast::print( os, node->qualifiers );
    275290        }
    276291
     
    278293                print( node->forall );
    279294                print( node->assertions );
    280                 print( node->qualifiers );
     295                ast::print( os, node->qualifiers );
    281296        }
    282297
    283298        void preprint( const ast::BaseInstType * node ) {
    284299                print( node->attributes );
    285                 print( node->qualifiers );
     300                ast::print( os, node->qualifiers );
    286301        }
    287302
     
    294309                }
    295310
    296                 print( node->storage );
     311                ast::print( os, node->storage );
    297312
    298313                if ( node->type ) {
     
    338353                if ( ! short_mode ) printAll( node->attributes );
    339354
    340                 print( node->storage );
    341                 print( node->funcSpec );
    342 
    343 
     355                ast::print( os, node->storage );
     356                ast::print( os, node->funcSpec );
    344357
    345358                if ( node->type && node->isTypeFixed ) {
     
    384397                                --indent;
    385398                        }
     399                }
     400
     401                if ( ! node->withExprs.empty() ) {
     402                        // Not with a clause, but the 'with clause'.
     403                        ++indent;
     404                        os << " with clause" << endl << indent;
     405                        printAll( node->withExprs );
     406                        --indent;
    386407                }
    387408
     
    746767        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    747768                os << "Suspend Statement";
    748                 switch (node->type) {
    749                         case ast::SuspendStmt::None     : os << " with implicit target"; break;
    750                         case ast::SuspendStmt::Generator: os << " for generator"; break;
    751                         case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
     769                switch (node->kind) {
     770                case ast::SuspendStmt::None     : os << " with implicit target"; break;
     771                case ast::SuspendStmt::Generator: os << " for generator"; break;
     772                case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
    752773                }
    753774                os << endl;
     
    759780                }
    760781                ++indent;
     782
     783                return node;
     784        }
     785
     786        virtual const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
     787                os << indent-1 << "target: ";
     788                safe_print( node->target );
     789
     790                if ( node->stmt ) {
     791                        os << indent-1 << "... with statment:" << endl;
     792                        node->stmt->accept( *this );
     793                }
     794
     795                if ( node->when_cond ) {
     796                        os << indent-1 << "... with when condition:" << endl;
     797                        node->when_cond->accept( *this );
     798                }
    761799
    762800                return node;
     
    800838        virtual const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
    801839                os << indent-1 << "target function: ";
    802                 safe_print( node->target_func );
     840                safe_print( node->target );
    803841
    804842                if ( !node->target_args.empty() ) {
     
    814852                }
    815853
    816                 if ( node->cond ) {
     854                if ( node->when_cond ) {
    817855                        os << indent-1 << "... with condition:" << endl;
    818                         node->cond->accept( *this );
    819                 }
    820 
     856                        node->when_cond->accept( *this );
     857                }
     858
     859                return node;
     860        }
     861
     862    virtual const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
     863                os << "Waituntil Statement" << endl;
     864                indent += 2;
     865                for( const auto & clause : node->clauses ) {
     866                        clause->accept( *this );
     867                }
     868        print(node);    // calls print( const ast::WaitStmt * node )
    821869                return node;
    822870        }
     
    16271675};
    16281676
     1677} // namespace
     1678
    16291679void print( ostream & os, const ast::Node * node, Indenter indent ) {
    16301680        Printer printer { os, indent, false };
     
    16371687}
    16381688
    1639 // Annoyingly these needed to be defined out of line to avoid undefined references.
    1640 // The size here needs to be explicit but at least the compiler will produce an error
    1641 // if the wrong size is specified
    1642 constexpr array<const char*, 3> Printer::Names::FuncSpecifiers;
    1643 constexpr array<const char*, 6> Printer::Names::StorageClasses;
    1644 constexpr array<const char*, 5> Printer::Names::Qualifiers;
     1689void print( ostream & os, Function::Specs specs ) {
     1690        print( os, specs, Names::FuncSpecifiers );
    16451691}
     1692
     1693void print( ostream & os, Storage::Classes storage ) {
     1694        print( os, storage, Names::StorageClasses );
     1695}
     1696
     1697void print( ostream & os, CV::Qualifiers qualifiers ) {
     1698        print( os, qualifiers, Names::Qualifiers );
     1699}
     1700
     1701} // namespace ast
  • src/AST/Print.hpp

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

    r34b4268 r24d6572  
    1010// Created On       : Wed May  8 13:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 20 14:34:00 2022
    13 // Update Count     : 36
     12// Last Modified On : Wed Apr  5 10:34:00 2023
     13// Update Count     : 37
    1414//
    1515
     
    205205};
    206206
     207// A while loop or a do-while loop:
     208enum WhileDoKind { While, DoWhile };
     209
    207210// While loop: while (...) ... else ... or do ... while (...) else ...;
    208211class WhileDoStmt final : public Stmt {
     
    212215        ptr<Stmt> else_;
    213216        std::vector<ptr<Stmt>> inits;
    214         bool isDoWhile;
     217        WhileDoKind isDoWhile;
    215218
    216219        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
    217                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     220                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    218221                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    219222
    220223        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_,
    221                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     224                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    222225                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    223226
     
    364367  public:
    365368        ptr<CompoundStmt> then;
    366         enum Type { None, Coroutine, Generator } type = None;
    367 
    368         SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, const std::vector<Label> && labels = {} )
    369                 : Stmt(loc, std::move(labels)), then(then), type(type) {}
     369        enum Kind { None, Coroutine, Generator } kind = None;
     370
     371        SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Kind kind, const std::vector<Label> && labels = {} )
     372                : Stmt(loc, std::move(labels)), then(then), kind(kind) {}
    370373
    371374        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    375378};
    376379
    377 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
    378 class WaitForStmt final : public Stmt {
    379   public:
    380         std::vector<ptr<WaitForClause>> clauses;
    381         ptr<Expr> timeout_time;
     380// Base class of WaitFor/WaitUntil statements
     381// form: KEYWORD(...) ... timeout(...) ... else ...
     382class WaitStmt : public Stmt {
     383  public:
     384    ptr<Expr> timeout_time;
    382385        ptr<Stmt> timeout_stmt;
    383386        ptr<Expr> timeout_cond;
     
    385388        ptr<Expr> else_cond;
    386389
     390    WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
     391                : Stmt(loc, std::move(labels)) {}
     392
     393  private:
     394    WaitStmt * clone() const override = 0;
     395        MUTATE_FRIEND
     396};
     397
     398// Base class for WaitFor/WaitUntil clauses
     399// form: when( when_cond ) KEYWORD( target ) stmt
     400class WhenClause : public StmtClause {
     401  public:
     402        ptr<Expr> target;
     403        ptr<Stmt> stmt;
     404        ptr<Expr> when_cond;
     405
     406        WhenClause( const CodeLocation & loc )
     407                : StmtClause( loc ) {}
     408
     409        const WhenClause * accept( Visitor & v ) const override { return v.visit( this ); }
     410  private:
     411        WhenClause * clone() const override { return new WhenClause{ *this }; }
     412        MUTATE_FRIEND
     413};
     414
     415// Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
     416class WaitForStmt final : public WaitStmt {
     417  public:
     418        std::vector<ptr<WaitForClause>> clauses;
     419
    387420        WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    388                 : Stmt(loc, std::move(labels)) {}
     421                : WaitStmt(loc, std::move(labels)) {}
    389422
    390423        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    394427};
    395428
    396 class WaitForClause final : public StmtClause {
    397   public:
    398         ptr<Expr> target_func;
     429// Clause in a waitfor statement: waitfor (..., ...) ...
     430class WaitForClause final : public WhenClause {
     431  public:
    399432        std::vector<ptr<Expr>> target_args;
    400         ptr<Stmt> stmt;
    401         ptr<Expr> cond;
    402433
    403434        WaitForClause( const CodeLocation & loc )
    404                 : StmtClause( loc ) {}
     435                : WhenClause( loc ) {}
    405436
    406437        const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); }
    407438  private:
    408439        WaitForClause * clone() const override { return new WaitForClause{ *this }; }
     440        MUTATE_FRIEND
     441};
     442
     443// waituntil statement: when (...) waituntil (...) ... timeout(...) ... else ...
     444class WaitUntilStmt final : public WaitStmt {
     445  public:
     446    // Non-ast node used during compilation to store data needed to generate predicates
     447    //    and set initial status values for clauses
     448    // Used to create a tree corresponding to the structure of the clauses in a WaitUntil
     449    struct ClauseNode {
     450        enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag
     451        // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing
     452
     453        ClauseNode * left;
     454        ClauseNode * right;
     455        WhenClause * leaf;  // only set if this node is a leaf (points into vector of clauses)
     456
     457        bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses
     458        bool whenState;     // used to track if when_cond is toggled on or off for generating init values
     459        bool childOfAnd;      // true on leaf nodes that are children of AND, false otherwise
     460
     461        ClauseNode( Op op, ClauseNode * left, ClauseNode * right )
     462            : op(op), left(left), right(right), leaf(nullptr),
     463            ambiguousWhen(false), whenState(true), childOfAnd(false) {}
     464        ClauseNode( Op op, WhenClause * leaf )
     465            : op(op), left(nullptr), right(nullptr), leaf(leaf),
     466            ambiguousWhen(false), whenState(true), childOfAnd(false) {}
     467        ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}
     468       
     469        ~ClauseNode() {
     470            if ( left ) delete left;
     471            if ( right ) delete right;
     472        }
     473    };
     474
     475        std::vector<ptr<WhenClause>> clauses;
     476    ClauseNode * predicateTree;
     477
     478        WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
     479                : WaitStmt(loc, std::move(labels)) {}
     480
     481    ~WaitUntilStmt() { delete predicateTree; }
     482
     483        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     484  private:
     485        WaitUntilStmt * clone() const override { return new WaitUntilStmt{ *this }; }
    409486        MUTATE_FRIEND
    410487};
     
    454531        MUTATE_FRIEND
    455532};
     533
    456534} // namespace ast
    457535
  • src/AST/SymbolTable.cpp

    r34b4268 r24d6572  
    1818#include <cassert>
    1919
     20#include "Copy.hpp"
     21#include <iostream>
     22#include <algorithm>
     23
    2024#include "Decl.hpp"
    2125#include "Expr.hpp"
    2226#include "Inspect.hpp"
    2327#include "Type.hpp"
    24 #include "CodeGen/OperatorTable.h"  // for isCtorDtorAssign
     28#include "CodeGen/OperatorTable.h"         // for isCtorDtorAssign
    2529#include "Common/SemanticError.h"
    2630#include "Common/Stats/Counter.h"
     
    2832#include "InitTweak/InitTweak.h"
    2933#include "ResolvExpr/Cost.h"
    30 #include "ResolvExpr/typeops.h"
     34#include "ResolvExpr/CandidateFinder.hpp"  // for referenceToRvalueConversion
     35#include "ResolvExpr/Unify.h"
    3136#include "SymTab/Mangler.h"
    3237
     
    6974        if ( baseExpr ) {
    7075                if (baseExpr->env) {
    71                         Expr * base = shallowCopy(baseExpr);
     76                        Expr * base = deepCopy(baseExpr);
    7277                        const TypeSubstitution * subs = baseExpr->env;
    7378                        base->env = nullptr;
     
    193198                        out.push_back(decl.second);
    194199                }
     200
     201                // std::cerr << otypeKey << ' ' << out.size() << std::endl;
    195202        }
    196203
     
    259266void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) {
    260267        // default handling of conflicts is to raise an error
    261         addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     268        addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    262269}
    263270
    264271void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) {
    265272        // default handling of conflicts is to raise an error
    266         addId( decl, OnConflict::error(), nullptr, deleter );
     273        addIdCommon( decl, OnConflict::error(), nullptr, deleter );
    267274}
    268275
     
    276283                } else {
    277284                        // typedef redeclarations are errors only if types are different
    278                         if ( ! ResolvExpr::typesCompatible( existing->base, added->base, SymbolTable{} ) ) {
     285                        if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) {
    279286                                SemanticError( added->location, "redeclaration of " + added->name );
    280287                        }
     
    641648        } else if ( existing.id->linkage.is_mangled
    642649                        || ResolvExpr::typesCompatible(
    643                                 added->get_type(), existing.id->get_type(), SymbolTable{} ) ) {
     650                                added->get_type(), existing.id->get_type() ) ) {
    644651
    645652                // it is a conflict if one declaration is deleted and the other is not
     
    676683}
    677684
    678 void SymbolTable::addId(
    679                 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    680                 const Decl * deleter ) {
     685void SymbolTable::addIdCommon(
     686                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
     687                const Expr * baseExpr, const Decl * deleter ) {
    681688        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    682689        if (kind == NUMBER_OF_KINDS) { // not a special decl
    683                 addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
     690                addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
    684691        }
    685692        else {
     
    694701                        assertf(false, "special decl with non-function type");
    695702                }
    696                 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
    697         }
    698 }
    699 
    700 void SymbolTable::addId(
    701                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    702                 const Decl * deleter ) {
     703                addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
     704        }
     705}
     706
     707void SymbolTable::addIdToTable(
     708                const DeclWithType * decl, const std::string & lookupKey,
     709                IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
     710                const Expr * baseExpr, const Decl * deleter ) {
    703711        ++*stats().add_calls;
    704712        const std::string &name = decl->name;
     
    777785void SymbolTable::addMembers(
    778786                const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) {
    779         for ( const Decl * decl : aggr->members ) {
    780                 if ( auto dwt = dynamic_cast< const DeclWithType * >( decl ) ) {
    781                         addId( dwt, handleConflicts, expr );
    782                         if ( dwt->name == "" ) {
    783                                 const Type * t = dwt->get_type()->stripReferences();
    784                                 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
    785                                         if ( ! dynamic_cast<const StructInstType *>(rty)
    786                                                 && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
    787                                         ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
    788                                         ast::ptr<ast::TypeSubstitution> tmp = expr->env;
    789                                         expr = mutate_field(expr, &Expr::env, nullptr);
    790                                         const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
    791                                         base = mutate_field(base, &Expr::env, tmp);
    792 
    793                                         addMembers(
    794                                                 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
    795                                 }
    796                         }
     787        for ( const ptr<Decl> & decl : aggr->members ) {
     788                auto dwt = decl.as<DeclWithType>();
     789                if ( nullptr == dwt ) continue;
     790                addIdCommon( dwt, handleConflicts, expr );
     791                // Inline through unnamed struct/union members.
     792                if ( "" != dwt->name ) continue;
     793                const Type * t = dwt->get_type()->stripReferences();
     794                if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
     795                        if ( ! dynamic_cast<const StructInstType *>(rty)
     796                                && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
     797                        ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
     798                        ast::ptr<ast::TypeSubstitution> tmp = expr->env;
     799                        expr = mutate_field(expr, &Expr::env, nullptr);
     800                        const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
     801                        base = mutate_field(base, &Expr::env, tmp);
     802
     803                        addMembers(
     804                                rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
    797805                }
    798806        }
  • src/AST/SymbolTable.hpp

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

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

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

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

    r34b4268 r24d6572  
    178178
    179179bool TypeEnvironment::combine(
    180                 const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
     180                const TypeEnvironment & o, OpenVarSet & open ) {
    181181        // short-circuit easy cases
    182182        if ( o.empty() ) return true;
     
    201201                        EqvClass & r = *rt;
    202202                        // merge bindings
    203                         if ( ! mergeBound( r, c, open, symtab ) ) return false;
     203                        if ( ! mergeBound( r, c, open ) ) return false;
    204204                        // merge previous unbound variables into this class, checking occurs if needed
    205205                        if ( r.bound ) for ( const auto & u : c.vars ) {
     
    216216                                } else if ( st != rt ) {
    217217                                        // bound, but not to the same class
    218                                         if ( ! mergeClasses( rt, st, open, symtab ) ) return false;
     218                                        if ( ! mergeClasses( rt, st, open ) ) return false;
    219219                                }       // ignore bound into the same class
    220220                        }
     
    280280bool TypeEnvironment::bindVar(
    281281                const TypeInstType * typeInst, const Type * bindTo, const TypeData & data,
    282                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
    283                 const SymbolTable & symtab
     282                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen
    284283) {
    285284        // remove references from bound type, so that type variables can only bind to value types
     
    300299                        if ( unifyInexact(
    301300                                        newType, target, *this, need, have, open,
    302                                         widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
     301                                        widen & WidenMode{ it->allowWidening, true }, common ) ) {
    303302                                if ( common ) {
    304303                                        it->bound = std::move(common);
     
    321320                const TypeInstType * var1, const TypeInstType * var2, TypeData && data,
    322321                AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
    323                 WidenMode widen, const SymbolTable & symtab
     322                WidenMode widen
    324323) {
    325324        auto c1 = internal_lookup( *var1 );
     
    358357
    359358                if ( unifyInexact(
    360                                 newType1, newType2, *this, need, have, open, newWidenMode, symtab, common ) ) {
     359                                newType1, newType2, *this, need, have, open, newWidenMode, common ) ) {
    361360                        c1->vars.insert( c2->vars.begin(), c2->vars.end() );
    362361                        c1->allowWidening = widen1 && widen2;
     
    409408
    410409bool TypeEnvironment::mergeBound(
    411                 EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
     410                EqvClass & to, const EqvClass & from, OpenVarSet & open ) {
    412411        if ( from.bound ) {
    413412                if ( to.bound ) {
     
    419418
    420419                        if ( unifyInexact(
    421                                         toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
     420                                        toType, fromType, *this, need, have, open, widen, common ) ) {
    422421                                // unifies, set common type if necessary
    423422                                if ( common ) {
     
    437436
    438437bool TypeEnvironment::mergeClasses(
    439         ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
     438        ClassList::iterator to, ClassList::iterator from, OpenVarSet & open
    440439) {
    441440        EqvClass & r = *to, & s = *from;
    442441
    443442        // ensure bounds match
    444         if ( ! mergeBound( r, s, open, symtab ) ) return false;
     443        if ( ! mergeBound( r, s, open ) ) return false;
    445444
    446445        // check safely bindable
  • src/AST/TypeEnvironment.hpp

    r34b4268 r24d6572  
    6363
    6464                int cmp = d1->var->name.compare( d2->var->name );
    65                 return cmp < 0 || ( cmp == 0 && d1->result < d2->result );
     65                return cmp > 0 || ( cmp == 0 && d1->result < d2->result );
    6666        }
    6767};
     
    169169        /// Merge environment with this one, checking compatibility.
    170170        /// Returns false if fails, but does NOT roll back partial changes.
    171         bool combine( const TypeEnvironment & o, OpenVarSet & openVars, const SymbolTable & symtab );
     171        bool combine( const TypeEnvironment & o, OpenVarSet & openVars );
    172172
    173173        /// Add all type variables in environment to open var list
     
    183183                const TypeInstType * typeInst, const Type * bindTo, const TypeData & data,
    184184                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    185                 ResolvExpr::WidenMode widen, const SymbolTable & symtab );
     185                ResolvExpr::WidenMode widen );
    186186
    187187        /// Binds the type classes represented by `var1` and `var2` together; will add one or both
     
    190190                const TypeInstType * var1, const TypeInstType * var2, TypeData && data,
    191191                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    192                 ResolvExpr::WidenMode widen, const SymbolTable & symtab );
     192                ResolvExpr::WidenMode widen );
    193193
    194194        /// Disallows widening for all bindings in the environment
     
    205205        /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
    206206        bool mergeBound(
    207                 EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
     207                EqvClass & to, const EqvClass & from, OpenVarSet & openVars );
    208208
    209209        /// Merges two type classes from local environment, returning false if fails
    210210        bool mergeClasses(
    211                 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
    212                 const SymbolTable & symtab );
     211                ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars);
    213212
    214213        /// Private lookup API; returns array index of string, or env.size() for not found
  • src/AST/TypeSubstitution.cpp

    r34b4268 r24d6572  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun  3 13:26:00 2017
    13 // Update Count     : 5
    14 //
     12// Last Modified On : Thr May 25 11:24:00 2023
     13// Update Count     : 6
     14//
     15
     16#include "TypeSubstitution.hpp"
    1517
    1618#include "Type.hpp"   // for TypeInstType, Type, StructInstType, UnionInstType
    17 #include "TypeSubstitution.hpp"
     19#include "Pass.hpp"   // for Pass, PureVisitor, WithGuards, WithVisitorRef
    1820
    1921namespace ast {
    20 
    21 
    22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
    2322
    2423TypeSubstitution::TypeSubstitution() {
     
    119118}
    120119
     120// definitition must happen after PassVisitor is included so that WithGuards can be used
     121struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor {
     122        //static size_t traceId;
     123
     124        Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
     125
     126        const Type * postvisit( const TypeInstType * aggregateUseType );
     127
     128        /// Records type variable bindings from forall-statements
     129        void previsit( const FunctionType * type );
     130        /// Records type variable bindings from forall-statements and instantiations of generic types
     131        // void handleAggregateType( const BaseInstType * type );
     132
     133        // void previsit( const StructInstType * aggregateUseType );
     134        // void previsit( const UnionInstType * aggregateUseType );
     135
     136        const TypeSubstitution & sub;
     137        int subCount = 0;
     138        bool freeOnly;
     139        typedef std::unordered_set< TypeEnvKey > BoundVarsType;
     140        BoundVarsType boundVars;
     141};
     142
     143// size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
     144
    121145void TypeSubstitution::normalize() {
    122146        Pass<Substituter> sub( *this, true );
     
    128152                }
    129153        } while ( sub.core.subCount );
     154}
     155
     156TypeSubstitution::ApplyResult<Node> TypeSubstitution::applyBase(
     157                const Node * input, bool isFree ) const {
     158        assert( input );
     159        Pass<Substituter> sub( *this, isFree );
     160        const Node * output = input->accept( sub );
     161        return { output, sub.core.subCount };
    130162}
    131163
  • src/AST/TypeSubstitution.hpp

    r34b4268 r24d6572  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 22:52:47 2019
    13 // Update Count     : 9
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May 25 12:31:00 2023
     13// Update Count     : 10
    1414//
    1515
     
    4646        TypeSubstitution &operator=( const TypeSubstitution &other );
    4747
    48         template< typename SynTreeClass >
     48        template< typename node_t >
    4949        struct ApplyResult {
    50                 ast::ptr<SynTreeClass> node;
     50                ast::ptr<node_t> node;
    5151                int count;
    5252        };
    5353
    54         template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const;
    55         template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const;
     54        template< typename node_t >
     55        ApplyResult<node_t> apply( const node_t * input ) const {
     56                ApplyResult<Node> ret = applyBase( input, false );
     57                return { ret.node.strict_as<node_t>(), ret.count };
     58        }
    5659
    5760        template< typename node_t, enum Node::ref_type ref_t >
    5861        int apply( ptr_base< node_t, ref_t > & input ) const {
    59                 const node_t * p = input.get();
    60                 auto ret = apply(p);
    61                 input = ret.node;
     62                ApplyResult<Node> ret = applyBase( input.get(), false );
     63                input = ret.node.strict_as<node_t>();
    6264                return ret.count;
     65        }
     66
     67        template< typename node_t >
     68        ApplyResult<node_t> applyFree( const node_t * input ) const {
     69                ApplyResult<Node> ret = applyBase( input, true );
     70                return { ret.node.strict_as<node_t>(), ret.count };
    6371        }
    6472
    6573        template< typename node_t, enum Node::ref_type ref_t >
    6674        int applyFree( ptr_base< node_t, ref_t > & input ) const {
    67                 const node_t * p = input.get();
    68                 auto ret = applyFree(p);
    69                 input = ret.node;
     75                ApplyResult<Node> ret = applyBase( input.get(), true );
     76                input = ret.node.strict_as<node_t>();
    7077                return ret.count;
    7178        }
     
    97104        // Mutator that performs the substitution
    98105        struct Substituter;
     106        ApplyResult<Node> applyBase( const Node * input, bool isFree ) const;
    99107
    100108        // TODO: worry about traversing into a forall-qualified function type or type decl with assertions
     
    158166} // namespace ast
    159167
    160 // include needs to happen after TypeSubstitution is defined so that both TypeSubstitution and
    161 // PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
    162 #include "Pass.hpp"
    163 #include "Copy.hpp"
    164 
    165 namespace ast {
    166 
    167 // definitition must happen after PassVisitor is included so that WithGuards can be used
    168 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor {
    169                 static size_t traceId;
    170 
    171                 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    172 
    173                 const Type * postvisit( const TypeInstType * aggregateUseType );
    174 
    175                 /// Records type variable bindings from forall-statements
    176                 void previsit( const FunctionType * type );
    177                 /// Records type variable bindings from forall-statements and instantiations of generic types
    178                 // void handleAggregateType( const BaseInstType * type );
    179 
    180                 // void previsit( const StructInstType * aggregateUseType );
    181                 // void previsit( const UnionInstType * aggregateUseType );
    182 
    183                 const TypeSubstitution & sub;
    184                 int subCount = 0;
    185                 bool freeOnly;
    186                 typedef std::unordered_set< TypeEnvKey > BoundVarsType;
    187                 BoundVarsType boundVars;
    188 
    189 };
    190 
    191 template< typename SynTreeClass >
    192 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
    193         assert( input );
    194         Pass<Substituter> sub( *this, false );
    195         input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    196         return { input, sub.core.subCount };
    197 }
    198 
    199 template< typename SynTreeClass >
    200 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
    201         assert( input );
    202         Pass<Substituter> sub( *this, true );
    203         input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    204         return { input, sub.core.subCount };
    205 }
    206 
    207 } // namespace ast
    208 
    209168// Local Variables: //
    210169// tab-width: 4 //
  • src/AST/Visitor.hpp

    r34b4268 r24d6572  
    5050    virtual const ast::FinallyClause *    visit( const ast::FinallyClause        * ) = 0;
    5151    virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
     52    virtual const ast::WhenClause *       visit( const ast::WhenClause           * ) = 0;
    5253    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5354    virtual const ast::WaitForClause *    visit( const ast::WaitForClause        * ) = 0;
     55    virtual const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) = 0;
    5456    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
    5557    virtual const ast::NullStmt *         visit( const ast::NullStmt             * ) = 0;
  • src/AST/porting.md

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

    r34b4268 r24d6572  
    1717#include <cassert>                   // for assert, assertf
    1818#include <list>                      // for _List_iterator, list, list<>::it...
     19#include <sstream>                   // for stringstream
    1920
    2021#include "AST/Decl.hpp"              // for DeclWithType
    2122#include "Common/UniqueName.h"       // for UniqueName
    22 #include "Common/utility.h"          // for CodeLocation, toString
    2323#include "GenType.h"                 // for genType
    2424#include "InitTweak/InitTweak.h"     // for getPointerBase
     
    273273        }
    274274
     275        template<typename pass_type>
     276        inline void genEnumInitializer( PassVisitor<pass_type> * visitor, Type * baseType, std::ostream & output,
     277        Initializer * init, long long * cur_val, Options options) {
     278                auto baseTypeAsBasic = baseType ? dynamic_cast<BasicType *>( baseType ) : nullptr;
     279                if ( init ) { // If value has an explicit initiazatior
     280                        output << " = ";
     281                        output << "(" << genType(baseType, "", options) << ")";
     282                        init->accept( *visitor );
     283                        if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) { // if it is an integral type and initilizer offered,
     284                        // need to update the cur_val
     285                                Expression* expr = ((SingleInit *)(init))->value;
     286                                while ( auto temp = dynamic_cast<CastExpr *>(expr) ) { // unwrap introduced cast
     287                                        expr = temp->arg;
     288                                }
     289                                *cur_val = ((ConstantExpr *)expr)->constant.get_ival()+1;
     290                        }
     291                } else if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) { // integral implicitly init to cur_val + 1
     292                        output << " = " << "(" << genType(baseType, "", options) << ")";
     293                        output << (*cur_val)++;
     294                }
     295        }
     296
    275297        void CodeGenerator::postvisit( EnumDecl * enumDecl ) {
    276298                extension( enumDecl );
    277299                std::list< Declaration* > &memb = enumDecl->get_members();
    278300                if (enumDecl->base && ! memb.empty()) {
    279                         unsigned long long last_val = -1; // if the first enum value has no explicit initializer,
    280                         // as other
     301                        long long cur_val = 0;
    281302                        for ( std::list< Declaration* >::iterator i = memb.begin(); i != memb.end();  i++) {
    282303                                ObjectDecl * obj = dynamic_cast< ObjectDecl* >( *i );
    283304                                assert( obj );
    284305                                output << "static ";
    285                                 output << genType(enumDecl->base, "", options) << " const ";
    286                                 output << mangleName( obj ) << " ";
    287                                 output << " = ";
    288                                 output << "(" << genType(enumDecl->base, "", options) << ")";
    289                                 if ( (BasicType *)(enumDecl->base) && ((BasicType *)(enumDecl->base))->isWholeNumber() ) {
    290                                         if ( obj->get_init() ) {
    291                                                 obj->get_init()->accept( *visitor );
    292                                                 Expression* expr = ((SingleInit *)(obj->init))->value;
    293                                                 while ( auto temp = dynamic_cast<CastExpr *>(expr) ) {
    294                                                         expr = temp->arg;
    295                                                 }
    296                                                 last_val = ((ConstantExpr *)expr)->constant.get_ival();
    297                                         } else {
    298                                                 output << ++last_val;
    299                                         } // if
    300                                 } else {
    301                                         if ( obj->get_init() ) {
    302                                                 obj->get_init()->accept( *visitor );
    303                                         } else {
    304                                                 // Should not reach here!
    305                                         }
    306                                 }
     306                                output << genType(enumDecl->base, mangleName( obj ), options);
     307                                genEnumInitializer( visitor, enumDecl->base, output, obj->get_init(), &cur_val, options);
    307308                                output << ";" << endl;
    308309                        } // for
  • src/CodeGen/GenType.cc

    r34b4268 r24d6572  
    255255        void GenType::postvisit( EnumInstType * enumInst ) {
    256256                if ( enumInst->baseEnum && enumInst->baseEnum->base ) {
    257                         typeString = genType(enumInst->baseEnum->base, "", options) + typeString;
     257                        typeString = genType(enumInst->baseEnum->base, typeString, options);
    258258                } else {
    259259                        typeString = enumInst->name + " " + typeString;
  • src/Common/CodeLocationTools.cpp

    r34b4268 r24d6572  
    128128    macro(FinallyClause, FinallyClause) \
    129129    macro(SuspendStmt, Stmt) \
     130    macro(WhenClause, WhenClause) \
    130131    macro(WaitForStmt, Stmt) \
    131132    macro(WaitForClause, WaitForClause) \
     133    macro(WaitUntilStmt, Stmt) \
    132134    macro(WithStmt, Decl) \
    133135    macro(NullStmt, NullStmt) \
     
    208210
    209211struct LeafKindVisitor : public ast::Visitor {
    210         LeafKind kind;
     212        LeafKind result;
    211213
    212214#define VISIT(node_type, return_type) \
    213215        const ast::return_type * visit( const ast::node_type * ) final { \
    214                 kind = LeafKind::node_type; \
     216                result = LeafKind::node_type; \
    215217                return nullptr; \
    216218        }
     
    222224
    223225LeafKind get_leaf_kind( ast::Node const * node ) {
    224         LeafKindVisitor visitor;
    225         node->accept( visitor );
    226         return visitor.kind;
     226        return ast::Pass<LeafKindVisitor>::read( node );
    227227}
    228228
  • src/Common/DeclStats.cpp

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

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

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

    r34b4268 r24d6572  
    3737                template<typename N>
    3838                Scope(N && n) : map(), note(std::forward<N>(n)) {}
    39                
     39
    4040                Scope() = default;
    4141                Scope(const Scope &) = default;
     
    4646        typedef std::vector< Scope > ScopeList;
    4747
    48         ScopeList scopes; ///< scoped list of maps
     48        /// Scoped list of maps.
     49        ScopeList scopes;
    4950public:
    5051        typedef typename MapType::key_type key_type;
     
    5859        typedef typename MapType::const_pointer const_pointer;
    5960
    60         class iterator : public std::iterator< std::bidirectional_iterator_tag, value_type > {
    61         friend class ScopedMap;
    62         friend class const_iterator;
    63                 typedef typename ScopedMap::MapType::iterator wrapped_iterator;
    64                 typedef typename ScopedMap::ScopeList scope_list;
    65                 typedef typename scope_list::size_type size_type;
    66 
    67                 /// Checks if this iterator points to a valid item
    68                 bool is_valid() const {
    69                         return it != (*scopes)[level].map.end();
    70                 }
    71 
    72                 /// Increments on invalid
    73                 iterator & next_valid() {
    74                         if ( ! is_valid() ) { ++(*this); }
    75                         return *this;
    76                 }
    77 
    78                 /// Decrements on invalid
    79                 iterator & prev_valid() {
    80                         if ( ! is_valid() ) { --(*this); }
    81                         return *this;
    82                 }
    83 
    84                 iterator(scope_list & _scopes, const wrapped_iterator & _it, size_type inLevel)
    85                         : scopes(&_scopes), it(_it), level(inLevel) {}
    86         public:
    87                 iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
    88                 iterator & operator= (const iterator & that) {
    89                         scopes = that.scopes; level = that.level; it = that.it;
    90                         return *this;
    91                 }
    92 
    93                 reference operator* () { return *it; }
    94                 pointer operator-> () const { return it.operator->(); }
    95 
    96                 iterator & operator++ () {
    97                         if ( it == (*scopes)[level].map.end() ) {
    98                                 if ( level == 0 ) return *this;
    99                                 --level;
    100                                 it = (*scopes)[level].map.begin();
    101                         } else {
    102                                 ++it;
    103                         }
    104                         return next_valid();
    105                 }
    106                 iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
    107 
    108                 iterator & operator-- () {
    109                         // may fail if this is the begin iterator; allowed by STL spec
    110                         if ( it == (*scopes)[level].map.begin() ) {
    111                                 ++level;
    112                                 it = (*scopes)[level].map.end();
    113                         }
    114                         --it;
    115                         return prev_valid();
    116                 }
    117                 iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
    118 
    119                 bool operator== (const iterator & that) const {
    120                         return scopes == that.scopes && level == that.level && it == that.it;
    121                 }
    122                 bool operator!= (const iterator & that) const { return !( *this == that ); }
    123 
    124                 size_type get_level() const { return level; }
    125 
    126                 Note & get_note() { return (*scopes)[level].note; }
    127                 const Note & get_note() const { return (*scopes)[level].note; }
    128 
    129         private:
    130                 scope_list *scopes;
    131                 wrapped_iterator it;
    132                 size_type level;
    133         };
    134 
    135         class const_iterator : public std::iterator< std::bidirectional_iterator_tag,
    136                                                      value_type > {
    137         friend class ScopedMap;
    138                 typedef typename ScopedMap::MapType::iterator wrapped_iterator;
    139                 typedef typename ScopedMap::MapType::const_iterator wrapped_const_iterator;
    140                 typedef typename ScopedMap::ScopeList scope_list;
    141                 typedef typename scope_list::size_type size_type;
    142 
    143                 /// Checks if this iterator points to a valid item
    144                 bool is_valid() const {
    145                         return it != (*scopes)[level].map.end();
    146                 }
    147 
    148                 /// Increments on invalid
    149                 const_iterator & next_valid() {
    150                         if ( ! is_valid() ) { ++(*this); }
    151                         return *this;
    152                 }
    153 
    154                 /// Decrements on invalid
    155                 const_iterator & prev_valid() {
    156                         if ( ! is_valid() ) { --(*this); }
    157                         return *this;
    158                 }
    159 
    160                 const_iterator(scope_list const & _scopes, const wrapped_const_iterator & _it, size_type inLevel)
    161                         : scopes(&_scopes), it(_it), level(inLevel) {}
    162         public:
    163                 const_iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
    164                 const_iterator(const const_iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
    165                 const_iterator & operator= (const iterator & that) {
    166                         scopes = that.scopes; level = that.level; it = that.it;
    167                         return *this;
    168                 }
    169                 const_iterator & operator= (const const_iterator & that) {
    170                         scopes = that.scopes; level = that.level; it = that.it;
    171                         return *this;
    172                 }
    173 
    174                 const_reference operator* () { return *it; }
    175                 const_pointer operator-> () { return it.operator->(); }
    176 
    177                 const_iterator & operator++ () {
    178                         if ( it == (*scopes)[level].map.end() ) {
    179                                 if ( level == 0 ) return *this;
    180                                 --level;
    181                                 it = (*scopes)[level].map.begin();
    182                         } else {
    183                                 ++it;
    184                         }
    185                         return next_valid();
    186                 }
    187                 const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
    188 
    189                 const_iterator & operator-- () {
    190                         // may fail if this is the begin iterator; allowed by STL spec
    191                         if ( it == (*scopes)[level].map.begin() ) {
    192                                 ++level;
    193                                 it = (*scopes)[level].map.end();
    194                         }
    195                         --it;
    196                         return prev_valid();
    197                 }
    198                 const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
    199 
    200                 bool operator== (const const_iterator & that) const {
    201                         return scopes == that.scopes && level == that.level && it == that.it;
    202                 }
    203                 bool operator!= (const const_iterator & that) const { return !( *this == that ); }
    204 
    205                 size_type get_level() const { return level; }
    206 
    207                 const Note & get_note() const { return (*scopes)[level].note; }
    208 
    209         private:
    210                 scope_list const *scopes;
    211                 wrapped_const_iterator it;
    212                 size_type level;
    213         };
     61        // Both iterator types are complete bidrectional iterators, see below.
     62        class iterator;
     63        class const_iterator;
    21464
    21565        /// Starts a new scope
     
    297147        }
    298148
    299         template< typename value_type_t >
    300         std::pair< iterator, bool > insert( iterator at, value_type_t && value ) {
    301                 MapType & scope = (*at.scopes)[ at.level ].map;
    302                 std::pair< typename MapType::iterator, bool > res = scope.insert( std::forward<value_type_t>( value ) );
    303                 return std::make_pair( iterator(scopes, std::move( res.first ), at.level), std::move( res.second ) );
    304         }
    305 
    306149        template< typename value_t >
    307150        std::pair< iterator, bool > insert( const Key & key, value_t && value ) { return insert( std::make_pair( key, std::forward<value_t>( value ) ) ); }
     
    324167        }
    325168
    326         iterator erase( iterator pos ) {
    327                 MapType & scope = (*pos.scopes)[ pos.level ].map;
    328                 const typename iterator::wrapped_iterator & new_it = scope.erase( pos.it );
    329                 iterator it( *pos.scopes, new_it, pos.level );
    330                 return it.next_valid();
     169        /// Erases element with key in the innermost scope that has it.
     170        size_type erase( const Key & key ) {
     171                for ( auto it = scopes.rbegin() ; it != scopes.rend() ; ++it ) {
     172                        size_type i = it->map.erase( key );
     173                        if ( 0 != i ) return i;
     174                }
     175                return 0;
    331176        }
    332177
     
    343188                return c;
    344189        }
     190
     191        bool contains( const Key & key ) const {
     192                return find( key ) != cend();
     193        }
     194};
     195
     196template<typename Key, typename Value, typename Note>
     197class ScopedMap<Key, Value, Note>::iterator :
     198                public std::iterator< std::bidirectional_iterator_tag, value_type > {
     199        friend class ScopedMap;
     200        friend class const_iterator;
     201        typedef typename ScopedMap::MapType::iterator wrapped_iterator;
     202        typedef typename ScopedMap::ScopeList scope_list;
     203        typedef typename scope_list::size_type size_type;
     204
     205        /// Checks if this iterator points to a valid item
     206        bool is_valid() const {
     207                return it != (*scopes)[level].map.end();
     208        }
     209
     210        /// Increments on invalid
     211        iterator & next_valid() {
     212                if ( ! is_valid() ) { ++(*this); }
     213                return *this;
     214        }
     215
     216        /// Decrements on invalid
     217        iterator & prev_valid() {
     218                if ( ! is_valid() ) { --(*this); }
     219                return *this;
     220        }
     221
     222        iterator(scope_list & _scopes, const wrapped_iterator & _it, size_type inLevel)
     223                : scopes(&_scopes), it(_it), level(inLevel) {}
     224public:
     225        iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
     226        iterator & operator= (const iterator & that) {
     227                scopes = that.scopes; level = that.level; it = that.it;
     228                return *this;
     229        }
     230
     231        reference operator* () { return *it; }
     232        pointer operator-> () const { return it.operator->(); }
     233
     234        iterator & operator++ () {
     235                if ( it == (*scopes)[level].map.end() ) {
     236                        if ( level == 0 ) return *this;
     237                        --level;
     238                        it = (*scopes)[level].map.begin();
     239                } else {
     240                        ++it;
     241                }
     242                return next_valid();
     243        }
     244        iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
     245
     246        iterator & operator-- () {
     247                // may fail if this is the begin iterator; allowed by STL spec
     248                if ( it == (*scopes)[level].map.begin() ) {
     249                        ++level;
     250                        it = (*scopes)[level].map.end();
     251                }
     252                --it;
     253                return prev_valid();
     254        }
     255        iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
     256
     257        bool operator== (const iterator & that) const {
     258                return scopes == that.scopes && level == that.level && it == that.it;
     259        }
     260        bool operator!= (const iterator & that) const { return !( *this == that ); }
     261
     262        size_type get_level() const { return level; }
     263
     264        Note & get_note() { return (*scopes)[level].note; }
     265        const Note & get_note() const { return (*scopes)[level].note; }
     266
     267private:
     268        scope_list *scopes;
     269        wrapped_iterator it;
     270        size_type level;
     271};
     272
     273template<typename Key, typename Value, typename Note>
     274class ScopedMap<Key, Value, Note>::const_iterator :
     275                public std::iterator< std::bidirectional_iterator_tag, value_type > {
     276        friend class ScopedMap;
     277        typedef typename ScopedMap::MapType::iterator wrapped_iterator;
     278        typedef typename ScopedMap::MapType::const_iterator wrapped_const_iterator;
     279        typedef typename ScopedMap::ScopeList scope_list;
     280        typedef typename scope_list::size_type size_type;
     281
     282        /// Checks if this iterator points to a valid item
     283        bool is_valid() const {
     284                return it != (*scopes)[level].map.end();
     285        }
     286
     287        /// Increments on invalid
     288        const_iterator & next_valid() {
     289                if ( ! is_valid() ) { ++(*this); }
     290                return *this;
     291        }
     292
     293        /// Decrements on invalid
     294        const_iterator & prev_valid() {
     295                if ( ! is_valid() ) { --(*this); }
     296                return *this;
     297        }
     298
     299        const_iterator(scope_list const & _scopes, const wrapped_const_iterator & _it, size_type inLevel)
     300                : scopes(&_scopes), it(_it), level(inLevel) {}
     301public:
     302        const_iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
     303        const_iterator(const const_iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
     304        const_iterator & operator= (const iterator & that) {
     305                scopes = that.scopes; level = that.level; it = that.it;
     306                return *this;
     307        }
     308        const_iterator & operator= (const const_iterator & that) {
     309                scopes = that.scopes; level = that.level; it = that.it;
     310                return *this;
     311        }
     312
     313        const_reference operator* () { return *it; }
     314        const_pointer operator-> () { return it.operator->(); }
     315
     316        const_iterator & operator++ () {
     317                if ( it == (*scopes)[level].map.end() ) {
     318                        if ( level == 0 ) return *this;
     319                        --level;
     320                        it = (*scopes)[level].map.begin();
     321                } else {
     322                        ++it;
     323                }
     324                return next_valid();
     325        }
     326        const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
     327
     328        const_iterator & operator-- () {
     329                // may fail if this is the begin iterator; allowed by STL spec
     330                if ( it == (*scopes)[level].map.begin() ) {
     331                        ++level;
     332                        it = (*scopes)[level].map.end();
     333                }
     334                --it;
     335                return prev_valid();
     336        }
     337        const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
     338
     339        bool operator== (const const_iterator & that) const {
     340                return scopes == that.scopes && level == that.level && it == that.it;
     341        }
     342        bool operator!= (const const_iterator & that) const { return !( *this == that ); }
     343
     344        size_type get_level() const { return level; }
     345
     346        const Note & get_note() const { return (*scopes)[level].note; }
     347
     348private:
     349        scope_list const *scopes;
     350        wrapped_const_iterator it;
     351        size_type level;
    345352};
    346353
  • src/Common/SemanticError.h

    r34b4268 r24d6572  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May  4 14:08:26 2022
    13 // Update Count     : 35
     12// Last Modified On : Sat Feb 25 12:01:31 2023
     13// Update Count     : 37
    1414//
    1515
     
    5454
    5555constexpr WarningData WarningFormats[] = {
    56         {"self-assign"            , Severity::Warn    , "self assignment of expression: %s"                          },
    57         {"reference-conversion"   , Severity::Warn    , "rvalue to reference conversion of rvalue: %s"               },
    58         {"qualifiers-zero_t-one_t", Severity::Warn    , "questionable use of type qualifier %s with %s"              },
    59         {"aggregate-forward-decl" , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
    60         {"superfluous-decl"       , Severity::Warn    , "declaration does not allocate storage: %s"                  },
    61         {"superfluous-else"       , Severity::Warn    , "else clause never executed for empty loop conditional"      },
    62         {"gcc-attributes"         , Severity::Warn    , "invalid attribute: %s"                                      },
    63         {"c++-like-copy"          , Severity::Warn    , "Constructor from reference is not a valid copy constructor" },
     56        {"self-assign"              , Severity::Warn    , "self assignment of expression: %s"                          },
     57        {"reference-conversion"     , Severity::Warn    , "rvalue to reference conversion of rvalue: %s"               },
     58        {"qualifiers-zero_t-one_t"  , Severity::Warn    , "questionable use of type qualifier(s) with %s"              },
     59        {"aggregate-forward-decl"   , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
     60        {"superfluous-decl"         , Severity::Warn    , "declaration does not allocate storage: %s"                  },
     61        {"superfluous-else"         , Severity::Warn    , "else clause never executed for empty loop conditional"      },
     62        {"gcc-attributes"           , Severity::Warn    , "invalid attribute: %s"                                      },
     63        {"c++-like-copy"            , Severity::Warn    , "Constructor from reference is not a valid copy constructor" },
     64        {"depreciated-trait-syntax" , Severity::Warn    , "trait type-parameters are now specified using the forall clause" },
    6465};
    6566
     
    7374        GccAttributes,
    7475        CppCopy,
     76        DeprecTraitSyntax,
    7577        NUMBER_OF_WARNINGS, // This MUST be the last warning
    7678};
  • src/Common/module.mk

    r34b4268 r24d6572  
    2020        Common/CodeLocationTools.hpp \
    2121        Common/CodeLocationTools.cpp \
    22         Common/CompilerError.h \
    23         Common/Debug.h \
    2422        Common/DeclStats.hpp \
    2523        Common/DeclStats.cpp \
    2624        Common/ErrorObjects.h \
    2725        Common/Eval.cc \
     26        Common/Eval.h \
    2827        Common/Examine.cc \
    2928        Common/Examine.h \
     
    3130        Common/Indenter.h \
    3231        Common/Indenter.cc \
     32        Common/Iterate.hpp \
    3333        Common/PassVisitor.cc \
    3434        Common/PassVisitor.h \
     
    5252        Common/Stats/Time.cc \
    5353        Common/Stats/Time.h \
    54         Common/UnimplementedError.h \
     54        Common/ToString.hpp \
    5555        Common/UniqueName.cc \
    5656        Common/UniqueName.h \
  • src/Common/utility.h

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

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

    r34b4268 r24d6572  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Henry Xue
    12 // Last Modified On : Tue Jul 20 04:27:35 2021
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 19:12:53 2023
     13// Update Count     : 6
    1414//
    1515
     
    2626        expraltp,
    2727        genericsp,
     28        invariant,
    2829        libcfap,
    2930        nopreludep,
     
    3233        useNewAST,
    3334        nomainp,
    34         parsep,
    3535        resolvep,
    3636        resolvprotop,
  • src/Concurrency/KeywordsNew.cpp

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

    r34b4268 r24d6572  
    305305
    306306        const ast::VariableExpr * variableExpr =
    307                 clause->target_func.as<ast::VariableExpr>();
     307                clause->target.as<ast::VariableExpr>();
    308308        ast::Expr * castExpr = new ast::CastExpr(
    309309                location,
    310310                new ast::CastExpr(
    311311                        location,
    312                         clause->target_func,
     312                        clause->target,
    313313                        ast::deepCopy( variableExpr->result.get() ),
    314314                        ast::GeneratedCast ),
     
    325325
    326326        ResolveContext context{ symtab, transUnit().global };
    327         out->push_back( maybeCond( location, clause->cond.get(), {
     327        out->push_back( maybeCond( location, clause->when_cond.get(), {
    328328                makeAccStmt( location, acceptables, index, "is_dtor",
    329                         detectIsDtor( location, clause->target_func ), context ),
     329                        detectIsDtor( location, clause->target ), context ),
    330330                makeAccStmt( location, acceptables, index, "func",
    331331                        funcExpr, context ),
  • src/Concurrency/module.mk

    r34b4268 r24d6572  
    1616
    1717SRC += \
     18        Concurrency/Actors.cpp \
     19        Concurrency/Actors.hpp \
    1820        Concurrency/KeywordsNew.cpp \
    1921        Concurrency/Keywords.cc \
     
    2123        Concurrency/WaitforNew.cpp \
    2224        Concurrency/Waitfor.cc \
    23         Concurrency/Waitfor.h
     25        Concurrency/Waitfor.h \
     26        Concurrency/Waituntil.cpp \
     27        Concurrency/Waituntil.hpp
  • src/ControlStruct/ExceptDeclNew.cpp

    r34b4268 r24d6572  
    1616#include "ExceptDecl.h"
    1717
     18#include <sstream>
     19
     20#include "AST/Copy.hpp"
    1821#include "AST/Decl.hpp"
    1922#include "AST/Pass.hpp"
  • src/ControlStruct/ExceptTranslateNew.cpp

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

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

    r34b4268 r24d6572  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:40:34 2019
    13 // Update Count     : 347
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Dec 19 16:36:00 2022
     13// Update Count     : 348
    1414//
     15
     16#include "Box.h"
    1517
    1618#include <algorithm>                     // for mismatch
     
    2426#include <utility>                       // for pair
    2527
    26 #include "Box.h"
    27 
    2828#include "CodeGen/OperatorTable.h"
    2929#include "Common/PassVisitor.h"          // for PassVisitor
     
    3131#include "Common/SemanticError.h"        // for SemanticError
    3232#include "Common/UniqueName.h"           // for UniqueName
    33 #include "Common/utility.h"              // for toString
     33#include "Common/ToString.hpp"           // for toCString
    3434#include "FindFunction.h"                // for findFunction, findAndReplace...
    3535#include "GenPoly/ErasableScopedMap.h"   // for ErasableScopedMap<>::const_i...
     
    3737#include "InitTweak/InitTweak.h"         // for getFunctionName, isAssignment
    3838#include "Lvalue.h"                      // for generalizedLvalue
    39 #include "ResolvExpr/typeops.h"          // for typesCompatible
     39#include "ResolvExpr/Unify.h"            // for typesCompatible
    4040#include "ScopedSet.h"                   // for ScopedSet, ScopedSet<>::iter...
    4141#include "ScrubTyVars.h"                 // for ScrubTyVars
     
    7272                };
    7373
     74                /// Updates the call sites of polymorphic functions.
    7475                /// Replaces polymorphic return types with out-parameters,
    7576                /// replaces calls to polymorphic functions with adapter calls,
    7677                /// and adds appropriate type variables to the function call.
    77                 class Pass1 final : public BoxPass, public WithConstTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {
     78                class CallAdapter final : public BoxPass, public WithConstTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<CallAdapter>, public WithShortCircuiting {
    7879                  public:
    79                         Pass1();
    80 
     80                        CallAdapter();
     81
     82                        void premutate( Declaration * declaration );
    8183                        void premutate( FunctionDecl * functionDecl );
    8284                        void premutate( TypeDecl * typeDecl );
     
    138140                };
    139141
     142                /// Updates declarations (and types) that require adapters.
    140143                /// * Moves polymorphic returns in function types to pointer-type parameters
    141144                /// * adds type size and assertion parameters to parameter lists
    142                 struct Pass2 final : public BoxPass, public WithGuards {
     145                struct DeclAdapter final : public BoxPass, public WithGuards {
    143146                        void handleAggDecl();
    144147
     
    210213                };
    211214
     215                /// Erases unneeded/unwanted polymorphic information.
    212216                /// Replaces initialization of polymorphic values with alloca,
    213217                /// declaration of dtype/ftype with appropriate void expression,
    214218                /// sizeof expressions of polymorphic types with the proper variable,
    215219                /// and strips fields from generic struct declarations.
    216                 struct Pass3 final : public BoxPass, public WithGuards {
    217                         template< typename DeclClass >
    218                         void handleDecl( DeclClass * decl, Type * type );
    219 
     220                struct Eraser final {
    220221                        void premutate( ObjectDecl * objectDecl );
    221222                        void premutate( FunctionDecl * functionDecl );
     
    223224                        void premutate( StructDecl * structDecl );
    224225                        void premutate( UnionDecl * unionDecl );
    225                         void premutate( TypeDecl * typeDecl );
    226                         void premutate( PointerType * pointerType );
    227                         void premutate( FunctionType * funcType );
    228226                };
    229227        } // anonymous namespace
     
    231229        void box( std::list< Declaration *>& translationUnit ) {
    232230                PassVisitor<LayoutFunctionBuilder> layoutBuilder;
    233                 PassVisitor<Pass1> pass1;
    234                 PassVisitor<Pass2> pass2;
     231                PassVisitor<CallAdapter> callAdapter;
     232                PassVisitor<DeclAdapter> declAdapter;
    235233                PassVisitor<PolyGenericCalculator> polyCalculator;
    236                 PassVisitor<Pass3> pass3;
     234                PassVisitor<Eraser> eraser;
    237235
    238236                acceptAll( translationUnit, layoutBuilder );
    239                 mutateAll( translationUnit, pass1 );
    240                 mutateAll( translationUnit, pass2 );
     237                mutateAll( translationUnit, callAdapter );
     238                mutateAll( translationUnit, declAdapter );
    241239                mutateAll( translationUnit, polyCalculator );
    242                 mutateAll( translationUnit, pass3 );
     240                mutateAll( translationUnit, eraser );
    243241        }
    244242
    245         ////////////////////////////////// LayoutFunctionBuilder ////////////////////////////////////////////
     243////////////////////////////////// LayoutFunctionBuilder ////////////////////////////////////////
    246244
    247245        /// Get a list of type declarations that will affect a layout function
     
    423421        }
    424422
    425         ////////////////////////////////////////// Pass1 ////////////////////////////////////////////////////
     423////////////////////////////////////////////// CallAdapter //////////////////////////////////////
    426424
    427425        namespace {
    428426                std::string makePolyMonoSuffix( FunctionType const * function, const TyVarMap &tyVars ) {
    429                         std::stringstream name;
    430 
    431427                        // NOTE: this function previously used isPolyObj, which failed to produce
    432428                        // the correct thing in some situations. It's not clear to me why this wasn't working.
     
    435431                        // to take those polymorphic types as pointers. Therefore, there can be two different functions
    436432                        // with the same mangled name, so we need to further mangle the names.
     433                        std::stringstream name;
    437434                        for ( DeclarationWithType const * const ret : function->returnVals ) {
    438                                 if ( isPolyType( ret->get_type(), tyVars ) ) {
    439                                         name << "P";
    440                                 } else {
    441                                         name << "M";
    442                                 }
    443                         }
    444                         name << "_";
     435                                name << ( isPolyType( ret->get_type(), tyVars ) ? 'P' : 'M' );
     436                        }
     437                        name << '_';
    445438                        for ( DeclarationWithType const * const arg : function->parameters ) {
    446                                 if ( isPolyType( arg->get_type(), tyVars ) ) {
    447                                         name << "P";
    448                                 } else {
    449                                         name << "M";
    450                                 }
    451                         } // for
     439                                name << ( isPolyType( arg->get_type(), tyVars ) ? 'P' : 'M' );
     440                        }
    452441                        return name.str();
    453442                }
     
    465454                Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone = true );
    466455
    467                 Pass1::Pass1() : tempNamer( "_temp" ) {}
    468 
    469                 void Pass1::premutate( FunctionDecl *functionDecl ) {
     456                CallAdapter::CallAdapter() : tempNamer( "_temp" ) {}
     457
     458                void CallAdapter::premutate( Declaration * ) {
     459                        // Prevent type declaration information from leaking out.
     460                        GuardScope( scopeTyVars );
     461                }
     462
     463                void CallAdapter::premutate( FunctionDecl *functionDecl ) {
    470464                        if ( functionDecl->get_statements() ) {         // empty routine body ?
    471465                                // std::cerr << "mutating function: " << functionDecl->get_mangleName() << std::endl;
     
    500494                                for ( FunctionType const * const funType : functions ) {
    501495                                        std::string mangleName = mangleAdapterName( funType, scopeTyVars );
    502                                         if ( adapters.find( mangleName ) == adapters.end() ) {
     496                                        if ( !adapters.contains( mangleName ) ) {
    503497                                                std::string adapterName = makeAdapterName( mangleName );
    504498                                                adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), nullptr ) ) );
     
    509503                }
    510504
    511                 void Pass1::premutate( TypeDecl *typeDecl ) {
     505                void CallAdapter::premutate( TypeDecl *typeDecl ) {
    512506                        addToTyVarMap( typeDecl, scopeTyVars );
    513507                }
    514508
    515                 void Pass1::premutate( CommaExpr *commaExpr ) {
     509                void CallAdapter::premutate( CommaExpr *commaExpr ) {
    516510                        // Attempting to find application expressions that were mutated by the copy constructor passes
    517511                        // to use an explicit return variable, so that the variable can be reused as a parameter to the
     
    531525                }
    532526
    533                 std::list< Expression *>::iterator Pass1::passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes ) {
     527                std::list< Expression *>::iterator CallAdapter::passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes ) {
    534528                        Type *polyType = isPolyType( parmType, exprTyVars );
    535529                        if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
     
    558552                }
    559553
    560                 std::list< Expression *>::iterator Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars ) {
     554                std::list< Expression *>::iterator CallAdapter::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars ) {
    561555                        assert( env );
    562556                        std::list< Expression *>::iterator arg = appExpr->args.begin();
     
    568562                        // even when converted to strings, sort in the original order.
    569563                        // (At least, that is the best explination I have.)
    570                         for ( std::pair<std::string, TypeDecl::Data> const & tyParam : exprTyVars ) {
     564                        for ( std::pair<const std::string, TypeDecl::Data> const & tyParam : exprTyVars ) {
    571565                                if ( !tyParam.second.isComplete ) continue;
    572566                                Type *concrete = env->lookup( tyParam.first );
     
    611605                }
    612606
    613                 ObjectDecl *Pass1::makeTemporary( Type *type ) {
     607                ObjectDecl *CallAdapter::makeTemporary( Type *type ) {
    614608                        ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), Type::StorageClasses(), LinkageSpec::C, 0, type, 0 );
    615609                        stmtsToAddBefore.push_back( new DeclStmt( newObj ) );
     
    617611                }
    618612
    619                 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType ) {
     613                Expression *CallAdapter::addRetParam( ApplicationExpr *appExpr, Type *retType ) {
    620614                        // Create temporary to hold return value of polymorphic function and produce that temporary as a result
    621615                        // using a comma expression.
     
    680674                }
    681675
    682                 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType ) {
     676                Expression *CallAdapter::addDynRetParam( ApplicationExpr *appExpr, Type *dynType ) {
    683677                        Type *concrete = replaceWithConcrete( dynType, env );
    684678                        // add out-parameter for return value
     
    686680                }
    687681
    688                 Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function ) {
     682                Expression *CallAdapter::applyAdapter( ApplicationExpr *appExpr, FunctionType *function ) {
    689683                        Expression *ret = appExpr;
    690684                        if ( isDynRet( function, scopeTyVars ) ) {
     
    735729                }
    736730
    737                 void Pass1::boxParam( Expression *&arg, Type *param, const TyVarMap &exprTyVars ) {
     731                void CallAdapter::boxParam( Expression *&arg, Type *param, const TyVarMap &exprTyVars ) {
    738732                        assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() );
    739733                        addCast( arg, param, exprTyVars );
     
    770764                }
    771765
    772                 void Pass1::boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars ) {
     766                void CallAdapter::boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars ) {
    773767                        for ( DeclarationWithType * param : function->parameters ) {
    774768                                assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() );
     
    778772                }
    779773
    780                 void Pass1::addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ) {
     774                void CallAdapter::addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ) {
    781775                        for ( TypeDecl * const tyVar : functionType->forall ) {
    782776                                for ( DeclarationWithType * const assert : tyVar->assertions ) {
     
    846840                }
    847841
    848                 FunctionDecl *Pass1::makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
     842                FunctionDecl *CallAdapter::makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
    849843                        FunctionType *adapterType = makeAdapterType( adaptee, tyVars );
    850844                        adapterType = ScrubTyVars::scrub( adapterType, tyVars );
     
    906900                }
    907901
    908                 void Pass1::passAdapters( ApplicationExpr * appExpr, FunctionType * functionType, const TyVarMap & exprTyVars ) {
     902                void CallAdapter::passAdapters( ApplicationExpr * appExpr, FunctionType * functionType, const TyVarMap & exprTyVars ) {
    909903                        // collect a list of function types passed as parameters or implicit parameters (assertions)
    910904                        std::list<FunctionType const *> functions;
     
    923917
    924918                        for ( FunctionType const * const funType : functions ) {
    925                                 FunctionType *originalFunction = funType->clone();
    926                                 FunctionType *realFunction = funType->clone();
    927                                 std::string mangleName = SymTab::Mangler::mangle( realFunction );
     919                                std::string mangleName = SymTab::Mangler::mangle( funType );
    928920
    929921                                // only attempt to create an adapter or pass one as a parameter if we haven't already done so for this
    930922                                // pre-substitution parameter function type.
    931923                                // The second part of the insert result is "is the value new".
    932                                 if ( adaptersDone.insert( mangleName ).second ) {
    933 
    934                                         // apply substitution to type variables to figure out what the adapter's type should look like
    935                                         assert( env );
    936                                         env->apply( realFunction );
    937                                         mangleName = SymTab::Mangler::mangle( realFunction );
    938                                         mangleName += makePolyMonoSuffix( originalFunction, exprTyVars );
    939 
    940                                         typedef ScopedMap< std::string, DeclarationWithType* >::iterator AdapterIter;
    941                                         AdapterIter adapter = adapters.find( mangleName );
    942                                         if ( adapter == adapters.end() ) {
    943                                                 // adapter has not been created yet in the current scope, so define it
    944                                                 FunctionDecl *newAdapter = makeAdapter( funType, realFunction, mangleName, exprTyVars );
    945                                                 std::pair< AdapterIter, bool > answer = adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, newAdapter ) );
    946                                                 adapter = answer.first;
    947                                                 stmtsToAddBefore.push_back( new DeclStmt( newAdapter ) );
    948                                         } // if
    949                                         assert( adapter != adapters.end() );
    950 
    951                                         // add the appropriate adapter as a parameter
    952                                         appExpr->get_args().push_front( new VariableExpr( adapter->second ) );
     924                                if ( !adaptersDone.insert( mangleName ).second ) continue;
     925
     926                                // Apply substitution to type variables to figure out what the adapter's type should look like.
     927                                assert( env );
     928                                FunctionType *realType = funType->clone();
     929                                env->apply( realType );
     930                                mangleName = SymTab::Mangler::mangle( realType );
     931                                mangleName += makePolyMonoSuffix( funType, exprTyVars );
     932
     933                                typedef ScopedMap< std::string, DeclarationWithType* >::iterator AdapterIter;
     934                                AdapterIter adapter = adapters.find( mangleName );
     935                                if ( adapter == adapters.end() ) {
     936                                        // Adapter has not been created yet in the current scope, so define it.
     937                                        FunctionDecl *newAdapter = makeAdapter( funType, realType, mangleName, exprTyVars );
     938                                        std::pair< AdapterIter, bool > answer = adapters.insert( mangleName, newAdapter );
     939                                        adapter = answer.first;
     940                                        stmtsToAddBefore.push_back( new DeclStmt( newAdapter ) );
    953941                                } // if
     942                                assert( adapter != adapters.end() );
     943
     944                                // Add the appropriate adapter as a parameter.
     945                                appExpr->args.push_front( new VariableExpr( adapter->second ) );
    954946                        } // for
    955947                } // passAdapters
     
    974966                }
    975967
    976                 Expression *Pass1::handleIntrinsics( ApplicationExpr *appExpr ) {
     968                Expression *CallAdapter::handleIntrinsics( ApplicationExpr *appExpr ) {
    977969                        if ( VariableExpr *varExpr = dynamic_cast< VariableExpr *>( appExpr->function ) ) {
    978970                                if ( varExpr->var->linkage == LinkageSpec::Intrinsic ) {
     
    10971089                }
    10981090
    1099                 Expression *Pass1::postmutate( ApplicationExpr *appExpr ) {
     1091                Expression *CallAdapter::postmutate( ApplicationExpr *appExpr ) {
    11001092                        // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl;
    11011093                        // for ( auto tyVar : scopeTyVars ) {
     
    11691161                }
    11701162
    1171                 Expression * Pass1::postmutate( UntypedExpr *expr ) {
     1163                Expression * CallAdapter::postmutate( UntypedExpr *expr ) {
    11721164                        if ( isPolyDeref( expr, scopeTyVars, env ) ) {
    11731165                                Expression *ret = expr->args.front();
     
    11791171                }
    11801172
    1181                 void Pass1::premutate( AddressExpr * ) { visit_children = false; }
    1182 
    1183                 Expression * Pass1::postmutate( AddressExpr * addrExpr ) {
     1173                void CallAdapter::premutate( AddressExpr * ) { visit_children = false; }
     1174
     1175                Expression * CallAdapter::postmutate( AddressExpr * addrExpr ) {
    11841176                        assert( addrExpr->arg->result && ! addrExpr->arg->result->isVoid() );
    11851177
     
    12121204                }
    12131205
    1214                 void Pass1::premutate( ReturnStmt *returnStmt ) {
     1206                void CallAdapter::premutate( ReturnStmt *returnStmt ) {
    12151207                        if ( retval && returnStmt->expr ) {
    12161208                                assert( returnStmt->expr->result && ! returnStmt->expr->result->isVoid() );
     
    12201212                }
    12211213
    1222                 void Pass1::premutate( PointerType *pointerType ) {
     1214                void CallAdapter::premutate( PointerType *pointerType ) {
    12231215                        GuardScope( scopeTyVars );
    12241216                        makeTyVarMap( pointerType, scopeTyVars );
    12251217                }
    12261218
    1227                 void Pass1::premutate( FunctionType *functionType ) {
     1219                void CallAdapter::premutate( FunctionType *functionType ) {
    12281220                        GuardScope( scopeTyVars );
    12291221                        makeTyVarMap( functionType, scopeTyVars );
    12301222                }
    12311223
    1232                 void Pass1::beginScope() {
     1224                void CallAdapter::beginScope() {
    12331225                        adapters.beginScope();
    12341226                }
    12351227
    1236                 void Pass1::endScope() {
     1228                void CallAdapter::endScope() {
    12371229                        adapters.endScope();
    12381230                }
    12391231
    1240 ////////////////////////////////////////// Pass2 ////////////////////////////////////////////////////
    1241 
    1242                 void Pass2::addAdapters( FunctionType *functionType ) {
     1232////////////////////////////////////////// DeclAdapter //////////////////////////////////////////
     1233
     1234                void DeclAdapter::addAdapters( FunctionType *functionType ) {
    12431235                        std::list< FunctionType const *> functions;
    12441236                        for ( DeclarationWithType * const arg : functionType->parameters ) {
     
    12601252                }
    12611253
    1262                 DeclarationWithType * Pass2::postmutate( FunctionDecl *functionDecl ) {
     1254                DeclarationWithType * DeclAdapter::postmutate( FunctionDecl *functionDecl ) {
    12631255                        FunctionType * ftype = functionDecl->type;
    12641256                        if ( ! ftype->returnVals.empty() && functionDecl->statements ) {
     
    12851277                }
    12861278
    1287                 void Pass2::premutate( StructDecl * ) {
     1279                void DeclAdapter::premutate( StructDecl * ) {
    12881280                        // prevent tyVars from leaking into containing scope
    12891281                        GuardScope( scopeTyVars );
    12901282                }
    12911283
    1292                 void Pass2::premutate( UnionDecl * ) {
     1284                void DeclAdapter::premutate( UnionDecl * ) {
    12931285                        // prevent tyVars from leaking into containing scope
    12941286                        GuardScope( scopeTyVars );
    12951287                }
    12961288
    1297                 void Pass2::premutate( TraitDecl * ) {
     1289                void DeclAdapter::premutate( TraitDecl * ) {
    12981290                        // prevent tyVars from leaking into containing scope
    12991291                        GuardScope( scopeTyVars );
    13001292                }
    13011293
    1302                 void Pass2::premutate( TypeDecl *typeDecl ) {
     1294                void DeclAdapter::premutate( TypeDecl *typeDecl ) {
    13031295                        addToTyVarMap( typeDecl, scopeTyVars );
    13041296                }
    13051297
    1306                 void Pass2::premutate( PointerType *pointerType ) {
     1298                void DeclAdapter::premutate( PointerType *pointerType ) {
    13071299                        GuardScope( scopeTyVars );
    13081300                        makeTyVarMap( pointerType, scopeTyVars );
    13091301                }
    13101302
    1311                 void Pass2::premutate( FunctionType *funcType ) {
     1303                void DeclAdapter::premutate( FunctionType *funcType ) {
    13121304                        GuardScope( scopeTyVars );
    13131305                        makeTyVarMap( funcType, scopeTyVars );
     
    13931385                }
    13941386
    1395 ////////////////////////////////////////// PolyGenericCalculator ////////////////////////////////////////////////////
     1387////////////////////////////////////////// PolyGenericCalculator ////////////////////////////////
    13961388
    13971389                PolyGenericCalculator::PolyGenericCalculator()
     
    14741466                        // make sure that any type information passed into the function is accounted for
    14751467                        for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) {
    1476                                 // condition here duplicates that in Pass2::mutate( FunctionType* )
     1468                                // condition here duplicates that in DeclAdapter::mutate( FunctionType* )
    14771469                                Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );
    14781470                                if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
     
    15011493                                        if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) {
    15021494                                                // do not try to monomorphize generic parameters
    1503                                                 if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() && ! genericParams.count( typeInst->name ) ) {
     1495                                                if ( scopeTyVars.contains( typeInst->get_name() ) && ! genericParams.count( typeInst->name ) ) {
    15041496                                                        // polymorphic aggregate members should be converted into monomorphic members.
    15051497                                                        // Using char[size_T] here respects the expected sizing rules of an aggregate type.
     
    17101702
    17111703                        if ( auto typeInst = dynamic_cast< TypeInstType const * >( ty ) ) {
    1712                                 if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() ) {
     1704                                if ( scopeTyVars.contains( typeInst->get_name() ) ) {
    17131705                                        // NOTE assumes here that getting put in the scopeTyVars included having the layout variables set
    17141706                                        return true;
     
    17181710                                // check if this type already has a layout generated for it
    17191711                                std::string typeName = mangleType( ty );
    1720                                 if ( knownLayouts.find( typeName ) != knownLayouts.end() ) return true;
     1712                                if ( knownLayouts.contains( typeName ) ) return true;
    17211713
    17221714                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
     
    17551747                                // check if this type already has a layout generated for it
    17561748                                std::string typeName = mangleType( ty );
    1757                                 if ( knownLayouts.find( typeName ) != knownLayouts.end() ) return true;
     1749                                if ( knownLayouts.contains( typeName ) ) return true;
    17581750
    17591751                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
     
    18461838                        } else {
    18471839                                std::string offsetName = offsetofName( mangleType( ty ) );
    1848                                 if ( knownOffsets.find( offsetName ) != knownOffsets.end() ) {
     1840                                if ( knownOffsets.contains( offsetName ) ) {
    18491841                                        // use the already-generated offsets for this type
    18501842                                        ret = new NameExpr( offsetName );
     
    18841876                }
    18851877
    1886 ////////////////////////////////////////// Pass3 ////////////////////////////////////////////////////
    1887 
    1888                 template< typename DeclClass >
    1889                 void Pass3::handleDecl( DeclClass * decl, Type * type ) {
    1890                         GuardScope( scopeTyVars );
    1891                         makeTyVarMap( type, scopeTyVars );
    1892                         ScrubTyVars::scrubAll( decl );
    1893                 }
    1894 
    1895                 void Pass3::premutate( ObjectDecl * objectDecl ) {
    1896                         handleDecl( objectDecl, objectDecl->type );
    1897                 }
    1898 
    1899                 void Pass3::premutate( FunctionDecl * functionDecl ) {
    1900                         handleDecl( functionDecl, functionDecl->type );
    1901                 }
    1902 
    1903                 void Pass3::premutate( TypedefDecl * typedefDecl ) {
    1904                         handleDecl( typedefDecl, typedefDecl->base );
     1878////////////////////////////////////////// Eraser ///////////////////////////////////////////////
     1879
     1880                void Eraser::premutate( ObjectDecl * objectDecl ) {
     1881                        ScrubTyVars::scrubAll( objectDecl );
     1882                }
     1883
     1884                void Eraser::premutate( FunctionDecl * functionDecl ) {
     1885                        ScrubTyVars::scrubAll( functionDecl );
     1886                }
     1887
     1888                void Eraser::premutate( TypedefDecl * typedefDecl ) {
     1889                        ScrubTyVars::scrubAll( typedefDecl );
    19051890                }
    19061891
    19071892                /// Strips the members from a generic aggregate
    1908                 void stripGenericMembers(AggregateDecl * decl) {
     1893                static void stripGenericMembers( AggregateDecl * decl ) {
    19091894                        if ( ! decl->parameters.empty() ) decl->members.clear();
    19101895                }
    19111896
    1912                 void Pass3::premutate( StructDecl * structDecl ) {
     1897                void Eraser::premutate( StructDecl * structDecl ) {
    19131898                        stripGenericMembers( structDecl );
    19141899                }
    19151900
    1916                 void Pass3::premutate( UnionDecl * unionDecl ) {
     1901                void Eraser::premutate( UnionDecl * unionDecl ) {
    19171902                        stripGenericMembers( unionDecl );
    1918                 }
    1919 
    1920                 void Pass3::premutate( TypeDecl * typeDecl ) {
    1921                         addToTyVarMap( typeDecl, scopeTyVars );
    1922                 }
    1923 
    1924                 void Pass3::premutate( PointerType * pointerType ) {
    1925                         GuardScope( scopeTyVars );
    1926                         makeTyVarMap( pointerType, scopeTyVars );
    1927                 }
    1928 
    1929                 void Pass3::premutate( FunctionType * functionType ) {
    1930                         GuardScope( scopeTyVars );
    1931                         makeTyVarMap( functionType, scopeTyVars );
    19321903                }
    19331904        } // anonymous namespace
     
    19391910// compile-command: "make install" //
    19401911// End: //
    1941 
  • src/GenPoly/ErasableScopedMap.h

    r34b4268 r24d6572  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // ScopedMap.h --
     7// ErasableScopedMap.h --
    88//
    99// Author           : Aaron B. Moss
     
    5151        typedef typename Scope::const_pointer const_pointer;
    5252
    53         // Both iterator types are complete bidirection iterators, defined below.
     53        // Both iterator types are complete bidirectional iterators, see below.
    5454        class iterator;
    5555        class const_iterator;
     
    118118        std::pair< iterator, bool > insert( const Key &key, const Value &value ) { return insert( std::make_pair( key, value ) ); }
    119119
     120        Value& operator[] ( const Key &key ) {
     121                iterator slot = find( key );
     122                if ( slot != end() ) return slot->second;
     123                return insert( key, Value() ).first->second;
     124        }
     125
    120126        /// Marks the given element as erased from this scope inward; returns 1 for erased an element, 0 otherwise
    121127        size_type erase( const Key &key ) {
     
    130136        }
    131137
    132         Value& operator[] ( const Key &key ) {
    133                 iterator slot = find( key );
    134                 if ( slot != end() ) return slot->second;
    135                 return insert( key, Value() ).first->second;
     138        bool contains( const Key & key ) const {
     139                return find( key ) != cend();
    136140        }
    137141};
  • src/GenPoly/FindFunction.cc

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

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

    r34b4268 r24d6572  
    2424#include <vector>                       // for vector
    2525
     26#include "AST/Expr.hpp"
    2627#include "AST/Type.hpp"
     28#include "AST/TypeSubstitution.hpp"
    2729#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it...
    2830#include "ResolvExpr/typeops.h"         // for flatten
     
    170172
    171173                if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    172                         if ( tyVars.find( typeInst->get_name() ) != tyVars.end() ) {
     174                        if ( tyVars.contains( typeInst->get_name() ) ) {
    173175                                return type;
    174176                        }
     
    187189
    188190                if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    189                         return tyVars.find(typeInst->typeString()) != tyVars.end() ? type : nullptr;
     191                        if ( tyVars.contains( typeInst->typeString() ) ) return type;
    190192                } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    191193                        return isPolyType( arrayType->base, env );
     
    203205
    204206        if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    205                 if ( typeVars.find( *inst ) != typeVars.end() ) return type;
     207                if ( typeVars.contains( *inst ) ) return type;
    206208        } else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) {
    207209                return isPolyType( array->base, subst );
     
    272274                return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
    273275        }
     276
     277const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) {
     278        if ( func->returns.empty() ) return nullptr;
     279
     280        TypeVarMap forallTypes = { ast::TypeData() };
     281        makeTypeVarMap( func, forallTypes );
     282        return isDynType( func->returns.front(), forallTypes );
     283}
    274284
    275285        bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {
     
    317327                return 0;
    318328        }
     329
     330const ast::Type * isPolyPtr(
     331                const ast::Type * type, const TypeVarMap & typeVars,
     332                const ast::TypeSubstitution * typeSubs ) {
     333        type = replaceTypeInst( type, typeSubs );
     334
     335        if ( auto * ptr = dynamic_cast<ast::PointerType const *>( type ) ) {
     336                return isPolyType( ptr->base, typeVars, typeSubs );
     337        }
     338        return nullptr;
     339}
    319340
    320341        Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {
     
    391412
    392413                if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) {
    393                         if ( tyVars.find( typeInstType->get_name() ) != tyVars.end() ) {
     414                        if ( tyVars.contains( typeInstType->get_name() ) ) {
    394415                                return true;
    395416                        }
     
    490511                }
    491512
     513                /// Flattens a list of types.
     514                // There is another flattenList in Unify.
    492515                void flattenList( vector<ast::ptr<ast::Type>> const & src,
    493516                                vector<ast::ptr<ast::Type>> & out ) {
     
    792815        }
    793816
     817void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) {
     818        typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) );
     819}
     820
    794821void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
    795         typeVars.insert( *type, ast::TypeData( type->base ) );
     822        typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) );
    796823}
    797824
     
    818845}
    819846
     847void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ) {
     848        for ( auto & typeDecl : decl->type_params ) {
     849                addToTypeVarMap( typeDecl, typeVars );
     850        }
     851}
     852
    820853        void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
    821854                for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {
  • src/GenPoly/GenPoly.h

    r34b4268 r24d6572  
    111111        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );
    112112        void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars );
     113        void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars );
    113114
    114115        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    115116        void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
    116117        void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
     118        void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars );
    117119
    118120        /// Prints type variable map
  • src/GenPoly/InstantiateGeneric.cc

    r34b4268 r24d6572  
    2828#include "GenPoly.h"                   // for isPolyType, typesPolyCompatible
    2929#include "InitTweak/InitTweak.h"
    30 #include "ResolvExpr/typeops.h"
     30#include "ResolvExpr/AdjustExprType.hpp"  // for adjustExprType
     31#include "ResolvExpr/Unify.h"          // for typesCompatible
    3132#include "ScopedSet.h"                 // for ScopedSet, ScopedSet<>::iterator
    3233#include "ScrubTyVars.h"               // for ScrubTyVars
  • src/GenPoly/InstantiateGenericNew.cpp

    r34b4268 r24d6572  
    3232#include "GenPoly/GenPoly.h"           // for isPolyType, typesPolyCompatible
    3333#include "GenPoly/ScrubTyVars.h"       // for scrubAll
    34 #include "ResolvExpr/typeops.h"        // for typesCompatible
     34#include "ResolvExpr/AdjustExprType.hpp"  // for adjustExprType
     35#include "ResolvExpr/Unify.h"          // for typesCompatible
    3536
    3637namespace GenPoly {
     
    361362                        ResolvExpr::typesCompatible(
    362363                                memberExpr->result,
    363                                 memberExpr->member->get_type(), ast::SymbolTable() ) ) {
     364                                memberExpr->member->get_type() ) ) {
    364365                return memberExpr;
    365366        }
  • src/GenPoly/Lvalue.cc

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

    r34b4268 r24d6572  
    2525#include "AST/Pass.hpp"
    2626#include "Common/SemanticError.h"      // for SemanticWarning
     27#include "Common/ToString.hpp"         // for toCString
    2728#include "Common/UniqueName.h"         // for UniqueName
    2829#include "GenPoly/GenPoly.h"           // for genFunctionType
     
    358359                                !ResolvExpr::typesCompatible(
    359360                                        srcType,
    360                                         strict_dynamic_cast<ast::ReferenceType const *>( dstType )->base,
    361                                         ast::SymbolTable() ) ) {
     361                                        strict_dynamic_cast<ast::ReferenceType const *>( dstType )->base ) ) {
    362362                        // Must keep cast if cast-to type is different from the actual type.
    363363                        return ast::mutate_field( expr, &ast::CastExpr::arg, ret );
     
    376376                if ( !ResolvExpr::typesCompatibleIgnoreQualifiers(
    377377                                dstType->stripReferences(),
    378                                 srcType->stripReferences(),
    379                                 ast::SymbolTable() ) ) {
     378                                srcType->stripReferences() ) ) {
    380379                        return ast::mutate_field( expr, &ast::CastExpr::arg, ret );
    381380                }
     
    392391                                ResolvExpr::typesCompatible(
    393392                                        expr->result,
    394                                         expr->arg->result, ast::SymbolTable() ) ) {
     393                                        expr->arg->result ) ) {
    395394                        PRINT(
    396395                                std::cerr << "types are compatible, removing cast: " << expr << '\n';
     
    589588                ast::OpenVarSet openVars;
    590589                ResolvExpr::unify( ret->arg2->result, ret->arg3->result, newEnv,
    591                         needAssertions, haveAssertions, openVars,
    592                         ast::SymbolTable(), common );
     590                        needAssertions, haveAssertions, openVars, common );
    593591                ret->result = common ? common : ast::deepCopy( ret->arg2->result );
    594592                return ret;
  • src/GenPoly/ScopedSet.h

    r34b4268 r24d6572  
    2121
    2222namespace GenPoly {
    23         /// A set where the items are placed into nested scopes;
    24         /// inserted items are placed into the innermost scope, lookup looks from the innermost scope outward
    25         template<typename Value>
    26         class ScopedSet {
    27                 typedef std::set< Value > Scope;
    28                 typedef std::vector< Scope > ScopeList;
    29 
    30                 ScopeList scopes; ///< scoped list of sets
    31         public:
    32                 typedef typename Scope::key_type key_type;
    33                 typedef typename Scope::value_type value_type;
    34                 typedef typename ScopeList::size_type size_type;
    35                 typedef typename ScopeList::difference_type difference_type;
    36                 typedef typename Scope::reference reference;
    37                 typedef typename Scope::const_reference const_reference;
    38                 typedef typename Scope::pointer pointer;
    39                 typedef typename Scope::const_pointer const_pointer;
    40 
    41                 class iterator : public std::iterator< std::bidirectional_iterator_tag,
    42                                                        value_type > {
    43                 friend class ScopedSet;
    44                 friend class const_iterator;
    45                         typedef typename std::set< Value >::iterator wrapped_iterator;
    46                         typedef typename std::vector< std::set< Value > > scope_list;
    47                         typedef typename scope_list::size_type size_type;
    48 
    49                         /// Checks if this iterator points to a valid item
    50                         bool is_valid() const {
    51                                 return it != (*scopes)[i].end();
    52                         }
    53 
    54                         /// Increments on invalid
    55                         iterator& next_valid() {
    56                                 if ( ! is_valid() ) { ++(*this); }
    57                                 return *this;
    58                         }
    59 
    60                         /// Decrements on invalid
    61                         iterator& prev_valid() {
    62                                 if ( ! is_valid() ) { --(*this); }
    63                                 return *this;
    64                         }
    65 
    66                         iterator(scope_list const &_scopes, const wrapped_iterator &_it, size_type _i)
    67                                 : scopes(&_scopes), it(_it), i(_i) {}
    68                 public:
    69                         iterator(const iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
    70                         iterator& operator= (const iterator &that) {
    71                                 scopes = that.scopes; i = that.i; it = that.it;
    72                                 return *this;
    73                         }
    74 
    75                         reference operator* () { return *it; }
    76                         pointer operator-> () { return it.operator->(); }
    77 
    78                         iterator& operator++ () {
    79                                 if ( it == (*scopes)[i].end() ) {
    80                                         if ( i == 0 ) return *this;
    81                                         --i;
    82                                         it = (*scopes)[i].begin();
    83                                 } else {
    84                                         ++it;
    85                                 }
    86                                 return next_valid();
    87                         }
    88                         iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
    89 
    90                         iterator& operator-- () {
    91                                 // may fail if this is the begin iterator; allowed by STL spec
    92                                 if ( it == (*scopes)[i].begin() ) {
    93                                         ++i;
    94                                         it = (*scopes)[i].end();
    95                                 }
    96                                 --it;
    97                                 return prev_valid();
    98                         }
    99                         iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
    100 
    101                         bool operator== (const iterator &that) {
    102                                 return scopes == that.scopes && i == that.i && it == that.it;
    103                         }
    104                         bool operator!= (const iterator &that) { return !( *this == that ); }
    105 
    106                         size_type get_level() const { return i; }
    107 
    108                 private:
    109                         scope_list const *scopes;
    110                         wrapped_iterator it;
    111                         size_type i;
    112                 };
    113 
    114                 class const_iterator : public std::iterator< std::bidirectional_iterator_tag,
    115                                                              value_type > {
    116                 friend class ScopedSet;
    117                         typedef typename std::set< Value >::iterator wrapped_iterator;
    118                         typedef typename std::set< Value >::const_iterator wrapped_const_iterator;
    119                         typedef typename std::vector< std::set< Value > > scope_list;
    120                         typedef typename scope_list::size_type size_type;
    121 
    122                         /// Checks if this iterator points to a valid item
    123                         bool is_valid() const {
    124                                 return it != (*scopes)[i].end();
    125                         }
    126 
    127                         /// Increments on invalid
    128                         const_iterator& next_valid() {
    129                                 if ( ! is_valid() ) { ++(*this); }
    130                                 return *this;
    131                         }
    132 
    133                         /// Decrements on invalid
    134                         const_iterator& prev_valid() {
    135                                 if ( ! is_valid() ) { --(*this); }
    136                                 return *this;
    137                         }
    138 
    139                         const_iterator(scope_list const &_scopes, const wrapped_const_iterator &_it, size_type _i)
    140                                 : scopes(&_scopes), it(_it), i(_i) {}
    141                 public:
    142                         const_iterator(const iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
    143                         const_iterator(const const_iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
    144                         const_iterator& operator= (const iterator &that) {
    145                                 scopes = that.scopes; i = that.i; it = that.it;
    146                                 return *this;
    147                         }
    148                         const_iterator& operator= (const const_iterator &that) {
    149                                 scopes = that.scopes; i = that.i; it = that.it;
    150                                 return *this;
    151                         }
    152 
    153                         const_reference operator* () { return *it; }
    154                         const_pointer operator-> () { return it.operator->(); }
    155 
    156                         const_iterator& operator++ () {
    157                                 if ( it == (*scopes)[i].end() ) {
    158                                         if ( i == 0 ) return *this;
    159                                         --i;
    160                                         it = (*scopes)[i].begin();
    161                                 } else {
    162                                         ++it;
    163                                 }
    164                                 return next_valid();
    165                         }
    166                         const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
    167 
    168                         const_iterator& operator-- () {
    169                                 // may fail if this is the begin iterator; allowed by STL spec
    170                                 if ( it == (*scopes)[i].begin() ) {
    171                                         ++i;
    172                                         it = (*scopes)[i].end();
    173                                 }
    174                                 --it;
    175                                 return prev_valid();
    176                         }
    177                         const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
    178 
    179                         bool operator== (const const_iterator &that) {
    180                                 return scopes == that.scopes && i == that.i && it == that.it;
    181                         }
    182                         bool operator!= (const const_iterator &that) { return !( *this == that ); }
    183 
    184                         size_type get_level() const { return i; }
    185 
    186                 private:
    187                         scope_list const *scopes;
    188                         wrapped_const_iterator it;
    189                         size_type i;
    190                 };
    191 
    192                 /// Starts a new scope
    193                 void beginScope() {
    194                         Scope scope;
    195                         scopes.push_back(scope);
    196                 }
    197 
    198                 /// Ends a scope; invalidates any iterators pointing to elements of that scope
    199                 void endScope() {
    200                         scopes.pop_back();
    201                 }
    202 
    203                 /// Default constructor initializes with one scope
    204                 ScopedSet() { beginScope(); }
    205 
    206                 iterator begin() { return iterator(scopes, scopes.back().begin(), scopes.size()-1).next_valid(); }
    207                 const_iterator begin() const { return const_iterator(scopes, scopes.back().begin(), scopes.size()-1).next_valid(); }
    208                 const_iterator cbegin() const { return const_iterator(scopes, scopes.back().begin(), scopes.size()-1).next_valid(); }
    209                 iterator end() { return iterator(scopes, scopes[0].end(), 0); }
    210                 const_iterator end() const { return const_iterator(scopes, scopes[0].end(), 0); }
    211                 const_iterator cend() const { return const_iterator(scopes, scopes[0].end(), 0); }
    212 
    213                 /// Gets the index of the current scope (counted from 1)
    214                 size_type currentScope() const { return scopes.size(); }
    215 
    216                 /// Finds the given key in the outermost scope it occurs; returns end() for none such
    217                 iterator find( const Value &key ) {
    218                         for ( size_type i = scopes.size() - 1; ; --i ) {
    219                                 typename Scope::iterator val = scopes[i].find( key );
    220                                 if ( val != scopes[i].end() ) return iterator( scopes, val, i );
    221                                 if ( i == 0 ) break;
    222                         }
    223                         return end();
    224                 }
    225                 const_iterator find( const Value &key ) const {
    226                         return const_iterator( const_cast< ScopedSet< Value >* >(this)->find( key ) );
    227                 }
    228 
    229                 /// Finds the given key in the outermost scope inside the given scope where it occurs
    230                 iterator findNext( const_iterator &it, const Value &key ) {
    231                         if ( it.i == 0 ) return end();
     23
     24/// A set where the items are placed into nested scopes;
     25/// inserted items are placed into the innermost scope, lookup looks from the innermost scope outward
     26template<typename Value>
     27class ScopedSet {
     28        typedef std::set< Value > Scope;
     29        typedef std::vector< Scope > ScopeList;
     30
     31        /// Scoped list of sets.
     32        ScopeList scopes;
     33public:
     34        typedef typename Scope::key_type key_type;
     35        typedef typename Scope::value_type value_type;
     36        typedef typename ScopeList::size_type size_type;
     37        typedef typename ScopeList::difference_type difference_type;
     38        typedef typename Scope::reference reference;
     39        typedef typename Scope::const_reference const_reference;
     40        typedef typename Scope::pointer pointer;
     41        typedef typename Scope::const_pointer const_pointer;
     42
     43        // Both iterator types are complete bidirectional iterators, see below.
     44        class iterator;
     45        class const_iterator;
     46
     47        /// Starts a new scope
     48        void beginScope() {
     49                Scope scope;
     50                scopes.push_back(scope);
     51        }
     52
     53        /// Ends a scope; invalidates any iterators pointing to elements of that scope
     54        void endScope() {
     55                scopes.pop_back();
     56        }
     57
     58        /// Default constructor initializes with one scope
     59        ScopedSet() { beginScope(); }
     60
     61        iterator begin() { return iterator(scopes, scopes.back().begin(), scopes.size()-1).next_valid(); }
     62        const_iterator begin() const { return const_iterator(scopes, scopes.back().begin(), scopes.size()-1).next_valid(); }
     63        const_iterator cbegin() const { return const_iterator(scopes, scopes.back().begin(), scopes.size()-1).next_valid(); }
     64        iterator end() { return iterator(scopes, scopes[0].end(), 0); }
     65        const_iterator end() const { return const_iterator(scopes, scopes[0].end(), 0); }
     66        const_iterator cend() const { return const_iterator(scopes, scopes[0].end(), 0); }
     67
     68        /// Gets the index of the current scope (counted from 1)
     69        size_type currentScope() const { return scopes.size(); }
     70
     71        /// Finds the given key in the outermost scope it occurs; returns end() for none such
     72        iterator find( const Value &key ) {
     73                for ( size_type i = scopes.size() - 1; ; --i ) {
     74                        typename Scope::iterator val = scopes[i].find( key );
     75                        if ( val != scopes[i].end() ) return iterator( scopes, val, i );
     76                        if ( i == 0 ) break;
     77                }
     78                return end();
     79        }
     80        const_iterator find( const Value &key ) const {
     81                return const_iterator( const_cast< ScopedSet< Value >* >(this)->find( key ) );
     82        }
     83
     84        /// Finds the given key in the outermost scope inside the given scope where it occurs
     85        iterator findNext( const_iterator &it, const Value &key ) {
     86                if ( it.i == 0 ) return end();
    23287                        for ( size_type i = it.i - 1; ; --i ) {
    233                                 typename Scope::iterator val = scopes[i].find( key );
    234                                 if ( val != scopes[i].end() ) return iterator( scopes, val, i );
    235                                 if ( i == 0 ) break;
    236                         }
    237                         return end();
    238                 }
    239                 const_iterator findNext( const_iterator &it, const Value &key ) const {
    240                         return const_iterator( const_cast< ScopedSet< Value >* >(this)->findNext( it, key ) );
    241                 }
    242 
    243                 /// Inserts the given value into the outermost scope
    244                 std::pair< iterator, bool > insert( const value_type &value ) {
    245                         std::pair< typename Scope::iterator, bool > res = scopes.back().insert( value );
    246                         return std::make_pair( iterator(scopes, res.first, scopes.size()-1), res.second );
    247                 }
    248 
    249         };
     88                        typename Scope::iterator val = scopes[i].find( key );
     89                        if ( val != scopes[i].end() ) return iterator( scopes, val, i );
     90                        if ( i == 0 ) break;
     91                }
     92                return end();
     93        }
     94        const_iterator findNext( const_iterator &it, const Value &key ) const {
     95                return const_iterator( const_cast< ScopedSet< Value >* >(this)->findNext( it, key ) );
     96        }
     97
     98        /// Inserts the given value into the outermost scope
     99        std::pair< iterator, bool > insert( const value_type &value ) {
     100                std::pair< typename Scope::iterator, bool > res = scopes.back().insert( value );
     101                return std::make_pair( iterator(scopes, res.first, scopes.size()-1), res.second );
     102        }
     103
     104        bool contains( const Value & key ) const {
     105                return find( key ) != cend();
     106        }
     107};
     108
     109template<typename Value>
     110class ScopedSet<Value>::iterator :
     111                public std::iterator< std::bidirectional_iterator_tag, value_type > {
     112        friend class ScopedSet;
     113        friend class const_iterator;
     114        typedef typename std::set< Value >::iterator wrapped_iterator;
     115        typedef typename std::vector< std::set< Value > > scope_list;
     116        typedef typename scope_list::size_type size_type;
     117
     118        /// Checks if this iterator points to a valid item
     119        bool is_valid() const {
     120                return it != (*scopes)[i].end();
     121        }
     122
     123        /// Increments on invalid
     124        iterator& next_valid() {
     125                if ( ! is_valid() ) { ++(*this); }
     126                return *this;
     127        }
     128
     129        /// Decrements on invalid
     130        iterator& prev_valid() {
     131                if ( ! is_valid() ) { --(*this); }
     132                return *this;
     133        }
     134
     135        iterator(scope_list const &_scopes, const wrapped_iterator &_it, size_type _i)
     136                : scopes(&_scopes), it(_it), i(_i) {}
     137public:
     138        iterator(const iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
     139        iterator& operator= (const iterator &that) {
     140                scopes = that.scopes; i = that.i; it = that.it;
     141                return *this;
     142        }
     143
     144        reference operator* () { return *it; }
     145        pointer operator-> () { return it.operator->(); }
     146
     147        iterator& operator++ () {
     148                if ( it == (*scopes)[i].end() ) {
     149                        if ( i == 0 ) return *this;
     150                        --i;
     151                        it = (*scopes)[i].begin();
     152                } else {
     153                        ++it;
     154                }
     155                return next_valid();
     156        }
     157        iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
     158
     159        iterator& operator-- () {
     160                // may fail if this is the begin iterator; allowed by STL spec
     161                if ( it == (*scopes)[i].begin() ) {
     162                        ++i;
     163                        it = (*scopes)[i].end();
     164                }
     165                --it;
     166                return prev_valid();
     167        }
     168        iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
     169
     170        bool operator== (const iterator &that) {
     171                return scopes == that.scopes && i == that.i && it == that.it;
     172        }
     173        bool operator!= (const iterator &that) { return !( *this == that ); }
     174
     175        size_type get_level() const { return i; }
     176
     177private:
     178        scope_list const *scopes;
     179        wrapped_iterator it;
     180        size_type i;
     181};
     182
     183template<typename Value>
     184class ScopedSet<Value>::const_iterator :
     185                public std::iterator< std::bidirectional_iterator_tag, value_type > {
     186        friend class ScopedSet;
     187        typedef typename std::set< Value >::iterator wrapped_iterator;
     188        typedef typename std::set< Value >::const_iterator wrapped_const_iterator;
     189        typedef typename std::vector< std::set< Value > > scope_list;
     190        typedef typename scope_list::size_type size_type;
     191
     192        /// Checks if this iterator points to a valid item
     193        bool is_valid() const {
     194                return it != (*scopes)[i].end();
     195        }
     196
     197        /// Increments on invalid
     198        const_iterator& next_valid() {
     199                if ( ! is_valid() ) { ++(*this); }
     200                return *this;
     201        }
     202
     203        /// Decrements on invalid
     204        const_iterator& prev_valid() {
     205                if ( ! is_valid() ) { --(*this); }
     206                return *this;
     207        }
     208
     209        const_iterator(scope_list const &_scopes, const wrapped_const_iterator &_it, size_type _i)
     210                : scopes(&_scopes), it(_it), i(_i) {}
     211public:
     212        const_iterator(const iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
     213        const_iterator(const const_iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
     214        const_iterator& operator= (const iterator &that) {
     215                scopes = that.scopes; i = that.i; it = that.it;
     216                return *this;
     217        }
     218        const_iterator& operator= (const const_iterator &that) {
     219                scopes = that.scopes; i = that.i; it = that.it;
     220                return *this;
     221        }
     222
     223        const_reference operator* () { return *it; }
     224        const_pointer operator-> () { return it.operator->(); }
     225
     226        const_iterator& operator++ () {
     227                if ( it == (*scopes)[i].end() ) {
     228                        if ( i == 0 ) return *this;
     229                        --i;
     230                        it = (*scopes)[i].begin();
     231                } else {
     232                        ++it;
     233                }
     234                return next_valid();
     235        }
     236        const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
     237
     238        const_iterator& operator-- () {
     239                // may fail if this is the begin iterator; allowed by STL spec
     240                if ( it == (*scopes)[i].begin() ) {
     241                        ++i;
     242                        it = (*scopes)[i].end();
     243                }
     244                --it;
     245                return prev_valid();
     246        }
     247        const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
     248
     249        bool operator== (const const_iterator &that) {
     250                return scopes == that.scopes && i == that.i && it == that.it;
     251        }
     252        bool operator!= (const const_iterator &that) { return !( *this == that ); }
     253
     254        size_type get_level() const { return i; }
     255
     256private:
     257        scope_list const *scopes;
     258        wrapped_const_iterator it;
     259        size_type i;
     260};
     261
    250262} // namespace GenPoly
    251263
  • src/GenPoly/ScrubTyVars.cc

    r34b4268 r24d6572  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct  7 15:42:00 2022
    13 // Update Count     : 5
     12// Last Modified On : Wed Dec  7 17:01:00 2022
     13// Update Count     : 6
    1414//
    1515
     
    117117namespace {
    118118
    119 enum class ScrubMode {
    120         FromMap,
    121         DynamicFromMap,
    122         All,
    123 };
    124 
    125119struct ScrubTypeVars :
    126120        public ast::WithGuards,
     
    184178
    185179ast::Type const * ScrubTypeVars::postvisit( ast::TypeInstType const * type ) {
     180        ast::TypeDecl::Kind kind;
    186181        // This implies that mode == ScrubMode::All.
    187182        if ( !typeVars ) {
    188                 if ( ast::TypeDecl::Ftype == type->kind ) {
    189                         return new ast::PointerType(
    190                                 new ast::FunctionType( ast::FixedArgs ) );
    191                 } else {
    192                         return new ast::PointerType(
    193                                 new ast::VoidType( type->qualifiers ) );
    194                 }
    195         }
    196 
    197         auto typeVar = typeVars->find( *type );
    198         if ( typeVar == typeVars->end() ) {
    199                 return type;
    200         }
    201 
    202         switch ( typeVar->second.kind ) {
    203         case ::TypeDecl::Dtype:
    204         case ::TypeDecl::Ttype:
     183                kind = type->kind;
     184        } else {
     185                // Otherwise, only scrub the type var if it is in map.
     186                auto typeVar = typeVars->find( *type );
     187                if ( typeVar == typeVars->end() ) {
     188                        return type;
     189                }
     190                kind = typeVar->second.kind;
     191        }
     192
     193        switch ( kind ) {
     194        case ast::TypeDecl::Dtype:
     195        case ast::TypeDecl::Ttype:
    205196                return new ast::PointerType(
    206197                        new ast::VoidType( type->qualifiers ) );
    207         case ::TypeDecl::Ftype:
     198        case ast::TypeDecl::Ftype:
    208199                return new ast::PointerType(
    209200                        new ast::FunctionType( ast::VariableArgs ) );
    210201        default:
    211                 assertf( false,
    212                         "Unhandled type variable kind: %d", typeVar->second.kind );
     202                assertf( false, "Unhandled type variable kind: %d", kind );
    213203                throw; // Just in case the assert is removed, stop here.
    214204        }
     
    253243}
    254244
     245} // namespace
     246
    255247const ast::Node * scrubTypeVarsBase(
    256                 const ast::Node * target,
    257                 ScrubMode mode, const TypeVarMap * typeVars ) {
     248                const ast::Node * node, const TypeVarMap * typeVars, ScrubMode mode ) {
    258249        if ( ScrubMode::All == mode ) {
    259250                assert( nullptr == typeVars );
     
    262253        }
    263254        ast::Pass<ScrubTypeVars> visitor( mode, typeVars );
    264         return target->accept( visitor );
    265 }
    266 
    267 } // namespace
    268 
    269 template<>
    270 ast::Node const * scrubTypeVars<ast::Node>(
    271         const ast::Node * target, const TypeVarMap & typeVars ) {
    272         return scrubTypeVarsBase( target, ScrubMode::FromMap, &typeVars );
    273 }
    274 
    275 template<>
    276 ast::Node const * scrubTypeVarsDynamic<ast::Node>(
    277         ast::Node const * target, const TypeVarMap & typeVars ) {
    278         return scrubTypeVarsBase( target, ScrubMode::DynamicFromMap, &typeVars );
    279 }
    280 
    281 template<>
    282 ast::Node const * scrubAllTypeVars<ast::Node>( const ast::Node * target ) {
    283         return scrubTypeVarsBase( target, ScrubMode::All, nullptr );
     255        return node->accept( visitor );
    284256}
    285257
  • src/GenPoly/ScrubTyVars.h

    r34b4268 r24d6572  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct  7 15:51:00 2022
    13 // Update Count     : 4
     12// Last Modified On : Wed Dec  7 16:57:00 2022
     13// Update Count     : 5
    1414//
    1515
     
    109109        }
    110110
     111// ScrubMode and scrubTypeVarsBase are internal.
     112enum class ScrubMode { FromMap, DynamicFromMap, All };
     113
     114const ast::Node * scrubTypeVarsBase(
     115        const ast::Node * target, const TypeVarMap * typeVars, ScrubMode mode );
     116
     117
    111118/// For all polymorphic types with type variables in `typeVars`,
    112119/// replaces generic types, dtypes, and ftypes with the appropriate void type,
     
    116123                node_t const * target, const TypeVarMap & typeVars ) {
    117124        return strict_dynamic_cast<node_t const *>(
    118                         scrubTypeVars<ast::Node>( target, typeVars ) );
     125                        scrubTypeVarsBase( target, &typeVars, ScrubMode::FromMap ) );
    119126}
    120127
     
    123130/// and sizeof/alignof expressions with the proper variable.
    124131template<typename node_t>
    125 ast::Node const * scrubTypeVarsDynamic(
     132node_t const * scrubTypeVarsDynamic(
    126133                node_t const * target, const TypeVarMap & typeVars ) {
    127134        return strict_dynamic_cast<node_t const *>(
    128                         scrubTypeVarsDynamic<ast::Node>( target, typeVars ) );
     135                        scrubTypeVarsBase( target, &typeVars, ScrubMode::DynamicFromMap ) );
    129136}
    130137
     
    134141node_t const * scrubAllTypeVars( node_t const * target ) {
    135142        return strict_dynamic_cast<node_t const *>(
    136                         scrubAllTypeVars<ast::Node>( target ) );
     143                        scrubTypeVarsBase( target, nullptr, ScrubMode::All ) );
    137144}
    138 
    139 // We specialize for Node as a base case.
    140 template<>
    141 ast::Node const * scrubTypeVars<ast::Node>(
    142                 const ast::Node * target, const TypeVarMap & typeVars );
    143 
    144 template<>
    145 ast::Node const * scrubTypeVarsDynamic<ast::Node>(
    146                 ast::Node const * target, const TypeVarMap & typeVars );
    147 
    148 template<>
    149 ast::Node const * scrubAllTypeVars<ast::Node>( const ast::Node * target );
    150145
    151146} // namespace GenPoly
  • src/GenPoly/SpecializeNew.cpp

    r34b4268 r24d6572  
    1616#include "Specialize.h"
    1717
     18#include "AST/Copy.hpp"                  // for deepCopy
    1819#include "AST/Inspect.hpp"               // for isIntrinsicCallExpr
    1920#include "AST/Pass.hpp"                  // for Pass
  • src/InitTweak/FixInit.cc

    r34b4268 r24d6572  
    3232#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    3333#include "Common/SemanticError.h"      // for SemanticError
     34#include "Common/ToString.hpp"         // for toCString
    3435#include "Common/UniqueName.h"         // for UniqueName
    35 #include "Common/utility.h"            // for CodeLocation, ValueGuard, toSt...
    3636#include "FixGlobalInit.h"             // for fixGlobalInit
    3737#include "GenInit.h"                   // for genCtorDtor
     
    3939#include "InitTweak.h"                 // for getFunctionName, getCallArg
    4040#include "ResolvExpr/Resolver.h"       // for findVoidExpression
    41 #include "ResolvExpr/typeops.h"        // for typesCompatible
     41#include "ResolvExpr/Unify.h"          // for typesCompatible
    4242#include "SymTab/Autogen.h"            // for genImplicitCall
    4343#include "SymTab/Indexer.h"            // for Indexer
     
    12331233                }
    12341234
    1235                 template< typename Visitor, typename... Params >
    1236                 void error( Visitor & v, CodeLocation loc, const Params &... params ) {
    1237                         SemanticErrorException err( loc, toString( params... ) );
    1238                         v.errors.append( err );
    1239                 }
    1240 
    12411235                template< typename... Params >
    12421236                void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
    1243                         // toggle warnings vs. errors here.
    1244                         // warn( params... );
    1245                         error( *this, loc, params... );
     1237                        SemanticErrorException err( loc, toString( params... ) );
     1238                        errors.append( err );
    12461239                }
    12471240
  • src/InitTweak/FixInitNew.cpp

    r34b4268 r24d6572  
    1414#include <utility>                     // for pair
    1515
     16#include "AST/DeclReplacer.hpp"
     17#include "AST/Expr.hpp"
    1618#include "AST/Inspect.hpp"             // for getFunction, getPointerBase, g...
     19#include "AST/Node.hpp"
     20#include "AST/Pass.hpp"
     21#include "AST/Print.hpp"
     22#include "AST/SymbolTable.hpp"
     23#include "AST/Type.hpp"
    1724#include "CodeGen/GenType.h"           // for genPrettyType
    1825#include "CodeGen/OperatorTable.h"
    19 #include "Common/CodeLocationTools.hpp"
    2026#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    2127#include "Common/SemanticError.h"      // for SemanticError
     28#include "Common/ToString.hpp"         // for toCString
    2229#include "Common/UniqueName.h"         // for UniqueName
    23 #include "Common/utility.h"            // for CodeLocation, ValueGuard, toSt...
    2430#include "FixGlobalInit.h"             // for fixGlobalInit
    2531#include "GenInit.h"                   // for genCtorDtor
    2632#include "GenPoly/GenPoly.h"           // for getFunctionType
    2733#include "ResolvExpr/Resolver.h"       // for findVoidExpression
    28 #include "ResolvExpr/typeops.h"        // for typesCompatible
     34#include "ResolvExpr/Unify.h"          // for typesCompatible
    2935#include "SymTab/Autogen.h"            // for genImplicitCall
     36#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3037#include "SymTab/Indexer.h"            // for Indexer
    3138#include "SymTab/Mangler.h"            // for Mangler
     
    4552#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    4653
    47 #include "AST/Expr.hpp"
    48 #include "AST/Node.hpp"
    49 #include "AST/Pass.hpp"
    50 #include "AST/Print.hpp"
    51 #include "AST/SymbolTable.hpp"
    52 #include "AST/Type.hpp"
    53 #include "AST/DeclReplacer.hpp"
    54 
    5554extern bool ctordtorp; // print all debug
    5655extern bool ctorp; // print ctor debug
     
    6362namespace InitTweak {
    6463namespace {
     64
     65        // Shallow copy the pointer list for return.
     66        std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) {
     67                if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
     68                        return inst->base->params;
     69                }
     70                if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
     71                        return inst->base->params;
     72                }
     73                return {};
     74        }
     75
     76        /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
     77        ast::FunctionDecl * genDefaultFunc(
     78                        const CodeLocation loc,
     79                        const std::string fname,
     80                        const ast::Type * paramType,
     81                        bool maybePolymorphic = true) {
     82                std::vector<ast::ptr<ast::TypeDecl>> typeParams;
     83                if ( maybePolymorphic ) typeParams = getGenericParams( paramType );
     84                auto dstParam = new ast::ObjectDecl( loc,
     85                        "_dst",
     86                        new ast::ReferenceType( paramType ),
     87                        nullptr,
     88                        {},
     89                        ast::Linkage::Cforall
     90                );
     91                return new ast::FunctionDecl( loc,
     92                        fname,
     93                        std::move(typeParams),
     94                        {dstParam},
     95                        {},
     96                        new ast::CompoundStmt(loc),
     97                        {},
     98                        ast::Linkage::Cforall
     99                );
     100        }
     101
    65102        struct SelfAssignChecker {
    66103                void previsit( const ast::ApplicationExpr * appExpr );
     
    107144        private:
    108145                /// hack to implement WithTypeSubstitution while conforming to mutation safety.
    109                 ast::TypeSubstitution * env;
    110                 bool                    envModified;
     146                ast::TypeSubstitution * env         = nullptr;
     147                bool                    envModified = false;
    111148        };
    112149
     
    121158                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    122159
    123           protected:
     160        protected:
    124161                ObjectSet curVars;
    125162        };
     
    202239
    203240                SemanticErrorException errors;
    204           private:
     241        private:
    205242                template< typename... Params >
    206243                void emit( CodeLocation, const Params &... params );
     
    288325                static UniqueName dtorNamer( "__cleanup_dtor" );
    289326                std::string name = dtorNamer.newName();
    290                 ast::FunctionDecl * dtorFunc = SymTab::genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
     327                ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
    291328                stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
    292329
     
    522559        {
    523560                static UniqueName tempNamer("_tmp_cp");
    524                 assert( env );
    525561                const CodeLocation loc = impCpCtorExpr->location;
    526562                // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )
     
    534570
    535571                // xxx - this originally mutates arg->result in place. is it correct?
     572                assert( env );
    536573                result = env->applyFree( result.get() ).node;
    537574                auto mutResult = result.get_and_mutate();
     
    10801117        void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
    10811118                switch( stmt->kind ) {
    1082                   case ast::BranchStmt::Continue:
    1083                   case ast::BranchStmt::Break:
     1119                case ast::BranchStmt::Continue:
     1120                case ast::BranchStmt::Break:
    10841121                        // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
    10851122                        // always be empty), but it serves as a small sanity check.
    1086                   case ast::BranchStmt::Goto:
     1123                case ast::BranchStmt::Goto:
    10871124                        handleGoto( stmt );
    10881125                        break;
    1089                   default:
     1126                default:
    10901127                        assert( false );
    10911128                } // switch
     
    13031340        }
    13041341
    1305         template< typename Visitor, typename... Params >
    1306         void error( Visitor & v, CodeLocation loc, const Params &... params ) {
    1307                 SemanticErrorException err( loc, toString( params... ) );
    1308                 v.errors.append( err );
    1309         }
    1310 
    13111342        template< typename... Params >
    13121343        void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
    1313                 // toggle warnings vs. errors here.
    1314                 // warn( params... );
    1315                 error( *this, loc, params... );
     1344                SemanticErrorException err( loc, toString( params... ) );
     1345                errors.append( err );
    13161346        }
    13171347
     
    13191349                // xxx - functions returning ast::ptr seems wrong...
    13201350                auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
    1321                 // Fix CodeLocation (at least until resolver is fixed).
    1322                 auto fix = localFillCodeLocations( untypedExpr->location, res.release() );
    1323                 return strict_dynamic_cast<const ast::Expr *>( fix );
     1351                return res.release();
    13241352        }
    13251353
  • src/InitTweak/GenInit.cc

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

    r34b4268 r24d6572  
    3535#include "GenPoly/GenPoly.h"       // for getFunctionType
    3636#include "InitTweak.h"
    37 #include "ResolvExpr/typeops.h"    // for typesCompatibleIgnoreQualifiers
     37#include "ResolvExpr/Unify.h"      // for typesCompatibleIgnoreQualifiers
    3838#include "SymTab/Autogen.h"
    3939#include "SymTab/Indexer.h"        // for Indexer
     
    10661066        const ast::Type * t2 = ftype->params.back();
    10671067
    1068         return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, ast::SymbolTable() );
     1068        return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
    10691069}
    10701070
  • src/MakeLibCfaNew.cpp

    r34b4268 r24d6572  
    1616#include "MakeLibCfa.h"
    1717
     18#include "AST/Copy.hpp"
    1819#include "AST/Fwd.hpp"
    1920#include "AST/Pass.hpp"
  • src/Parser/DeclarationNode.cc

    r34b4268 r24d6572  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 12:34:05 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug  8 17:07:00 2022
    13 // Update Count     : 1185
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Apr 20 11:46:00 2023
     13// Update Count     : 1393
    1414//
     15
     16#include "DeclarationNode.h"
    1517
    1618#include <cassert>                 // for assert, assertf, strict_dynamic_cast
     
    2123#include <string>                  // for string, operator+, allocator, char...
    2224
     25#include "AST/Attribute.hpp"       // for Attribute
     26#include "AST/Copy.hpp"            // for shallowCopy
     27#include "AST/Decl.hpp"            // for Decl
     28#include "AST/Expr.hpp"            // for Expr
     29#include "AST/Print.hpp"           // for print
     30#include "AST/Stmt.hpp"            // for AsmStmt, DirectiveStmt
     31#include "AST/StorageClasses.hpp"  // for Storage::Class
     32#include "AST/Type.hpp"            // for Type
     33#include "Common/CodeLocation.h"   // for CodeLocation
     34#include "Common/Iterate.hpp"      // for reverseIterate
    2335#include "Common/SemanticError.h"  // for SemanticError
    2436#include "Common/UniqueName.h"     // for UniqueName
    25 #include "Common/utility.h"        // for maybeClone, maybeBuild, CodeLocation
    26 #include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
    27 #include "SynTree/LinkageSpec.h"   // for Spec, linkageName, Cforall
    28 #include "SynTree/Attribute.h"     // for Attribute
    29 #include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, InlineMemberDecl, Declaration
    30 #include "SynTree/Expression.h"    // for Expression, ConstantExpr
    31 #include "SynTree/Statement.h"     // for AsmStmt
    32 #include "SynTree/Type.h"          // for Type, Type::StorageClasses, Type::...
     37#include "Common/utility.h"        // for maybeClone
     38#include "Parser/ExpressionNode.h" // for ExpressionNode
     39#include "Parser/InitializerNode.h"// for InitializerNode
     40#include "Parser/StatementNode.h"  // for StatementNode
    3341#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
    3442#include "TypedefTable.h"          // for TypedefTable
     
    4149
    4250// These must harmonize with the corresponding DeclarationNode enumerations.
    43 const char * DeclarationNode::basicTypeNames[] = { "void", "_Bool", "char", "int", "int128",
    44                                                                                                    "float", "double", "long double", "float80", "float128",
    45                                                                                                    "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames" };
    46 const char * DeclarationNode::complexTypeNames[] = { "_Complex", "NoComplexTypeNames", "_Imaginary" }; // Imaginary unsupported => parse, but make invisible and print error message
    47 const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" };
    48 const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" };
    49 const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" };
     51const char * DeclarationNode::basicTypeNames[] = {
     52        "void", "_Bool", "char", "int", "int128",
     53        "float", "double", "long double", "float80", "float128",
     54        "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames"
     55};
     56const char * DeclarationNode::complexTypeNames[] = {
     57        "_Complex", "NoComplexTypeNames", "_Imaginary"
     58}; // Imaginary unsupported => parse, but make invisible and print error message
     59const char * DeclarationNode::signednessNames[] = {
     60        "signed", "unsigned", "NoSignednessNames"
     61};
     62const char * DeclarationNode::lengthNames[] = {
     63        "short", "long", "long long", "NoLengthNames"
     64};
     65const char * DeclarationNode::builtinTypeNames[] = {
     66        "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames"
     67};
    5068
    5169UniqueName DeclarationNode::anonymous( "__anonymous" );
    5270
    53 extern LinkageSpec::Spec linkage;                                               // defined in parser.yy
     71extern ast::Linkage::Spec linkage;                                              // defined in parser.yy
    5472
    5573DeclarationNode::DeclarationNode() :
     
    5775
    5876//      variable.name = nullptr;
    59         variable.tyClass = TypeDecl::NUMBER_OF_KINDS;
     77        variable.tyClass = ast::TypeDecl::NUMBER_OF_KINDS;
    6078        variable.assertions = nullptr;
    6179        variable.initializer = nullptr;
    6280
    63 //      attr.name = nullptr;
    64         attr.expr = nullptr;
    65         attr.type = nullptr;
    66 
    6781        assert.condition = nullptr;
    6882        assert.message = nullptr;
     
    7084
    7185DeclarationNode::~DeclarationNode() {
    72 //      delete attr.name;
    73         delete attr.expr;
    74         delete attr.type;
    75 
    7686//      delete variable.name;
    7787        delete variable.assertions;
    7888        delete variable.initializer;
    7989
    80 //      delete type;
     90//      delete type;
    8191        delete bitfieldWidth;
    8292
     
    103113        newnode->hasEllipsis = hasEllipsis;
    104114        newnode->linkage = linkage;
    105         newnode->asmName = maybeClone( asmName );
    106         cloneAll( attributes, newnode->attributes );
     115        newnode->asmName = maybeCopy( asmName );
     116        newnode->attributes = attributes;
    107117        newnode->initializer = maybeClone( initializer );
    108118        newnode->extension = extension;
     
    115125        newnode->variable.initializer = maybeClone( variable.initializer );
    116126
    117 //      newnode->attr.name = attr.name ? new string( *attr.name ) : nullptr;
    118         newnode->attr.expr = maybeClone( attr.expr );
    119         newnode->attr.type = maybeClone( attr.type );
    120 
    121127        newnode->assert.condition = maybeClone( assert.condition );
    122         newnode->assert.message = maybeClone( assert.message );
     128        newnode->assert.message = maybeCopy( assert.message );
    123129        return newnode;
    124130} // DeclarationNode::clone
     
    130136        } // if
    131137
    132         if ( linkage != LinkageSpec::Cforall ) {
    133                 os << LinkageSpec::name( linkage ) << " ";
    134         } // if
    135 
    136         storageClasses.print( os );
    137         funcSpecs.print( os );
     138        if ( linkage != ast::Linkage::Cforall ) {
     139                os << ast::Linkage::name( linkage ) << " ";
     140        } // if
     141
     142        ast::print( os, storageClasses );
     143        ast::print( os, funcSpecs );
    138144
    139145        if ( type ) {
     
    154160        } // if
    155161
    156         for ( Attribute * attr: reverseIterate( attributes ) ) {
    157                 os << string( indent + 2, ' ' ) << "attr " << attr->name.c_str();
    158         } // for
     162        if ( ! attributes.empty() ) {
     163                os << string( indent + 2, ' ' ) << "with attributes " << endl;
     164                for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( attributes ) ) {
     165                        os << string( indent + 4, ' ' ) << attr->name.c_str() << endl;
     166                } // for
     167        } // if
    159168
    160169        os << endl;
     
    168177}
    169178
    170 DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) {
     179DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) {
    171180        DeclarationNode * newnode = new DeclarationNode;
    172181        newnode->storageClasses = sc;
     
    174183} // DeclarationNode::newStorageClass
    175184
    176 DeclarationNode * DeclarationNode::newFuncSpecifier( Type::FuncSpecifiers fs ) {
     185DeclarationNode * DeclarationNode::newFuncSpecifier( ast::Function::Specs fs ) {
    177186        DeclarationNode * newnode = new DeclarationNode;
    178187        newnode->funcSpecs = fs;
     
    180189} // DeclarationNode::newFuncSpecifier
    181190
    182 DeclarationNode * DeclarationNode::newTypeQualifier( Type::Qualifiers tq ) {
     191DeclarationNode * DeclarationNode::newTypeQualifier( ast::CV::Qualifiers tq ) {
    183192        DeclarationNode * newnode = new DeclarationNode;
    184193        newnode->type = new TypeData();
     
    240249}
    241250
    242 DeclarationNode * DeclarationNode::newAggregate( AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
     251DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
    243252        DeclarationNode * newnode = new DeclarationNode;
    244253        newnode->type = new TypeData( TypeData::Aggregate );
    245254        newnode->type->aggregate.kind = kind;
    246         newnode->type->aggregate.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
     255        newnode->type->aggregate.anon = name == nullptr;
     256        newnode->type->aggregate.name = newnode->type->aggregate.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
    247257        newnode->type->aggregate.actuals = actuals;
    248258        newnode->type->aggregate.fields = fields;
     
    250260        newnode->type->aggregate.tagged = false;
    251261        newnode->type->aggregate.parent = nullptr;
    252         newnode->type->aggregate.anon = name == nullptr;
    253262        return newnode;
    254263} // DeclarationNode::newAggregate
     
    257266        DeclarationNode * newnode = new DeclarationNode;
    258267        newnode->type = new TypeData( TypeData::Enum );
    259         newnode->type->enumeration.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
     268        newnode->type->enumeration.anon = name == nullptr;
     269        newnode->type->enumeration.name = newnode->type->enumeration.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
    260270        newnode->type->enumeration.constants = constants;
    261271        newnode->type->enumeration.body = body;
    262         newnode->type->enumeration.anon = name == nullptr;
    263272        newnode->type->enumeration.typed = typed;
    264273        newnode->type->enumeration.hiding = hiding;
    265         if ( base && base->type)  {
     274        if ( base && base->type )  {
    266275                newnode->type->base = base->type;
    267276        } // if
     
    269278        return newnode;
    270279} // DeclarationNode::newEnum
    271 
    272 
    273280
    274281DeclarationNode * DeclarationNode::newName( const string * name ) {
     
    323330} // DeclarationNode::newFromTypeGen
    324331
    325 DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {
     332DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) {
    326333        DeclarationNode * newnode = newName( name );
    327334        newnode->type = nullptr;
     
    335342        newnode->type = new TypeData( TypeData::Aggregate );
    336343        newnode->type->aggregate.name = name;
    337         newnode->type->aggregate.kind = AggregateDecl::Trait;
     344        newnode->type->aggregate.kind = ast::AggregateDecl::Trait;
    338345        newnode->type->aggregate.params = params;
    339346        newnode->type->aggregate.fields = asserts;
     
    345352        newnode->type = new TypeData( TypeData::AggregateInst );
    346353        newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
    347         newnode->type->aggInst.aggregate->aggregate.kind = AggregateDecl::Trait;
     354        newnode->type->aggInst.aggregate->aggregate.kind = ast::AggregateDecl::Trait;
    348355        newnode->type->aggInst.aggregate->aggregate.name = name;
    349356        newnode->type->aggInst.params = params;
     
    380387        newnode->type->array.dimension = size;
    381388        newnode->type->array.isStatic = isStatic;
    382         if ( newnode->type->array.dimension == nullptr || newnode->type->array.dimension->isExpressionType<ConstantExpr * >() ) {
     389        if ( newnode->type->array.dimension == nullptr || newnode->type->array.dimension->isExpressionType<ast::ConstantExpr *>() ) {
    383390                newnode->type->array.isVarLen = false;
    384391        } else {
     
    450457        DeclarationNode * newnode = new DeclarationNode;
    451458        newnode->type = nullptr;
    452         std::list< Expression * > exprs;
     459        std::vector<ast::ptr<ast::Expr>> exprs;
    453460        buildList( expr, exprs );
    454         newnode->attributes.push_back( new Attribute( *name, exprs ) );
     461        newnode->attributes.push_back(
     462                new ast::Attribute( *name, std::move( exprs ) ) );
    455463        delete name;
    456464        return newnode;
     
    469477}
    470478
    471 DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, Expression * message ) {
     479DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, ast::Expr * message ) {
    472480        DeclarationNode * newnode = new DeclarationNode;
    473481        newnode->assert.condition = condition;
     
    476484}
    477485
    478 
    479 void appendError( string & dst, const string & src ) {
     486static void appendError( string & dst, const string & src ) {
    480487        if ( src.empty() ) return;
    481488        if ( dst.empty() ) { dst = src; return; }
     
    484491
    485492void DeclarationNode::checkQualifiers( const TypeData * src, const TypeData * dst ) {
    486         const Type::Qualifiers qsrc = src->qualifiers, qdst = dst->qualifiers; // optimization
    487 
    488         if ( (qsrc & qdst).any() ) {                                            // duplicates ?
    489                 for ( unsigned int i = 0; i < Type::NumTypeQualifier; i += 1 ) { // find duplicates
    490                         if ( qsrc[i] && qdst[i] ) {
    491                                 appendError( error, string( "duplicate " ) + Type::QualifiersNames[i] );
    492                         } // if
    493                 } // for
     493        const ast::CV::Qualifiers qsrc = src->qualifiers, qdst = dst->qualifiers; // optimization
     494        const ast::CV::Qualifiers duplicates = qsrc & qdst;
     495
     496        if ( duplicates.any() ) {
     497                std::stringstream str;
     498                str << "duplicate ";
     499                ast::print( str, duplicates );
     500                str << "qualifier(s)";
     501                appendError( error, str.str() );
    494502        } // for
    495503} // DeclarationNode::checkQualifiers
    496504
    497505void DeclarationNode::checkSpecifiers( DeclarationNode * src ) {
    498         if ( (funcSpecs & src->funcSpecs).any() ) {                     // duplicates ?
    499                 for ( unsigned int i = 0; i < Type::NumFuncSpecifier; i += 1 ) { // find duplicates
    500                         if ( funcSpecs[i] && src->funcSpecs[i] ) {
    501                                 appendError( error, string( "duplicate " ) + Type::FuncSpecifiersNames[i] );
    502                         } // if
    503                 } // for
    504         } // if
    505 
    506         if ( storageClasses.any() && src->storageClasses.any() ) { // any reason to check ?
    507                 if ( (storageClasses & src->storageClasses ).any() ) { // duplicates ?
    508                         for ( unsigned int i = 0; i < Type::NumStorageClass; i += 1 ) { // find duplicates
    509                                 if ( storageClasses[i] && src->storageClasses[i] ) {
    510                                         appendError( error, string( "duplicate " ) + Type::StorageClassesNames[i] );
    511                                 } // if
    512                         } // for
    513                         // src is the new item being added and has a single bit
    514                 } else if ( ! src->storageClasses.is_threadlocal_any() ) { // conflict ?
    515                         appendError( error, string( "conflicting " ) + Type::StorageClassesNames[storageClasses.ffs()] +
    516                                                  " & " + Type::StorageClassesNames[src->storageClasses.ffs()] );
    517                         src->storageClasses.reset();                            // FIX to preserve invariant of one basic storage specifier
    518                 } // if
     506        ast::Function::Specs fsDups = funcSpecs & src->funcSpecs;
     507        if ( fsDups.any() ) {
     508                std::stringstream str;
     509                str << "duplicate ";
     510                ast::print( str, fsDups );
     511                str << "function specifier(s)";
     512                appendError( error, str.str() );
     513        } // if
     514
     515        // Skip if everything is unset.
     516        if ( storageClasses.any() && src->storageClasses.any() ) {
     517                ast::Storage::Classes dups = storageClasses & src->storageClasses;
     518                // Check for duplicates.
     519                if ( dups.any() ) {
     520                        std::stringstream str;
     521                        str << "duplicate ";
     522                        ast::print( str, dups );
     523                        str << "storage class(es)";
     524                        appendError( error, str.str() );
     525                // Check for conflicts.
     526                } else if ( !src->storageClasses.is_threadlocal_any() ) {
     527                        std::stringstream str;
     528                        str << "conflicting ";
     529                        ast::print( str, ast::Storage::Classes( 1 << storageClasses.ffs() ) );
     530                        str << "& ";
     531                        ast::print( str, ast::Storage::Classes( 1 << src->storageClasses.ffs() ) );
     532                        str << "storage classes";
     533                        appendError( error, str.str() );
     534                        // FIX to preserve invariant of one basic storage specifier
     535                        src->storageClasses.reset();
     536                }
    519537        } // if
    520538
     
    526544        storageClasses |= q->storageClasses;
    527545
    528         for ( Attribute * attr: reverseIterate( q->attributes ) ) {
    529                 attributes.push_front( attr->clone() );
    530         } // for
     546        std::vector<ast::ptr<ast::Attribute>> tmp;
     547        tmp.reserve( q->attributes.size() );
     548        for ( auto const & attr : q->attributes ) {
     549                tmp.emplace_back( ast::shallowCopy( attr.get() ) );
     550        }
     551        spliceBegin( attributes, tmp );
     552
    531553        return this;
    532554} // DeclarationNode::copySpecifiers
     
    576598
    577599        checkQualifiers( type, q->type );
    578         if ( (builtin == Zero || builtin == One) && q->type->qualifiers.val != 0 && error.length() == 0 ) {
    579                 SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, Type::QualifiersNames[ilog2( q->type->qualifiers.val )], builtinTypeNames[builtin] );
     600        if ( (builtin == Zero || builtin == One) && q->type->qualifiers.any() && error.length() == 0 ) {
     601                SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, builtinTypeNames[builtin] );
    580602        } // if
    581603        addQualifiersToType( q->type, type );
     
    598620        } else {
    599621                switch ( dst->kind ) {
    600                   case TypeData::Unknown:
     622                case TypeData::Unknown:
    601623                        src->qualifiers |= dst->qualifiers;
    602624                        dst = src;
    603625                        src = nullptr;
    604626                        break;
    605                   case TypeData::Basic:
     627                case TypeData::Basic:
    606628                        dst->qualifiers |= src->qualifiers;
    607629                        if ( src->kind != TypeData::Unknown ) {
     
    631653                        } // if
    632654                        break;
    633                   default:
     655                default:
    634656                        switch ( src->kind ) {
    635                           case TypeData::Aggregate:
    636                           case TypeData::Enum:
     657                        case TypeData::Aggregate:
     658                        case TypeData::Enum:
    637659                                dst->base = new TypeData( TypeData::AggregateInst );
    638660                                dst->base->aggInst.aggregate = src;
     
    643665                                src = nullptr;
    644666                                break;
    645                           default:
     667                        default:
    646668                                if ( dst->forall ) {
    647669                                        dst->forall->appendList( src->forall );
     
    714736
    715737DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) {
    716         if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
    717                 if ( variable.assertions ) {
    718                         variable.assertions->appendList( assertions );
    719                 } else {
    720                         variable.assertions = assertions;
    721                 } // if
    722                 return this;
     738        if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
     739                if ( variable.assertions ) {
     740                        variable.assertions->appendList( assertions );
     741                } else {
     742                        variable.assertions = assertions;
     743                } // if
     744                return this;
    723745        } // if
    724746
    725747        assert( type );
    726748        switch ( type->kind ) {
    727           case TypeData::Symbolic:
     749        case TypeData::Symbolic:
    728750                if ( type->symbolic.assertions ) {
    729751                        type->symbolic.assertions->appendList( assertions );
     
    732754                } // if
    733755                break;
    734           default:
     756        default:
    735757                assert( false );
    736758        } // switch
     
    796818DeclarationNode * DeclarationNode::copyAttribute( DeclarationNode * a ) {
    797819        if ( a ) {
    798                 for ( Attribute *attr: reverseIterate( a->attributes ) ) {
    799                         attributes.push_front( attr );
    800                 } // for
     820                spliceBegin( attributes, a->attributes );
    801821                a->attributes.clear();
    802822        } // if
     
    831851                if ( type ) {
    832852                        switch ( type->kind ) {
    833                           case TypeData::Aggregate:
    834                           case TypeData::Enum:
     853                        case TypeData::Aggregate:
     854                        case TypeData::Enum:
    835855                                p->type->base = new TypeData( TypeData::AggregateInst );
    836856                                p->type->base->aggInst.aggregate = type;
     
    841861                                break;
    842862
    843                           default:
     863                        default:
    844864                                p->type->base = type;
    845865                        } // switch
     
    863883
    864884DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
    865   if ( ! a ) return this;
     885        if ( ! a ) return this;
    866886        assert( a->type->kind == TypeData::Array );
    867887        TypeData * lastArray = findLast( a->type );
    868888        if ( type ) {
    869889                switch ( type->kind ) {
    870                   case TypeData::Aggregate:
    871                   case TypeData::Enum:
     890                case TypeData::Aggregate:
     891                case TypeData::Enum:
    872892                        lastArray->base = new TypeData( TypeData::AggregateInst );
    873893                        lastArray->base->aggInst.aggregate = type;
     
    877897                        lastArray->base->qualifiers |= type->qualifiers;
    878898                        break;
    879                   default:
     899                default:
    880900                        lastArray->base = type;
    881901                } // switch
     
    919939
    920940DeclarationNode * DeclarationNode::addTypeInitializer( DeclarationNode * init ) {
    921         assertf( variable.tyClass != TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
     941        assertf( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
    922942        variable.initializer = init;
    923943        return this;
     
    9831003}
    9841004
    985 void buildList( const DeclarationNode * firstNode, std::list< Declaration * > & outputList ) {
     1005// If a typedef wraps an anonymous declaration, name the inner declaration
     1006// so it has a consistent name across translation units.
     1007static void nameTypedefedDecl(
     1008                DeclarationNode * innerDecl,
     1009                const DeclarationNode * outerDecl ) {
     1010        TypeData * outer = outerDecl->type;
     1011        assert( outer );
     1012        // First make sure this is a typedef:
     1013        if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) {
     1014                return;
     1015        }
     1016        TypeData * inner = innerDecl->type;
     1017        assert( inner );
     1018        // Always clear any CVs associated with the aggregate:
     1019        inner->qualifiers.reset();
     1020        // Handle anonymous aggregates: typedef struct { int i; } foo
     1021        if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) {
     1022                delete inner->aggregate.name;
     1023                inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     1024                inner->aggregate.anon = false;
     1025                assert( outer->base );
     1026                delete outer->base->aggInst.aggregate->aggregate.name;
     1027                outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     1028                outer->base->aggInst.aggregate->aggregate.anon = false;
     1029                outer->base->aggInst.aggregate->qualifiers.reset();
     1030        // Handle anonymous enumeration: typedef enum { A, B, C } foo
     1031        } else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) {
     1032                delete inner->enumeration.name;
     1033                inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     1034                inner->enumeration.anon = false;
     1035                assert( outer->base );
     1036                delete outer->base->aggInst.aggregate->enumeration.name;
     1037                outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     1038                outer->base->aggInst.aggregate->enumeration.anon = false;
     1039                // No qualifiers.reset() here.
     1040        }
     1041}
     1042
     1043// This code handles a special issue with the attribute transparent_union.
     1044//
     1045//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
     1046//
     1047// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
     1048// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
     1049// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
     1050// alias.
     1051static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) {
     1052        if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
     1053                // Is the typedef alias a union aggregate?
     1054                if ( nullptr == unionDecl ) return;
     1055
     1056                // If typedef is an alias for a union, then its alias type was hoisted above and remembered.
     1057                if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
     1058                        auto instType = ast::mutate( unionInstType );
     1059                        // Remove all transparent_union attributes from typedef and move to alias union.
     1060                        for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) {
     1061                                assert( *attr );
     1062                                if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
     1063                                        unionDecl->attributes.emplace_back( attr->release() );
     1064                                        attr = instType->attributes.erase( attr );
     1065                                } else {
     1066                                        attr++;
     1067                                }
     1068                        }
     1069                        typedefDecl->base = instType;
     1070                }
     1071        }
     1072}
     1073
     1074// Get the non-anonymous name of the instance type of the declaration,
     1075// if one exists.
     1076static const std::string * getInstTypeOfName( ast::Decl * decl ) {
     1077        if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
     1078                if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
     1079                        if ( aggr->name.find("anonymous") == std::string::npos ) {
     1080                                return &aggr->name;
     1081                        }
     1082                }
     1083        }
     1084        return nullptr;
     1085}
     1086
     1087void buildList( DeclarationNode * firstNode,
     1088                std::vector<ast::ptr<ast::Decl>> & outputList ) {
    9861089        SemanticErrorException errors;
    987         std::back_insert_iterator< std::list< Declaration * > > out( outputList );
    988 
    989         for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
     1090        std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
     1091
     1092        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    9901093                try {
    991                         bool extracted = false;
    992                         bool anon = false;
     1094                        bool extracted_named = false;
     1095                        ast::UnionDecl * unionDecl = nullptr;
     1096
    9931097                        if ( DeclarationNode * extr = cur->extractAggregate() ) {
    994                                 // handle the case where a structure declaration is contained within an object or type declaration
    995                                 Declaration * decl = extr->build();
    996                                 if ( decl ) {
    997                                         // hoist the structure declaration
    998                                         decl->location = cur->location;
    999                                         * out++ = decl;
     1098                                assert( cur->type );
     1099                                nameTypedefedDecl( extr, cur );
     1100
     1101                                if ( ast::Decl * decl = extr->build() ) {
     1102                                        // Remember the declaration if it is a union aggregate ?
     1103                                        unionDecl = dynamic_cast<ast::UnionDecl *>( decl );
     1104
     1105                                        *out++ = decl;
    10001106
    10011107                                        // need to remember the cases where a declaration contains an anonymous aggregate definition
    1002                                         extracted = true;
    10031108                                        assert( extr->type );
    10041109                                        if ( extr->type->kind == TypeData::Aggregate ) {
    1005                                                 anon = extr->type->aggregate.anon;
     1110                                                // typedef struct { int A } B is the only case?
     1111                                                extracted_named = !extr->type->aggregate.anon;
    10061112                                        } else if ( extr->type->kind == TypeData::Enum ) {
    1007                                                 // xxx - is it useful to have an implicit anonymous enum member?
    1008                                                 anon = extr->type->enumeration.anon;
     1113                                                // typedef enum { A } B is the only case?
     1114                                                extracted_named = !extr->type->enumeration.anon;
     1115                                        } else {
     1116                                                extracted_named = true;
    10091117                                        }
    10101118                                } // if
     
    10121120                        } // if
    10131121
    1014                         Declaration * decl = cur->build();
    1015                         if ( decl ) {
    1016                                 // don't include anonymous declaration for named aggregates, but do include them for anonymous aggregates, e.g.:
    1017                                 // struct S {
    1018                                 //   struct T { int x; }; // no anonymous member
    1019                                 //   struct { int y; };   // anonymous member
    1020                                 //   struct T;            // anonymous member
    1021                                 // };
    1022                                 if ( ! (extracted && decl->name == "" && ! anon && ! cur->get_inLine()) ) {
    1023                                         if ( decl->name == "" ) {
    1024                                                 if ( DeclarationWithType * dwt = dynamic_cast<DeclarationWithType *>( decl ) ) {
    1025                                                         if ( ReferenceToType * aggr = dynamic_cast<ReferenceToType *>( dwt->get_type() ) ) {
    1026                                                                 if ( aggr->name.find("anonymous") == std::string::npos ) {
    1027                                                                         if ( ! cur->get_inLine() ) {
    1028                                                                                 // temporary: warn about anonymous member declarations of named types, since
    1029                                                                                 // this conflicts with the syntax for the forward declaration of an anonymous type
    1030                                                                                 SemanticWarning( cur->location, Warning::AggrForwardDecl, aggr->name.c_str() );
    1031                                                                         } // if
    1032                                                                 } // if
    1033                                                         } // if
    1034                                                 } // if
    1035                                         } // if
    1036                                         decl->location = cur->location;
    1037                                         *out++ = decl;
     1122                        if ( ast::Decl * decl = cur->build() ) {
     1123                                moveUnionAttribute( decl, unionDecl );
     1124
     1125                                if ( "" == decl->name && !cur->get_inLine() ) {
     1126                                        // Don't include anonymous declaration for named aggregates,
     1127                                        // but do include them for anonymous aggregates, e.g.:
     1128                                        // struct S {
     1129                                        //   struct T { int x; }; // no anonymous member
     1130                                        //   struct { int y; };   // anonymous member
     1131                                        //   struct T;            // anonymous member
     1132                                        // };
     1133                                        if ( extracted_named ) {
     1134                                                continue;
     1135                                        }
     1136
     1137                                        if ( auto name = getInstTypeOfName( decl ) ) {
     1138                                                // Temporary: warn about anonymous member declarations of named types, since
     1139                                                // this conflicts with the syntax for the forward declaration of an anonymous type.
     1140                                                SemanticWarning( cur->location, Warning::AggrForwardDecl, name->c_str() );
     1141                                        }
    10381142                                } // if
     1143                                *out++ = decl;
    10391144                        } // if
    1040                 } catch( SemanticErrorException & e ) {
     1145                } catch ( SemanticErrorException & e ) {
    10411146                        errors.append( e );
    10421147                } // try
     
    10491154
    10501155// currently only builds assertions, function parameters, and return values
    1051 void buildList( const DeclarationNode * firstNode, std::list< DeclarationWithType * > & outputList ) {
     1156void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
    10521157        SemanticErrorException errors;
    1053         std::back_insert_iterator< std::list< DeclarationWithType * > > out( outputList );
    1054 
    1055         for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
     1158        std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
     1159
     1160        for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
    10561161                try {
    1057                         Declaration * decl = cur->build();
    1058                         assert( decl );
    1059                         if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     1162                        ast::Decl * decl = cur->build();
     1163                        assertf( decl, "buildList: build for ast::DeclWithType." );
     1164                        if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    10601165                                dwt->location = cur->location;
    10611166                                *out++ = dwt;
    1062                         } else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) {
     1167                        } else if ( ast::StructDecl * agg = dynamic_cast<ast::StructDecl *>( decl ) ) {
    10631168                                // e.g., int foo(struct S) {}
    1064                                 StructInstType * inst = new StructInstType( Type::Qualifiers(), agg->name );
    1065                                 auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    1066                                 obj->location = cur->location;
     1169                                auto inst = new ast::StructInstType( agg->name );
     1170                                auto obj = new ast::ObjectDecl( cur->location, "", inst );
     1171                                obj->linkage = linkage;
    10671172                                *out++ = obj;
    10681173                                delete agg;
    1069                         } else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) {
     1174                        } else if ( ast::UnionDecl * agg = dynamic_cast<ast::UnionDecl *>( decl ) ) {
    10701175                                // e.g., int foo(union U) {}
    1071                                 UnionInstType * inst = new UnionInstType( Type::Qualifiers(), agg->name );
    1072                                 auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    1073                                 obj->location = cur->location;
     1176                                auto inst = new ast::UnionInstType( agg->name );
     1177                                auto obj = new ast::ObjectDecl( cur->location,
     1178                                        "", inst, nullptr, ast::Storage::Classes(),
     1179                                        linkage );
    10741180                                *out++ = obj;
    1075                         } else if ( EnumDecl * agg = dynamic_cast< EnumDecl * >( decl ) ) {
     1181                        } else if ( ast::EnumDecl * agg = dynamic_cast<ast::EnumDecl *>( decl ) ) {
    10761182                                // e.g., int foo(enum E) {}
    1077                                 EnumInstType * inst = new EnumInstType( Type::Qualifiers(), agg->name );
    1078                                 auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    1079                                 obj->location = cur->location;
     1183                                auto inst = new ast::EnumInstType( agg->name );
     1184                                auto obj = new ast::ObjectDecl( cur->location,
     1185                                        "",
     1186                                        inst,
     1187                                        nullptr,
     1188                                        ast::Storage::Classes(),
     1189                                        linkage
     1190                                );
    10801191                                *out++ = obj;
     1192                        } else {
     1193                                assertf( false, "buildList: Could not convert to ast::DeclWithType." );
    10811194                        } // if
    1082                 } catch( SemanticErrorException & e ) {
     1195                } catch ( SemanticErrorException & e ) {
    10831196                        errors.append( e );
    10841197                } // try
     
    10901203} // buildList
    10911204
    1092 void buildTypeList( const DeclarationNode * firstNode, std::list< Type * > & outputList ) {
     1205void buildTypeList( const DeclarationNode * firstNode,
     1206                std::vector<ast::ptr<ast::Type>> & outputList ) {
    10931207        SemanticErrorException errors;
    1094         std::back_insert_iterator< std::list< Type * > > out( outputList );
    1095         const DeclarationNode * cur = firstNode;
    1096 
    1097         while ( cur ) {
     1208        std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
     1209
     1210        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    10981211                try {
    10991212                        * out++ = cur->buildType();
    1100                 } catch( SemanticErrorException & e ) {
     1213                } catch ( SemanticErrorException & e ) {
    11011214                        errors.append( e );
    11021215                } // try
    1103                 cur = dynamic_cast< DeclarationNode * >( cur->get_next() );
    1104         } // while
     1216        } // for
    11051217
    11061218        if ( ! errors.isEmpty() ) {
     
    11091221} // buildTypeList
    11101222
    1111 Declaration * DeclarationNode::build() const {
     1223ast::Decl * DeclarationNode::build() const {
    11121224        if ( ! error.empty() ) SemanticError( this, error + " in declaration of " );
    11131225
    11141226        if ( asmStmt ) {
    1115                 return new AsmDecl( strict_dynamic_cast<AsmStmt *>( asmStmt->build() ) );
     1227                auto stmt = strict_dynamic_cast<ast::AsmStmt *>( asmStmt->build() );
     1228                return new ast::AsmDecl( stmt->location, stmt );
    11161229        } // if
    11171230        if ( directiveStmt ) {
    1118                 return new DirectiveDecl( strict_dynamic_cast<DirectiveStmt *>( directiveStmt->build() ) );
    1119         } // if
    1120 
    1121         if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
     1231                auto stmt = strict_dynamic_cast<ast::DirectiveStmt *>( directiveStmt->build() );
     1232                return new ast::DirectiveDecl( stmt->location, stmt );
     1233        } // if
     1234
     1235        if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
    11221236                // otype is internally converted to dtype + otype parameters
    1123                 static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::Dtype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::Dimension };
    1124                 static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
     1237                static const ast::TypeDecl::Kind kindMap[] = { ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Ftype, ast::TypeDecl::Ttype, ast::TypeDecl::Dimension };
     1238                static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == ast::TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
    11251239                assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
    1126                 TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype || variable.tyClass == TypeDecl::DStype, variable.initializer ? variable.initializer->buildType() : nullptr );
    1127                 buildList( variable.assertions, ret->get_assertions() );
     1240                ast::TypeDecl * ret = new ast::TypeDecl( location,
     1241                        *name,
     1242                        ast::Storage::Classes(),
     1243                        (ast::Type *)nullptr,
     1244                        kindMap[ variable.tyClass ],
     1245                        variable.tyClass == ast::TypeDecl::Otype || variable.tyClass == ast::TypeDecl::DStype,
     1246                        variable.initializer ? variable.initializer->buildType() : nullptr
     1247                );
     1248                buildList( variable.assertions, ret->assertions );
    11281249                return ret;
    11291250        } // if
     
    11471268                } // if
    11481269                bool isDelete = initializer && initializer->get_isDelete();
    1149                 Declaration * decl = buildDecl( type, name ? *name : string( "" ), storageClasses, maybeBuild< Expression >( bitfieldWidth ), funcSpecs, linkage, asmName, isDelete ? nullptr : maybeBuild< Initializer >(initializer), attributes )->set_extension( extension );
     1270                ast::Decl * decl = buildDecl(
     1271                        type,
     1272                        name ? *name : string( "" ),
     1273                        storageClasses,
     1274                        maybeBuild( bitfieldWidth ),
     1275                        funcSpecs,
     1276                        linkage,
     1277                        asmName,
     1278                        isDelete ? nullptr : maybeBuild( initializer ),
     1279                        copy( attributes )
     1280                )->set_extension( extension );
    11501281                if ( isDelete ) {
    1151                         DeclarationWithType * dwt = strict_dynamic_cast<DeclarationWithType *>( decl );
     1282                        auto dwt = strict_dynamic_cast<ast::DeclWithType *>( decl );
    11521283                        dwt->isDeleted = true;
    11531284                }
     
    11561287
    11571288        if ( assert.condition ) {
    1158                 return new StaticAssertDecl( maybeBuild< Expression >( assert.condition ), strict_dynamic_cast< ConstantExpr * >( maybeClone( assert.message ) ) );
     1289                auto cond = maybeBuild( assert.condition );
     1290                auto msg = strict_dynamic_cast<ast::ConstantExpr *>( maybeCopy( assert.message ) );
     1291                return new ast::StaticAssertDecl( location, cond, msg );
    11591292        }
    11601293
     
    11671300        } // if
    11681301        if ( enumInLine ) {
    1169                 return new InlineMemberDecl( *name, storageClasses, linkage, nullptr );
     1302                return new ast::InlineMemberDecl( location,
     1303                        *name, (ast::Type*)nullptr, storageClasses, linkage );
    11701304        } // if
    11711305        assertf( name, "ObjectDecl must a have name\n" );
    1172         return (new ObjectDecl( *name, storageClasses, linkage, maybeBuild< Expression >( bitfieldWidth ), nullptr, maybeBuild< Initializer >( initializer ) ))->set_asmName( asmName )->set_extension( extension );
    1173 }
    1174 
    1175 Type * DeclarationNode::buildType() const {
     1306        auto ret = new ast::ObjectDecl( location,
     1307                *name,
     1308                (ast::Type*)nullptr,
     1309                maybeBuild( initializer ),
     1310                storageClasses,
     1311                linkage,
     1312                maybeBuild( bitfieldWidth )
     1313        );
     1314        ret->asmName = asmName;
     1315        ret->extension = extension;
     1316        return ret;
     1317}
     1318
     1319ast::Type * DeclarationNode::buildType() const {
    11761320        assert( type );
    11771321
    1178         if ( attr.expr ) {
    1179                 return new AttrType( buildQualifiers( type ), *name, attr.expr->build(), attributes );
    1180         } else if ( attr.type ) {
    1181                 return new AttrType( buildQualifiers( type ), *name, attr.type->buildType(), attributes );
    1182         } // if
    1183 
    11841322        switch ( type->kind ) {
    1185           case TypeData::Enum:
    1186           case TypeData::Aggregate: {
    1187                   ReferenceToType * ret = buildComAggInst( type, attributes, linkage );
    1188                   buildList( type->aggregate.actuals, ret->get_parameters() );
    1189                   return ret;
    1190           }
    1191           case TypeData::Symbolic: {
    1192                   TypeInstType * ret = new TypeInstType( buildQualifiers( type ), *type->symbolic.name, false, attributes );
    1193                   buildList( type->symbolic.actuals, ret->get_parameters() );
    1194                   return ret;
    1195           }
    1196           default:
    1197                 Type * simpletypes = typebuild( type );
    1198                 simpletypes->get_attributes() = attributes;             // copy because member is const
     1323        case TypeData::Enum:
     1324        case TypeData::Aggregate: {
     1325                ast::BaseInstType * ret =
     1326                        buildComAggInst( type, copy( attributes ), linkage );
     1327                buildList( type->aggregate.actuals, ret->params );
     1328                return ret;
     1329        }
     1330        case TypeData::Symbolic: {
     1331                ast::TypeInstType * ret = new ast::TypeInstType(
     1332                        *type->symbolic.name,
     1333                        // This is just a default, the true value is not known yet.
     1334                        ast::TypeDecl::Dtype,
     1335                        buildQualifiers( type ),
     1336                        copy( attributes ) );
     1337                buildList( type->symbolic.actuals, ret->params );
     1338                return ret;
     1339        }
     1340        default:
     1341                ast::Type * simpletypes = typebuild( type );
     1342                // copy because member is const
     1343                simpletypes->attributes = attributes;
    11991344                return simpletypes;
    12001345        } // switch
  • src/Parser/ExpressionNode.cc

    r34b4268 r24d6572  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 13:17:07 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug  7 09:18:56 2021
    13 // Update Count     : 1077
    14 //
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr  4 11:07:00 2023
     13// Update Count     : 1083
     14//
     15
     16#include "ExpressionNode.h"
    1517
    1618#include <cassert>                 // for assert
     
    2123#include <string>                  // for string, operator+, operator==
    2224
     25#include "AST/Expr.hpp"            // for NameExpr
     26#include "AST/Type.hpp"            // for BaseType, SueInstType
    2327#include "Common/SemanticError.h"  // for SemanticError
    2428#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild, CodeLo...
    25 #include "ParseNode.h"             // for ExpressionNode, maybeMoveBuildType
    26 #include "SynTree/Constant.h"      // for Constant
    27 #include "SynTree/Declaration.h"   // for EnumDecl, StructDecl, UnionDecl
    28 #include "SynTree/Expression.h"    // for Expression, ConstantExpr, NameExpr
    29 #include "SynTree/Statement.h"     // for CompoundStmt, Statement
    30 #include "SynTree/Type.h"          // for BasicType, Type, Type::Qualifiers
     29#include "DeclarationNode.h"       // for DeclarationNode
     30#include "InitializerNode.h"       // for InitializerNode
    3131#include "parserutility.h"         // for notZeroExpr
    32 
    33 class Initializer;
    3432
    3533using namespace std;
     
    4846// because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their
    4947// type.
    50 
    51 extern const Type::Qualifiers noQualifiers;                             // no qualifiers on constants
    5248
    5349// static inline bool checkH( char c ) { return c == 'h' || c == 'H'; }
     
    7167        size_t end = str.length() - 1;
    7268        if ( posn == end ) { type = 3; return; }                        // no length after 'l' => long
    73        
     69
    7470        string::size_type next = posn + 1;                                      // advance to length
    7571        if ( str[next] == '3' ) {                                                       // 32
     
    122118                if ( str[i] == '1' ) v |= 1;
    123119                i += 1;
    124           if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
     120                if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
    125121                v <<= 1;
    126122        } // for
    127123} // scanbin
    128124
    129 Expression * build_constantInteger( string & str ) {
    130         static const BasicType::Kind kind[2][6] = {
     125ast::Expr * build_constantInteger(
     126                const CodeLocation & location, string & str ) {
     127        static const ast::BasicType::Kind kind[2][6] = {
    131128                // short (h) must be before char (hh) because shorter type has the longer suffix
    132                 { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, /* BasicType::SignedInt128 */ BasicType::LongLongSignedInt, },
    133                 { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, /* BasicType::UnsignedInt128 */ BasicType::LongLongUnsignedInt, },
     129                { ast::BasicType::ShortSignedInt, ast::BasicType::SignedChar, ast::BasicType::SignedInt, ast::BasicType::LongSignedInt, ast::BasicType::LongLongSignedInt, /* BasicType::SignedInt128 */ ast::BasicType::LongLongSignedInt, },
     130                { ast::BasicType::ShortUnsignedInt, ast::BasicType::UnsignedChar, ast::BasicType::UnsignedInt, ast::BasicType::LongUnsignedInt, ast::BasicType::LongLongUnsignedInt, /* BasicType::UnsignedInt128 */ ast::BasicType::LongLongUnsignedInt, },
    134131        };
    135132
     
    141138        string str2( "0x0" );
    142139        unsigned long long int v, v2 = 0;                                       // converted integral value
    143         Expression * ret, * ret2;
     140        ast::Expr * ret, * ret2;
    144141
    145142        int type = -1;                                                                          // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
     
    149146        // special constants
    150147        if ( str == "0" ) {
    151                 ret = new ConstantExpr( Constant( (Type *)new ZeroType( noQualifiers ), str, (unsigned long long int)0 ) );
     148                ret = new ast::ConstantExpr( location, new ast::ZeroType(), str, 0 );
    152149                goto CLEANUP;
    153150        } // if
    154151        if ( str == "1" ) {
    155                 ret = new ConstantExpr( Constant( (Type *)new OneType( noQualifiers ), str, (unsigned long long int)1 ) );
     152                ret = new ast::ConstantExpr( location, new ast::OneType(), str, 1 );
    156153                goto CLEANUP;
    157154        } // if
    158 
    159         string::size_type posn;
    160155
    161156        // 'u' can appear before or after length suffix
     
    166161        } else {
    167162                // At least one digit in integer constant, so safe to backup while looking for suffix.
    168 
    169                 posn = str.find_last_of( "pP" );                                // pointer value
    170                 if ( posn != string::npos ) { ltype = 5; str.erase( posn, 1 ); goto FINI; }
    171 
    172                 posn = str.find_last_of( "zZ" );                                // size_t
    173                 if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; }
    174 
    175                 posn = str.rfind( "hh" );                                               // char
    176                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    177 
    178                 posn = str.rfind( "HH" );                                               // char
    179                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    180 
    181                 posn = str.find_last_of( "hH" );                                // short
    182                 if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; }
    183 
    184                 posn = str.find_last_of( "nN" );                                // int (natural number)
    185                 if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; }
    186 
    187                 if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; }
    188 
    189                 lnthSuffix( str, type, ltype );                                 // must be after check for "ll"
    190           FINI: ;
     163                // This declaration and the comma expressions in the conditions mimic
     164                // the declare and check pattern allowed in later compiler versions.
     165                // (Only some early compilers/C++ standards do not support it.)
     166                string::size_type posn;
     167                // pointer value
     168                if ( posn = str.find_last_of( "pP" ), posn != string::npos ) {
     169                        ltype = 5; str.erase( posn, 1 );
     170                // size_t
     171                } else if ( posn = str.find_last_of( "zZ" ), posn != string::npos ) {
     172                        Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 );
     173                // signed char
     174                } else if ( posn = str.rfind( "hh" ), posn != string::npos ) {
     175                        type = 1; str.erase( posn, 2 );
     176                // signed char
     177                } else if ( posn = str.rfind( "HH" ), posn != string::npos ) {
     178                        type = 1; str.erase( posn, 2 );
     179                // short
     180                } else if ( posn = str.find_last_of( "hH" ), posn != string::npos ) {
     181                        type = 0; str.erase( posn, 1 );
     182                // int (natural number)
     183                } else if ( posn = str.find_last_of( "nN" ), posn != string::npos ) {
     184                        type = 2; str.erase( posn, 1 );
     185                } else if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) {
     186                        type = 4;
     187                } else {
     188                        lnthSuffix( str, type, ltype );
     189                } // if
    191190        } // if
    192191
     
    196195        if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target " + str );
    197196#endif // ! __SIZEOF_INT128__
    198        
     197
    199198        if ( str[0] == '0' ) {                                                          // radix character ?
    200199                dec = false;
     
    206205                                unsigned int len = str.length();
    207206                                if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large " + str );
    208                           if ( len <= (2 + 16) ) goto FHEX1;            // hex digits < 2^64
    209                                 str2 = "0x" + str.substr( len - 16 );
    210                                 sscanf( (char *)str2.c_str(), "%llx", &v2 );
    211                                 str = str.substr( 0, len - 16 );
    212                           FHEX1: ;
     207                                // hex digits < 2^64
     208                                if ( len > (2 + 16) ) {
     209                                        str2 = "0x" + str.substr( len - 16 );
     210                                        sscanf( (char *)str2.c_str(), "%llx", &v2 );
     211                                        str = str.substr( 0, len - 16 );
     212                                } // if
    213213                                sscanf( (char *)str.c_str(), "%llx", &v );
    214214#endif // __SIZEOF_INT128__
     
    301301
    302302        // Constant type is correct for overload resolving.
    303         ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][type] ), str, v ) );
     303        ret = new ast::ConstantExpr( location,
     304                new ast::BasicType( kind[Unsigned][type] ), str, v );
    304305        if ( Unsigned && type < 2 ) {                                           // hh or h, less than int ?
    305306                // int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values.
    306                 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
     307                ret = new ast::CastExpr( location,
     308                        ret,
     309                        new ast::BasicType( kind[Unsigned][type] ),
     310                        ast::ExplicitCast );
    307311        } else if ( ltype != -1 ) {                                                     // explicit length ?
    308312                if ( ltype == 6 ) {                                                             // int128, (int128)constant
    309 //                      ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
    310                         ret2 = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::LongLongSignedInt ), str2, v2 ) );
    311                         ret = build_compoundLiteral( DeclarationNode::newBasicType( DeclarationNode::Int128 )->addType( DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ),
    312                                                                                  new InitializerNode( (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true ) );
     313                        ret2 = new ast::ConstantExpr( location,
     314                                new ast::BasicType( ast::BasicType::LongLongSignedInt ),
     315                                str2,
     316                                v2 );
     317                        ret = build_compoundLiteral( location,
     318                                DeclarationNode::newBasicType(
     319                                        DeclarationNode::Int128
     320                                )->addType(
     321                                        DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ),
     322                                new InitializerNode(
     323                                        (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true )
     324                        );
    313325                } else {                                                                                // explicit length, (length_type)constant
    314                         ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false );
     326                        ret = new ast::CastExpr( location,
     327                                ret,
     328                                new ast::TypeInstType( lnthsInt[Unsigned][ltype], ast::TypeDecl::Dtype ),
     329                                ast::ExplicitCast );
    315330                        if ( ltype == 5 ) {                                                     // pointer, intptr( (uintptr_t)constant )
    316                                 ret = build_func( new ExpressionNode( build_varref( new string( "intptr" ) ) ), new ExpressionNode( ret ) );
     331                                ret = build_func( location,
     332                                        new ExpressionNode(
     333                                                build_varref( location, new string( "intptr" ) ) ),
     334                                        new ExpressionNode( ret ) );
    317335                        } // if
    318336                } // if
     
    358376
    359377
    360 Expression * build_constantFloat( string & str ) {
    361         static const BasicType::Kind kind[2][12] = {
    362                 { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x },
    363                 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::NUMBER_OF_BASIC_TYPES, BasicType::NUMBER_OF_BASIC_TYPES, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex },
     378ast::Expr * build_constantFloat(
     379                const CodeLocation & location, string & str ) {
     380        static const ast::BasicType::Kind kind[2][12] = {
     381                { ast::BasicType::Float, ast::BasicType::Double, ast::BasicType::LongDouble, ast::BasicType::uuFloat80, ast::BasicType::uuFloat128, ast::BasicType::uFloat16, ast::BasicType::uFloat32, ast::BasicType::uFloat32x, ast::BasicType::uFloat64, ast::BasicType::uFloat64x, ast::BasicType::uFloat128, ast::BasicType::uFloat128x },
     382                { ast::BasicType::FloatComplex, ast::BasicType::DoubleComplex, ast::BasicType::LongDoubleComplex, ast::BasicType::NUMBER_OF_BASIC_TYPES, ast::BasicType::NUMBER_OF_BASIC_TYPES, ast::BasicType::uFloat16Complex, ast::BasicType::uFloat32Complex, ast::BasicType::uFloat32xComplex, ast::BasicType::uFloat64Complex, ast::BasicType::uFloat64xComplex, ast::BasicType::uFloat128Complex, ast::BasicType::uFloat128xComplex },
    364383        };
    365384
     
    398417
    399418        assert( 0 <= type && type < 12 );
    400         Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[complx][type] ), str, v ) );
    401         if ( explnth ) {                                                                        // explicit length ?
    402                 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[complx][type] ), false );
     419        ast::Expr * ret = new ast::ConstantExpr( location,
     420                new ast::BasicType( kind[complx][type] ),
     421                str,
     422                v );
     423        // explicit length ?
     424        if ( explnth ) {
     425                ret = new ast::CastExpr( location,
     426                        ret,
     427                        new ast::BasicType( kind[complx][type] ),
     428                        ast::ExplicitCast );
    403429        } // if
    404430
     
    415441} // sepString
    416442
    417 Expression * build_constantChar( string & str ) {
     443ast::Expr * build_constantChar( const CodeLocation & location, string & str ) {
    418444        string units;                                                                           // units
    419445        sepString( str, units, '\'' );                                          // separate constant from units
    420446
    421         Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::Char ), str, (unsigned long long int)(unsigned char)str[1] ) );
     447        ast::Expr * ret = new ast::ConstantExpr( location,
     448                new ast::BasicType( ast::BasicType::Char ),
     449                str,
     450                (unsigned long long int)(unsigned char)str[1] );
    422451        if ( units.length() != 0 ) {
    423                 ret = new UntypedExpr( new NameExpr( units ), { ret } );
     452                ret = new ast::UntypedExpr( location,
     453                        new ast::NameExpr( location, units ),
     454                        { ret } );
    424455        } // if
    425456
     
    428459} // build_constantChar
    429460
    430 Expression * build_constantStr( string & str ) {
     461ast::Expr * build_constantStr(
     462                const CodeLocation & location,
     463                string & str ) {
    431464        assert( str.length() > 0 );
    432465        string units;                                                                           // units
    433466        sepString( str, units, '"' );                                           // separate constant from units
    434467
    435         Type * strtype;
     468        ast::Type * strtype;
    436469        switch ( str[0] ) {                                                                     // str has >= 2 characters, i.e, null string "" => safe to look at subscripts 0/1
    437           case 'u':
     470        case 'u':
    438471                if ( str[1] == '8' ) goto Default;                              // utf-8 characters => array of char
    439472                // lookup type of associated typedef
    440                 strtype = new TypeInstType( Type::Qualifiers( ), "char16_t", false );
     473                strtype = new ast::TypeInstType( "char16_t", ast::TypeDecl::Dtype );
    441474                break;
    442           case 'U':
    443                 strtype = new TypeInstType( Type::Qualifiers( ), "char32_t", false );
     475        case 'U':
     476                strtype = new ast::TypeInstType( "char32_t", ast::TypeDecl::Dtype );
    444477                break;
    445           case 'L':
    446                 strtype = new TypeInstType( Type::Qualifiers( ), "wchar_t", false );
     478        case 'L':
     479                strtype = new ast::TypeInstType( "wchar_t", ast::TypeDecl::Dtype );
    447480                break;
    448           Default:                                                                                      // char default string type
    449           default:
    450                 strtype = new BasicType( Type::Qualifiers( ), BasicType::Char );
     481        Default:                                                                                        // char default string type
     482        default:
     483                strtype = new ast::BasicType( ast::BasicType::Char );
    451484        } // switch
    452         ArrayType * at = new ArrayType( noQualifiers, strtype,
    453                                                                         new ConstantExpr( Constant::from_ulong( str.size() + 1 - 2 ) ), // +1 for '\0' and -2 for '"'
    454                                                                         false, false );
    455         Expression * ret = new ConstantExpr( Constant( at, str, std::nullopt ) );
     485        ast::ArrayType * at = new ast::ArrayType(
     486                strtype,
     487                // Length is adjusted: +1 for '\0' and -2 for '"'
     488                ast::ConstantExpr::from_ulong( location, str.size() + 1 - 2 ),
     489                ast::FixedLen,
     490                ast::DynamicDim );
     491        ast::Expr * ret = new ast::ConstantExpr( location, at, str, std::nullopt );
    456492        if ( units.length() != 0 ) {
    457                 ret = new UntypedExpr( new NameExpr( units ), { ret } );
     493                ret = new ast::UntypedExpr( location,
     494                        new ast::NameExpr( location, units ),
     495                        { ret } );
    458496        } // if
    459497
     
    462500} // build_constantStr
    463501
    464 Expression * build_field_name_FLOATING_FRACTIONconstant( const string & str ) {
     502ast::Expr * build_field_name_FLOATING_FRACTIONconstant(
     503                const CodeLocation & location, const string & str ) {
    465504        if ( str.find_first_not_of( "0123456789", 1 ) != string::npos ) SemanticError( yylloc, "invalid tuple index " + str );
    466         Expression * ret = build_constantInteger( *new string( str.substr(1) ) );
     505        ast::Expr * ret = build_constantInteger( location,
     506                *new string( str.substr(1) ) );
    467507        delete &str;
    468508        return ret;
    469509} // build_field_name_FLOATING_FRACTIONconstant
    470510
    471 Expression * build_field_name_FLOATING_DECIMALconstant( const string & str ) {
     511ast::Expr * build_field_name_FLOATING_DECIMALconstant(
     512                const CodeLocation & location, const string & str ) {
    472513        if ( str[str.size() - 1] != '.' ) SemanticError( yylloc, "invalid tuple index " + str );
    473         Expression * ret = build_constantInteger( *new string( str.substr( 0, str.size()-1 ) ) );
     514        ast::Expr * ret = build_constantInteger(
     515                location, *new string( str.substr( 0, str.size()-1 ) ) );
    474516        delete &str;
    475517        return ret;
    476518} // build_field_name_FLOATING_DECIMALconstant
    477519
    478 Expression * build_field_name_FLOATINGconstant( const string & str ) {
     520ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation & location,
     521                const string & str ) {
    479522        // str is of the form A.B -> separate at the . and return member expression
    480523        int a, b;
     
    482525        stringstream ss( str );
    483526        ss >> a >> dot >> b;
    484         UntypedMemberExpr * ret = new UntypedMemberExpr( new ConstantExpr( Constant::from_int( b ) ), new ConstantExpr( Constant::from_int( a ) ) );
     527        auto ret = new ast::UntypedMemberExpr( location,
     528                ast::ConstantExpr::from_int( location, b ),
     529                ast::ConstantExpr::from_int( location, a )
     530        );
    485531        delete &str;
    486532        return ret;
    487533} // build_field_name_FLOATINGconstant
    488534
    489 Expression * make_field_name_fraction_constants( Expression * fieldName, Expression * fracts ) {
    490         if ( fracts ) {
    491                 if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( fracts ) ) {
    492                         memberExpr->set_member( make_field_name_fraction_constants( fieldName, memberExpr->get_aggregate() ) );
    493                         return memberExpr;
    494                 } else {
    495                         return new UntypedMemberExpr( fracts, fieldName );
    496                 } // if
    497         } // if
    498         return fieldName;
     535ast::Expr * make_field_name_fraction_constants( const CodeLocation & location,
     536                ast::Expr * fieldName,
     537                ast::Expr * fracts ) {
     538        if ( nullptr == fracts ) {
     539                return fieldName;
     540        } else if ( auto memberExpr = dynamic_cast<ast::UntypedMemberExpr *>( fracts ) ) {
     541                memberExpr->member = make_field_name_fraction_constants( location,
     542                        fieldName,
     543                        ast::mutate( memberExpr->aggregate.get() ) );
     544                return memberExpr;
     545        } else {
     546                return new ast::UntypedMemberExpr( location, fracts, fieldName );
     547        } // if
    499548} // make_field_name_fraction_constants
    500549
    501 Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ) {
    502         return make_field_name_fraction_constants( fieldName, maybeMoveBuild< Expression >( fracts ) );
     550ast::Expr * build_field_name_fraction_constants( const CodeLocation & location,
     551                ast::Expr * fieldName,
     552                ExpressionNode * fracts ) {
     553        return make_field_name_fraction_constants( location, fieldName, maybeMoveBuild( fracts ) );
    503554} // build_field_name_fraction_constants
    504555
    505 NameExpr * build_varref( const string * name ) {
    506         NameExpr * expr = new NameExpr( *name );
     556ast::NameExpr * build_varref( const CodeLocation & location,
     557                const string * name ) {
     558        ast::NameExpr * expr = new ast::NameExpr( location, *name );
    507559        delete name;
    508560        return expr;
    509561} // build_varref
    510562
    511 QualifiedNameExpr * build_qualified_expr( const DeclarationNode * decl_node, const NameExpr * name ) {
    512         Declaration * newDecl = maybeBuild< Declaration >(decl_node);
    513         if ( DeclarationWithType * newDeclWithType = dynamic_cast< DeclarationWithType * >( newDecl ) ) {
    514                 const Type * t = newDeclWithType->get_type();
    515                 if ( t ) {
    516                         if ( const TypeInstType * typeInst = dynamic_cast<const TypeInstType *>( t ) ) {
    517                                 newDecl= new EnumDecl( typeInst->name );
     563ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
     564                const DeclarationNode * decl_node,
     565                const ast::NameExpr * name ) {
     566        ast::Decl * newDecl = maybeBuild( decl_node );
     567        if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
     568                if ( const ast::Type * t = newDeclWithType->get_type() ) {
     569                        if ( auto typeInst = dynamic_cast<const ast::TypeInstType *>( t ) ) {
     570                                newDecl = new ast::EnumDecl( location, typeInst->name );
    518571                        }
    519572                }
    520573        }
    521         return new QualifiedNameExpr( newDecl, name->name );
     574        return new ast::QualifiedNameExpr( location, newDecl, name->name );
    522575}
    523576
    524 QualifiedNameExpr * build_qualified_expr( const EnumDecl * decl_node, const NameExpr * name ) {
    525         EnumDecl * newDecl = const_cast< EnumDecl * >( decl_node );
    526         return new QualifiedNameExpr( newDecl, name->name );
     577ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
     578                const ast::EnumDecl * decl,
     579                const ast::NameExpr * name ) {
     580        return new ast::QualifiedNameExpr( location, decl, name->name );
    527581}
    528582
    529 DimensionExpr * build_dimensionref( const string * name ) {
    530         DimensionExpr * expr = new DimensionExpr( *name );
     583ast::DimensionExpr * build_dimensionref( const CodeLocation & location,
     584                const string * name ) {
     585        ast::DimensionExpr * expr = new ast::DimensionExpr( location, *name );
    531586        delete name;
    532587        return expr;
     
    544599}; // OperName
    545600
    546 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node, CastExpr::CastKind kind ) {
    547         Type * targetType = maybeMoveBuildType( decl_node );
    548         if ( dynamic_cast< VoidType * >( targetType ) ) {
     601ast::Expr * build_cast( const CodeLocation & location,
     602                DeclarationNode * decl_node,
     603                ExpressionNode * expr_node,
     604                ast::CastExpr::CastKind kind ) {
     605        ast::Type * targetType = maybeMoveBuildType( decl_node );
     606        if ( dynamic_cast<ast::VoidType *>( targetType ) ) {
    549607                delete targetType;
    550                 return new CastExpr( maybeMoveBuild< Expression >(expr_node), false, kind );
     608                return new ast::CastExpr( location,
     609                        maybeMoveBuild( expr_node ),
     610                        ast::ExplicitCast, kind );
    551611        } else {
    552                 return new CastExpr( maybeMoveBuild< Expression >(expr_node), targetType, false, kind );
     612                return new ast::CastExpr( location,
     613                        maybeMoveBuild( expr_node ),
     614                        targetType,
     615                        ast::ExplicitCast, kind );
    553616        } // if
    554617} // build_cast
    555618
    556 Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node ) {
    557         return new KeywordCastExpr( maybeMoveBuild< Expression >(expr_node), target );
     619ast::Expr * build_keyword_cast( const CodeLocation & location,
     620                ast::AggregateDecl::Aggregate target,
     621                ExpressionNode * expr_node ) {
     622        return new ast::KeywordCastExpr( location,
     623                maybeMoveBuild( expr_node ),
     624                target
     625        );
    558626}
    559627
    560 Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) {
    561         return new VirtualCastExpr( maybeMoveBuild< Expression >( expr_node ), maybeMoveBuildType( decl_node ) );
     628ast::Expr * build_virtual_cast( const CodeLocation & location,
     629                DeclarationNode * decl_node,
     630                ExpressionNode * expr_node ) {
     631        return new ast::VirtualCastExpr( location,
     632                maybeMoveBuild( expr_node ),
     633                maybeMoveBuildType( decl_node )
     634        );
    562635} // build_virtual_cast
    563636
    564 Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member ) {
    565         return new UntypedMemberExpr( member, maybeMoveBuild< Expression >(expr_node) );
     637ast::Expr * build_fieldSel( const CodeLocation & location,
     638                ExpressionNode * expr_node,
     639                ast::Expr * member ) {
     640        return new ast::UntypedMemberExpr( location,
     641                member,
     642                maybeMoveBuild( expr_node )
     643        );
    566644} // build_fieldSel
    567645
    568 Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member ) {
    569         UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) );
     646ast::Expr * build_pfieldSel( const CodeLocation & location,
     647                ExpressionNode * expr_node,
     648                ast::Expr * member ) {
     649        auto deref = new ast::UntypedExpr( location,
     650                new ast::NameExpr( location, "*?" )
     651        );
    570652        deref->location = expr_node->location;
    571         deref->get_args().push_back( maybeMoveBuild< Expression >(expr_node) );
    572         UntypedMemberExpr * ret = new UntypedMemberExpr( member, deref );
     653        deref->args.push_back( maybeMoveBuild( expr_node ) );
     654        auto ret = new ast::UntypedMemberExpr( location, member, deref );
    573655        return ret;
    574656} // build_pfieldSel
    575657
    576 Expression * build_offsetOf( DeclarationNode * decl_node, NameExpr * member ) {
    577         Expression * ret = new UntypedOffsetofExpr( maybeMoveBuildType( decl_node ), member->get_name() );
     658ast::Expr * build_offsetOf( const CodeLocation & location,
     659                DeclarationNode * decl_node,
     660                ast::NameExpr * member ) {
     661        ast::Expr * ret = new ast::UntypedOffsetofExpr( location,
     662                maybeMoveBuildType( decl_node ),
     663                member->name
     664        );
     665        ret->result = new ast::BasicType( ast::BasicType::LongUnsignedInt );
    578666        delete member;
    579667        return ret;
    580668} // build_offsetOf
    581669
    582 Expression * build_and_or( ExpressionNode * expr_node1, ExpressionNode * expr_node2, bool kind ) {
    583         return new LogicalExpr( notZeroExpr( maybeMoveBuild< Expression >(expr_node1) ), notZeroExpr( maybeMoveBuild< Expression >(expr_node2) ), kind );
     670ast::Expr * build_and_or( const CodeLocation & location,
     671                ExpressionNode * expr_node1,
     672                ExpressionNode * expr_node2,
     673                ast::LogicalFlag flag ) {
     674        return new ast::LogicalExpr( location,
     675                notZeroExpr( maybeMoveBuild( expr_node1 ) ),
     676                notZeroExpr( maybeMoveBuild( expr_node2 ) ),
     677                flag
     678        );
    584679} // build_and_or
    585680
    586 Expression * build_unary_val( OperKinds op, ExpressionNode * expr_node ) {
    587         list< Expression * > args;
    588         args.push_back( maybeMoveBuild< Expression >(expr_node) );
    589         return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
     681ast::Expr * build_unary_val( const CodeLocation & location,
     682                OperKinds op,
     683                ExpressionNode * expr_node ) {
     684        std::vector<ast::ptr<ast::Expr>> args;
     685        args.push_back( maybeMoveBuild( expr_node ) );
     686        return new ast::UntypedExpr( location,
     687                new ast::NameExpr( location, OperName[ (int)op ] ),
     688                std::move( args )
     689        );
    590690} // build_unary_val
    591691
    592 Expression * build_unary_ptr( OperKinds op, ExpressionNode * expr_node ) {
    593         list< Expression * > args;
    594         args.push_back(  maybeMoveBuild< Expression >(expr_node) ); // xxx -- this is exactly the same as the val case now, refactor this code.
    595         return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
    596 } // build_unary_ptr
    597 
    598 Expression * build_binary_val( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 ) {
    599         list< Expression * > args;
    600         args.push_back( maybeMoveBuild< Expression >(expr_node1) );
    601         args.push_back( maybeMoveBuild< Expression >(expr_node2) );
    602         return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
     692ast::Expr * build_binary_val( const CodeLocation & location,
     693                OperKinds op,
     694                ExpressionNode * expr_node1,
     695                ExpressionNode * expr_node2 ) {
     696        std::vector<ast::ptr<ast::Expr>> args;
     697        args.push_back( maybeMoveBuild( expr_node1 ) );
     698        args.push_back( maybeMoveBuild( expr_node2 ) );
     699        return new ast::UntypedExpr( location,
     700                new ast::NameExpr( location, OperName[ (int)op ] ),
     701                std::move( args )
     702        );
    603703} // build_binary_val
    604704
    605 Expression * build_binary_ptr( OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 ) {
    606         list< Expression * > args;
    607         args.push_back( maybeMoveBuild< Expression >(expr_node1) );
    608         args.push_back( maybeMoveBuild< Expression >(expr_node2) );
    609         return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
    610 } // build_binary_ptr
    611 
    612 Expression * build_cond( ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 ) {
    613         return new ConditionalExpr( notZeroExpr( maybeMoveBuild< Expression >(expr_node1) ), maybeMoveBuild< Expression >(expr_node2), maybeMoveBuild< Expression >(expr_node3) );
     705ast::Expr * build_cond( const CodeLocation & location,
     706                ExpressionNode * expr_node1,
     707                ExpressionNode * expr_node2,
     708                ExpressionNode * expr_node3 ) {
     709        return new ast::ConditionalExpr( location,
     710                notZeroExpr( maybeMoveBuild( expr_node1 ) ),
     711                maybeMoveBuild( expr_node2 ),
     712                maybeMoveBuild( expr_node3 )
     713        );
    614714} // build_cond
    615715
    616 Expression * build_tuple( ExpressionNode * expr_node ) {
    617         list< Expression * > exprs;
     716ast::Expr * build_tuple( const CodeLocation & location,
     717                ExpressionNode * expr_node ) {
     718        std::vector<ast::ptr<ast::Expr>> exprs;
    618719        buildMoveList( expr_node, exprs );
    619         return new UntypedTupleExpr( exprs );;
     720        return new ast::UntypedTupleExpr( location, std::move( exprs ) );
    620721} // build_tuple
    621722
    622 Expression * build_func( ExpressionNode * function, ExpressionNode * expr_node ) {
    623         list< Expression * > args;
     723ast::Expr * build_func( const CodeLocation & location,
     724                ExpressionNode * function,
     725                ExpressionNode * expr_node ) {
     726        std::vector<ast::ptr<ast::Expr>> args;
    624727        buildMoveList( expr_node, args );
    625         return new UntypedExpr( maybeMoveBuild< Expression >(function), args );
     728        return new ast::UntypedExpr( location,
     729                maybeMoveBuild( function ),
     730                std::move( args )
     731        );
    626732} // build_func
    627733
    628 Expression * build_compoundLiteral( DeclarationNode * decl_node, InitializerNode * kids ) {
    629         Declaration * newDecl = maybeBuild< Declaration >(decl_node); // compound literal type
    630         if ( DeclarationWithType * newDeclWithType = dynamic_cast< DeclarationWithType * >( newDecl ) ) { // non-sue compound-literal type
    631                 return new CompoundLiteralExpr( newDeclWithType->get_type(), maybeMoveBuild< Initializer >(kids) );
     734ast::Expr * build_compoundLiteral( const CodeLocation & location,
     735                DeclarationNode * decl_node,
     736                InitializerNode * kids ) {
     737        // compound literal type
     738        ast::Decl * newDecl = maybeBuild( decl_node );
     739        // non-sue compound-literal type
     740        if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
     741                return new ast::CompoundLiteralExpr( location,
     742                        newDeclWithType->get_type(),
     743                        maybeMoveBuild( kids ) );
    632744        // these types do not have associated type information
    633         } else if ( StructDecl * newDeclStructDecl = dynamic_cast< StructDecl * >( newDecl )  ) {
    634                 if ( newDeclStructDecl->has_body() ) {
    635                         return new CompoundLiteralExpr( new StructInstType( Type::Qualifiers(), newDeclStructDecl ), maybeMoveBuild< Initializer >(kids) );
     745        } else if ( auto newDeclStructDecl = dynamic_cast<ast::StructDecl *>( newDecl ) ) {
     746                if ( newDeclStructDecl->body ) {
     747                        return new ast::CompoundLiteralExpr( location,
     748                                new ast::StructInstType( newDeclStructDecl ),
     749                                maybeMoveBuild( kids ) );
    636750                } else {
    637                         return new CompoundLiteralExpr( new StructInstType( Type::Qualifiers(), newDeclStructDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
    638                 } // if
    639         } else if ( UnionDecl * newDeclUnionDecl = dynamic_cast< UnionDecl * >( newDecl )  ) {
    640                 if ( newDeclUnionDecl->has_body() ) {
    641                         return new CompoundLiteralExpr( new UnionInstType( Type::Qualifiers(), newDeclUnionDecl ), maybeMoveBuild< Initializer >(kids) );
     751                        return new ast::CompoundLiteralExpr( location,
     752                                new ast::StructInstType( newDeclStructDecl->name ),
     753                                maybeMoveBuild( kids ) );
     754                } // if
     755        } else if ( auto newDeclUnionDecl = dynamic_cast<ast::UnionDecl *>( newDecl )  ) {
     756                if ( newDeclUnionDecl->body ) {
     757                        return new ast::CompoundLiteralExpr( location,
     758                                new ast::UnionInstType( newDeclUnionDecl ),
     759                                maybeMoveBuild( kids ) );
    642760                } else {
    643                         return new CompoundLiteralExpr( new UnionInstType( Type::Qualifiers(), newDeclUnionDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
    644                 } // if
    645         } else if ( EnumDecl * newDeclEnumDecl = dynamic_cast< EnumDecl * >( newDecl )  ) {
    646                 if ( newDeclEnumDecl->has_body() ) {
    647                         return new CompoundLiteralExpr( new EnumInstType( Type::Qualifiers(), newDeclEnumDecl ), maybeMoveBuild< Initializer >(kids) );
     761                        return new ast::CompoundLiteralExpr( location,
     762                                new ast::UnionInstType( newDeclUnionDecl->name ),
     763                                maybeMoveBuild( kids ) );
     764                } // if
     765        } else if ( auto newDeclEnumDecl = dynamic_cast<ast::EnumDecl *>( newDecl )  ) {
     766                if ( newDeclEnumDecl->body ) {
     767                        return new ast::CompoundLiteralExpr( location,
     768                                new ast::EnumInstType( newDeclEnumDecl ),
     769                                maybeMoveBuild( kids ) );
    648770                } else {
    649                         return new CompoundLiteralExpr( new EnumInstType( Type::Qualifiers(), newDeclEnumDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
     771                        return new ast::CompoundLiteralExpr( location,
     772                                new ast::EnumInstType( newDeclEnumDecl->name ),
     773                                maybeMoveBuild( kids ) );
    650774                } // if
    651775        } else {
     
    656780// Local Variables: //
    657781// tab-width: 4 //
    658 // mode: c++ //
    659 // compile-command: "make install" //
    660782// End: //
  • src/Parser/InitializerNode.cc

    r34b4268 r24d6572  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:20:24 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 28 23:27:20 2017
    13 // Update Count     : 26
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr  4 11:18:00 2023
     13// Update Count     : 27
    1414//
     15
     16#include "InitializerNode.h"
    1517
    1618#include <iostream>                // for operator<<, ostream, basic_ostream
     
    1820#include <string>                  // for operator<<, string
    1921
     22#include "AST/Expr.hpp"            // for Expr
     23#include "AST/Init.hpp"            // for Designator, Init, ListInit, Sing...
     24#include "Common/SemanticError.h"  // for SemanticError
     25#include "Common/utility.h"        // for maybeBuild
     26#include "ExpressionNode.h"        // for ExpressionNode
     27#include "DeclarationNode.h"       // for buildList
     28
    2029using namespace std;
    2130
    22 #include "Common/SemanticError.h"  // for SemanticError
    23 #include "Common/utility.h"        // for maybeBuild
    24 #include "ParseNode.h"             // for InitializerNode, ExpressionNode
    25 #include "SynTree/Expression.h"    // for Expression
    26 #include "SynTree/Initializer.h"   // for Initializer, ListInit, SingleInit
     31static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
     32        return maybeConstructed ? ast::MaybeConstruct : ast::NoConstruct;
     33}
    2734
    2835InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des )
     
    3340        if ( kids )
    3441                set_last( nullptr );
    35 } // InitializerNode::InitializerNode
     42} // InitializerNode::InitializerNode
    3643
    3744InitializerNode::InitializerNode( InitializerNode * init, bool aggrp, ExpressionNode * des )
     
    8592} // InitializerNode::printOneLine
    8693
    87 Initializer * InitializerNode::build() const {
     94ast::Init * InitializerNode::build() const {
    8895        assertf( ! isDelete, "Should not build delete stmt InitializerNode" );
    8996        if ( aggregate ) {
    9097                // steal designators from children
    91                 std::list< Designation * > designlist;
     98                std::vector<ast::ptr<ast::Designation>> designlist;
    9299                InitializerNode * child = next_init();
    93                 for ( ; child != nullptr; child = dynamic_cast< InitializerNode * >( child->get_next() ) ) {
    94                         std::list< Expression * > desList;
    95                         buildList< Expression, ExpressionNode >( child->designator, desList );
    96                         designlist.push_back( new Designation( desList ) );
     100                for ( ; child != nullptr ; child = dynamic_cast< InitializerNode * >( child->get_next() ) ) {
     101                        std::deque<ast::ptr<ast::Expr>> desList;
     102                        buildList( child->designator, desList );
     103                        designlist.push_back(
     104                                new ast::Designation( location, std::move( desList ) ) );
    97105                } // for
    98                 std::list< Initializer * > initlist;
    99                 buildList< Initializer, InitializerNode >( next_init(), initlist );
    100                 return new ListInit( initlist, designlist, maybeConstructed );
    101         } else {
    102                 if ( get_expression() ) {
    103                         assertf( get_expression()->expr, "The expression of initializer must have value" );
    104                         return new SingleInit( maybeBuild< Expression >( get_expression() ), maybeConstructed );
    105                 } // if
     106                std::vector<ast::ptr<ast::Init>> initlist;
     107                buildList( next_init(), initlist );
     108                return new ast::ListInit( location,
     109                        std::move( initlist ),
     110                        std::move( designlist ),
     111                        toConstructFlag( maybeConstructed )
     112                );
     113        } else if ( get_expression() ) {
     114                assertf( get_expression()->expr, "The expression of initializer must have value" );
     115                return new ast::SingleInit( location,
     116                        maybeBuild( get_expression() ),
     117                        toConstructFlag( maybeConstructed )
     118                );
    106119        } // if
    107120        return nullptr;
  • src/Parser/ParseNode.h

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

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

    r34b4268 r24d6572  
    1010// Author           : Rodolfo G. Esteves
    1111// Created On       : Sat May 16 14:59:41 2015
    12 // Last Modified By : Peter A. Buhr
    13 // Last Modified On : Wed Feb  2 20:29:30 2022
    14 // Update Count     : 425
     12// Last Modified By : Andrew Beach
     13// Last Modified On : Tue Apr 11 10:16:00 2023
     14// Update Count     : 428
    1515//
    1616
     17#include "StatementNode.h"
     18
    1719#include <cassert>                 // for assert, strict_dynamic_cast, assertf
    18 #include <list>                    // for list
    1920#include <memory>                  // for unique_ptr
    2021#include <string>                  // for string
    2122
     23#include "AST/Label.hpp"           // for Label
     24#include "AST/Stmt.hpp"            // for Stmt, AsmStmt, BranchStmt, CaseCla...
    2225#include "Common/SemanticError.h"  // for SemanticError
    2326#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
    24 #include "ParseNode.h"             // for StatementNode, ExpressionNode, bui...
    25 #include "SynTree/Expression.h"    // for Expression, ConstantExpr
    26 #include "SynTree/Label.h"         // for Label, noLabels
    27 #include "SynTree/Declaration.h"
    28 #include "SynTree/Statement.h"     // for Statement, BranchStmt, CaseStmt
     27#include "DeclarationNode.h"       // for DeclarationNode
     28#include "ExpressionNode.h"        // for ExpressionNode
    2929#include "parserutility.h"         // for notZeroExpr
    3030
     
    3333using namespace std;
    3434
     35// Some helpers for cases that really want a single node but check for lists.
     36static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
     37        std::vector<ast::ptr<ast::Stmt>> list;
     38        buildMoveList( node, list );
     39        assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
     40        return list.front().release();
     41}
     42
     43static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
     44        std::vector<ast::ptr<ast::Stmt>> list;
     45        buildMoveList( node, list );
     46        assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
     47        return list.empty() ? nullptr : list.front().release();
     48}
    3549
    3650StatementNode::StatementNode( DeclarationNode * decl ) {
     
    3852        DeclarationNode * agg = decl->extractAggregate();
    3953        if ( agg ) {
    40                 StatementNode * nextStmt = new StatementNode( new DeclStmt( maybeBuild< Declaration >( decl ) ) );
     54                StatementNode * nextStmt = new StatementNode(
     55                        new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
    4156                set_next( nextStmt );
    4257                if ( decl->get_next() ) {
     
    5166                agg = decl;
    5267        } // if
    53         stmt.reset( new DeclStmt( maybeMoveBuild< Declaration >(agg) ) );
     68        // Local copy to avoid accessing the pointer after it is moved from.
     69        CodeLocation declLocation = agg->location;
     70        stmt.reset( new ast::DeclStmt( declLocation, maybeMoveBuild( agg ) ) );
    5471} // StatementNode::StatementNode
    5572
    56 StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
    57         StatementNode * prev = this;
     73StatementNode * StatementNode::add_label(
     74                const CodeLocation & location,
     75                const std::string * name,
     76                DeclarationNode * attr ) {
     77        stmt->labels.emplace_back( location,
     78                *name,
     79                attr ? std::move( attr->attributes )
     80                        : std::vector<ast::ptr<ast::Attribute>>{} );
     81        delete attr;
     82        delete name;
     83        return this;
     84}
     85
     86ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
     87        ClauseNode * prev = this;
    5888        // find end of list and maintain previous pointer
    59         for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) {
    60                 StatementNode * node = strict_dynamic_cast< StatementNode * >(curr);
    61                 assert( dynamic_cast< CaseStmt * >(node->stmt.get()) );
     89        for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
     90                ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
     91                assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
    6292                prev = curr;
    6393        } // for
     94        ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
    6495        // convert from StatementNode list to Statement list
    65         StatementNode * node = dynamic_cast< StatementNode * >(prev);
    66         list< Statement * > stmts;
     96        std::vector<ast::ptr<ast::Stmt>> stmts;
    6797        buildMoveList( stmt, stmts );
    6898        // splice any new Statements to end of current Statements
    69         CaseStmt * caseStmt = dynamic_cast< CaseStmt * >(node->stmt.get());
    70         caseStmt->get_statements().splice( caseStmt->get_statements().end(), stmts );
     99        auto caseStmt = strict_dynamic_cast<ast::CaseClause *>( node->clause.get() );
     100        for ( auto const & newStmt : stmts ) {
     101                caseStmt->stmts.emplace_back( newStmt );
     102        }
     103        stmts.clear();
    71104        return this;
    72 } // StatementNode::append_last_case
    73 
    74 Statement * build_expr( ExpressionNode * ctl ) {
    75         Expression * e = maybeMoveBuild< Expression >( ctl );
    76 
    77         if ( e ) return new ExprStmt( e );
    78         else return new NullStmt();
     105} // ClauseNode::append_last_case
     106
     107ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
     108        if ( ast::Expr * e = maybeMoveBuild( ctl ) ) {
     109                return new ast::ExprStmt( location, e );
     110        } else {
     111                return new ast::NullStmt( location );
     112        }
    79113} // build_expr
    80114
    81 Expression * build_if_control( CondCtl * ctl, list< Statement * > & init ) {
    82         if ( ctl->init != 0 ) {
    83                 buildMoveList( ctl->init, init );
     115static ast::Expr * build_if_control( CondCtl * ctl,
     116                std::vector<ast::ptr<ast::Stmt>> & inits ) {
     117        assert( inits.empty() );
     118        if ( nullptr != ctl->init ) {
     119                buildMoveList( ctl->init, inits );
    84120        } // if
    85121
    86         Expression * cond = nullptr;
     122        ast::Expr * cond = nullptr;
    87123        if ( ctl->condition ) {
    88124                // compare the provided condition against 0
    89                 cond = notZeroExpr( maybeMoveBuild< Expression >(ctl->condition) );
     125                cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
    90126        } else {
    91                 for ( Statement * stmt : init ) {
     127                for ( ast::ptr<ast::Stmt> & stmt : inits ) {
    92128                        // build the && of all of the declared variables compared against 0
    93                         DeclStmt * declStmt = strict_dynamic_cast< DeclStmt * >( stmt );
    94                         DeclarationWithType * dwt = strict_dynamic_cast< DeclarationWithType * >( declStmt->decl );
    95                         Expression * nze = notZeroExpr( new VariableExpr( dwt ) );
    96                         cond = cond ? new LogicalExpr( cond, nze, true ) : nze;
     129                        auto declStmt = stmt.strict_as<ast::DeclStmt>();
     130                        auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
     131                        ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
     132                        cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
    97133                }
    98134        }
     
    101137} // build_if_control
    102138
    103 Statement * build_if( CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
    104         list< Statement * > astinit;                                            // maybe empty
    105         Expression * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    106 
    107         Statement * astthen, * astelse = nullptr;
    108         list< Statement * > aststmt;
    109         buildMoveList< Statement, StatementNode >( then, aststmt );
    110         assert( aststmt.size() == 1 );
    111         astthen = aststmt.front();
    112 
    113         if ( else_ ) {
    114                 list< Statement * > aststmt;
    115                 buildMoveList< Statement, StatementNode >( else_, aststmt );
    116                 assert( aststmt.size() == 1 );
    117                 astelse = aststmt.front();
    118         } // if
    119 
    120         return new IfStmt( astcond, astthen, astelse, astinit );
     139ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
     140        std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
     141        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
     142
     143        ast::Stmt const * astthen = buildMoveSingle( then );
     144        ast::Stmt const * astelse = buildMoveOptional( else_ );
     145
     146        return new ast::IfStmt( location, astcond, astthen, astelse,
     147                std::move( astinit )
     148        );
    121149} // build_if
    122150
    123 Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
    124         list< Statement * > aststmt;
    125         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    126         if ( ! isSwitch ) {                                                                     // choose statement
    127                 for ( Statement * stmt : aststmt ) {
    128                         CaseStmt * caseStmt = strict_dynamic_cast< CaseStmt * >( stmt );
    129                         if ( ! caseStmt->stmts.empty() ) {                      // code after "case" => end of case list
    130                                 CompoundStmt * block = strict_dynamic_cast< CompoundStmt * >( caseStmt->stmts.front() );
    131                                 block->kids.push_back( new BranchStmt( "", BranchStmt::Break ) );
     151ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
     152        std::vector<ast::ptr<ast::CaseClause>> aststmt;
     153        buildMoveList( stmt, aststmt );
     154        // If it is not a switch it is a choose statement.
     155        if ( ! isSwitch ) {
     156                for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) {
     157                        // Code after "case" is the end of case list.
     158                        if ( !stmt->stmts.empty() ) {
     159                                auto mutStmt = ast::mutate( stmt.get() );
     160                                // I believe the stmts are actually always one block.
     161                                auto stmts = mutStmt->stmts.front().get_and_mutate();
     162                                auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts );
     163                                block->kids.push_back( new ast::BranchStmt( block->location,
     164                                        ast::BranchStmt::Break,
     165                                        ast::Label( block->location ) ) );
     166                                stmt = mutStmt;
    132167                        } // if
    133168                } // for
    134169        } // if
    135170        // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
    136         return new SwitchStmt( maybeMoveBuild< Expression >(ctl), aststmt );
     171        return new ast::SwitchStmt( location,
     172                maybeMoveBuild( ctl ), std::move( aststmt ) );
    137173} // build_switch
    138174
    139 Statement * build_case( ExpressionNode * ctl ) {
    140         return new CaseStmt( maybeMoveBuild< Expression >(ctl), {} ); // stmt starts empty and then added to
     175ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
     176        // stmt starts empty and then added to
     177        auto expr = maybeMoveBuild( ctl );
     178        return new ast::CaseClause( location, expr, {} );
    141179} // build_case
    142180
    143 Statement * build_default() {
    144         return new CaseStmt( nullptr, {}, true );                       // stmt starts empty and then added to
     181ast::CaseClause * build_default( const CodeLocation & location ) {
     182        // stmt starts empty and then added to
     183        return new ast::CaseClause( location, nullptr, {} );
    145184} // build_default
    146185
    147 Statement * build_while( CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
    148         list< Statement * > astinit;                                            // maybe empty
    149         Expression * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    150 
    151         list< Statement * > aststmt;                                            // loop body, compound created if empty
    152         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    153         assert( aststmt.size() == 1 );
    154 
    155         list< Statement * > astelse;                                            // else clause, maybe empty
    156         buildMoveList< Statement, StatementNode >( else_, astelse );
    157 
    158         return new WhileDoStmt( astcond, aststmt.front(), astelse.front(), astinit, false );
     186ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
     187        std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
     188        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
     189
     190        return new ast::WhileDoStmt( location,
     191                astcond,
     192                buildMoveSingle( stmt ),
     193                buildMoveOptional( else_ ),
     194                std::move( astinit ),
     195                ast::While
     196        );
    159197} // build_while
    160198
    161 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
    162         list< Statement * > aststmt;                                            // loop body, compound created if empty
    163         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    164         assert( aststmt.size() == 1 );                                          // compound created if empty
    165 
    166         list< Statement * > astelse;                                            // else clause, maybe empty
    167         buildMoveList< Statement, StatementNode >( else_, astelse );
    168 
     199ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
    169200        // do-while cannot have declarations in the contitional, so init is always empty
    170         return new WhileDoStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), aststmt.front(), astelse.front(), {}, true );
     201        return new ast::WhileDoStmt( location,
     202                notZeroExpr( maybeMoveBuild( ctl ) ),
     203                buildMoveSingle( stmt ),
     204                buildMoveOptional( else_ ),
     205                {},
     206                ast::DoWhile
     207        );
    171208} // build_do_while
    172209
    173 Statement * build_for( ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
    174         list< Statement * > astinit;                                            // maybe empty
     210ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
     211        std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
    175212        buildMoveList( forctl->init, astinit );
    176213
    177         Expression * astcond = nullptr;                                         // maybe empty
    178         astcond = notZeroExpr( maybeMoveBuild< Expression >(forctl->condition) );
    179 
    180         Expression * astincr = nullptr;                                         // maybe empty
    181         astincr = maybeMoveBuild< Expression >(forctl->change);
     214        ast::Expr * astcond = nullptr;                                          // maybe empty
     215        astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
     216
     217        ast::Expr * astincr = nullptr;                                          // maybe empty
     218        astincr = maybeMoveBuild( forctl->change );
    182219        delete forctl;
    183220
    184         list< Statement * > aststmt;                                            // loop body, compound created if empty
    185         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    186         assert( aststmt.size() == 1 );
    187 
    188         list< Statement * > astelse;                                            // else clause, maybe empty
    189         buildMoveList< Statement, StatementNode >( else_, astelse );
    190 
    191         return new ForStmt( astinit, astcond, astincr, aststmt.front(), astelse.front() );
     221        return new ast::ForStmt( location,
     222                std::move( astinit ),
     223                astcond,
     224                astincr,
     225                buildMoveSingle( stmt ),
     226                buildMoveOptional( else_ )
     227        );
    192228} // build_for
    193229
    194 Statement * build_branch( BranchStmt::Type kind ) {
    195         Statement * ret = new BranchStmt( "", kind );
    196         return ret;
     230ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
     231        return new ast::BranchStmt( location,
     232                kind,
     233                ast::Label( location )
     234        );
    197235} // build_branch
    198236
    199 Statement * build_branch( string * identifier, BranchStmt::Type kind ) {
    200         Statement * ret = new BranchStmt( * identifier, kind );
     237ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) {
     238        ast::Stmt * ret = new ast::BranchStmt( location,
     239                kind,
     240                ast::Label( location, *identifier )
     241        );
    201242        delete identifier;                                                                      // allocated by lexer
    202243        return ret;
    203244} // build_branch
    204245
    205 Statement * build_computedgoto( ExpressionNode * ctl ) {
    206         return new BranchStmt( maybeMoveBuild< Expression >(ctl), BranchStmt::Goto );
     246ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
     247        ast::Expr * expr = maybeMoveBuild( ctl );
     248        return new ast::BranchStmt( expr->location, expr );
    207249} // build_computedgoto
    208250
    209 Statement * build_return( ExpressionNode * ctl ) {
    210         list< Expression * > exps;
     251ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
     252        std::vector<ast::ptr<ast::Expr>> exps;
    211253        buildMoveList( ctl, exps );
    212         return new ReturnStmt( exps.size() > 0 ? exps.back() : nullptr );
     254        return new ast::ReturnStmt( location,
     255                exps.size() > 0 ? exps.back().release() : nullptr
     256        );
    213257} // build_return
    214258
    215 Statement * build_throw( ExpressionNode * ctl ) {
    216         list< Expression * > exps;
     259static ast::Stmt * build_throw_stmt(
     260                const CodeLocation & location,
     261                ExpressionNode * ctl,
     262                ast::ExceptionKind kind ) {
     263        std::vector<ast::ptr<ast::Expr>> exps;
    217264        buildMoveList( ctl, exps );
    218265        assertf( exps.size() < 2, "CFA internal error: leaking memory" );
    219         return new ThrowStmt( ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr );
     266        return new ast::ThrowStmt( location,
     267                kind,
     268                !exps.empty() ? exps.back().release() : nullptr,
     269                (ast::Expr *)nullptr
     270        );
     271}
     272
     273ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
     274        return build_throw_stmt( loc, ctl, ast::Terminate );
    220275} // build_throw
    221276
    222 Statement * build_resume( ExpressionNode * ctl ) {
    223         list< Expression * > exps;
    224         buildMoveList( ctl, exps );
    225         assertf( exps.size() < 2, "CFA internal error: leaking memory" );
    226         return new ThrowStmt( ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr );
     277ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
     278        return build_throw_stmt( loc, ctl, ast::Resume );
    227279} // build_resume
    228280
    229 Statement * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
     281ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
    230282        (void)ctl;
    231283        (void)target;
     
    233285} // build_resume_at
    234286
    235 Statement * build_try( StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
    236         list< CatchStmt * > aststmt;
    237         buildMoveList< CatchStmt, StatementNode >( catch_, aststmt );
    238         CompoundStmt * tryBlock = strict_dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(try_));
    239         FinallyStmt * finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_) );
    240         return new TryStmt( tryBlock, aststmt, finallyBlock );
     287ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
     288        std::vector<ast::ptr<ast::CatchClause>> aststmt;
     289        buildMoveList( catch_, aststmt );
     290        ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
     291        ast::FinallyClause * finallyBlock = nullptr;
     292        if ( finally_ ) {
     293                finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() );
     294        }
     295        return new ast::TryStmt( location,
     296                tryBlock,
     297                std::move( aststmt ),
     298                finallyBlock
     299        );
    241300} // build_try
    242301
    243 Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
    244         list< Statement * > aststmt;
    245         buildMoveList< Statement, StatementNode >( body, aststmt );
    246         assert( aststmt.size() == 1 );
    247         return new CatchStmt( kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), aststmt.front() );
     302ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
     303        return new ast::CatchClause( location,
     304                kind,
     305                maybeMoveBuild( decl ),
     306                maybeMoveBuild( cond ),
     307                buildMoveSingle( body )
     308        );
    248309} // build_catch
    249310
    250 Statement * build_finally( StatementNode * stmt ) {
    251         list< Statement * > aststmt;
    252         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    253         assert( aststmt.size() == 1 );
    254         return new FinallyStmt( dynamic_cast< CompoundStmt * >( aststmt.front() ) );
     311ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
     312        return new ast::FinallyClause( location,
     313                strict_dynamic_cast<const ast::CompoundStmt *>(
     314                        buildMoveSingle( stmt )
     315                )
     316        );
    255317} // build_finally
    256318
    257 SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) {
    258         auto node = new SuspendStmt();
    259 
    260         node->type = type;
    261 
    262         list< Statement * > stmts;
    263         buildMoveList< Statement, StatementNode >( then, stmts );
    264         if(!stmts.empty()) {
    265                 assert( stmts.size() == 1 );
    266                 node->then = dynamic_cast< CompoundStmt * >( stmts.front() );
    267         }
    268 
    269         return node;
    270 }
    271 
    272 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
    273         auto node = new WaitForStmt();
    274 
    275         WaitForStmt::Target target;
    276         target.function = maybeBuild<Expression>( targetExpr );
     319ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
     320        return new ast::SuspendStmt( location,
     321                strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
     322                        buildMoveOptional( then )
     323                ),
     324                kind
     325        );
     326} // build_suspend
     327
     328ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
     329        auto clause = new ast::WaitForClause( location );
     330        clause->target = maybeBuild( targetExpr );
     331        clause->stmt = maybeMoveBuild( stmt );
     332        clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    277333
    278334        ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
    279335        targetExpr->set_next( nullptr );
    280         buildMoveList< Expression >( next, target.arguments );
     336        buildMoveList( next, clause->target_args );
    281337
    282338        delete targetExpr;
    283339
    284         node->clauses.push_back( WaitForStmt::Clause{
    285                 target,
    286                 maybeMoveBuild<Statement >( stmt ),
    287                 notZeroExpr( maybeMoveBuild<Expression>( when ) )
    288         });
    289 
    290         return node;
     340        existing->clauses.insert( existing->clauses.begin(), clause );
     341
     342        return existing;
    291343} // build_waitfor
    292344
    293 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when, WaitForStmt * node ) {
    294         WaitForStmt::Target target;
    295         target.function = maybeBuild<Expression>( targetExpr );
    296 
    297         ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
    298         targetExpr->set_next( nullptr );
    299         buildMoveList< Expression >( next, target.arguments );
    300 
    301         delete targetExpr;
    302 
    303         node->clauses.insert( node->clauses.begin(), WaitForStmt::Clause{
    304                 std::move( target ),
    305                 maybeMoveBuild<Statement >( stmt ),
    306                 notZeroExpr( maybeMoveBuild<Expression>( when ) )
    307         });
    308 
    309         return node;
    310 } // build_waitfor
    311 
    312 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when ) {
    313         auto node = new WaitForStmt();
    314 
    315         if( timeout ) {
    316                 node->timeout.time      = maybeMoveBuild<Expression>( timeout );
    317                 node->timeout.statement = maybeMoveBuild<Statement >( stmt    );
    318                 node->timeout.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) );
    319         } else {
    320                 node->orelse.statement  = maybeMoveBuild<Statement >( stmt );
    321                 node->orelse.condition  = notZeroExpr( maybeMoveBuild<Expression>( when ) );
    322         } // if
    323 
    324         return node;
     345ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
     346        existing->else_stmt = maybeMoveBuild( stmt );
     347        existing->else_cond = notZeroExpr( maybeMoveBuild( when ) );
     348
     349        (void)location;
     350        return existing;
     351} // build_waitfor_else
     352
     353ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
     354        existing->timeout_time = maybeMoveBuild( timeout );
     355        existing->timeout_stmt = maybeMoveBuild( stmt );
     356        existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) );
     357
     358        (void)location;
     359        return existing;
    325360} // build_waitfor_timeout
    326361
    327 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when,  StatementNode * else_, ExpressionNode * else_when ) {
    328         auto node = new WaitForStmt();
    329 
    330         node->timeout.time      = maybeMoveBuild<Expression>( timeout );
    331         node->timeout.statement = maybeMoveBuild<Statement >( stmt    );
    332         node->timeout.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) );
    333 
    334         node->orelse.statement  = maybeMoveBuild<Statement >( else_ );
    335         node->orelse.condition  = notZeroExpr( maybeMoveBuild<Expression>( else_when ) );
    336 
    337         return node;
    338 } // build_waitfor_timeout
    339 
    340 Statement * build_with( ExpressionNode * exprs, StatementNode * stmt ) {
    341         list< Expression * > e;
     362ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
     363    ast::WhenClause * clause = new ast::WhenClause( loc );
     364    clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     365    clause->stmt = maybeMoveBuild( stmt );
     366    clause->target = maybeMoveBuild( targetExpr );
     367    return new ast::WaitUntilStmt::ClauseNode( clause );
     368}
     369ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
     370    ast::WhenClause * clause = new ast::WhenClause( loc );
     371    clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     372    clause->stmt = maybeMoveBuild( stmt );
     373    return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
     374}
     375ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
     376    ast::WhenClause * clause = new ast::WhenClause( loc );
     377    clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     378    clause->stmt = maybeMoveBuild( stmt );
     379    clause->target = maybeMoveBuild( timeout );
     380    return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::TIMEOUT, clause );
     381}
     382
     383ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {
     384    ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
     385    retStmt->predicateTree = root;
     386   
     387    // iterative tree traversal
     388    std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
     389    ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
     390    ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
     391    ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
     392    nodeStack.push_back(root);
     393
     394    do {
     395        currNode = nodeStack.back();
     396        nodeStack.pop_back(); // remove node since it will be processed
     397
     398        switch (currNode->op) {
     399            case ast::WaitUntilStmt::ClauseNode::LEAF:
     400                retStmt->clauses.push_back(currNode->leaf);
     401                break;
     402            case ast::WaitUntilStmt::ClauseNode::ELSE:
     403                retStmt->else_stmt = currNode->leaf->stmt
     404                    ? ast::deepCopy( currNode->leaf->stmt )
     405                    : nullptr;
     406               
     407                retStmt->else_cond = currNode->leaf->when_cond
     408                    ? ast::deepCopy( currNode->leaf->when_cond )
     409                    : nullptr;
     410
     411                delete currNode->leaf;
     412                break;
     413            case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
     414                retStmt->timeout_time = currNode->leaf->target
     415                    ? ast::deepCopy( currNode->leaf->target )
     416                    : nullptr;
     417                retStmt->timeout_stmt = currNode->leaf->stmt
     418                    ? ast::deepCopy( currNode->leaf->stmt )
     419                    : nullptr;
     420                retStmt->timeout_cond = currNode->leaf->when_cond
     421                    ? ast::deepCopy( currNode->leaf->when_cond )
     422                    : nullptr;
     423
     424                delete currNode->leaf;
     425                break;
     426            default:
     427                nodeStack.push_back( currNode->right ); // process right after left
     428                nodeStack.push_back( currNode->left );
     429
     430                // Cut else/timeout out of the tree
     431                if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
     432                    if ( lastInternalNode )
     433                        lastInternalNode->right = currNode->left;
     434                    else    // if not set then root is LEFT_OR
     435                        retStmt->predicateTree = currNode->left;
     436   
     437                    currNode->left = nullptr;
     438                    cleanup = currNode;
     439                }
     440               
     441                lastInternalNode = currNode;
     442                break;
     443        }
     444    } while ( !nodeStack.empty() );
     445
     446    if ( cleanup ) delete cleanup;
     447
     448    return retStmt;
     449}
     450
     451ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
     452        std::vector<ast::ptr<ast::Expr>> e;
    342453        buildMoveList( exprs, e );
    343         Statement * s = maybeMoveBuild<Statement>( stmt );
    344         return new DeclStmt( new WithStmt( e, s ) );
     454        ast::Stmt * s = maybeMoveBuild( stmt );
     455        return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
    345456} // build_with
    346457
    347 Statement * build_compound( StatementNode * first ) {
    348         CompoundStmt * cs = new CompoundStmt();
    349         buildMoveList( first, cs->get_kids() );
     458ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
     459        auto cs = new ast::CompoundStmt( location );
     460        buildMoveList( first, cs->kids );
    350461        return cs;
    351462} // build_compound
     
    355466// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
    356467// conical form for code generation.
    357 StatementNode * maybe_build_compound( StatementNode * first ) {
     468StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
    358469        // Optimization: if the control-structure statement is a compound statement, do not wrap it.
    359470        // e.g., if (...) {...} do not wrap the existing compound statement.
    360         if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
    361                 CompoundStmt * cs = new CompoundStmt();
    362                 buildMoveList( first, cs->get_kids() );
    363                 return new StatementNode( cs );
     471        if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
     472                return new StatementNode( build_compound( location, first ) );
    364473        } // if
    365474        return first;
     
    367476
    368477// Question
    369 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    370         list< Expression * > out, in;
    371         list< ConstantExpr * > clob;
     478ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
     479        std::vector<ast::ptr<ast::Expr>> out, in;
     480        std::vector<ast::ptr<ast::ConstantExpr>> clob;
    372481
    373482        buildMoveList( output, out );
    374483        buildMoveList( input, in );
    375484        buildMoveList( clobber, clob );
    376         return new AsmStmt( voltile, instruction, out, in, clob, gotolabels ? gotolabels->labels : noLabels );
     485        return new ast::AsmStmt( location,
     486                is_volatile,
     487                maybeMoveBuild( instruction ),
     488                std::move( out ),
     489                std::move( in ),
     490                std::move( clob ),
     491                gotolabels ? gotolabels->labels : std::vector<ast::Label>()
     492        );
    377493} // build_asm
    378494
    379 Statement * build_directive( string * directive ) {
    380         return new DirectiveStmt( *directive );
     495ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
     496        auto stmt = new ast::DirectiveStmt( location, *directive );
     497        delete directive;
     498        return stmt;
    381499} // build_directive
    382500
    383 Statement * build_mutex( ExpressionNode * exprs, StatementNode * stmt ) {
    384         list< Expression * > expList;
     501ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
     502        std::vector<ast::ptr<ast::Expr>> expList;
    385503        buildMoveList( exprs, expList );
    386         Statement * body = maybeMoveBuild<Statement>( stmt );
    387         return new MutexStmt( body, expList );
     504        ast::Stmt * body = maybeMoveBuild( stmt );
     505        return new ast::MutexStmt( location, body, std::move( expList ) );
    388506} // build_mutex
    389507
  • src/Parser/TypeData.cc

    r34b4268 r24d6572  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 15:12:51 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue May 10 22:36:52 2022
    13 // Update Count     : 677
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr  4 13:39:00 2023
     13// Update Count     : 680
    1414//
     15
     16#include "TypeData.h"
    1517
    1618#include <cassert>                 // for assert
    1719#include <ostream>                 // for operator<<, ostream, basic_ostream
    1820
     21#include "AST/Decl.hpp"            // for AggregateDecl, ObjectDecl, TypeDe...
     22#include "AST/Init.hpp"            // for SingleInit, ListInit
     23#include "AST/Print.hpp"           // for print
    1924#include "Common/SemanticError.h"  // for SemanticError
    20 #include "Common/utility.h"        // for maybeClone, maybeBuild, maybeMoveB...
    21 #include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
    22 #include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, FunctionDecl
    23 #include "SynTree/Expression.h"    // for Expression, ConstantExpr (ptr only)
    24 #include "SynTree/Initializer.h"   // for SingleInit, Initializer (ptr only)
    25 #include "SynTree/Statement.h"     // for CompoundStmt, Statement
    26 #include "SynTree/Type.h"          // for BasicType, Type, Type::ForallList
    27 #include "TypeData.h"
     25#include "Common/utility.h"        // for splice, spliceBegin
     26#include "Parser/ExpressionNode.h" // for ExpressionNode
     27#include "Parser/StatementNode.h"  // for StatementNode
    2828
    2929class Attribute;
     
    3333TypeData::TypeData( Kind k ) : location( yylloc ), kind( k ), base( nullptr ), forall( nullptr ) /*, PTR1( (void*)(0xdeadbeefdeadbeef)), PTR2( (void*)(0xdeadbeefdeadbeef) ) */ {
    3434        switch ( kind ) {
    35           case Unknown:
    36           case Pointer:
    37           case Reference:
    38           case EnumConstant:
    39           case GlobalScope:
    40                 // nothing else to initialize
    41                 break;
    42           case Basic:
    43                 // basic = new Basic_t;
    44                 break;
    45           case Array:
    46                 // array = new Array_t;
     35        case Unknown:
     36        case Pointer:
     37        case Reference:
     38        case EnumConstant:
     39        case GlobalScope:
     40        case Basic:
     41                // No unique data to initialize.
     42                break;
     43        case Array:
    4744                array.dimension = nullptr;
    4845                array.isVarLen = false;
    4946                array.isStatic = false;
    5047                break;
    51           case Function:
    52                 // function = new Function_t;
     48        case Function:
    5349                function.params = nullptr;
    5450                function.idList = nullptr;
     
    5753                function.withExprs = nullptr;
    5854                break;
    59                 // Enum is an Aggregate, so both structures are initialized together.
    60           case Enum:
    61                 // enumeration = new Enumeration_t;
     55        case Enum:
    6256                enumeration.name = nullptr;
    6357                enumeration.constants = nullptr;
     
    6559                enumeration.anon = false;
    6660                break;
    67           case Aggregate:
    68                 // aggregate = new Aggregate_t;
    69                 aggregate.kind = AggregateDecl::NoAggregate;
     61        case Aggregate:
     62                aggregate.kind = ast::AggregateDecl::NoAggregate;
    7063                aggregate.name = nullptr;
    7164                aggregate.params = nullptr;
     
    7770                aggregate.anon = false;
    7871                break;
    79           case AggregateInst:
    80                 // aggInst = new AggInst_t;
     72        case AggregateInst:
    8173                aggInst.aggregate = nullptr;
    8274                aggInst.params = nullptr;
    8375                aggInst.hoistType = false;
    8476                break;
    85           case Symbolic:
    86           case SymbolicInst:
    87                 // symbolic = new Symbolic_t;
     77        case Symbolic:
     78        case SymbolicInst:
    8879                symbolic.name = nullptr;
    8980                symbolic.params = nullptr;
     
    9182                symbolic.assertions = nullptr;
    9283                break;
    93           case Tuple:
    94                 // tuple = new Tuple_t;
     84        case Tuple:
    9585                tuple = nullptr;
    9686                break;
    97           case Typeof:
    98           case Basetypeof:
    99                 // typeexpr = new Typeof_t;
     87        case Typeof:
     88        case Basetypeof:
    10089                typeexpr = nullptr;
    10190                break;
    102           case Vtable:
    103                 break;
    104           case Builtin:
    105                 // builtin = new Builtin_t;
    106                 case Qualified:
     91        case Vtable:
     92        case Builtin:
     93                // No unique data to initialize.
     94                break;
     95        case Qualified:
    10796                qualified.parent = nullptr;
    10897                qualified.child = nullptr;
     
    117106
    118107        switch ( kind ) {
    119           case Unknown:
    120           case Pointer:
    121           case Reference:
    122           case EnumConstant:
    123           case GlobalScope:
    124                 // nothing to destroy
    125                 break;
    126           case Basic:
    127                 // delete basic;
    128                 break;
    129           case Array:
     108        case Unknown:
     109        case Pointer:
     110        case Reference:
     111        case EnumConstant:
     112        case GlobalScope:
     113        case Basic:
     114                // No unique data to deconstruct.
     115                break;
     116        case Array:
    130117                delete array.dimension;
    131                 // delete array;
    132                 break;
    133           case Function:
     118                break;
     119        case Function:
    134120                delete function.params;
    135121                delete function.idList;
     
    137123                delete function.body;
    138124                delete function.withExprs;
    139                 // delete function;
    140                 break;
    141           case Aggregate:
     125                break;
     126        case Aggregate:
    142127                delete aggregate.name;
    143128                delete aggregate.params;
    144129                delete aggregate.actuals;
    145130                delete aggregate.fields;
    146                 // delete aggregate;
    147                 break;
    148           case AggregateInst:
     131                break;
     132        case AggregateInst:
    149133                delete aggInst.aggregate;
    150134                delete aggInst.params;
    151                 // delete aggInst;
    152                 break;
    153           case Enum:
     135                break;
     136        case Enum:
    154137                delete enumeration.name;
    155138                delete enumeration.constants;
    156                 // delete enumeration;
    157                 break;
    158           case Symbolic:
    159           case SymbolicInst:
     139                break;
     140        case Symbolic:
     141        case SymbolicInst:
    160142                delete symbolic.name;
    161143                delete symbolic.params;
    162144                delete symbolic.actuals;
    163145                delete symbolic.assertions;
    164                 // delete symbolic;
    165                 break;
    166           case Tuple:
    167                 // delete tuple->members;
     146                break;
     147        case Tuple:
    168148                delete tuple;
    169149                break;
    170           case Typeof:
    171           case Basetypeof:
    172                 // delete typeexpr->expr;
     150        case Typeof:
     151        case Basetypeof:
    173152                delete typeexpr;
    174153                break;
    175           case Vtable:
    176                 break;
    177           case Builtin:
    178                 // delete builtin;
    179                 break;
    180           case Qualified:
     154        case Vtable:
     155        case Builtin:
     156                // No unique data to deconstruct.
     157                break;
     158        case Qualified:
    181159                delete qualified.parent;
    182160                delete qualified.child;
     161                break;
    183162        } // switch
    184163} // TypeData::~TypeData
     
    192171
    193172        switch ( kind ) {
    194           case Unknown:
    195           case EnumConstant:
    196           case Pointer:
    197           case Reference:
    198           case GlobalScope:
     173        case Unknown:
     174        case EnumConstant:
     175        case Pointer:
     176        case Reference:
     177        case GlobalScope:
    199178                // nothing else to copy
    200179                break;
    201           case Basic:
     180        case Basic:
    202181                newtype->basictype = basictype;
    203182                newtype->complextype = complextype;
     
    205184                newtype->length = length;
    206185                break;
    207           case Array:
     186        case Array:
    208187                newtype->array.dimension = maybeClone( array.dimension );
    209188                newtype->array.isVarLen = array.isVarLen;
    210189                newtype->array.isStatic = array.isStatic;
    211190                break;
    212           case Function:
     191        case Function:
    213192                newtype->function.params = maybeClone( function.params );
    214193                newtype->function.idList = maybeClone( function.idList );
     
    217196                newtype->function.withExprs = maybeClone( function.withExprs );
    218197                break;
    219           case Aggregate:
     198        case Aggregate:
    220199                newtype->aggregate.kind = aggregate.kind;
    221200                newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
     
    228207                newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
    229208                break;
    230           case AggregateInst:
     209        case AggregateInst:
    231210                newtype->aggInst.aggregate = maybeClone( aggInst.aggregate );
    232211                newtype->aggInst.params = maybeClone( aggInst.params );
    233212                newtype->aggInst.hoistType = aggInst.hoistType;
    234213                break;
    235           case Enum:
     214        case Enum:
    236215                newtype->enumeration.name = enumeration.name ? new string( *enumeration.name ) : nullptr;
    237216                newtype->enumeration.constants = maybeClone( enumeration.constants );
     
    239218                newtype->enumeration.anon = enumeration.anon;
    240219                break;
    241           case Symbolic:
    242           case SymbolicInst:
     220        case Symbolic:
     221        case SymbolicInst:
    243222                newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr;
    244223                newtype->symbolic.params = maybeClone( symbolic.params );
     
    247226                newtype->symbolic.isTypedef = symbolic.isTypedef;
    248227                break;
    249           case Tuple:
     228        case Tuple:
    250229                newtype->tuple = maybeClone( tuple );
    251230                break;
    252           case Typeof:
    253           case Basetypeof:
     231        case Typeof:
     232        case Basetypeof:
    254233                newtype->typeexpr = maybeClone( typeexpr );
    255234                break;
    256           case Vtable:
    257                 break;
    258           case Builtin:
     235        case Vtable:
     236                break;
     237        case Builtin:
    259238                assert( builtintype == DeclarationNode::Zero || builtintype == DeclarationNode::One );
    260239                newtype->builtintype = builtintype;
    261240                break;
    262                 case Qualified:
     241        case Qualified:
    263242                newtype->qualified.parent = maybeClone( qualified.parent );
    264243                newtype->qualified.child = maybeClone( qualified.child );
     
    270249
    271250void TypeData::print( ostream &os, int indent ) const {
    272         for ( int i = 0; i < Type::NumTypeQualifier; i += 1 ) {
    273                 if ( qualifiers[i] ) os << Type::QualifiersNames[ i ] << ' ';
    274         } // for
     251        ast::print( os, qualifiers );
    275252
    276253        if ( forall ) {
     
    280257
    281258        switch ( kind ) {
    282           case Basic:
     259        case Basic:
    283260                if ( signedness != DeclarationNode::NoSignedness ) os << DeclarationNode::signednessNames[ signedness ] << " ";
    284261                if ( length != DeclarationNode::NoLength ) os << DeclarationNode::lengthNames[ length ] << " ";
     
    286263                if ( basictype != DeclarationNode::NoBasicType ) os << DeclarationNode::basicTypeNames[ basictype ] << " ";
    287264                break;
    288           case Pointer:
     265        case Pointer:
    289266                os << "pointer ";
    290267                if ( base ) {
     
    293270                } // if
    294271                break;
    295           case Reference:
     272        case Reference:
    296273                os << "reference ";
    297274                if ( base ) {
     
    300277                } // if
    301278                break;
    302           case Array:
     279        case Array:
    303280                if ( array.isStatic ) {
    304281                        os << "static ";
     
    316293                } // if
    317294                break;
    318           case Function:
     295        case Function:
    319296                os << "function" << endl;
    320297                if ( function.params ) {
     
    344321                } // if
    345322                break;
    346           case Aggregate:
    347                 os << AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
     323        case Aggregate:
     324                os << ast::AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
    348325                if ( aggregate.params ) {
    349326                        os << string( indent + 2, ' ' ) << "with type parameters" << endl;
     
    362339                } // if
    363340                break;
    364           case AggregateInst:
     341        case AggregateInst:
    365342                if ( aggInst.aggregate ) {
    366343                        os << "instance of " ;
     
    374351                } // if
    375352                break;
    376           case Enum:
    377                 os << "enumeration ";
     353        case Enum:
     354                os << "enumeration " << *enumeration.name << endl;;
    378355                if ( enumeration.constants ) {
    379356                        os << "with constants" << endl;
     
    388365                } // if
    389366                break;
    390           case EnumConstant:
     367        case EnumConstant:
    391368                os << "enumeration constant ";
    392369                break;
    393           case Symbolic:
     370        case Symbolic:
    394371                if ( symbolic.isTypedef ) {
    395372                        os << "typedef definition ";
     
    411388                } // if
    412389                break;
    413           case SymbolicInst:
     390        case SymbolicInst:
    414391                os << *symbolic.name;
    415392                if ( symbolic.actuals ) {
     
    419396                } // if
    420397                break;
    421           case Tuple:
     398        case Tuple:
    422399                os << "tuple ";
    423400                if ( tuple ) {
     
    426403                } // if
    427404                break;
    428           case Basetypeof:
     405        case Basetypeof:
    429406                os << "base-";
    430407                #if defined(__GNUC__) && __GNUC__ >= 7
     
    432409                #endif
    433410                // FALL THROUGH
    434           case Typeof:
     411        case Typeof:
    435412                os << "type-of expression ";
    436413                if ( typeexpr ) {
     
    438415                } // if
    439416                break;
    440           case Vtable:
     417        case Vtable:
    441418                os << "vtable";
    442419                break;
    443           case Builtin:
     420        case Builtin:
    444421                os << DeclarationNode::builtinTypeNames[builtintype];
    445422                break;
    446           case GlobalScope:
    447                 break;
    448           case Qualified:
     423        case GlobalScope:
     424                break;
     425        case Qualified:
    449426                qualified.parent->print( os );
    450427                os << ".";
    451428                qualified.child->print( os );
    452429                break;
    453           case Unknown:
     430        case Unknown:
    454431                os << "entity of unknown type ";
    455432                break;
    456           default:
     433        default:
    457434                os << "internal error: TypeData::print " << kind << endl;
    458435                assert( false );
     
    462439const std::string * TypeData::leafName() const {
    463440        switch ( kind ) {
    464           case Unknown:
    465           case Pointer:
    466           case Reference:
    467           case EnumConstant:
    468           case GlobalScope:
    469           case Array:
    470           case Basic:
    471           case Function:
    472           case AggregateInst:
    473           case Tuple:
    474           case Typeof:
    475           case Basetypeof:
    476           case Builtin:
    477           case Vtable:
     441        case Unknown:
     442        case Pointer:
     443        case Reference:
     444        case EnumConstant:
     445        case GlobalScope:
     446        case Array:
     447        case Basic:
     448        case Function:
     449        case AggregateInst:
     450        case Tuple:
     451        case Typeof:
     452        case Basetypeof:
     453        case Builtin:
     454        case Vtable:
    478455                assertf(false, "Tried to get leaf name from kind without a name: %d", kind);
    479456                break;
    480           case Aggregate:
     457        case Aggregate:
    481458                return aggregate.name;
    482           case Enum:
     459        case Enum:
    483460                return enumeration.name;
    484           case Symbolic:
    485           case SymbolicInst:
     461        case Symbolic:
     462        case SymbolicInst:
    486463                return symbolic.name;
    487           case Qualified:
     464        case Qualified:
    488465                return qualified.child->leafName();
    489466        } // switch
     
    492469
    493470
    494 template< typename ForallList >
    495 void buildForall( const DeclarationNode * firstNode, ForallList &outputList ) {
    496         buildList( firstNode, outputList );
     471void buildForall(
     472                const DeclarationNode * firstNode,
     473                std::vector<ast::ptr<ast::TypeInstType>> &outputList ) {
     474        {
     475                std::vector<ast::ptr<ast::Type>> tmpList;
     476                buildTypeList( firstNode, tmpList );
     477                for ( auto tmp : tmpList ) {
     478                        outputList.emplace_back(
     479                                strict_dynamic_cast<const ast::TypeInstType *>(
     480                                        tmp.release() ) );
     481                }
     482        }
    497483        auto n = firstNode;
    498         for ( typename ForallList::iterator i = outputList.begin(); i != outputList.end(); ++i, n = (DeclarationNode*)n->get_next() ) {
    499                 TypeDecl * td = static_cast<TypeDecl *>(*i);
    500                 if ( n->variable.tyClass == TypeDecl::Otype ) {
    501                         // add assertion parameters to `type' tyvars in reverse order
    502                         // add dtor:  void ^?{}(T *)
    503                         FunctionType * dtorType = new FunctionType( Type::Qualifiers(), false );
    504                         dtorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
    505                         td->get_assertions().push_front( new FunctionDecl( "^?{}", Type::StorageClasses(), LinkageSpec::Cforall, dtorType, nullptr ) );
    506 
    507                         // add copy ctor:  void ?{}(T *, T)
    508                         FunctionType * copyCtorType = new FunctionType( Type::Qualifiers(), false );
    509                         copyCtorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
    510                         copyCtorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
    511                         td->get_assertions().push_front( new FunctionDecl( "?{}", Type::StorageClasses(), LinkageSpec::Cforall, copyCtorType, nullptr ) );
    512 
    513                         // add default ctor:  void ?{}(T *)
    514                         FunctionType * ctorType = new FunctionType( Type::Qualifiers(), false );
    515                         ctorType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
    516                         td->get_assertions().push_front( new FunctionDecl( "?{}", Type::StorageClasses(), LinkageSpec::Cforall, ctorType, nullptr ) );
    517 
    518                         // add assignment operator:  T * ?=?(T *, T)
    519                         FunctionType * assignType = new FunctionType( Type::Qualifiers(), false );
    520                         assignType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) );
    521                         assignType->get_parameters().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
    522                         assignType->get_returnVals().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) );
    523                         td->get_assertions().push_front( new FunctionDecl( "?=?", Type::StorageClasses(), LinkageSpec::Cforall, assignType, nullptr ) );
    524                 } // if
     484        for ( auto i = outputList.begin() ;
     485                        i != outputList.end() ;
     486                        ++i, n = (DeclarationNode*)n->get_next() ) {
     487                // Only the object type class adds additional assertions.
     488                if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
     489                        continue;
     490                }
     491
     492                ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
     493                std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
     494                auto mutTypeDecl = ast::mutate( td );
     495                const CodeLocation & location = mutTypeDecl->location;
     496                *i = mutTypeDecl;
     497
     498                // add assertion parameters to `type' tyvars in reverse order
     499                // add assignment operator:  T * ?=?(T *, T)
     500                newAssertions.push_back( new ast::FunctionDecl(
     501                        location,
     502                        "?=?",
     503                        {}, // forall
     504                        {}, // assertions
     505                        {
     506                                new ast::ObjectDecl(
     507                                        location,
     508                                        "",
     509                                        new ast::ReferenceType( i->get() ),
     510                                        (ast::Init *)nullptr,
     511                                        ast::Storage::Classes(),
     512                                        ast::Linkage::Cforall,
     513                                        (ast::Expr *)nullptr
     514                                ),
     515                                new ast::ObjectDecl(
     516                                        location,
     517                                        "",
     518                                        i->get(),
     519                                        (ast::Init *)nullptr,
     520                                        ast::Storage::Classes(),
     521                                        ast::Linkage::Cforall,
     522                                        (ast::Expr *)nullptr
     523                                ),
     524                        }, // params
     525                        {
     526                                new ast::ObjectDecl(
     527                                        location,
     528                                        "",
     529                                        i->get(),
     530                                        (ast::Init *)nullptr,
     531                                        ast::Storage::Classes(),
     532                                        ast::Linkage::Cforall,
     533                                        (ast::Expr *)nullptr
     534                                ),
     535                        }, // returns
     536                        (ast::CompoundStmt *)nullptr,
     537                        ast::Storage::Classes(),
     538                        ast::Linkage::Cforall
     539                ) );
     540
     541                // add default ctor:  void ?{}(T *)
     542                newAssertions.push_back( new ast::FunctionDecl(
     543                        location,
     544                        "?{}",
     545                        {}, // forall
     546                        {}, // assertions
     547                        {
     548                                new ast::ObjectDecl(
     549                                        location,
     550                                        "",
     551                                        new ast::ReferenceType( i->get() ),
     552                                        (ast::Init *)nullptr,
     553                                        ast::Storage::Classes(),
     554                                        ast::Linkage::Cforall,
     555                                        (ast::Expr *)nullptr
     556                                ),
     557                        }, // params
     558                        {}, // returns
     559                        (ast::CompoundStmt *)nullptr,
     560                        ast::Storage::Classes(),
     561                        ast::Linkage::Cforall
     562                ) );
     563
     564                // add copy ctor:  void ?{}(T *, T)
     565                newAssertions.push_back( new ast::FunctionDecl(
     566                        location,
     567                        "?{}",
     568                        {}, // forall
     569                        {}, // assertions
     570                        {
     571                                new ast::ObjectDecl(
     572                                        location,
     573                                        "",
     574                                        new ast::ReferenceType( i->get() ),
     575                                        (ast::Init *)nullptr,
     576                                        ast::Storage::Classes(),
     577                                        ast::Linkage::Cforall,
     578                                        (ast::Expr *)nullptr
     579                                ),
     580                                new ast::ObjectDecl(
     581                                        location,
     582                                        "",
     583                                        i->get(),
     584                                        (ast::Init *)nullptr,
     585                                        ast::Storage::Classes(),
     586                                        ast::Linkage::Cforall,
     587                                        (ast::Expr *)nullptr
     588                                ),
     589                        }, // params
     590                        {}, // returns
     591                        (ast::CompoundStmt *)nullptr,
     592                        ast::Storage::Classes(),
     593                        ast::Linkage::Cforall
     594                ) );
     595
     596                // add dtor:  void ^?{}(T *)
     597                newAssertions.push_back( new ast::FunctionDecl(
     598                        location,
     599                        "^?{}",
     600                        {}, // forall
     601                        {}, // assertions
     602                        {
     603                                new ast::ObjectDecl(
     604                                        location,
     605                                        "",
     606                                        new ast::ReferenceType( i->get() ),
     607                                        (ast::Init *)nullptr,
     608                                        ast::Storage::Classes(),
     609                                        ast::Linkage::Cforall,
     610                                        (ast::Expr *)nullptr
     611                                ),
     612                        }, // params
     613                        {}, // returns
     614                        (ast::CompoundStmt *)nullptr,
     615                        ast::Storage::Classes(),
     616                        ast::Linkage::Cforall
     617                ) );
     618
     619                spliceBegin( mutTypeDecl->assertions, newAssertions );
     620        } // for
     621}
     622
     623
     624void buildForall(
     625                const DeclarationNode * firstNode,
     626                std::vector<ast::ptr<ast::TypeDecl>> &outputForall ) {
     627        buildList( firstNode, outputForall );
     628        auto n = firstNode;
     629        for ( auto i = outputForall.begin() ;
     630                        i != outputForall.end() ;
     631                        ++i, n = (DeclarationNode*)n->get_next() ) {
     632                // Only the object type class adds additional assertions.
     633                if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
     634                        continue;
     635                }
     636
     637                ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
     638                std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
     639                auto mutTypeDecl = ast::mutate( td );
     640                const CodeLocation & location = mutTypeDecl->location;
     641                *i = mutTypeDecl;
     642
     643                // add assertion parameters to `type' tyvars in reverse order
     644                // add assignment operator:  T * ?=?(T *, T)
     645                newAssertions.push_back( new ast::FunctionDecl(
     646                        location,
     647                        "?=?",
     648                        {}, // forall
     649                        {}, // assertions
     650                        {
     651                                new ast::ObjectDecl(
     652                                        location,
     653                                        "",
     654                                        new ast::ReferenceType( new ast::TypeInstType( td->name, *i ) ),
     655                                        (ast::Init *)nullptr,
     656                                        ast::Storage::Classes(),
     657                                        ast::Linkage::Cforall,
     658                                        (ast::Expr *)nullptr
     659                                ),
     660                                new ast::ObjectDecl(
     661                                        location,
     662                                        "",
     663                                        new ast::TypeInstType( td->name, *i ),
     664                                        (ast::Init *)nullptr,
     665                                        ast::Storage::Classes(),
     666                                        ast::Linkage::Cforall,
     667                                        (ast::Expr *)nullptr
     668                                ),
     669                        }, // params
     670                        {
     671                                new ast::ObjectDecl(
     672                                        location,
     673                                        "",
     674                                        new ast::TypeInstType( td->name, *i ),
     675                                        (ast::Init *)nullptr,
     676                                        ast::Storage::Classes(),
     677                                        ast::Linkage::Cforall,
     678                                        (ast::Expr *)nullptr
     679                                ),
     680                        }, // returns
     681                        (ast::CompoundStmt *)nullptr,
     682                        ast::Storage::Classes(),
     683                        ast::Linkage::Cforall
     684                ) );
     685
     686                // add default ctor:  void ?{}(T *)
     687                newAssertions.push_back( new ast::FunctionDecl(
     688                        location,
     689                        "?{}",
     690                        {}, // forall
     691                        {}, // assertions
     692                        {
     693                                new ast::ObjectDecl(
     694                                        location,
     695                                        "",
     696                                        new ast::ReferenceType(
     697                                                new ast::TypeInstType( td->name, i->get() ) ),
     698                                        (ast::Init *)nullptr,
     699                                        ast::Storage::Classes(),
     700                                        ast::Linkage::Cforall,
     701                                        (ast::Expr *)nullptr
     702                                ),
     703                        }, // params
     704                        {}, // returns
     705                        (ast::CompoundStmt *)nullptr,
     706                        ast::Storage::Classes(),
     707                        ast::Linkage::Cforall
     708                ) );
     709
     710                // add copy ctor:  void ?{}(T *, T)
     711                newAssertions.push_back( new ast::FunctionDecl(
     712                        location,
     713                        "?{}",
     714                        {}, // forall
     715                        {}, // assertions
     716                        {
     717                                new ast::ObjectDecl(
     718                                        location,
     719                                        "",
     720                                        new ast::ReferenceType(
     721                                                new ast::TypeInstType( td->name, *i ) ),
     722                                        (ast::Init *)nullptr,
     723                                        ast::Storage::Classes(),
     724                                        ast::Linkage::Cforall,
     725                                        (ast::Expr *)nullptr
     726                                ),
     727                                new ast::ObjectDecl(
     728                                        location,
     729                                        "",
     730                                        new ast::TypeInstType( td->name, *i ),
     731                                        (ast::Init *)nullptr,
     732                                        ast::Storage::Classes(),
     733                                        ast::Linkage::Cforall,
     734                                        (ast::Expr *)nullptr
     735                                ),
     736                        }, // params
     737                        {}, // returns
     738                        (ast::CompoundStmt *)nullptr,
     739                        ast::Storage::Classes(),
     740                        ast::Linkage::Cforall
     741                ) );
     742
     743                // add dtor:  void ^?{}(T *)
     744                newAssertions.push_back( new ast::FunctionDecl(
     745                        location,
     746                        "^?{}",
     747                        {}, // forall
     748                        {}, // assertions
     749                        {
     750                                new ast::ObjectDecl(
     751                                        location,
     752                                        "",
     753                                        new ast::ReferenceType(
     754                                                new ast::TypeInstType( i->get() )
     755                                        ),
     756                                        (ast::Init *)nullptr,
     757                                        ast::Storage::Classes(),
     758                                        ast::Linkage::Cforall,
     759                                        (ast::Expr *)nullptr
     760                                ),
     761                        }, // params
     762                        {}, // returns
     763                        (ast::CompoundStmt *)nullptr,
     764                        ast::Storage::Classes(),
     765                        ast::Linkage::Cforall
     766                ) );
     767
     768                spliceBegin( mutTypeDecl->assertions, newAssertions );
    525769        } // for
    526770} // buildForall
    527771
    528772
    529 Type * typebuild( const TypeData * td ) {
     773ast::Type * typebuild( const TypeData * td ) {
    530774        assert( td );
    531775        switch ( td->kind ) {
    532           case TypeData::Unknown:
     776        case TypeData::Unknown:
    533777                // fill in implicit int
    534                 return new BasicType( buildQualifiers( td ), BasicType::SignedInt );
    535           case TypeData::Basic:
     778                return new ast::BasicType(
     779                        ast::BasicType::SignedInt,
     780                        buildQualifiers( td )
     781                );
     782        case TypeData::Basic:
    536783                return buildBasicType( td );
    537           case TypeData::Pointer:
     784        case TypeData::Pointer:
    538785                return buildPointer( td );
    539           case TypeData::Array:
     786        case TypeData::Array:
    540787                return buildArray( td );
    541           case TypeData::Reference:
     788        case TypeData::Reference:
    542789                return buildReference( td );
    543           case TypeData::Function:
    544                 return buildFunction( td );
    545           case TypeData::AggregateInst:
     790        case TypeData::Function:
     791                return buildFunctionType( td );
     792        case TypeData::AggregateInst:
    546793                return buildAggInst( td );
    547           case TypeData::EnumConstant:
    548                 return new EnumInstType( buildQualifiers( td ), "" );
    549           case TypeData::SymbolicInst:
     794        case TypeData::EnumConstant:
     795                return new ast::EnumInstType( "", buildQualifiers( td ) );
     796        case TypeData::SymbolicInst:
    550797                return buildSymbolicInst( td );
    551           case TypeData::Tuple:
     798        case TypeData::Tuple:
    552799                return buildTuple( td );
    553           case TypeData::Typeof:
    554           case TypeData::Basetypeof:
     800        case TypeData::Typeof:
     801        case TypeData::Basetypeof:
    555802                return buildTypeof( td );
    556           case TypeData::Vtable:
     803        case TypeData::Vtable:
    557804                return buildVtable( td );
    558           case TypeData::Builtin:
     805        case TypeData::Builtin:
    559806                switch ( td->builtintype ) {
    560                   case DeclarationNode::Zero:
    561                         return new ZeroType( noQualifiers );
    562                   case DeclarationNode::One:
    563                         return new OneType( noQualifiers );
    564                   default:
    565                         return new VarArgsType( buildQualifiers( td ) );
     807                case DeclarationNode::Zero:
     808                        return new ast::ZeroType();
     809                case DeclarationNode::One:
     810                        return new ast::OneType();
     811                default:
     812                        return new ast::VarArgsType( buildQualifiers( td ) );
    566813                } // switch
    567           case TypeData::GlobalScope:
    568                 return new GlobalScopeType();
    569           case TypeData::Qualified:
    570                 return new QualifiedType( buildQualifiers( td ), typebuild( td->qualified.parent ), typebuild( td->qualified.child ) );
    571           case TypeData::Symbolic:
    572           case TypeData::Enum:
    573           case TypeData::Aggregate:
     814        case TypeData::GlobalScope:
     815                return new ast::GlobalScopeType();
     816        case TypeData::Qualified:
     817                return new ast::QualifiedType(
     818                        typebuild( td->qualified.parent ),
     819                        typebuild( td->qualified.child ),
     820                        buildQualifiers( td )
     821                );
     822        case TypeData::Symbolic:
     823        case TypeData::Enum:
     824        case TypeData::Aggregate:
    574825                assert( false );
    575826        } // switch
     
    583834
    584835        switch ( td->kind ) {
    585           case TypeData::Aggregate:
     836        case TypeData::Aggregate:
    586837                if ( ! toplevel && td->aggregate.body ) {
    587838                        ret = td->clone();
    588839                } // if
    589840                break;
    590           case TypeData::Enum:
     841        case TypeData::Enum:
    591842                if ( ! toplevel && td->enumeration.body ) {
    592843                        ret = td->clone();
    593844                } // if
    594845                break;
    595           case TypeData::AggregateInst:
     846        case TypeData::AggregateInst:
    596847                if ( td->aggInst.aggregate ) {
    597848                        ret = typeextractAggregate( td->aggInst.aggregate, false );
    598849                } // if
    599850                break;
    600           default:
     851        default:
    601852                if ( td->base ) {
    602853                        ret = typeextractAggregate( td->base, false );
     
    607858
    608859
    609 Type::Qualifiers buildQualifiers( const TypeData * td ) {
     860ast::CV::Qualifiers buildQualifiers( const TypeData * td ) {
    610861        return td->qualifiers;
    611862} // buildQualifiers
     
    616867} // genTSError
    617868
    618 Type * buildBasicType( const TypeData * td ) {
    619         BasicType::Kind ret;
     869ast::Type * buildBasicType( const TypeData * td ) {
     870        ast::BasicType::Kind ret;
    620871
    621872        switch ( td->basictype ) {
    622           case DeclarationNode::Void:
     873        case DeclarationNode::Void:
    623874                if ( td->signedness != DeclarationNode::NoSignedness ) {
    624875                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    627878                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
    628879                } // if
    629                 return new VoidType( buildQualifiers( td ) );
    630                 break;
    631 
    632           case DeclarationNode::Bool:
     880                return new ast::VoidType( buildQualifiers( td ) );
     881                break;
     882
     883        case DeclarationNode::Bool:
    633884                if ( td->signedness != DeclarationNode::NoSignedness ) {
    634885                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    638889                } // if
    639890
    640                 ret = BasicType::Bool;
    641                 break;
    642 
    643           case DeclarationNode::Char:
     891                ret = ast::BasicType::Bool;
     892                break;
     893
     894        case DeclarationNode::Char:
    644895                // C11 Standard 6.2.5.15: The three types char, signed char, and unsigned char are collectively called the
    645896                // character types. The implementation shall define char to have the same range, representation, and behavior as
    646897                // either signed char or unsigned char.
    647                 static BasicType::Kind chartype[] = { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::Char };
     898                static ast::BasicType::Kind chartype[] = { ast::BasicType::SignedChar, ast::BasicType::UnsignedChar, ast::BasicType::Char };
    648899
    649900                if ( td->length != DeclarationNode::NoLength ) {
     
    654905                break;
    655906
    656           case DeclarationNode::Int:
    657                 static BasicType::Kind inttype[2][4] = {
    658                         { BasicType::ShortSignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt },
    659                         { BasicType::ShortUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt },
     907        case DeclarationNode::Int:
     908                static ast::BasicType::Kind inttype[2][4] = {
     909                        { ast::BasicType::ShortSignedInt, ast::BasicType::LongSignedInt, ast::BasicType::LongLongSignedInt, ast::BasicType::SignedInt },
     910                        { ast::BasicType::ShortUnsignedInt, ast::BasicType::LongUnsignedInt, ast::BasicType::LongLongUnsignedInt, ast::BasicType::UnsignedInt },
    660911                };
    661912
    662           Integral: ;
     913        Integral: ;
    663914                if ( td->signedness == DeclarationNode::NoSignedness ) {
    664915                        const_cast<TypeData *>(td)->signedness = DeclarationNode::Signed;
     
    667918                break;
    668919
    669           case DeclarationNode::Int128:
    670                 ret = td->signedness == DeclarationNode::Unsigned ? BasicType::UnsignedInt128 : BasicType::SignedInt128;
     920        case DeclarationNode::Int128:
     921                ret = td->signedness == DeclarationNode::Unsigned ? ast::BasicType::UnsignedInt128 : ast::BasicType::SignedInt128;
    671922                if ( td->length != DeclarationNode::NoLength ) {
    672923                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
     
    674925                break;
    675926
    676           case DeclarationNode::Float:
    677           case DeclarationNode::Double:
    678           case DeclarationNode::LongDouble:                                     // not set until below
    679           case DeclarationNode::uuFloat80:
    680           case DeclarationNode::uuFloat128:
    681           case DeclarationNode::uFloat16:
    682           case DeclarationNode::uFloat32:
    683           case DeclarationNode::uFloat32x:
    684           case DeclarationNode::uFloat64:
    685           case DeclarationNode::uFloat64x:
    686           case DeclarationNode::uFloat128:
    687           case DeclarationNode::uFloat128x:
    688                 static BasicType::Kind floattype[2][12] = {
    689                         { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, (BasicType::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex, },
    690                         { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x, },
     927        case DeclarationNode::Float:
     928        case DeclarationNode::Double:
     929        case DeclarationNode::LongDouble:                                       // not set until below
     930        case DeclarationNode::uuFloat80:
     931        case DeclarationNode::uuFloat128:
     932        case DeclarationNode::uFloat16:
     933        case DeclarationNode::uFloat32:
     934        case DeclarationNode::uFloat32x:
     935        case DeclarationNode::uFloat64:
     936        case DeclarationNode::uFloat64x:
     937        case DeclarationNode::uFloat128:
     938        case DeclarationNode::uFloat128x:
     939                static ast::BasicType::Kind floattype[2][12] = {
     940                        { ast::BasicType::FloatComplex, ast::BasicType::DoubleComplex, ast::BasicType::LongDoubleComplex, (ast::BasicType::Kind)-1, (ast::BasicType::Kind)-1, ast::BasicType::uFloat16Complex, ast::BasicType::uFloat32Complex, ast::BasicType::uFloat32xComplex, ast::BasicType::uFloat64Complex, ast::BasicType::uFloat64xComplex, ast::BasicType::uFloat128Complex, ast::BasicType::uFloat128xComplex, },
     941                        { ast::BasicType::Float, ast::BasicType::Double, ast::BasicType::LongDouble, ast::BasicType::uuFloat80, ast::BasicType::uuFloat128, ast::BasicType::uFloat16, ast::BasicType::uFloat32, ast::BasicType::uFloat32x, ast::BasicType::uFloat64, ast::BasicType::uFloat64x, ast::BasicType::uFloat128, ast::BasicType::uFloat128x, },
    691942                };
    692943
    693           FloatingPoint: ;
     944        FloatingPoint: ;
    694945                if ( td->signedness != DeclarationNode::NoSignedness ) {
    695946                        genTSError( DeclarationNode::signednessNames[ td->signedness ], td->basictype );
     
    715966                break;
    716967
    717           case DeclarationNode::NoBasicType:
     968        case DeclarationNode::NoBasicType:
    718969                // No basic type in declaration => default double for Complex/Imaginary and int type for integral types
    719970                if ( td->complextype == DeclarationNode::Complex || td->complextype == DeclarationNode::Imaginary ) {
     
    724975                const_cast<TypeData *>(td)->basictype = DeclarationNode::Int;
    725976                goto Integral;
    726           default:
    727                 assertf( false, "unknown basic type" );
     977        default:
     978                assertf( false, "unknown basic type" );
    728979                return nullptr;
    729980        } // switch
    730981
    731         BasicType * bt = new BasicType( buildQualifiers( td ), ret );
    732         buildForall( td->forall, bt->get_forall() );
     982        ast::BasicType * bt = new ast::BasicType( ret, buildQualifiers( td ) );
    733983        return bt;
    734984} // buildBasicType
    735985
    736986
    737 PointerType * buildPointer( const TypeData * td ) {
    738         PointerType * pt;
     987ast::PointerType * buildPointer( const TypeData * td ) {
     988        ast::PointerType * pt;
    739989        if ( td->base ) {
    740                 pt = new PointerType( buildQualifiers( td ), typebuild( td->base ) );
     990                pt = new ast::PointerType(
     991                        typebuild( td->base ),
     992                        buildQualifiers( td )
     993                );
    741994        } else {
    742                 pt = new PointerType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
     995                pt = new ast::PointerType(
     996                        new ast::BasicType( ast::BasicType::SignedInt ),
     997                        buildQualifiers( td )
     998                );
    743999        } // if
    744         buildForall( td->forall, pt->get_forall() );
    7451000        return pt;
    7461001} // buildPointer
    7471002
    7481003
    749 ArrayType * buildArray( const TypeData * td ) {
    750         ArrayType * at;
     1004ast::ArrayType * buildArray( const TypeData * td ) {
     1005        ast::ArrayType * at;
    7511006        if ( td->base ) {
    752                 at = new ArrayType( buildQualifiers( td ), typebuild( td->base ), maybeBuild< Expression >( td->array.dimension ),
    753                                                         td->array.isVarLen, td->array.isStatic );
     1007                at = new ast::ArrayType(
     1008                        typebuild( td->base ),
     1009                        maybeBuild( td->array.dimension ),
     1010                        td->array.isVarLen ? ast::VariableLen : ast::FixedLen,
     1011                        td->array.isStatic ? ast::StaticDim : ast::DynamicDim,
     1012                        buildQualifiers( td )
     1013                );
    7541014        } else {
    755                 at = new ArrayType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ),
    756                                                         maybeBuild< Expression >( td->array.dimension ), td->array.isVarLen, td->array.isStatic );
     1015                at = new ast::ArrayType(
     1016                        new ast::BasicType( ast::BasicType::SignedInt ),
     1017                        maybeBuild( td->array.dimension ),
     1018                        td->array.isVarLen ? ast::VariableLen : ast::FixedLen,
     1019                        td->array.isStatic ? ast::StaticDim : ast::DynamicDim,
     1020                        buildQualifiers( td )
     1021                );
    7571022        } // if
    758         buildForall( td->forall, at->get_forall() );
    7591023        return at;
    7601024} // buildArray
    7611025
    7621026
    763 ReferenceType * buildReference( const TypeData * td ) {
    764         ReferenceType * rt;
     1027ast::ReferenceType * buildReference( const TypeData * td ) {
     1028        ast::ReferenceType * rt;
    7651029        if ( td->base ) {
    766                 rt = new ReferenceType( buildQualifiers( td ), typebuild( td->base ) );
     1030                rt = new ast::ReferenceType(
     1031                        typebuild( td->base ),
     1032                        buildQualifiers( td )
     1033                );
    7671034        } else {
    768                 rt = new ReferenceType( buildQualifiers( td ), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
     1035                rt = new ast::ReferenceType(
     1036                        new ast::BasicType( ast::BasicType::SignedInt ),
     1037                        buildQualifiers( td )
     1038                );
    7691039        } // if
    770         buildForall( td->forall, rt->get_forall() );
    7711040        return rt;
    7721041} // buildReference
    7731042
    7741043
    775 AggregateDecl * buildAggregate( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
     1044ast::AggregateDecl * buildAggregate( const TypeData * td, std::vector<ast::ptr<ast::Attribute>> attributes, ast::Linkage::Spec linkage ) {
    7761045        assert( td->kind == TypeData::Aggregate );
    777         AggregateDecl * at;
     1046        ast::AggregateDecl * at;
    7781047        switch ( td->aggregate.kind ) {
    779           case AggregateDecl::Struct:
    780           case AggregateDecl::Coroutine:
    781           case AggregateDecl::Exception:
    782           case AggregateDecl::Generator:
    783           case AggregateDecl::Monitor:
    784           case AggregateDecl::Thread:
    785                 at = new StructDecl( *td->aggregate.name, td->aggregate.kind, attributes, linkage );
    786                 buildForall( td->aggregate.params, at->get_parameters() );
    787                 break;
    788           case AggregateDecl::Union:
    789                 at = new UnionDecl( *td->aggregate.name, attributes, linkage );
    790                 buildForall( td->aggregate.params, at->get_parameters() );
    791                 break;
    792           case AggregateDecl::Trait:
    793                 at = new TraitDecl( *td->aggregate.name, attributes, linkage );
    794                 buildList( td->aggregate.params, at->get_parameters() );
    795                 break;
    796           default:
     1048        case ast::AggregateDecl::Struct:
     1049        case ast::AggregateDecl::Coroutine:
     1050        case ast::AggregateDecl::Exception:
     1051        case ast::AggregateDecl::Generator:
     1052        case ast::AggregateDecl::Monitor:
     1053        case ast::AggregateDecl::Thread:
     1054                at = new ast::StructDecl( td->location,
     1055                        *td->aggregate.name,
     1056                        td->aggregate.kind,
     1057                        std::move( attributes ),
     1058                        linkage
     1059                );
     1060                buildForall( td->aggregate.params, at->params );
     1061                break;
     1062        case ast::AggregateDecl::Union:
     1063                at = new ast::UnionDecl( td->location,
     1064                        *td->aggregate.name,
     1065                        std::move( attributes ),
     1066                        linkage
     1067                );
     1068                buildForall( td->aggregate.params, at->params );
     1069                break;
     1070        case ast::AggregateDecl::Trait:
     1071                at = new ast::TraitDecl( td->location,
     1072                        *td->aggregate.name,
     1073                        std::move( attributes ),
     1074                        linkage
     1075                );
     1076                buildList( td->aggregate.params, at->params );
     1077                break;
     1078        default:
    7971079                assert( false );
    7981080        } // switch
    7991081
    800         buildList( td->aggregate.fields, at->get_members() );
     1082        buildList( td->aggregate.fields, at->members );
    8011083        at->set_body( td->aggregate.body );
    8021084
     
    8051087
    8061088
    807 ReferenceToType * buildComAggInst( const TypeData * type, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
     1089ast::BaseInstType * buildComAggInst(
     1090                const TypeData * type,
     1091                std::vector<ast::ptr<ast::Attribute>> && attributes,
     1092                ast::Linkage::Spec linkage ) {
    8081093        switch ( type->kind ) {
    809           case TypeData::Enum: {
    810                   if ( type->enumeration.body ) {
    811                           EnumDecl * typedecl = buildEnum( type, attributes, linkage );
    812                           return new EnumInstType( buildQualifiers( type ), typedecl );
    813                   } else {
    814                           return new EnumInstType( buildQualifiers( type ), *type->enumeration.name );
    815                   } // if
    816           }
    817           case TypeData::Aggregate: {
    818                   ReferenceToType * ret;
    819                   if ( type->aggregate.body ) {
    820                           AggregateDecl * typedecl = buildAggregate( type, attributes, linkage );
    821                           switch ( type->aggregate.kind ) {
    822                                 case AggregateDecl::Struct:
    823                                 case AggregateDecl::Coroutine:
    824                                 case AggregateDecl::Monitor:
    825                                 case AggregateDecl::Thread:
    826                                   ret = new StructInstType( buildQualifiers( type ), (StructDecl *)typedecl );
    827                                   break;
    828                                 case AggregateDecl::Union:
    829                                   ret = new UnionInstType( buildQualifiers( type ), (UnionDecl *)typedecl );
    830                                   break;
    831                                 case AggregateDecl::Trait:
    832                                   assert( false );
    833                                   //ret = new TraitInstType( buildQualifiers( type ), (TraitDecl *)typedecl );
    834                                   break;
    835                                 default:
    836                                   assert( false );
    837                           } // switch
    838                   } else {
    839                           switch ( type->aggregate.kind ) {
    840                                 case AggregateDecl::Struct:
    841                                 case AggregateDecl::Coroutine:
    842                                 case AggregateDecl::Monitor:
    843                                 case AggregateDecl::Thread:
    844                                   ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
    845                                   break;
    846                                 case AggregateDecl::Union:
    847                                   ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
    848                                   break;
    849                                 case AggregateDecl::Trait:
    850                                   ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
    851                                   break;
    852                                 default:
    853                                   assert( false );
    854                           } // switch
    855                   } // if
    856                   return ret;
    857           }
    858           default:
     1094        case TypeData::Enum:
     1095                if ( type->enumeration.body ) {
     1096                        ast::EnumDecl * typedecl =
     1097                                buildEnum( type, std::move( attributes ), linkage );
     1098                        return new ast::EnumInstType(
     1099                                typedecl,
     1100                                buildQualifiers( type )
     1101                        );
     1102                } else {
     1103                        return new ast::EnumInstType(
     1104                                *type->enumeration.name,
     1105                                buildQualifiers( type )
     1106                        );
     1107                } // if
     1108                break;
     1109        case TypeData::Aggregate:
     1110                if ( type->aggregate.body ) {
     1111                        ast::AggregateDecl * typedecl =
     1112                                buildAggregate( type, std::move( attributes ), linkage );
     1113                        switch ( type->aggregate.kind ) {
     1114                        case ast::AggregateDecl::Struct:
     1115                        case ast::AggregateDecl::Coroutine:
     1116                        case ast::AggregateDecl::Monitor:
     1117                        case ast::AggregateDecl::Thread:
     1118                                return new ast::StructInstType(
     1119                                        strict_dynamic_cast<ast::StructDecl *>( typedecl ),
     1120                                        buildQualifiers( type )
     1121                                );
     1122                        case ast::AggregateDecl::Union:
     1123                                return new ast::UnionInstType(
     1124                                        strict_dynamic_cast<ast::UnionDecl *>( typedecl ),
     1125                                        buildQualifiers( type )
     1126                                );
     1127                        case ast::AggregateDecl::Trait:
     1128                                assert( false );
     1129                                break;
     1130                        default:
     1131                                assert( false );
     1132                        } // switch
     1133                } else {
     1134                        switch ( type->aggregate.kind ) {
     1135                        case ast::AggregateDecl::Struct:
     1136                        case ast::AggregateDecl::Coroutine:
     1137                        case ast::AggregateDecl::Monitor:
     1138                        case ast::AggregateDecl::Thread:
     1139                                return new ast::StructInstType(
     1140                                        *type->aggregate.name,
     1141                                        buildQualifiers( type )
     1142                                );
     1143                        case ast::AggregateDecl::Union:
     1144                                return new ast::UnionInstType(
     1145                                        *type->aggregate.name,
     1146                                        buildQualifiers( type )
     1147                                );
     1148                        case ast::AggregateDecl::Trait:
     1149                                return new ast::TraitInstType(
     1150                                        *type->aggregate.name,
     1151                                        buildQualifiers( type )
     1152                                );
     1153                        default:
     1154                                assert( false );
     1155                        } // switch
     1156                        break;
     1157                } // if
     1158                break;
     1159        default:
    8591160                assert( false );
    8601161        } // switch
     1162        assert( false );
    8611163} // buildAggInst
    8621164
    8631165
    864 ReferenceToType * buildAggInst( const TypeData * td ) {
     1166ast::BaseInstType * buildAggInst( const TypeData * td ) {
    8651167        assert( td->kind == TypeData::AggregateInst );
    8661168
    867         // ReferenceToType * ret = buildComAggInst( td->aggInst.aggregate, std::list< Attribute * >() );
    868         ReferenceToType * ret = nullptr;
     1169        ast::BaseInstType * ret = nullptr;
    8691170        TypeData * type = td->aggInst.aggregate;
    8701171        switch ( type->kind ) {
    871           case TypeData::Enum: {
    872                   return new EnumInstType( buildQualifiers( type ), *type->enumeration.name );
    873           }
    874           case TypeData::Aggregate: {
    875                   switch ( type->aggregate.kind ) {
    876                         case AggregateDecl::Struct:
    877                         case AggregateDecl::Coroutine:
    878                         case AggregateDecl::Monitor:
    879                         case AggregateDecl::Thread:
    880                           ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
    881                           break;
    882                         case AggregateDecl::Union:
    883                           ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
    884                           break;
    885                         case AggregateDecl::Trait:
    886                           ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
    887                           break;
    888                         default:
    889                           assert( false );
    890                   } // switch
    891           }
    892           break;
    893           default:
     1172        case TypeData::Enum:
     1173                return new ast::EnumInstType(
     1174                        *type->enumeration.name,
     1175                        buildQualifiers( type )
     1176                );
     1177        case TypeData::Aggregate:
     1178                switch ( type->aggregate.kind ) {
     1179                case ast::AggregateDecl::Struct:
     1180                case ast::AggregateDecl::Coroutine:
     1181                case ast::AggregateDecl::Monitor:
     1182                case ast::AggregateDecl::Thread:
     1183                        ret = new ast::StructInstType(
     1184                                *type->aggregate.name,
     1185                                buildQualifiers( type )
     1186                        );
     1187                        break;
     1188                case ast::AggregateDecl::Union:
     1189                        ret = new ast::UnionInstType(
     1190                                *type->aggregate.name,
     1191                                buildQualifiers( type )
     1192                        );
     1193                        break;
     1194                case ast::AggregateDecl::Trait:
     1195                        ret = new ast::TraitInstType(
     1196                                *type->aggregate.name,
     1197                                buildQualifiers( type )
     1198                        );
     1199                        break;
     1200                default:
     1201                        assert( false );
     1202                } // switch
     1203                break;
     1204        default:
    8941205                assert( false );
    8951206        } // switch
    8961207
    897         ret->set_hoistType( td->aggInst.hoistType );
    898         buildList( td->aggInst.params, ret->get_parameters() );
    899         buildForall( td->forall, ret->get_forall() );
     1208        ret->hoistType = td->aggInst.hoistType;
     1209        buildList( td->aggInst.params, ret->params );
    9001210        return ret;
    9011211} // buildAggInst
    9021212
    9031213
    904 NamedTypeDecl * buildSymbolic( const TypeData * td, std::list< Attribute * > attributes, const string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) {
     1214ast::NamedTypeDecl * buildSymbolic(
     1215                const TypeData * td,
     1216                std::vector<ast::ptr<ast::Attribute>> attributes,
     1217                const std::string & name,
     1218                ast::Storage::Classes scs,
     1219                ast::Linkage::Spec linkage ) {
    9051220        assert( td->kind == TypeData::Symbolic );
    906         NamedTypeDecl * ret;
     1221        ast::NamedTypeDecl * ret;
    9071222        assert( td->base );
    9081223        if ( td->symbolic.isTypedef ) {
    909                 ret = new TypedefDecl( name, td->location, scs, typebuild( td->base ), linkage );
     1224                ret = new ast::TypedefDecl(
     1225                        td->location,
     1226                        name,
     1227                        scs,
     1228                        typebuild( td->base ),
     1229                        linkage
     1230                );
    9101231        } else {
    911                 ret = new TypeDecl( name, scs, typebuild( td->base ), TypeDecl::Dtype, true );
     1232                ret = new ast::TypeDecl(
     1233                        td->location,
     1234                        name,
     1235                        scs,
     1236                        typebuild( td->base ),
     1237                        ast::TypeDecl::Dtype,
     1238                        true
     1239                );
    9121240        } // if
    913         buildList( td->symbolic.assertions, ret->get_assertions() );
    914         ret->base->attributes.splice( ret->base->attributes.end(), attributes );
     1241        buildList( td->symbolic.assertions, ret->assertions );
     1242        splice( ret->base.get_and_mutate()->attributes, attributes );
    9151243        return ret;
    9161244} // buildSymbolic
    9171245
    9181246
    919 EnumDecl * buildEnum( const TypeData * td, std::list< Attribute * > attributes, LinkageSpec::Spec linkage ) {
     1247ast::EnumDecl * buildEnum(
     1248                const TypeData * td,
     1249                std::vector<ast::ptr<ast::Attribute>> && attributes,
     1250                ast::Linkage::Spec linkage ) {
    9201251        assert( td->kind == TypeData::Enum );
    921         Type * baseType = td->base ? typebuild(td->base) : nullptr;
    922         EnumDecl * ret = new EnumDecl( *td->enumeration.name, attributes, td->enumeration.typed, linkage, baseType );
    923         buildList( td->enumeration.constants, ret->get_members() );
    924         list< Declaration * >::iterator members = ret->get_members().begin();
    925         ret->hide = td->enumeration.hiding == EnumHiding::Hide ? EnumDecl::EnumHiding::Hide : EnumDecl::EnumHiding::Visible;
     1252        ast::Type * baseType = td->base ? typebuild(td->base) : nullptr;
     1253        ast::EnumDecl * ret = new ast::EnumDecl(
     1254                td->location,
     1255                *td->enumeration.name,
     1256                td->enumeration.typed,
     1257                std::move( attributes ),
     1258                linkage,
     1259                baseType
     1260        );
     1261        buildList( td->enumeration.constants, ret->members );
     1262        auto members = ret->members.begin();
     1263        ret->hide = td->enumeration.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
    9261264        for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
    9271265                if ( cur->enumInLine ) {
     
    9301268                        SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
    9311269                } else if ( cur->has_enumeratorValue() ) {
    932                         ObjectDecl * member = dynamic_cast< ObjectDecl * >(* members);
    933                         member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_enumeratorValue() ) ) );
     1270                        ast::Decl * member = members->get_and_mutate();
     1271                        ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
     1272                        object->init = new ast::SingleInit(
     1273                                td->location,
     1274                                maybeMoveBuild( cur->consume_enumeratorValue() ),
     1275                                ast::NoConstruct
     1276                        );
    9341277                } else if ( !cur->initializer ) {
    935                         if ( baseType && (!dynamic_cast<BasicType *>(baseType) || !dynamic_cast<BasicType *>(baseType)->isWholeNumber())) {
     1278                        if ( baseType && (!dynamic_cast<ast::BasicType *>(baseType) || !dynamic_cast<ast::BasicType *>(baseType)->isInteger())) {
    9361279                                SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." );
    9371280                        }
     
    9401283                // if
    9411284        } // for
    942         ret->set_body( td->enumeration.body );
     1285        ret->body = td->enumeration.body;
    9431286        return ret;
    9441287} // buildEnum
    9451288
    9461289
    947 TypeInstType * buildSymbolicInst( const TypeData * td ) {
     1290ast::TypeInstType * buildSymbolicInst( const TypeData * td ) {
    9481291        assert( td->kind == TypeData::SymbolicInst );
    949         TypeInstType * ret = new TypeInstType( buildQualifiers( td ), *td->symbolic.name, false );
    950         buildList( td->symbolic.actuals, ret->get_parameters() );
    951         buildForall( td->forall, ret->get_forall() );
     1292        ast::TypeInstType * ret = new ast::TypeInstType(
     1293                *td->symbolic.name,
     1294                ast::TypeDecl::Dtype,
     1295                buildQualifiers( td )
     1296        );
     1297        buildList( td->symbolic.actuals, ret->params );
    9521298        return ret;
    9531299} // buildSymbolicInst
    9541300
    9551301
    956 TupleType * buildTuple( const TypeData * td ) {
     1302ast::TupleType * buildTuple( const TypeData * td ) {
    9571303        assert( td->kind == TypeData::Tuple );
    958         std::list< Type * > types;
     1304        std::vector<ast::ptr<ast::Type>> types;
    9591305        buildTypeList( td->tuple, types );
    960         TupleType * ret = new TupleType( buildQualifiers( td ), types );
    961         buildForall( td->forall, ret->get_forall() );
     1306        ast::TupleType * ret = new ast::TupleType(
     1307                std::move( types ),
     1308                buildQualifiers( td )
     1309        );
    9621310        return ret;
    9631311} // buildTuple
    9641312
    9651313
    966 TypeofType * buildTypeof( const TypeData * td ) {
     1314ast::TypeofType * buildTypeof( const TypeData * td ) {
    9671315        assert( td->kind == TypeData::Typeof || td->kind == TypeData::Basetypeof );
    9681316        assert( td->typeexpr );
    969         // assert( td->typeexpr->expr );
    970         return new TypeofType{ buildQualifiers( td ), td->typeexpr->build(), td->kind == TypeData::Basetypeof };
     1317        return new ast::TypeofType(
     1318                td->typeexpr->build(),
     1319                td->kind == TypeData::Typeof
     1320                        ? ast::TypeofType::Typeof : ast::TypeofType::Basetypeof,
     1321                buildQualifiers( td )
     1322        );
    9711323} // buildTypeof
    9721324
    9731325
    974 VTableType * buildVtable( const TypeData * td ) {
     1326ast::VTableType * buildVtable( const TypeData * td ) {
    9751327        assert( td->base );
    976         return new VTableType{ buildQualifiers( td ), typebuild( td->base ) };
     1328        return new ast::VTableType(
     1329                typebuild( td->base ),
     1330                buildQualifiers( td )
     1331        );
    9771332} // buildVtable
    9781333
    9791334
    980 Declaration * buildDecl( const TypeData * td, const string &name, Type::StorageClasses scs, Expression * bitfieldWidth, Type::FuncSpecifiers funcSpec, LinkageSpec::Spec linkage, Expression *asmName, Initializer * init, std::list< Attribute * > attributes ) {
     1335ast::FunctionDecl * buildFunctionDecl(
     1336                const TypeData * td,
     1337                const string &name,
     1338                ast::Storage::Classes scs,
     1339                ast::Function::Specs funcSpec,
     1340                ast::Linkage::Spec linkage,
     1341                ast::Expr * asmName,
     1342                std::vector<ast::ptr<ast::Attribute>> && attributes ) {
     1343        assert( td->kind == TypeData::Function );
     1344        // For some reason FunctionDecl takes a bool instead of an ArgumentFlag.
     1345        bool isVarArgs = !td->function.params || td->function.params->hasEllipsis;
     1346        ast::CV::Qualifiers cvq = buildQualifiers( td );
     1347        std::vector<ast::ptr<ast::TypeDecl>> forall;
     1348        std::vector<ast::ptr<ast::DeclWithType>> assertions;
     1349        std::vector<ast::ptr<ast::DeclWithType>> params;
     1350        std::vector<ast::ptr<ast::DeclWithType>> returns;
     1351        buildList( td->function.params, params );
     1352        buildForall( td->forall, forall );
     1353        // Functions do not store their assertions there anymore.
     1354        for ( ast::ptr<ast::TypeDecl> & type_param : forall ) {
     1355                auto mut = type_param.get_and_mutate();
     1356                splice( assertions, mut->assertions );
     1357        }
     1358        if ( td->base ) {
     1359                switch ( td->base->kind ) {
     1360                case TypeData::Tuple:
     1361                        buildList( td->base->tuple, returns );
     1362                        break;
     1363                default:
     1364                        returns.push_back( dynamic_cast<ast::DeclWithType *>(
     1365                                buildDecl(
     1366                                        td->base,
     1367                                        "",
     1368                                        ast::Storage::Classes(),
     1369                                        (ast::Expr *)nullptr, // bitfieldWidth
     1370                                        ast::Function::Specs(),
     1371                                        ast::Linkage::Cforall,
     1372                                        (ast::Expr *)nullptr // asmName
     1373                                )
     1374                        ) );
     1375                } // switch
     1376        } else {
     1377                returns.push_back( new ast::ObjectDecl(
     1378                        td->location,
     1379                        "",
     1380                        new ast::BasicType( ast::BasicType::SignedInt ),
     1381                        (ast::Init *)nullptr,
     1382                        ast::Storage::Classes(),
     1383                        ast::Linkage::Cforall
     1384                ) );
     1385        } // if
     1386        ast::Stmt * stmt = maybeBuild( td->function.body );
     1387        ast::CompoundStmt * body = dynamic_cast<ast::CompoundStmt *>( stmt );
     1388        ast::FunctionDecl * decl = new ast::FunctionDecl( td->location,
     1389                name,
     1390                std::move( forall ),
     1391                std::move( assertions ),
     1392                std::move( params ),
     1393                std::move( returns ),
     1394                body,
     1395                scs,
     1396                linkage,
     1397                std::move( attributes ),
     1398                funcSpec,
     1399                (isVarArgs) ? ast::VariableArgs : ast::FixedArgs
     1400        );
     1401        buildList( td->function.withExprs, decl->withExprs );
     1402        decl->asmName = asmName;
     1403        // This may be redundant on a declaration.
     1404        decl->type.get_and_mutate()->qualifiers = cvq;
     1405        return decl;
     1406} // buildFunctionDecl
     1407
     1408
     1409ast::Decl * buildDecl(
     1410                const TypeData * td,
     1411                const string &name,
     1412                ast::Storage::Classes scs,
     1413                ast::Expr * bitfieldWidth,
     1414                ast::Function::Specs funcSpec,
     1415                ast::Linkage::Spec linkage,
     1416                ast::Expr * asmName,
     1417                ast::Init * init,
     1418                std::vector<ast::ptr<ast::Attribute>> && attributes ) {
    9811419        if ( td->kind == TypeData::Function ) {
    9821420                if ( td->function.idList ) {                                    // KR function ?
     
    9841422                } // if
    9851423
    986                 FunctionDecl * decl;
    987                 Statement * stmt = maybeBuild<Statement>( td->function.body );
    988                 CompoundStmt * body = dynamic_cast< CompoundStmt * >( stmt );
    989                 decl = new FunctionDecl( name, scs, linkage, buildFunction( td ), body, attributes, funcSpec );
    990                 buildList( td->function.withExprs, decl->withExprs );
    991                 return decl->set_asmName( asmName );
     1424                return buildFunctionDecl(
     1425                        td, name, scs, funcSpec, linkage,
     1426                        asmName, std::move( attributes ) );
    9921427        } else if ( td->kind == TypeData::Aggregate ) {
    993                 return buildAggregate( td, attributes, linkage );
     1428                return buildAggregate( td, std::move( attributes ), linkage );
    9941429        } else if ( td->kind == TypeData::Enum ) {
    995                 return buildEnum( td, attributes, linkage );
     1430                return buildEnum( td, std::move( attributes ), linkage );
    9961431        } else if ( td->kind == TypeData::Symbolic ) {
    997                 return buildSymbolic( td, attributes, name, scs, linkage );
     1432                return buildSymbolic( td, std::move( attributes ), name, scs, linkage );
    9981433        } else {
    999                 return (new ObjectDecl( name, scs, linkage, bitfieldWidth, typebuild( td ), init, attributes ))->set_asmName( asmName );
     1434                auto ret = new ast::ObjectDecl( td->location,
     1435                        name,
     1436                        typebuild( td ),
     1437                        init,
     1438                        scs,
     1439                        linkage,
     1440                        bitfieldWidth,
     1441                        std::move( attributes )
     1442                );
     1443                ret->asmName = asmName;
     1444                return ret;
    10001445        } // if
    10011446        return nullptr;
     
    10031448
    10041449
    1005 FunctionType * buildFunction( const TypeData * td ) {
     1450ast::FunctionType * buildFunctionType( const TypeData * td ) {
    10061451        assert( td->kind == TypeData::Function );
    1007         FunctionType * ft = new FunctionType( buildQualifiers( td ), ! td->function.params || td->function.params->hasEllipsis );
    1008         buildList( td->function.params, ft->parameters );
     1452        ast::FunctionType * ft = new ast::FunctionType(
     1453                ( !td->function.params || td->function.params->hasEllipsis )
     1454                        ? ast::VariableArgs : ast::FixedArgs,
     1455                buildQualifiers( td )
     1456        );
     1457        buildTypeList( td->function.params, ft->params );
    10091458        buildForall( td->forall, ft->forall );
    10101459        if ( td->base ) {
    10111460                switch ( td->base->kind ) {
    1012                   case TypeData::Tuple:
    1013                         buildList( td->base->tuple, ft->returnVals );
     1461                case TypeData::Tuple:
     1462                        buildTypeList( td->base->tuple, ft->returns );
    10141463                        break;
    1015                   default:
    1016                         ft->get_returnVals().push_back( dynamic_cast< DeclarationWithType * >( buildDecl( td->base, "", Type::StorageClasses(), nullptr, Type::FuncSpecifiers(), LinkageSpec::Cforall, nullptr ) ) );
     1464                default:
     1465                        ft->returns.push_back( typebuild( td->base ) );
     1466                        break;
    10171467                } // switch
    10181468        } else {
    1019                 ft->get_returnVals().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
     1469                ft->returns.push_back(
     1470                        new ast::BasicType( ast::BasicType::SignedInt ) );
    10201471        } // if
    10211472        return ft;
    1022 } // buildFunction
     1473} // buildFunctionType
    10231474
    10241475
     
    10511502                                param->type = decl->type;                               // set copy declaration type to parameter type
    10521503                                decl->type = nullptr;                                   // reset declaration type
    1053                                 param->attributes.splice( param->attributes.end(), decl->attributes ); // copy and reset attributes from declaration to parameter
     1504                                // Copy and reset attributes from declaration to parameter:
     1505                                splice( param->attributes, decl->attributes );
    10541506                        } // if
    10551507                } // for
  • src/Parser/TypeData.h

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

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

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

    r34b4268 r24d6572  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Thu Oct 13 20:46:04 2022
    13  * Update Count     : 764
     12 * Last Modified On : Tue May  2 08:45:21 2023
     13 * Update Count     : 769
    1414 */
    1515
     
    2323// line-number directives) and C/C++ style comments, which are ignored.
    2424
    25 //**************************** Includes and Defines ****************************
     25// *************************** Includes and Defines ****************************
    2626
    2727#ifdef __clang__
     
    4444
    4545#include "config.h"                                                                             // configure info
     46#include "DeclarationNode.h"                            // for DeclarationNode
     47#include "ExpressionNode.h"                             // for LabelNode
     48#include "InitializerNode.h"                            // for InitializerNode
    4649#include "ParseNode.h"
     50#include "ParserTypes.h"                                // for Token
     51#include "StatementNode.h"                              // for CondCtl, ForCtrl
    4752#include "TypedefTable.h"
     53// This (generated) header must come late as it is missing includes.
     54#include "parser.hh"                                    // generated info
    4855
    4956string * build_postfix_name( string * name );
     
    214221__alignof               { KEYWORD_RETURN(ALIGNOF); }                    // GCC
    215222__alignof__             { KEYWORD_RETURN(ALIGNOF); }                    // GCC
     223and                             { QKEYWORD_RETURN(WAND); }                              // CFA
    216224asm                             { KEYWORD_RETURN(ASM); }
    217225__asm                   { KEYWORD_RETURN(ASM); }                                // GCC
     
    250258enable                  { KEYWORD_RETURN(ENABLE); }                             // CFA
    251259enum                    { KEYWORD_RETURN(ENUM); }
     260exception               { KEYWORD_RETURN(EXCEPTION); }                  // CFA
    252261__extension__   { KEYWORD_RETURN(EXTENSION); }                  // GCC
    253 exception               { KEYWORD_RETURN(EXCEPTION); }                  // CFA
    254262extern                  { KEYWORD_RETURN(EXTERN); }
    255263fallthrough             { KEYWORD_RETURN(FALLTHROUGH); }                // CFA
     
    340348vtable                  { KEYWORD_RETURN(VTABLE); }                             // CFA
    341349waitfor                 { KEYWORD_RETURN(WAITFOR); }                    // CFA
     350waituntil               { KEYWORD_RETURN(WAITUNTIL); }                  // CFA
    342351when                    { KEYWORD_RETURN(WHEN); }                               // CFA
    343352while                   { KEYWORD_RETURN(WHILE); }
     
    502511        SemanticErrorThrow = true;
    503512        cerr << (yyfilename ? yyfilename : "*unknown file*") << ':' << yylineno << ':' << column - yyleng + 1
    504                  << ": " << ErrorHelpers::error_str() << errmsg << " at token \"" << (yytext[0] == '\0' ? "EOF" : yytext) << '"' << endl;
     513                 << ": " << ErrorHelpers::error_str() << errmsg << " before token \"" << (yytext[0] == '\0' ? "EOF" : yytext) << '"' << endl;
    505514}
    506515
  • src/Parser/module.mk

    r34b4268 r24d6572  
    2121SRC += \
    2222       Parser/DeclarationNode.cc \
     23       Parser/DeclarationNode.h \
    2324       Parser/ExpressionNode.cc \
     25       Parser/ExpressionNode.h \
    2426       Parser/InitializerNode.cc \
     27       Parser/InitializerNode.h \
    2528       Parser/lex.ll \
    2629       Parser/ParseNode.cc \
     
    3033       Parser/parserutility.cc \
    3134       Parser/parserutility.h \
     35       Parser/RunParser.cpp \
     36       Parser/RunParser.hpp \
    3237       Parser/StatementNode.cc \
     38       Parser/StatementNode.h \
    3339       Parser/TypeData.cc \
    3440       Parser/TypeData.h \
  • src/Parser/parser.yy

    r34b4268 r24d6572  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Nov 21 22:34:30 2022
    13 // Update Count     : 5848
     12// Last Modified On : Wed Apr 26 16:45:37 2023
     13// Update Count     : 6330
    1414//
    1515
     
    4444
    4545#include <cstdio>
     46#include <sstream>
    4647#include <stack>
    4748using namespace std;
    4849
    49 #include "SynTree/Declaration.h"
    50 #include "ParseNode.h"
     50#include "SynTree/Type.h"                               // for Type
     51#include "DeclarationNode.h"                            // for DeclarationNode, ...
     52#include "ExpressionNode.h"                             // for ExpressionNode, ...
     53#include "InitializerNode.h"                            // for InitializerNode, ...
     54#include "ParserTypes.h"
     55#include "StatementNode.h"                              // for build_...
    5156#include "TypedefTable.h"
    5257#include "TypeData.h"
    53 #include "SynTree/LinkageSpec.h"
    5458#include "Common/SemanticError.h"                                               // error_str
    5559#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
    5660
    57 #include "SynTree/Attribute.h"     // for Attribute
     61#include "SynTree/Attribute.h"                                                  // for Attribute
    5862
    5963// lex uses __null in a boolean context, it's fine.
     
    6367
    6468extern DeclarationNode * parseTree;
    65 extern LinkageSpec::Spec linkage;
     69extern ast::Linkage::Spec linkage;
    6670extern TypedefTable typedefTable;
    6771
    68 stack<LinkageSpec::Spec> linkageStack;
     72stack<ast::Linkage::Spec> linkageStack;
    6973
    7074bool appendStr( string & to, string & from ) {
     
    199203} // fieldDecl
    200204
    201 #define NEW_ZERO new ExpressionNode( build_constantInteger( *new string( "0" ) ) )
    202 #define NEW_ONE  new ExpressionNode( build_constantInteger( *new string( "1" ) ) )
     205#define NEW_ZERO new ExpressionNode( build_constantInteger( yylloc, *new string( "0" ) ) )
     206#define NEW_ONE  new ExpressionNode( build_constantInteger( yylloc, *new string( "1" ) ) )
    203207#define UPDOWN( compop, left, right ) (compop == OperKinds::LThan || compop == OperKinds::LEThan ? left : right)
    204208#define MISSING_ANON_FIELD "Missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body."
     
    206210#define MISSING_HIGH "Missing high value for down-to range so index is uninitialized."
    207211
    208 ForCtrl * forCtrl( DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
     212static ForCtrl * makeForCtrl(
     213                const CodeLocation & location,
     214                DeclarationNode * init,
     215                enum OperKinds compop,
     216                ExpressionNode * comp,
     217                ExpressionNode * inc ) {
     218        // Wrap both comp/inc if they are non-null.
     219        if ( comp ) comp = new ExpressionNode( build_binary_val( location,
     220                compop,
     221                new ExpressionNode( build_varref( location, new string( *init->name ) ) ),
     222                comp ) );
     223        if ( inc ) inc = new ExpressionNode( build_binary_val( location,
     224                // choose += or -= for upto/downto
     225                compop == OperKinds::LThan || compop == OperKinds::LEThan ? OperKinds::PlusAssn : OperKinds::MinusAssn,
     226                new ExpressionNode( build_varref( location, new string( *init->name ) ) ),
     227                inc ) );
     228        // The StatementNode call frees init->name, it must happen later.
     229        return new ForCtrl( new StatementNode( init ), comp, inc );
     230}
     231
     232ForCtrl * forCtrl( const CodeLocation & location, DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    209233        if ( index->initializer ) {
    210234                SemanticError( yylloc, "Direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." );
     
    213237                SemanticError( yylloc, "Multiple loop indexes disallowed in for-loop declaration." );
    214238        } // if
    215         return new ForCtrl( index->addInitializer( new InitializerNode( start ) ),
    216                 // NULL comp/inc => leave blank
    217                 comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index->name ) ) ), comp ) ) : nullptr,
    218                 inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
    219                                                         OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index->name ) ) ), inc ) ) : nullptr );
     239        DeclarationNode * initDecl = index->addInitializer( new InitializerNode( start ) );
     240        return makeForCtrl( location, initDecl, compop, comp, inc );
    220241} // forCtrl
    221242
    222 ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    223         ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->expr.get());
    224         if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) {
    225                 type = new ExpressionNode( new CastExpr( maybeMoveBuild<Expression>(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) );
     243ForCtrl * forCtrl( const CodeLocation & location, ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
     244        ast::ConstantExpr * constant = dynamic_cast<ast::ConstantExpr *>(type->expr.get());
     245        if ( constant && (constant->rep == "0" || constant->rep == "1") ) {
     246                type = new ExpressionNode( new ast::CastExpr( location, maybeMoveBuild(type), new ast::BasicType( ast::BasicType::SignedInt ) ) );
    226247        } // if
    227 //      type = new ExpressionNode( build_func( new ExpressionNode( build_varref( new string( "__for_control_index_constraints__" ) ) ), type ) );
    228         return new ForCtrl(
    229                 distAttr( DeclarationNode::newTypeof( type, true ), DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) ) ),
    230                 // NULL comp/inc => leave blank
    231                 comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ) : nullptr,
    232                 inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
    233                                                         OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) : nullptr );
     248        DeclarationNode * initDecl = distAttr(
     249                DeclarationNode::newTypeof( type, true ),
     250                DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) )
     251        );
     252        return makeForCtrl( location, initDecl, compop, comp, inc );
    234253} // forCtrl
    235254
    236 ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    237         if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->expr.get()) ) {
    238                 return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    239         } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->expr.get()) ) {
    240                 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(commaExpr->arg1 ) ) {
    241                         return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
     255ForCtrl * forCtrl( const CodeLocation & location, ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
     256        if ( auto identifier = dynamic_cast<ast::NameExpr *>(index->expr.get()) ) {
     257                return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc );
     258        } else if ( auto commaExpr = dynamic_cast<ast::CommaExpr *>( index->expr.get() ) ) {
     259                if ( auto identifier = commaExpr->arg1.as<ast::NameExpr>() ) {
     260                        return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc );
    242261                } else {
    243262                        SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
     
    281300%union {
    282301        Token tok;
    283         ParseNode * pn;
    284         ExpressionNode * en;
     302        ExpressionNode * expr;
    285303        DeclarationNode * decl;
    286         AggregateDecl::Aggregate aggKey;
    287         TypeDecl::Kind tclass;
    288         StatementNode * sn;
    289         WaitForStmt * wfs;
    290         Expression * constant;
     304        ast::AggregateDecl::Aggregate aggKey;
     305        ast::TypeDecl::Kind tclass;
     306        StatementNode * stmt;
     307        ClauseNode * clause;
     308        ast::WaitForStmt * wfs;
     309    ast::WaitUntilStmt::ClauseNode * wucn;
    291310        CondCtl * ifctl;
    292         ForCtrl * fctl;
    293         OperKinds compop;
    294         LabelNode * label;
    295         InitializerNode * in;
    296         OperKinds op;
     311        ForCtrl * forctl;
     312        LabelNode * labels;
     313        InitializerNode * init;
     314        OperKinds oper;
    297315        std::string * str;
    298         bool flag;
    299         EnumHiding hide;
    300         CatchStmt::Kind catch_kind;
    301         GenericExpr * genexpr;
     316        bool is_volatile;
     317        EnumHiding enum_hiding;
     318        ast::ExceptionKind except_kind;
     319        ast::GenericExpr * genexpr;
    302320}
    303321
    304 //************************* TERMINAL TOKENS ********************************
     322// ************************ TERMINAL TOKENS ********************************
    305323
    306324// keywords
     
    331349%token ATTRIBUTE EXTENSION                                                              // GCC
    332350%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
    333 %token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR    // CFA
     351%token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR WAITUNTIL // CFA
    334352%token DISABLE ENABLE TRY THROW THROWRESUME AT                  // CFA
    335353%token ASM                                                                                              // C99, extension ISO/IEC 9899:1999 Section J.5.10(1)
     
    337355
    338356// names and constants: lexer differentiates between identifier and typedef names
    339 %token<tok> IDENTIFIER          QUOTED_IDENTIFIER       TYPEDIMname             TYPEDEFname             TYPEGENname
    340 %token<tok> TIMEOUT                     WOR                                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
     357%token<tok> IDENTIFIER          TYPEDIMname             TYPEDEFname             TYPEGENname
     358%token<tok> TIMEOUT                     WAND    WOR                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
    341359%token<tok> INTEGERconstant     CHARACTERconstant       STRINGliteral
    342360%token<tok> DIRECTIVE
     
    364382%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    365383%type<tok> quasi_keyword
    366 %type<constant> string_literal
     384%type<expr> string_literal
    367385%type<str> string_literal_list
    368386
    369 %type<hide> hide_opt                                    visible_hide_opt
     387%type<enum_hiding> hide_opt                                     visible_hide_opt
    370388
    371389// expressions
    372 %type<en> constant
    373 %type<en> tuple                                                 tuple_expression_list
    374 %type<op> ptrref_operator                               unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
    375 %type<en> primary_expression                    postfix_expression                      unary_expression
    376 %type<en> cast_expression_list                  cast_expression                         exponential_expression          multiplicative_expression       additive_expression
    377 %type<en> shift_expression                              relational_expression           equality_expression
    378 %type<en> AND_expression                                exclusive_OR_expression         inclusive_OR_expression
    379 %type<en> logical_AND_expression                logical_OR_expression
    380 %type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    381 %type<en> comma_expression                              comma_expression_opt
    382 %type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
     390%type<expr> constant
     391%type<expr> tuple                                                       tuple_expression_list
     392%type<oper> ptrref_operator                             unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
     393%type<expr> primary_expression                  postfix_expression                      unary_expression
     394%type<expr> cast_expression_list                        cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     395%type<expr> shift_expression                            relational_expression           equality_expression
     396%type<expr> AND_expression                              exclusive_OR_expression         inclusive_OR_expression
     397%type<expr> logical_AND_expression              logical_OR_expression
     398%type<expr> conditional_expression              constant_expression                     assignment_expression           assignment_expression_opt
     399%type<expr> comma_expression                            comma_expression_opt
     400%type<expr> argument_expression_list_opt        argument_expression_list        argument_expression                     default_initializer_opt
    383401%type<ifctl> conditional_declaration
    384 %type<fctl> for_control_expression              for_control_expression_list
    385 %type<compop> upupeq updown updowneq downupdowneq
    386 %type<en> subrange
     402%type<forctl> for_control_expression            for_control_expression_list
     403%type<oper> upupeq updown updowneq downupdowneq
     404%type<expr> subrange
    387405%type<decl> asm_name_opt
    388 %type<en> asm_operands_opt                              asm_operands_list                       asm_operand
    389 %type<label> label_list
    390 %type<en> asm_clobbers_list_opt
    391 %type<flag> asm_volatile_opt
    392 %type<en> handler_predicate_opt
     406%type<expr> asm_operands_opt                            asm_operands_list                       asm_operand
     407%type<labels> label_list
     408%type<expr> asm_clobbers_list_opt
     409%type<is_volatile> asm_volatile_opt
     410%type<expr> handler_predicate_opt
    393411%type<genexpr> generic_association              generic_assoc_list
    394412
    395413// statements
    396 %type<sn> statement                                             labeled_statement                       compound_statement
    397 %type<sn> statement_decl                                statement_decl_list                     statement_list_nodecl
    398 %type<sn> selection_statement                   if_statement
    399 %type<sn> switch_clause_list_opt                switch_clause_list
    400 %type<en> case_value
    401 %type<sn> case_clause                                   case_value_list                         case_label                                      case_label_list
    402 %type<sn> iteration_statement                   jump_statement
    403 %type<sn> expression_statement                  asm_statement
    404 %type<sn> with_statement
    405 %type<en> with_clause_opt
    406 %type<sn> exception_statement                   handler_clause                          finally_clause
    407 %type<catch_kind> handler_key
    408 %type<sn> mutex_statement
    409 %type<en> when_clause                                   when_clause_opt                         waitfor                                         timeout
    410 %type<sn> waitfor_statement
    411 %type<wfs> waitfor_clause
     414%type<stmt> statement                                           labeled_statement                       compound_statement
     415%type<stmt> statement_decl                              statement_decl_list                     statement_list_nodecl
     416%type<stmt> selection_statement                 if_statement
     417%type<clause> switch_clause_list_opt            switch_clause_list
     418%type<expr> case_value
     419%type<clause> case_clause                               case_value_list                         case_label                                      case_label_list
     420%type<stmt> iteration_statement                 jump_statement
     421%type<stmt> expression_statement                        asm_statement
     422%type<stmt> with_statement
     423%type<expr> with_clause_opt
     424%type<stmt> exception_statement
     425%type<clause> handler_clause                    finally_clause
     426%type<except_kind> handler_key
     427%type<stmt> mutex_statement
     428%type<expr> when_clause                                 when_clause_opt                         waitfor         waituntil               timeout
     429%type<stmt> waitfor_statement                           waituntil_statement
     430%type<wfs> wor_waitfor_clause
     431%type<wucn> waituntil_clause                    wand_waituntil_clause       wor_waituntil_clause
    412432
    413433// declarations
     
    421441%type<decl> assertion assertion_list assertion_list_opt
    422442
    423 %type<en> bit_subrange_size_opt bit_subrange_size
     443%type<expr> bit_subrange_size_opt bit_subrange_size
    424444
    425445%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    434454
    435455%type<decl> enumerator_list enum_type enum_type_nobody
    436 %type<in> enumerator_value_opt
     456%type<init> enumerator_value_opt
    437457
    438458%type<decl> external_definition external_definition_list external_definition_list_opt
     
    441461
    442462%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
    443 %type<en> field field_name_list field_name fraction_constants_opt
     463%type<expr> field field_name_list field_name fraction_constants_opt
    444464
    445465%type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
     
    482502%type<decl> typedef_name typedef_declaration typedef_expression
    483503
    484 %type<decl> variable_type_redeclarator type_ptr type_array type_function
     504%type<decl> variable_type_redeclarator variable_type_ptr variable_type_array variable_type_function
     505%type<decl> general_function_declarator function_type_redeclarator function_type_array function_type_no_ptr function_type_ptr
    485506
    486507%type<decl> type_parameter_redeclarator type_parameter_ptr type_parameter_array type_parameter_function
     
    489510%type<decl> type_parameter type_parameter_list type_initializer_opt
    490511
    491 %type<en> type_parameters_opt type_list array_type_list
     512%type<expr> type_parameters_opt type_list array_type_list
    492513
    493514%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     
    500521
    501522// initializers
    502 %type<in>  initializer initializer_list_opt initializer_opt
     523%type<init>  initializer initializer_list_opt initializer_opt
    503524
    504525// designators
    505 %type<en>  designator designator_list designation
     526%type<expr>  designator designator_list designation
    506527
    507528
     
    512533// Similar issues exit with the waitfor statement.
    513534
    514 // Order of these lines matters (low-to-high precedence). THEN is left associative over WOR/TIMEOUT/ELSE, WOR is left
    515 // associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE.
     535// Order of these lines matters (low-to-high precedence). THEN is left associative over WAND/WOR/TIMEOUT/ELSE, WAND/WOR
     536// is left associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE.
    516537%precedence THEN                // rule precedence for IF/WAITFOR statement
     538%precedence ANDAND              // token precedence for start of WAND in WAITFOR statement
     539%precedence WAND                // token precedence for start of WAND in WAITFOR statement
     540%precedence OROR                // token precedence for start of WOR in WAITFOR statement
    517541%precedence WOR                 // token precedence for start of WOR in WAITFOR statement
    518542%precedence TIMEOUT             // token precedence for start of TIMEOUT in WAITFOR statement
     
    592616constant:
    593617                // ENUMERATIONconstant is not included here; it is treated as a variable with type "enumeration constant".
    594         INTEGERconstant                                                         { $$ = new ExpressionNode( build_constantInteger( *$1 ) ); }
    595         | FLOATING_DECIMALconstant                                      { $$ = new ExpressionNode( build_constantFloat( *$1 ) ); }
    596         | FLOATING_FRACTIONconstant                                     { $$ = new ExpressionNode( build_constantFloat( *$1 ) ); }
    597         | FLOATINGconstant                                                      { $$ = new ExpressionNode( build_constantFloat( *$1 ) ); }
    598         | CHARACTERconstant                                                     { $$ = new ExpressionNode( build_constantChar( *$1 ) ); }
     618        INTEGERconstant                                                         { $$ = new ExpressionNode( build_constantInteger( yylloc, *$1 ) ); }
     619        | FLOATING_DECIMALconstant                                      { $$ = new ExpressionNode( build_constantFloat( yylloc, *$1 ) ); }
     620        | FLOATING_FRACTIONconstant                                     { $$ = new ExpressionNode( build_constantFloat( yylloc, *$1 ) ); }
     621        | FLOATINGconstant                                                      { $$ = new ExpressionNode( build_constantFloat( yylloc, *$1 ) ); }
     622        | CHARACTERconstant                                                     { $$ = new ExpressionNode( build_constantChar( yylloc, *$1 ) ); }
    599623        ;
    600624
    601625quasi_keyword:                                                                                  // CFA
    602626        TIMEOUT
     627        | WAND
    603628        | WOR
    604629        | CATCH
     
    621646
    622647string_literal:
    623         string_literal_list                                                     { $$ = build_constantStr( *$1 ); }
     648        string_literal_list                                                     { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); }
    624649        ;
    625650
     
    638663primary_expression:
    639664        IDENTIFIER                                                                                      // typedef name cannot be used as a variable name
    640                 { $$ = new ExpressionNode( build_varref( $1 ) ); }
     665                { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
    641666        | quasi_keyword
    642                 { $$ = new ExpressionNode( build_varref( $1 ) ); }
     667                { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
    643668        | TYPEDIMname                                                                           // CFA, generic length argument
    644669                // { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( DeclarationNode::newFromTypedef( $1 ) ) ) ); }
    645670                // { $$ = new ExpressionNode( build_varref( $1 ) ); }
    646                 { $$ = new ExpressionNode( build_dimensionref( $1 ) ); }
     671                { $$ = new ExpressionNode( build_dimensionref( yylloc, $1 ) ); }
    647672        | tuple
    648673        | '(' comma_expression ')'
    649674                { $$ = $2; }
    650675        | '(' compound_statement ')'                                            // GCC, lambda expression
    651                 { $$ = new ExpressionNode( new StmtExpr( dynamic_cast<CompoundStmt *>(maybeMoveBuild<Statement>($2) ) ) ); }
     676                { $$ = new ExpressionNode( new ast::StmtExpr( yylloc, dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( $2 ) ) ) ); }
    652677        | type_name '.' identifier                                                      // CFA, nested type
    653                 { $$ = new ExpressionNode( build_qualified_expr( $1, build_varref( $3 ) ) ); }
     678                { $$ = new ExpressionNode( build_qualified_expr( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
    654679        | type_name '.' '[' field_name_list ']'                         // CFA, nested type / tuple field selector
    655680                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
     
    657682                {
    658683                        // add the missing control expression to the GenericExpr and return it
    659                         $5->control = maybeMoveBuild<Expression>( $3 );
     684                        $5->control = maybeMoveBuild( $3 );
    660685                        $$ = new ExpressionNode( $5 );
    661686                }
     
    683708                {
    684709                        // steal the association node from the singleton and delete the wrapper
    685                         $1->associations.splice($1->associations.end(), $3->associations);
     710                        assert( 1 == $3->associations.size() );
     711                        $1->associations.push_back( $3->associations.front() );
    686712                        delete $3;
    687713                        $$ = $1;
     
    693719                {
    694720                        // create a GenericExpr wrapper with one association pair
    695                         $$ = new GenericExpr( nullptr, { { maybeMoveBuildType($1), maybeMoveBuild<Expression>( $3 ) } } );
     721                        $$ = new ast::GenericExpr( yylloc, nullptr, { { maybeMoveBuildType( $1 ), maybeMoveBuild( $3 ) } } );
    696722                }
    697723        | DEFAULT ':' assignment_expression
    698                 { $$ = new GenericExpr( nullptr, { { maybeMoveBuild<Expression>( $3 ) } } ); }
     724                { $$ = new ast::GenericExpr( yylloc, nullptr, { { maybeMoveBuild( $3 ) } } ); }
    699725        ;
    700726
     
    705731                // Switching to this behaviour may help check if a C compatibilty case uses comma-exprs in subscripts.
    706732                // Current: Commas in subscripts make tuples.
    707                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
     733                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
    708734        | postfix_expression '[' assignment_expression ']'
    709735                // CFA, comma_expression disallowed in this context because it results in a common user error: subscripting a
     
    711737                // little advantage to this feature and many disadvantages. It is possible to write x[(i,j)] in CFA, which is
    712738                // equivalent to the old x[i,j].
    713                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
     739                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    714740        | constant '[' assignment_expression ']'                        // 3[a], 'a'[a], 3.5[a]
    715                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
     741                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    716742        | string_literal '[' assignment_expression ']'          // "abc"[3], 3["abc"]
    717                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }
     743                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    718744        | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
    719745                {
    720746                        Token fn;
    721747                        fn.str = new std::string( "?{}" );                      // location undefined - use location of '{'?
    722                         $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
     748                        $$ = new ExpressionNode( new ast::ConstructorExpr( yylloc, build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
    723749                }
    724750        | postfix_expression '(' argument_expression_list_opt ')'
    725                 { $$ = new ExpressionNode( build_func( $1, $3 ) ); }
     751                { $$ = new ExpressionNode( build_func( yylloc, $1, $3 ) ); }
    726752        | VA_ARG '(' primary_expression ',' declaration_specifier_nobody abstract_parameter_declarator_opt ')'
    727753                // { SemanticError( yylloc, "va_arg is currently unimplemented." ); $$ = nullptr; }
    728                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( new string( "__builtin_va_arg") ) ),
     754                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, new string( "__builtin_va_arg") ) ),
    729755                                                                                           (ExpressionNode *)($3->set_last( (ExpressionNode *)($6 ? $6->addType( $5 ) : $5) )) ) ); }
    730756        | postfix_expression '`' identifier                                     // CFA, postfix call
    731                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
     757                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    732758        | constant '`' identifier                                                       // CFA, postfix call
    733                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
     759                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    734760        | string_literal '`' identifier                                         // CFA, postfix call
    735                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
     761                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    736762        | postfix_expression '.' identifier
    737                 { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
     763                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
    738764        | postfix_expression '.' INTEGERconstant                        // CFA, tuple index
    739                 { $$ = new ExpressionNode( build_fieldSel( $1, build_constantInteger( *$3 ) ) ); }
     765                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_constantInteger( yylloc, *$3 ) ) ); }
    740766        | postfix_expression FLOATING_FRACTIONconstant          // CFA, tuple index
    741                 { $$ = new ExpressionNode( build_fieldSel( $1, build_field_name_FLOATING_FRACTIONconstant( *$2 ) ) ); }
     767                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_field_name_FLOATING_FRACTIONconstant( yylloc, *$2 ) ) ); }
    742768        | postfix_expression '.' '[' field_name_list ']'        // CFA, tuple field selector
    743                 { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
     769                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    744770        | postfix_expression '.' aggregate_control
    745                 { $$ = new ExpressionNode( build_keyword_cast( $3, $1 ) ); }
     771                { $$ = new ExpressionNode( build_keyword_cast( yylloc, $3, $1 ) ); }
    746772        | postfix_expression ARROW identifier
    747                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
     773                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
    748774        | postfix_expression ARROW INTEGERconstant                      // CFA, tuple index
    749                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_constantInteger( *$3 ) ) ); }
     775                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_constantInteger( yylloc, *$3 ) ) ); }
    750776        | postfix_expression ARROW '[' field_name_list ']'      // CFA, tuple field selector
    751                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
     777                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    752778        | postfix_expression ICR
    753                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, $1 ) ); }
     779                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::IncrPost, $1 ) ); }
    754780        | postfix_expression DECR
    755                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::DecrPost, $1 ) ); }
     781                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::DecrPost, $1 ) ); }
    756782        | '(' type_no_function ')' '{' initializer_list_opt comma_opt '}' // C99, compound-literal
    757                 { $$ = new ExpressionNode( build_compoundLiteral( $2, new InitializerNode( $5, true ) ) ); }
     783                { $$ = new ExpressionNode( build_compoundLiteral( yylloc, $2, new InitializerNode( $5, true ) ) ); }
    758784        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    759                 { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
     785                { $$ = new ExpressionNode( build_compoundLiteral( yylloc, $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    760786        | '^' primary_expression '{' argument_expression_list_opt '}' // CFA, destructor call
    761787                {
    762788                        Token fn;
    763789                        fn.str = new string( "^?{}" );                          // location undefined
    764                         $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) );
     790                        $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) );
    765791                }
    766792        ;
     
    781807        '@'                                                                                                     // CFA, default parameter
    782808                { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; }
    783                 // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
     809                // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
    784810        | assignment_expression
    785811        ;
     
    793819        field_name
    794820        | FLOATING_DECIMALconstant field
    795                 { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), maybeMoveBuild<Expression>( $2 ) ) ); }
     821                { $$ = new ExpressionNode( build_fieldSel( yylloc, new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( yylloc, *$1 ) ), maybeMoveBuild( $2 ) ) ); }
    796822        | FLOATING_DECIMALconstant '[' field_name_list ']'
    797                 { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), build_tuple( $3 ) ) ); }
     823                { $$ = new ExpressionNode( build_fieldSel( yylloc, new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( yylloc, *$1 ) ), build_tuple( yylloc, $3 ) ) ); }
    798824        | field_name '.' field
    799                 { $$ = new ExpressionNode( build_fieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
     825                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); }
    800826        | field_name '.' '[' field_name_list ']'
    801                 { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
     827                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    802828        | field_name ARROW field
    803                 { $$ = new ExpressionNode( build_pfieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
     829                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, maybeMoveBuild( $3 ) ) ); }
    804830        | field_name ARROW '[' field_name_list ']'
    805                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
     831                { $$ = new ExpressionNode( build_pfieldSel( yylloc, $1, build_tuple( yylloc, $4 ) ) ); }
    806832        ;
    807833
    808834field_name:
    809835        INTEGERconstant fraction_constants_opt
    810                 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_constantInteger( *$1 ), $2 ) ); }
     836                { $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_constantInteger( yylloc, *$1 ), $2 ) ); }
    811837        | FLOATINGconstant fraction_constants_opt
    812                 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); }
     838                { $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_field_name_FLOATINGconstant( yylloc, *$1 ), $2 ) ); }
    813839        | identifier_at fraction_constants_opt                          // CFA, allow anonymous fields
    814840                {
    815                         $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) );
     841                        $$ = new ExpressionNode( build_field_name_fraction_constants( yylloc, build_varref( yylloc, $1 ), $2 ) );
    816842                }
    817843        ;
     
    822848        | fraction_constants_opt FLOATING_FRACTIONconstant
    823849                {
    824                         Expression * constant = build_field_name_FLOATING_FRACTIONconstant( *$2 );
    825                         $$ = $1 != nullptr ? new ExpressionNode( build_fieldSel( $1, constant ) ) : new ExpressionNode( constant );
     850                        ast::Expr * constant = build_field_name_FLOATING_FRACTIONconstant( yylloc, *$2 );
     851                        $$ = $1 != nullptr ? new ExpressionNode( build_fieldSel( yylloc, $1, constant ) ) : new ExpressionNode( constant );
    826852                }
    827853        ;
     
    833859        | constant
    834860        | string_literal
    835                 { $$ = new ExpressionNode( $1 ); }
     861                { $$ = $1; }
    836862        | EXTENSION cast_expression                                                     // GCC
    837863                { $$ = $2->set_extension( true ); }
     
    842868                {
    843869                        switch ( $1 ) {
    844                           case OperKinds::AddressOf:
    845                                 $$ = new ExpressionNode( new AddressExpr( maybeMoveBuild<Expression>( $2 ) ) );
     870                        case OperKinds::AddressOf:
     871                                $$ = new ExpressionNode( new ast::AddressExpr( maybeMoveBuild( $2 ) ) );
    846872                                break;
    847                           case OperKinds::PointTo:
    848                                 $$ = new ExpressionNode( build_unary_val( $1, $2 ) );
     873                        case OperKinds::PointTo:
     874                                $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) );
    849875                                break;
    850                           case OperKinds::And:
    851                                 $$ = new ExpressionNode( new AddressExpr( new AddressExpr( maybeMoveBuild<Expression>( $2 ) ) ) );
     876                        case OperKinds::And:
     877                                $$ = new ExpressionNode( new ast::AddressExpr( new ast::AddressExpr( maybeMoveBuild( $2 ) ) ) );
    852878                                break;
    853                           default:
     879                        default:
    854880                                assert( false );
    855881                        }
    856882                }
    857883        | unary_operator cast_expression
    858                 { $$ = new ExpressionNode( build_unary_val( $1, $2 ) ); }
     884                { $$ = new ExpressionNode( build_unary_val( yylloc, $1, $2 ) ); }
    859885        | ICR unary_expression
    860                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::Incr, $2 ) ); }
     886                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Incr, $2 ) ); }
    861887        | DECR unary_expression
    862                 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::Decr, $2 ) ); }
     888                { $$ = new ExpressionNode( build_unary_val( yylloc, OperKinds::Decr, $2 ) ); }
    863889        | SIZEOF unary_expression
    864                 { $$ = new ExpressionNode( new SizeofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }
     890                { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuild( $2 ) ) ); }
    865891        | SIZEOF '(' type_no_function ')'
    866                 { $$ = new ExpressionNode( new SizeofExpr( maybeMoveBuildType( $3 ) ) ); }
     892                { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
    867893        | ALIGNOF unary_expression                                                      // GCC, variable alignment
    868                 { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuild<Expression>( $2 ) ) ); }
     894                { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuild( $2 ) ) ); }
    869895        | ALIGNOF '(' type_no_function ')'                                      // GCC, type alignment
    870                 { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuildType( $3 ) ) ); }
     896                { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
    871897        | OFFSETOF '(' type_no_function ',' identifier ')'
    872                 { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); }
     898                { $$ = new ExpressionNode( build_offsetOf( yylloc, $3, build_varref( yylloc, $5 ) ) ); }
    873899        | TYPEID '(' type_no_function ')'
    874900                {
     
    895921        unary_expression
    896922        | '(' type_no_function ')' cast_expression
    897                 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
     923                { $$ = new ExpressionNode( build_cast( yylloc, $2, $4 ) ); }
    898924        | '(' aggregate_control '&' ')' cast_expression         // CFA
    899                 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
     925                { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); }
    900926        | '(' aggregate_control '*' ')' cast_expression         // CFA
    901                 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
     927                { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); }
    902928        | '(' VIRTUAL ')' cast_expression                                       // CFA
    903                 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild<Expression>( $4 ), maybeMoveBuildType( nullptr ) ) ); }
     929                { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $4 ), maybeMoveBuildType( nullptr ) ) ); }
    904930        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    905                 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild<Expression>( $5 ), maybeMoveBuildType( $3 ) ) ); }
     931                { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); }
    906932        | '(' RETURN type_no_function ')' cast_expression       // CFA
    907                 { $$ = new ExpressionNode( build_cast( $3, $5, CastExpr::Return ) ); }
     933                { $$ = new ExpressionNode( build_cast( yylloc, $3, $5, ast::CastExpr::Return ) ); }
    908934        | '(' COERCE type_no_function ')' cast_expression       // CFA
    909935                { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }
     
    911937                { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; }
    912938//      | '(' type_no_function ')' tuple
    913 //              { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
     939//              { $$ = new ast::ExpressionNode( build_cast( yylloc, $2, $4 ) ); }
    914940        ;
    915941
     
    929955        cast_expression
    930956        | exponential_expression '\\' cast_expression
    931                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Exp, $1, $3 ) ); }
     957                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Exp, $1, $3 ) ); }
    932958        ;
    933959
     
    935961        exponential_expression
    936962        | multiplicative_expression '*' exponential_expression
    937                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Mul, $1, $3 ) ); }
     963                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Mul, $1, $3 ) ); }
    938964        | multiplicative_expression '/' exponential_expression
    939                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Div, $1, $3 ) ); }
     965                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Div, $1, $3 ) ); }
    940966        | multiplicative_expression '%' exponential_expression
    941                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Mod, $1, $3 ) ); }
     967                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Mod, $1, $3 ) ); }
    942968        ;
    943969
     
    945971        multiplicative_expression
    946972        | additive_expression '+' multiplicative_expression
    947                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Plus, $1, $3 ) ); }
     973                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Plus, $1, $3 ) ); }
    948974        | additive_expression '-' multiplicative_expression
    949                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Minus, $1, $3 ) ); }
     975                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Minus, $1, $3 ) ); }
    950976        ;
    951977
     
    953979        additive_expression
    954980        | shift_expression LS additive_expression
    955                 { $$ = new ExpressionNode( build_binary_val( OperKinds::LShift, $1, $3 ) ); }
     981                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LShift, $1, $3 ) ); }
    956982        | shift_expression RS additive_expression
    957                 { $$ = new ExpressionNode( build_binary_val( OperKinds::RShift, $1, $3 ) ); }
     983                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::RShift, $1, $3 ) ); }
    958984        ;
    959985
     
    961987        shift_expression
    962988        | relational_expression '<' shift_expression
    963                 { $$ = new ExpressionNode( build_binary_val( OperKinds::LThan, $1, $3 ) ); }
     989                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LThan, $1, $3 ) ); }
    964990        | relational_expression '>' shift_expression
    965                 { $$ = new ExpressionNode( build_binary_val( OperKinds::GThan, $1, $3 ) ); }
     991                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::GThan, $1, $3 ) ); }
    966992        | relational_expression LE shift_expression
    967                 { $$ = new ExpressionNode( build_binary_val( OperKinds::LEThan, $1, $3 ) ); }
     993                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::LEThan, $1, $3 ) ); }
    968994        | relational_expression GE shift_expression
    969                 { $$ = new ExpressionNode( build_binary_val( OperKinds::GEThan, $1, $3 ) ); }
     995                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::GEThan, $1, $3 ) ); }
    970996        ;
    971997
     
    973999        relational_expression
    9741000        | equality_expression EQ relational_expression
    975                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Eq, $1, $3 ) ); }
     1001                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Eq, $1, $3 ) ); }
    9761002        | equality_expression NE relational_expression
    977                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Neq, $1, $3 ) ); }
     1003                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Neq, $1, $3 ) ); }
    9781004        ;
    9791005
     
    9811007        equality_expression
    9821008        | AND_expression '&' equality_expression
    983                 { $$ = new ExpressionNode( build_binary_val( OperKinds::BitAnd, $1, $3 ) ); }
     1009                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::BitAnd, $1, $3 ) ); }
    9841010        ;
    9851011
     
    9871013        AND_expression
    9881014        | exclusive_OR_expression '^' AND_expression
    989                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Xor, $1, $3 ) ); }
     1015                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Xor, $1, $3 ) ); }
    9901016        ;
    9911017
     
    9931019        exclusive_OR_expression
    9941020        | inclusive_OR_expression '|' exclusive_OR_expression
    995                 { $$ = new ExpressionNode( build_binary_val( OperKinds::BitOr, $1, $3 ) ); }
     1021                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::BitOr, $1, $3 ) ); }
    9961022        ;
    9971023
     
    9991025        inclusive_OR_expression
    10001026        | logical_AND_expression ANDAND inclusive_OR_expression
    1001                 { $$ = new ExpressionNode( build_and_or( $1, $3, true ) ); }
     1027                { $$ = new ExpressionNode( build_and_or( yylloc, $1, $3, ast::AndExpr ) ); }
    10021028        ;
    10031029
     
    10051031        logical_AND_expression
    10061032        | logical_OR_expression OROR logical_AND_expression
    1007                 { $$ = new ExpressionNode( build_and_or( $1, $3, false ) ); }
     1033                { $$ = new ExpressionNode( build_and_or( yylloc, $1, $3, ast::OrExpr ) ); }
    10081034        ;
    10091035
     
    10111037        logical_OR_expression
    10121038        | logical_OR_expression '?' comma_expression ':' conditional_expression
    1013                 { $$ = new ExpressionNode( build_cond( $1, $3, $5 ) ); }
     1039                { $$ = new ExpressionNode( build_cond( yylloc, $1, $3, $5 ) ); }
    10141040                // FIX ME: computes $1 twice
    10151041        | logical_OR_expression '?' /* empty */ ':' conditional_expression // GCC, omitted first operand
    1016                 { $$ = new ExpressionNode( build_cond( $1, $1, $4 ) ); }
     1042                { $$ = new ExpressionNode( build_cond( yylloc, $1, $1, $4 ) ); }
    10171043        ;
    10181044
     
    10291055//                              SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr;
    10301056//                      } else {
    1031                                 $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) );
     1057                                $$ = new ExpressionNode( build_binary_val( yylloc, $2, $1, $3 ) );
    10321058//                      } // if
    10331059                }
     
    10741100//              { $$ = new ExpressionNode( build_tuple( $3 ) ); }
    10751101        '[' ',' tuple_expression_list ']'
    1076                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
     1102                { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
    10771103        | '[' push assignment_expression pop ',' tuple_expression_list ']'
    1078                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $6 ) ) )); }
     1104                { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $6 ) ) )); }
    10791105        ;
    10801106
     
    10921118        assignment_expression
    10931119        | comma_expression ',' assignment_expression
    1094                 { $$ = new ExpressionNode( new CommaExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
     1120                { $$ = new ExpressionNode( new ast::CommaExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    10951121        ;
    10961122
     
    11131139        | mutex_statement
    11141140        | waitfor_statement
     1141        | waituntil_statement
    11151142        | exception_statement
    11161143        | enable_disable_statement
     
    11181145        | asm_statement
    11191146        | DIRECTIVE
    1120                 { $$ = new StatementNode( build_directive( $1 ) ); }
     1147                { $$ = new StatementNode( build_directive( yylloc, $1 ) ); }
    11211148        ;
    11221149
     
    11241151                // labels cannot be identifiers 0 or 1
    11251152        identifier_or_type_name ':' attribute_list_opt statement
    1126                 { $$ = $4->add_label( $1, $3 ); }
     1153                { $$ = $4->add_label( yylloc, $1, $3 ); }
    11271154        | identifier_or_type_name ':' attribute_list_opt error // syntax error
    11281155                {
     
    11361163compound_statement:
    11371164        '{' '}'
    1138                 { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); }
     1165                { $$ = new StatementNode( build_compound( yylloc, (StatementNode *)0 ) ); }
    11391166        | '{' push
    11401167          local_label_declaration_opt                                           // GCC, local labels appear at start of block
    11411168          statement_decl_list                                                           // C99, intermix declarations and statements
    11421169          pop '}'
    1143                 { $$ = new StatementNode( build_compound( $4 ) ); }
     1170                { $$ = new StatementNode( build_compound( yylloc, $4 ) ); }
    11441171        ;
    11451172
     
    11721199expression_statement:
    11731200        comma_expression_opt ';'
    1174                 { $$ = new StatementNode( build_expr( $1 ) ); }
    1175         | MUTEX '(' ')' comma_expression ';'
    1176                 { $$ = new StatementNode( build_mutex( nullptr, new StatementNode( build_expr( $4 ) ) ) ); }
     1201                { $$ = new StatementNode( build_expr( yylloc, $1 ) ); }
    11771202        ;
    11781203
     
    11831208                { $$ = $2; }
    11841209        | SWITCH '(' comma_expression ')' case_clause
    1185                 { $$ = new StatementNode( build_switch( true, $3, $5 ) ); }
     1210                { $$ = new StatementNode( build_switch( yylloc, true, $3, $5 ) ); }
    11861211        | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA
    11871212                {
    1188                         StatementNode *sw = new StatementNode( build_switch( true, $3, $8 ) );
     1213                        StatementNode *sw = new StatementNode( build_switch( yylloc, true, $3, $8 ) );
    11891214                        // The semantics of the declaration list is changed to include associated initialization, which is performed
    11901215                        // *before* the transfer to the appropriate case clause by hoisting the declarations into a compound
     
    11921217                        // therefore, are removed from the grammar even though C allows it. The change also applies to choose
    11931218                        // statement.
    1194                         $$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     1219                        $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
    11951220                }
    11961221        | SWITCH '(' comma_expression ')' '{' error '}'         // CFA, syntax error
    11971222                { SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; }
    11981223        | CHOOSE '(' comma_expression ')' case_clause           // CFA
    1199                 { $$ = new StatementNode( build_switch( false, $3, $5 ) ); }
     1224                { $$ = new StatementNode( build_switch( yylloc, false, $3, $5 ) ); }
    12001225        | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA
    12011226                {
    1202                         StatementNode *sw = new StatementNode( build_switch( false, $3, $8 ) );
    1203                         $$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     1227                        StatementNode *sw = new StatementNode( build_switch( yylloc, false, $3, $8 ) );
     1228                        $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
    12041229                }
    12051230        | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, syntax error
     
    12101235        IF '(' conditional_declaration ')' statement            %prec THEN
    12111236                // explicitly deal with the shift/reduce conflict on if/else
    1212                 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); }
     1237                { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), nullptr ) ); }
    12131238        | IF '(' conditional_declaration ')' statement ELSE statement
    1214                 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
     1239                { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), maybe_build_compound( yylloc, $7 ) ) ); }
    12151240        ;
    12161241
     
    12241249        | declaration comma_expression                                          // semi-colon separated
    12251250                { $$ = new CondCtl( $1, $2 ); }
    1226         ;
     1251        ;
    12271252
    12281253// CASE and DEFAULT clauses are only allowed in the SWITCH statement, precluding Duff's device. In addition, a case
     
    12321257        constant_expression                                                     { $$ = $1; }
    12331258        | constant_expression ELLIPSIS constant_expression      // GCC, subrange
    1234                 { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
     1259                { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    12351260        | subrange                                                                                      // CFA, subrange
    12361261        ;
    12371262
    12381263case_value_list:                                                                                // CFA
    1239         case_value                                                                      { $$ = new StatementNode( build_case( $1 ) ); }
     1264        case_value                                                                      { $$ = new ClauseNode( build_case( yylloc, $1 ) ); }
    12401265                // convert case list, e.g., "case 1, 3, 5:" into "case 1: case 3: case 5"
    1241         | case_value_list ',' case_value                        { $$ = (StatementNode *)($1->set_last( new StatementNode( build_case( $3 ) ) ) ); }
     1266        | case_value_list ',' case_value                        { $$ = $1->set_last( new ClauseNode( build_case( yylloc, $3 ) ) ); }
    12421267        ;
    12431268
     
    12481273        | CASE case_value_list error                                            // syntax error
    12491274                { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
    1250         | DEFAULT ':'                                                           { $$ = new StatementNode( build_default() ); }
     1275        | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
    12511276                // A semantic check is required to ensure only one default clause per switch/choose statement.
    12521277        | DEFAULT error                                                                         //  syntax error
     
    12561281case_label_list:                                                                                // CFA
    12571282        case_label
    1258         | case_label_list case_label                            { $$ = (StatementNode *)( $1->set_last( $2 )); }
     1283        | case_label_list case_label                            { $$ = $1->set_last( $2 ); }
    12591284        ;
    12601285
    12611286case_clause:                                                                                    // CFA
    1262         case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); }
     1287        case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( yylloc, $2 ) ); }
    12631288        ;
    12641289
     
    12711296switch_clause_list:                                                                             // CFA
    12721297        case_label_list statement_list_nodecl
    1273                 { $$ = $1->append_last_case( new StatementNode( build_compound( $2 ) ) ); }
     1298                { $$ = $1->append_last_case( new StatementNode( build_compound( yylloc, $2 ) ) ); }
    12741299        | switch_clause_list case_label_list statement_list_nodecl
    1275                 { $$ = (StatementNode *)( $1->set_last( $2->append_last_case( new StatementNode( build_compound( $3 ) ) ) ) ); }
     1300                { $$ = $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ); }
    12761301        ;
    12771302
    12781303iteration_statement:
    12791304        WHILE '(' ')' statement                                                         %prec THEN // CFA => while ( 1 )
    1280                 { $$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) ); }
     1305                { $$ = new StatementNode( build_while( yylloc, new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( yylloc, $4 ) ) ); }
    12811306        | WHILE '(' ')' statement ELSE statement                        // CFA
    12821307                {
    1283                         $$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) );
    1284                         SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
     1308                        $$ = new StatementNode( build_while( yylloc, new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( yylloc, $4 ) ) );
     1309                        SemanticWarning( yylloc, Warning::SuperfluousElse );
    12851310                }
    12861311        | WHILE '(' conditional_declaration ')' statement       %prec THEN
    1287                 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
     1312                { $$ = new StatementNode( build_while( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
    12881313        | WHILE '(' conditional_declaration ')' statement ELSE statement // CFA
    1289                 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ), $7 ) ); }
     1314                { $$ = new StatementNode( build_while( yylloc, $3, maybe_build_compound( yylloc, $5 ), $7 ) ); }
    12901315        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    1291                 { $$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) ); }
     1316                { $$ = new StatementNode( build_do_while( yylloc, NEW_ONE, maybe_build_compound( yylloc, $2 ) ) ); }
    12921317        | DO statement WHILE '(' ')' ELSE statement                     // CFA
    12931318                {
    1294                         $$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) );
    1295                         SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
     1319                        $$ = new StatementNode( build_do_while( yylloc, NEW_ONE, maybe_build_compound( yylloc, $2 ) ) );
     1320                        SemanticWarning( yylloc, Warning::SuperfluousElse );
    12961321                }
    12971322        | DO statement WHILE '(' comma_expression ')' ';'
    1298                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
     1323                { $$ = new StatementNode( build_do_while( yylloc, $5, maybe_build_compound( yylloc, $2 ) ) ); }
    12991324        | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
    1300                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); }
     1325                { $$ = new StatementNode( build_do_while( yylloc, $5, maybe_build_compound( yylloc, $2 ), $8 ) ); }
    13011326        | FOR '(' ')' statement                                                         %prec THEN // CFA => for ( ;; )
    1302                 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
     1327                { $$ = new StatementNode( build_for( yylloc, new ForCtrl( nullptr, nullptr, nullptr ), maybe_build_compound( yylloc, $4 ) ) ); }
    13031328        | FOR '(' ')' statement ELSE statement                          // CFA
    13041329                {
    1305                         $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
    1306                         SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
     1330                        $$ = new StatementNode( build_for( yylloc, new ForCtrl( nullptr, nullptr, nullptr ), maybe_build_compound( yylloc, $4 ) ) );
     1331                        SemanticWarning( yylloc, Warning::SuperfluousElse );
    13071332                }
    13081333        | FOR '(' for_control_expression_list ')' statement     %prec THEN
    1309                 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
     1334                { $$ = new StatementNode( build_for( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
    13101335        | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA
    1311                 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ), $7 ) ); }
     1336                { $$ = new StatementNode( build_for( yylloc, $3, maybe_build_compound( yylloc, $5 ), $7 ) ); }
    13121337        ;
    13131338
     
    13231348                        if ( $1->condition ) {
    13241349                                if ( $3->condition ) {
    1325                                         $1->condition->expr.reset( new LogicalExpr( $1->condition->expr.release(), $3->condition->expr.release(), true ) );
     1350                                        $1->condition->expr.reset( new ast::LogicalExpr( yylloc, $1->condition->expr.release(), $3->condition->expr.release(), ast::AndExpr ) );
    13261351                                } // if
    13271352                        } else $1->condition = $3->condition;
    13281353                        if ( $1->change ) {
    13291354                                if ( $3->change ) {
    1330                                         $1->change->expr.reset( new CommaExpr( $1->change->expr.release(), $3->change->expr.release() ) );
     1355                                        $1->change->expr.reset( new ast::CommaExpr( yylloc, $1->change->expr.release(), $3->change->expr.release() ) );
    13311356                                } // if
    13321357                        } else $1->change = $3->change;
     
    13371362for_control_expression:
    13381363        ';' comma_expression_opt ';' comma_expression_opt
    1339                 { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); }
     1364                { $$ = new ForCtrl( nullptr, $2, $4 ); }
    13401365        | comma_expression ';' comma_expression_opt ';' comma_expression_opt
    1341                 { $$ = new ForCtrl( $1, $3, $5 ); }
     1366                {
     1367                        StatementNode * init = $1 ? new StatementNode( new ast::ExprStmt( yylloc, maybeMoveBuild( $1 ) ) ) : nullptr;
     1368                        $$ = new ForCtrl( init, $3, $5 );
     1369                }
    13421370        | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';'
    1343                 { $$ = new ForCtrl( $1, $2, $4 ); }
     1371                { $$ = new ForCtrl( new StatementNode( $1 ), $2, $4 ); }
    13441372
    13451373        | '@' ';' comma_expression                                                      // CFA, empty loop-index
    1346                 { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, nullptr ); }
     1374                { $$ = new ForCtrl( nullptr, $3, nullptr ); }
    13471375        | '@' ';' comma_expression ';' comma_expression         // CFA, empty loop-index
    1348                 { $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, $5 ); }
     1376                { $$ = new ForCtrl( nullptr, $3, $5 ); }
    13491377
    13501378        | comma_expression                                                                      // CFA, anonymous loop-index
    1351                 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), NEW_ZERO, OperKinds::LThan, $1->clone(), NEW_ONE ); }
     1379                { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), NEW_ZERO, OperKinds::LThan, $1->clone(), NEW_ONE ); }
    13521380        | downupdowneq comma_expression                                         // CFA, anonymous loop-index
    1353                 { $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $1, NEW_ZERO, $2->clone() ), $1, UPDOWN( $1, $2->clone(), NEW_ZERO ), NEW_ONE ); }
     1381                { $$ = forCtrl( yylloc, $2, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $1, NEW_ZERO, $2->clone() ), $1, UPDOWN( $1, $2->clone(), NEW_ZERO ), NEW_ONE ); }
    13541382
    13551383        | comma_expression updowneq comma_expression            // CFA, anonymous loop-index
    1356                 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), NEW_ONE ); }
     1384                { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), NEW_ONE ); }
    13571385        | '@' updowneq comma_expression                                         // CFA, anonymous loop-index
    13581386                {
    13591387                        if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1360                         else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, NEW_ONE );
     1388                        else $$ = forCtrl( yylloc, $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, NEW_ONE );
    13611389                }
    13621390        | comma_expression updowneq '@'                                         // CFA, anonymous loop-index
     
    13661394                }
    13671395        | comma_expression updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
    1368                 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), $5 ); }
     1396                { $$ = forCtrl( yylloc, $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), $5 ); }
    13691397        | '@' updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
    13701398                {
    13711399                        if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1372                         else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, $5 );
     1400                        else $$ = forCtrl( yylloc, $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, $5 );
    13731401                }
    13741402        | comma_expression updowneq '@' '~' comma_expression // CFA, anonymous loop-index
     
    13891417
    13901418        | comma_expression ';' comma_expression                         // CFA
    1391                 { $$ = forCtrl( $3, $1, NEW_ZERO, OperKinds::LThan, $3->clone(), NEW_ONE ); }
     1419                { $$ = forCtrl( yylloc, $3, $1, NEW_ZERO, OperKinds::LThan, $3->clone(), NEW_ONE ); }
    13921420        | comma_expression ';' downupdowneq comma_expression // CFA
    1393                 { $$ = forCtrl( $4, $1, UPDOWN( $3, NEW_ZERO, $4->clone() ), $3, UPDOWN( $3, $4->clone(), NEW_ZERO ), NEW_ONE ); }
     1421                { $$ = forCtrl( yylloc, $4, $1, UPDOWN( $3, NEW_ZERO, $4->clone() ), $3, UPDOWN( $3, $4->clone(), NEW_ZERO ), NEW_ONE ); }
    13941422
    13951423        | comma_expression ';' comma_expression updowneq comma_expression // CFA
    1396                 { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), NEW_ONE ); }
     1424                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), NEW_ONE ); }
    13971425        | comma_expression ';' '@' updowneq comma_expression // CFA
    13981426                {
    13991427                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1400                         else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, NEW_ONE );
     1428                        else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, NEW_ONE );
    14011429                }
    14021430        | comma_expression ';' comma_expression updowneq '@' // CFA
     
    14041432                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14051433                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1406                         else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
     1434                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
    14071435                }
    14081436        | comma_expression ';' '@' updowneq '@'                         // CFA, error
     
    14101438
    14111439        | comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA
    1412                 { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
     1440                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
    14131441        | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, error
    14141442                {
    14151443                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1416                         else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, $7 );
     1444                        else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, $7 );
    14171445                }
    14181446        | comma_expression ';' comma_expression updowneq '@' '~' comma_expression // CFA
     
    14201448                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14211449                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1422                         else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, $7 );
     1450                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, $7 );
    14231451                }
    14241452        | comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA
    1425                 { $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
     1453                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
    14261454        | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, error
    14271455                {
    14281456                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1429                         else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, nullptr );
     1457                        else $$ = forCtrl( yylloc, $5, $1, $5->clone(), $4, nullptr, nullptr );
    14301458                }
    14311459        | comma_expression ';' comma_expression updowneq '@' '~' '@' // CFA
     
    14331461                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14341462                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1435                         else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, nullptr );
     1463                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, nullptr );
    14361464                }
    14371465        | comma_expression ';' '@' updowneq '@' '~' '@' // CFA
     
    14391467
    14401468        | declaration comma_expression                                          // CFA
    1441                 { $$ = forCtrl( $1, NEW_ZERO, OperKinds::LThan, $2, NEW_ONE ); }
     1469                { $$ = forCtrl( yylloc, $1, NEW_ZERO, OperKinds::LThan, $2, NEW_ONE ); }
    14421470        | declaration downupdowneq comma_expression                     // CFA
    1443                 { $$ = forCtrl( $1, UPDOWN( $2, NEW_ZERO, $3 ), $2, UPDOWN( $2, $3->clone(), NEW_ZERO ), NEW_ONE ); }
     1471                { $$ = forCtrl( yylloc, $1, UPDOWN( $2, NEW_ZERO, $3 ), $2, UPDOWN( $2, $3->clone(), NEW_ZERO ), NEW_ONE ); }
    14441472
    14451473        | declaration comma_expression updowneq comma_expression // CFA
    1446                 { $$ = forCtrl( $1, UPDOWN( $3, $2->clone(), $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), NEW_ONE ); }
     1474                { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2->clone(), $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), NEW_ONE ); }
    14471475        | declaration '@' updowneq comma_expression                     // CFA
    14481476                {
    14491477                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1450                         else $$ = forCtrl( $1, $4, $3, nullptr, NEW_ONE );
     1478                        else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, NEW_ONE );
    14511479                }
    14521480        | declaration comma_expression updowneq '@'                     // CFA
     
    14541482                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14551483                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1456                         else $$ = forCtrl( $1, $2, $3, nullptr, NEW_ONE );
     1484                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, NEW_ONE );
    14571485                }
    14581486
    14591487        | declaration comma_expression updowneq comma_expression '~' comma_expression // CFA
    1460                 { $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), $6 ); }
     1488                { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), $6 ); }
    14611489        | declaration '@' updowneq comma_expression '~' comma_expression // CFA
    14621490                {
    14631491                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1464                         else $$ = forCtrl( $1, $4, $3, nullptr, $6 );
     1492                        else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, $6 );
    14651493                }
    14661494        | declaration comma_expression updowneq '@' '~' comma_expression // CFA
     
    14681496                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14691497                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1470                         else $$ = forCtrl( $1, $2, $3, nullptr, $6 );
     1498                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, $6 );
    14711499                }
    14721500        | declaration comma_expression updowneq comma_expression '~' '@' // CFA
    1473                 { $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), nullptr ); }
     1501                { $$ = forCtrl( yylloc, $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), nullptr ); }
    14741502        | declaration '@' updowneq comma_expression '~' '@' // CFA
    14751503                {
    14761504                        if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
    1477                         else $$ = forCtrl( $1, $4, $3, nullptr, nullptr );
     1505                        else $$ = forCtrl( yylloc, $1, $4, $3, nullptr, nullptr );
    14781506                }
    14791507        | declaration comma_expression updowneq '@' '~' '@'     // CFA
     
    14811509                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14821510                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    1483                         else $$ = forCtrl( $1, $2, $3, nullptr, nullptr );
     1511                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, nullptr );
    14841512                }
    14851513        | declaration '@' updowneq '@' '~' '@'                          // CFA, error
     
    14961524                        SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr;
    14971525                }
    1498         ;
     1526        ;
    14991527
    15001528downupdowneq:
     
    15051533        | ErangeDownEq
    15061534                { $$ = OperKinds::GEThan; }
    1507         ;
     1535        ;
    15081536
    15091537updown:
     
    15121540        | ErangeDown
    15131541                { $$ = OperKinds::GThan; }
    1514         ;
     1542        ;
    15151543
    15161544updowneq:
     
    15201548        | ErangeDownEq
    15211549                { $$ = OperKinds::GEThan; }
    1522         ;
     1550        ;
    15231551
    15241552jump_statement:
    15251553        GOTO identifier_or_type_name ';'
    1526                 { $$ = new StatementNode( build_branch( $2, BranchStmt::Goto ) ); }
     1554                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Goto ) ); }
    15271555        | GOTO '*' comma_expression ';'                                         // GCC, computed goto
    15281556                // The syntax for the GCC computed goto violates normal expression precedence, e.g., goto *i+3; => goto *(i+3);
     
    15311559                // A semantic check is required to ensure fallthru appears only in the body of a choose statement.
    15321560        | fall_through_name ';'                                                         // CFA
    1533                 { $$ = new StatementNode( build_branch( BranchStmt::FallThrough ) ); }
     1561                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThrough ) ); }
    15341562        | fall_through_name identifier_or_type_name ';'         // CFA
    1535                 { $$ = new StatementNode( build_branch( $2, BranchStmt::FallThrough ) ); }
     1563                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::FallThrough ) ); }
    15361564        | fall_through_name DEFAULT ';'                                         // CFA
    1537                 { $$ = new StatementNode( build_branch( BranchStmt::FallThroughDefault ) ); }
     1565                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::FallThroughDefault ) ); }
    15381566        | CONTINUE ';'
    15391567                // A semantic check is required to ensure this statement appears only in the body of an iteration statement.
    1540                 { $$ = new StatementNode( build_branch( BranchStmt::Continue ) ); }
     1568                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::Continue ) ); }
    15411569        | CONTINUE identifier_or_type_name ';'                          // CFA, multi-level continue
    15421570                // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and
    15431571                // the target of the transfer appears only at the start of an iteration statement.
    1544                 { $$ = new StatementNode( build_branch( $2, BranchStmt::Continue ) ); }
     1572                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Continue ) ); }
    15451573        | BREAK ';'
    15461574                // A semantic check is required to ensure this statement appears only in the body of an iteration statement.
    1547                 { $$ = new StatementNode( build_branch( BranchStmt::Break ) ); }
     1575                { $$ = new StatementNode( build_branch( yylloc, ast::BranchStmt::Break ) ); }
    15481576        | BREAK identifier_or_type_name ';'                                     // CFA, multi-level exit
    15491577                // A semantic check is required to ensure this statement appears only in the body of an iteration statement, and
    15501578                // the target of the transfer appears only at the start of an iteration statement.
    1551                 { $$ = new StatementNode( build_branch( $2, BranchStmt::Break ) ); }
     1579                { $$ = new StatementNode( build_branch( yylloc, $2, ast::BranchStmt::Break ) ); }
    15521580        | RETURN comma_expression_opt ';'
    1553                 { $$ = new StatementNode( build_return( $2 ) ); }
     1581                { $$ = new StatementNode( build_return( yylloc, $2 ) ); }
    15541582        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    15551583                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    15561584        | SUSPEND ';'
    1557                 { $$ = new StatementNode( build_suspend( nullptr ) ); }
     1585                { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::None ) ); }
    15581586        | SUSPEND compound_statement
    1559                 { $$ = new StatementNode( build_suspend( $2 ) ); }
     1587                { $$ = new StatementNode( build_suspend( yylloc, $2, ast::SuspendStmt::None ) ); }
    15601588        | SUSPEND COROUTINE ';'
    1561                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
     1589                { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Coroutine ) ); }
    15621590        | SUSPEND COROUTINE compound_statement
    1563                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
     1591                { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Coroutine ) ); }
    15641592        | SUSPEND GENERATOR ';'
    1565                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
     1593                { $$ = new StatementNode( build_suspend( yylloc, nullptr, ast::SuspendStmt::Generator ) ); }
    15661594        | SUSPEND GENERATOR compound_statement
    1567                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
     1595                { $$ = new StatementNode( build_suspend( yylloc, $3, ast::SuspendStmt::Generator ) ); }
    15681596        | THROW assignment_expression_opt ';'                           // handles rethrow
    1569                 { $$ = new StatementNode( build_throw( $2 ) ); }
     1597                { $$ = new StatementNode( build_throw( yylloc, $2 ) ); }
    15701598        | THROWRESUME assignment_expression_opt ';'                     // handles reresume
    1571                 { $$ = new StatementNode( build_resume( $2 ) ); }
     1599                { $$ = new StatementNode( build_resume( yylloc, $2 ) ); }
    15721600        | THROWRESUME assignment_expression_opt AT assignment_expression ';' // handles reresume
    15731601                { $$ = new StatementNode( build_resume_at( $2, $4 ) ); }
     
    15811609with_statement:
    15821610        WITH '(' tuple_expression_list ')' statement
    1583                 { $$ = new StatementNode( build_with( $3, $5 ) ); }
    1584         ;
    1585 
    1586 // If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex".
     1611                { $$ = new StatementNode( build_with( yylloc, $3, $5 ) ); }
     1612        ;
     1613
     1614// If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so possibly change syntax to "with mutex".
    15871615mutex_statement:
    1588         MUTEX '(' argument_expression_list ')' statement
    1589                 { $$ = new StatementNode( build_mutex( $3, $5 ) ); }
     1616        MUTEX '(' argument_expression_list_opt ')' statement
     1617                {
     1618                        if ( ! $3 ) { SemanticError( yylloc, "mutex argument list cannot be empty." ); $$ = nullptr; }
     1619                        $$ = new StatementNode( build_mutex( yylloc, $3, $5 ) );
     1620                }
    15901621        ;
    15911622
     
    15981629                { $$ = nullptr; }
    15991630        | when_clause
    1600         ;
    1601 
    1602 waitfor:
    1603         WAITFOR '(' cast_expression ')'
    1604                 { $$ = $3; }
    1605 //      | WAITFOR '(' cast_expression ',' argument_expression_list_opt ')'
    1606 //              { $$ = (ExpressionNode *)$3->set_last( $5 ); }
    1607         | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
    1608                 { $$ = (ExpressionNode *)($3->set_last( $5 )); }
    16091631        ;
    16101632
     
    16171639
    16181640timeout:
    1619         TIMEOUT '(' comma_expression ')'                        { $$ = $3; }
    1620         ;
    1621 
    1622 waitfor_clause:
     1641        TIMEOUT '(' comma_expression ')'                        { $$ = $3; }
     1642        ;
     1643
     1644wor:
     1645        OROR
     1646        | WOR
     1647
     1648waitfor:
     1649        WAITFOR '(' cast_expression ')'
     1650                { $$ = $3; }
     1651        | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
     1652                { $$ = (ExpressionNode *)($3->set_last( $5 )); }
     1653        ;
     1654
     1655wor_waitfor_clause:
    16231656        when_clause_opt waitfor statement                                       %prec THEN
    1624                 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }
    1625         | when_clause_opt waitfor statement WOR waitfor_clause
    1626                 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); }
    1627         | when_clause_opt timeout statement                                     %prec THEN
    1628                 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }
    1629         | when_clause_opt ELSE statement
    1630                 { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
     1657                // Called first: create header for WaitForStmt.
     1658                { $$ = build_waitfor( yylloc, new ast::WaitForStmt( yylloc ), $1, $2, maybe_build_compound( yylloc, $3 ) ); }
     1659        | wor_waitfor_clause wor when_clause_opt waitfor statement
     1660                { $$ = build_waitfor( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); }
     1661        | wor_waitfor_clause wor when_clause_opt ELSE statement
     1662                { $$ = build_waitfor_else( yylloc, $1, $3, maybe_build_compound( yylloc, $5 ) ); }
     1663        | wor_waitfor_clause wor when_clause_opt timeout statement      %prec THEN
     1664                { $$ = build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); }
    16311665        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1632         | when_clause_opt timeout statement WOR ELSE statement // syntax error
     1666        | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
    16331667                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    1634         | when_clause_opt timeout statement WOR when_clause ELSE statement
    1635                 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); }
     1668        | wor_waitfor_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
     1669                { $$ = build_waitfor_else( yylloc, build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ), $7, maybe_build_compound( yylloc, $9 ) ); }
    16361670        ;
    16371671
    16381672waitfor_statement:
    1639         when_clause_opt waitfor statement                                       %prec THEN
    1640                 { $$ = new StatementNode( build_waitfor( $2, $3, $1 ) ); }
    1641         | when_clause_opt waitfor statement WOR waitfor_clause
    1642                 { $$ = new StatementNode( build_waitfor( $2, $3, $1, $5 ) ); }
     1673        wor_waitfor_clause                                                                      %prec THEN
     1674                { $$ = new StatementNode( $1 ); }
     1675        ;
     1676
     1677wand:
     1678        ANDAND
     1679        | WAND
     1680        ;
     1681
     1682waituntil:
     1683        WAITUNTIL '(' comma_expression ')'
     1684                { $$ = $3; }
     1685        ;
     1686
     1687waituntil_clause:
     1688        when_clause_opt waituntil statement
     1689                { $$ = build_waituntil_clause( yylloc, $1, $2, maybe_build_compound( yylloc, $3 ) ); }
     1690        | '(' wor_waituntil_clause ')'
     1691                { $$ = $2; }
     1692        ;
     1693
     1694wand_waituntil_clause:
     1695        waituntil_clause                                                                        %prec THEN
     1696                { $$ = $1; }
     1697        | waituntil_clause wand wand_waituntil_clause
     1698                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::AND, $1, $3 ); }
     1699        ;
     1700
     1701wor_waituntil_clause:
     1702        wand_waituntil_clause
     1703                { $$ = $1; }
     1704        | wor_waituntil_clause wor wand_waituntil_clause
     1705                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR, $1, $3 ); }
     1706        | wor_waituntil_clause wor when_clause_opt ELSE statement
     1707                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_else( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
     1708        | wor_waituntil_clause wor when_clause_opt timeout statement    %prec THEN
     1709                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); }
     1710        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
     1711        | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
     1712                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
     1713        | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
     1714                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1,
     1715                new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR,
     1716                    build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ),
     1717                    build_waituntil_else( yylloc, $7, maybe_build_compound( yylloc, $9 ) ) ) ); }
     1718        ;
     1719
     1720waituntil_statement:
     1721        wor_waituntil_clause                                                            %prec THEN
     1722                // SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement.
     1723                {
     1724            $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) );
     1725            // $$ = new StatementNode( build_compound( yylloc, nullptr ) );
     1726        }
    16431727        ;
    16441728
    16451729exception_statement:
    1646         TRY compound_statement handler_clause                                   %prec THEN
    1647                 { $$ = new StatementNode( build_try( $2, $3, 0 ) ); }
     1730        TRY compound_statement handler_clause                                   %prec THEN
     1731                { $$ = new StatementNode( build_try( yylloc, $2, $3, nullptr ) ); }
    16481732        | TRY compound_statement finally_clause
    1649                 { $$ = new StatementNode( build_try( $2, 0, $3 ) ); }
     1733                { $$ = new StatementNode( build_try( yylloc, $2, nullptr, $3 ) ); }
    16501734        | TRY compound_statement handler_clause finally_clause
    1651                 { $$ = new StatementNode( build_try( $2, $3, $4 ) ); }
     1735                { $$ = new StatementNode( build_try( yylloc, $2, $3, $4 ) ); }
    16521736        ;
    16531737
    16541738handler_clause:
    16551739        handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1656                 { $$ = new StatementNode( build_catch( $1, $4, $6, $8 ) ); }
     1740                { $$ = new ClauseNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
    16571741        | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1658                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $5, $7, $9 ) ) ); }
     1742                { $$ = $1->set_last( new ClauseNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
    16591743        ;
    16601744
     
    16661750
    16671751handler_key:
    1668         CATCH                                                                           { $$ = CatchStmt::Terminate; }
    1669         | RECOVER                                                                       { $$ = CatchStmt::Terminate; }
    1670         | CATCHRESUME                                                           { $$ = CatchStmt::Resume; }
    1671         | FIXUP                                                                         { $$ = CatchStmt::Resume; }
     1752        CATCH                                                                           { $$ = ast::Terminate; }
     1753        | RECOVER                                                                       { $$ = ast::Terminate; }
     1754        | CATCHRESUME                                                           { $$ = ast::Resume; }
     1755        | FIXUP                                                                         { $$ = ast::Resume; }
    16721756        ;
    16731757
    16741758finally_clause:
    1675         FINALLY compound_statement                                      { $$ = new StatementNode( build_finally( $2 ) ); }
     1759        FINALLY compound_statement                                      { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); }
    16761760        ;
    16771761
     
    16991783asm_statement:
    17001784        ASM asm_volatile_opt '(' string_literal ')' ';'
    1701                 { $$ = new StatementNode( build_asm( $2, $4, 0 ) ); }
     1785                { $$ = new StatementNode( build_asm( yylloc, $2, $4, nullptr ) ); }
    17021786        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ')' ';' // remaining GCC
    1703                 { $$ = new StatementNode( build_asm( $2, $4, $6 ) ); }
     1787                { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6 ) ); }
    17041788        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ':' asm_operands_opt ')' ';'
    1705                 { $$ = new StatementNode( build_asm( $2, $4, $6, $8 ) ); }
     1789                { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6, $8 ) ); }
    17061790        | ASM asm_volatile_opt '(' string_literal ':' asm_operands_opt ':' asm_operands_opt ':' asm_clobbers_list_opt ')' ';'
    1707                 { $$ = new StatementNode( build_asm( $2, $4, $6, $8, $10 ) ); }
     1791                { $$ = new StatementNode( build_asm( yylloc, $2, $4, $6, $8, $10 ) ); }
    17081792        | ASM asm_volatile_opt GOTO '(' string_literal ':' ':' asm_operands_opt ':' asm_clobbers_list_opt ':' label_list ')' ';'
    1709                 { $$ = new StatementNode( build_asm( $2, $5, 0, $8, $10, $12 ) ); }
     1793                { $$ = new StatementNode( build_asm( yylloc, $2, $5, nullptr, $8, $10, $12 ) ); }
    17101794        ;
    17111795
     
    17311815asm_operand:                                                                                    // GCC
    17321816        string_literal '(' constant_expression ')'
    1733                 { $$ = new ExpressionNode( new AsmExpr( nullptr, $1, maybeMoveBuild<Expression>( $3 ) ) ); }
     1817                { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    17341818        | '[' IDENTIFIER ']' string_literal '(' constant_expression ')'
    1735                 { $$ = new ExpressionNode( new AsmExpr( $2, $4, maybeMoveBuild<Expression>( $6 ) ) ); }
     1819                {
     1820                        $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, maybeMoveBuild( $4 ), maybeMoveBuild( $6 ) ) );
     1821                        delete $2.str;
     1822                }
    17361823        ;
    17371824
     
    17401827                { $$ = nullptr; }                                                               // use default argument
    17411828        | string_literal
    1742                 { $$ = new ExpressionNode( $1 ); }
     1829                { $$ = $1; }
    17431830        | asm_clobbers_list_opt ',' string_literal
    1744                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
     1831                { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); }
    17451832        ;
    17461833
     
    17481835        identifier
    17491836                {
    1750                         $$ = new LabelNode(); $$->labels.push_back( *$1 );
     1837                        $$ = new LabelNode(); $$->labels.emplace_back( yylloc, *$1 );
    17511838                        delete $1;                                                                      // allocated by lexer
    17521839                }
    17531840        | label_list ',' identifier
    17541841                {
    1755                         $$ = $1; $1->labels.push_back( *$3 );
     1842                        $$ = $1; $1->labels.emplace_back( yylloc, *$3 );
    17561843                        delete $3;                                                                      // allocated by lexer
    17571844                }
     
    18041891                {
    18051892                        // printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" );
    1806                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     1893                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    18071894                        //   printf( "\tattr %s\n", attr->name.c_str() );
    18081895                        // } // for
     
    18141901static_assert:
    18151902        STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11
    1816                 { $$ = DeclarationNode::newStaticAssert( $3, $5 ); }
     1903                { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); }
    18171904        | STATICASSERT '(' constant_expression ')' ';'          // CFA
    1818                 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( *new string( "\"\"" ) ) ); }
     1905                { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); }
    18191906
    18201907// C declaration syntax is notoriously confusing and error prone. Cforall provides its own type, variable and function
     
    18801967//      '[' ']' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' // S/R conflict
    18811968//              {
    1882 //                      $$ = DeclarationNode::newFunction( $3, DeclarationNode::newTuple( 0 ), $6, 0, true );
     1969//                      $$ = DeclarationNode::newFunction( $3, DeclarationNode::newTuple( 0 ), $6, nullptr, true );
    18831970//              }
    18841971//      '[' ']' identifier '(' push cfa_parameter_ellipsis_list_opt pop ')'
    18851972//              {
    18861973//                      typedefTable.setNextIdentifier( *$5 );
    1887 //                      $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, 0, true );
     1974//                      $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, nullptr, true );
    18881975//              }
    18891976//      | '[' ']' TYPEDEFname '(' push cfa_parameter_ellipsis_list_opt pop ')'
    18901977//              {
    18911978//                      typedefTable.setNextIdentifier( *$5 );
    1892 //                      $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, 0, true );
     1979//                      $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, nullptr, true );
    18931980//              }
    18941981//      | '[' ']' typegen_name
     
    19021989        cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
    19031990                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    1904                 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
     1991                { $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
    19051992        | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
    1906                 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
     1993                { $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
    19071994        ;
    19081995
     
    19402027                {
    19412028                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "4" );
    1942                         $$ = $3->addType( $2 )->addTypedef();
     2029                        if ( $2->type->forall || ($2->type->kind == TypeData::Aggregate && $2->type->aggregate.params) ) {
     2030                                SemanticError( yylloc, "forall qualifier in typedef is currently unimplemented." ); $$ = nullptr;
     2031                        } else $$ = $3->addType( $2 )->addTypedef(); // watchout frees $2 and $3
    19432032                }
    19442033        | typedef_declaration pop ',' push declarator
     
    19482037                }
    19492038        | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
    1950                 {
    1951                         typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "6" );
    1952                         $$ = $4->addType( $3 )->addQualifiers( $1 )->addTypedef();
    1953                 }
     2039                { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
    19542040        | type_specifier TYPEDEF declarator
    1955                 {
    1956                         typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "7" );
    1957                         $$ = $3->addType( $1 )->addTypedef();
    1958                 }
     2041                { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
    19592042        | type_specifier TYPEDEF type_qualifier_list declarator
    1960                 {
    1961                         typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "8" );
    1962                         $$ = $4->addQualifiers( $1 )->addTypedef()->addType( $1 );
    1963                 }
     2043                { SemanticError( yylloc, "Type qualifiers/specifiers before TYPEDEF is deprecated, move after TYPEDEF." ); $$ = nullptr; }
    19642044        ;
    19652045
     
    19682048        TYPEDEF identifier '=' assignment_expression
    19692049                {
    1970                         SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     2050                        SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    19712051                }
    19722052        | typedef_expression pop ',' push identifier '=' assignment_expression
    19732053                {
    1974                         SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     2054                        SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    19752055                }
    19762056        ;
     
    19822062        | typedef_expression                                                            // deprecated GCC, naming expression type
    19832063        | sue_declaration_specifier
     2064                {
     2065                        assert( $1->type );
     2066                        if ( $1->type->qualifiers.any() ) {                     // CV qualifiers ?
     2067                                SemanticError( yylloc, "Useless type qualifier(s) in empty declaration." ); $$ = nullptr;
     2068                        }
     2069                        // enums are never empty declarations because there must have at least one enumeration.
     2070                        if ( $1->type->kind == TypeData::AggregateInst && $1->storageClasses.any() ) { // storage class ?
     2071                                SemanticError( yylloc, "Useless storage qualifier(s) in empty aggregate declaration." ); $$ = nullptr;
     2072                        }
     2073                }
    19842074        ;
    19852075
     
    19872077                // A semantic check is required to ensure asm_name only appears on declarations with implicit or explicit static
    19882078                // storage-class
    1989         declarator asm_name_opt initializer_opt
     2079        variable_declarator asm_name_opt initializer_opt
    19902080                { $$ = $1->addAsmName( $2 )->addInitializer( $3 ); }
     2081        | variable_type_redeclarator asm_name_opt initializer_opt
     2082                { $$ = $1->addAsmName( $2 )->addInitializer( $3 ); }
     2083
     2084        | general_function_declarator asm_name_opt
     2085                { $$ = $1->addAsmName( $2 )->addInitializer( nullptr ); }
     2086        | general_function_declarator asm_name_opt '=' VOID
     2087                { $$ = $1->addAsmName( $2 )->addInitializer( new InitializerNode( true ) ); }
     2088
    19912089        | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    19922090                { $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
    19932091        ;
    19942092
     2093general_function_declarator:
     2094        function_type_redeclarator
     2095        | function_declarator
     2096        ;
     2097
    19952098declaration_specifier:                                                                  // type specifier + storage class
    19962099        basic_declaration_specifier
     2100        | type_declaration_specifier
    19972101        | sue_declaration_specifier
    1998         | type_declaration_specifier
     2102        | sue_declaration_specifier invalid_types
     2103                {
     2104                        SemanticError( yylloc, ::toString( "Missing ';' after end of ",
     2105                                $1->type->enumeration.name ? "enum" : ast::AggregateDecl::aggrString( $1->type->aggregate.kind ),
     2106                                " declaration" ) );
     2107                        $$ = nullptr;
     2108                }
     2109        ;
     2110
     2111invalid_types:
     2112        aggregate_key
     2113        | basic_type_name
     2114        | indirect_type
    19992115        ;
    20002116
     
    20132129        basic_type_specifier
    20142130        | sue_type_specifier
    2015                 {
    2016                         // printf( "sue_type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2017                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    2018                         //   printf( "\tattr %s\n", attr->name.c_str() );
    2019                         // } // for
    2020                 }
    20212131        | type_type_specifier
    20222132        ;
     
    20652175                { $$ = DeclarationNode::newTypeQualifier( Type::Atomic ); }
    20662176        | forall
     2177                { $$ = DeclarationNode::newForall( $1 ); }
    20672178        ;
    20682179
    20692180forall:
    20702181        FORALL '(' type_parameter_list ')'                                      // CFA
    2071                 { $$ = DeclarationNode::newForall( $3 ); }
     2182                { $$ = $3; }
    20722183        ;
    20732184
     
    22262337                { $$ = DeclarationNode::newTypeof( $3 ); }
    22272338        | BASETYPEOF '(' type ')'                                                       // CFA: basetypeof( x ) y;
    2228                 { $$ = DeclarationNode::newTypeof( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ), true ); }
     2339                { $$ = DeclarationNode::newTypeof( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ), true ); }
    22292340        | BASETYPEOF '(' comma_expression ')'                           // CFA: basetypeof( a+b ) y;
    22302341                { $$ = DeclarationNode::newTypeof( $3, true ); }
     
    22392350                {
    22402351                        // printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2241                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2352                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    22422353                        //   printf( "\tattr %s\n", attr->name.c_str() );
    22432354                        // } // for
     
    22552366                {
    22562367                        // printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2257                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2368                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    22582369                        //   printf( "\tattr %s\n", attr->name.c_str() );
    22592370                        // } // for
     
    23332444                {
    23342445                        // printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2335                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2446                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    23362447                        //   printf( "\tattr %s\n", attr->name.c_str() );
    23372448                        // } // for
     
    23572468          '{' field_declaration_list_opt '}' type_parameters_opt
    23582469                {
    2359                         // printf( "aggregate_type1 %s\n", $3.str->c_str() );
    2360                         // if ( $2 )
    2361                         //      for ( Attribute * attr: reverseIterate( $2->attributes ) ) {
    2362                         //              printf( "copySpecifiers12 %s\n", attr->name.c_str() );
    2363                         //      } // for
    23642470                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
    2365                         // printf( "aggregate_type2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2366                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    2367                         //      printf( "aggregate_type3 %s\n", attr->name.c_str() );
    2368                         // } // for
    23692471                }
    23702472        | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
     
    23752477          '{' field_declaration_list_opt '}' type_parameters_opt
    23762478                {
    2377                         // printf( "AGG3\n" );
    23782479                        DeclarationNode::newFromTypedef( $3 );
    23792480                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    23862487          '{' field_declaration_list_opt '}' type_parameters_opt
    23872488                {
    2388                         // printf( "AGG4\n" );
    23892489                        DeclarationNode::newFromTypeGen( $3, nullptr );
    23902490                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    24132513                        // switched to a TYPEGENname. Link any generic arguments from typegen_name to new generic declaration and
    24142514                        // delete newFromTypeGen.
    2415                         $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $3->type->symbolic.actuals, nullptr, false )->addQualifiers( $2 );
    2416                         $3->type->symbolic.name = nullptr;
    2417                         $3->type->symbolic.actuals = nullptr;
    2418                         delete $3;
     2515                        if ( $3->type->kind == TypeData::SymbolicInst && ! $3->type->symbolic.isTypedef ) {
     2516                                $$ = $3->addQualifiers( $2 );
     2517                        } else {
     2518                                $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $3->type->symbolic.actuals, nullptr, false )->addQualifiers( $2 );
     2519                                $3->type->symbolic.name = nullptr;                      // copied to $$
     2520                                $3->type->symbolic.actuals = nullptr;
     2521                                delete $3;
     2522                        }
    24192523                }
    24202524        ;
     
    24272531aggregate_data:
    24282532        STRUCT vtable_opt
    2429                 { $$ = AggregateDecl::Struct; }
     2533                { $$ = ast::AggregateDecl::Struct; }
    24302534        | UNION
    2431                 { $$ = AggregateDecl::Union; }
     2535                { $$ = ast::AggregateDecl::Union; }
    24322536        | EXCEPTION                                                                                     // CFA
    2433                 { $$ = AggregateDecl::Exception; }
    2434           //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2537                { $$ = ast::AggregateDecl::Exception; }
     2538          //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = ast::AggregateDecl::NoAggregate; }
    24352539        ;
    24362540
    24372541aggregate_control:                                                                              // CFA
    24382542        MONITOR
    2439                 { $$ = AggregateDecl::Monitor; }
     2543                { $$ = ast::AggregateDecl::Monitor; }
    24402544        | MUTEX STRUCT
    2441                 { $$ = AggregateDecl::Monitor; }
     2545                { $$ = ast::AggregateDecl::Monitor; }
    24422546        | GENERATOR
    2443                 { $$ = AggregateDecl::Generator; }
     2547                { $$ = ast::AggregateDecl::Generator; }
    24442548        | MUTEX GENERATOR
    2445                 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2549                {
     2550                        SemanticError( yylloc, "monitor generator is currently unimplemented." );
     2551                        $$ = ast::AggregateDecl::NoAggregate;
     2552                }
    24462553        | COROUTINE
    2447                 { $$ = AggregateDecl::Coroutine; }
     2554                { $$ = ast::AggregateDecl::Coroutine; }
    24482555        | MUTEX COROUTINE
    2449                 { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2556                {
     2557                        SemanticError( yylloc, "monitor coroutine is currently unimplemented." );
     2558                        $$ = ast::AggregateDecl::NoAggregate;
     2559                }
    24502560        | THREAD
    2451                 { $$ = AggregateDecl::Thread; }
     2561                { $$ = ast::AggregateDecl::Thread; }
    24522562        | MUTEX THREAD
    2453                 { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2563                {
     2564                        SemanticError( yylloc, "monitor thread is currently unimplemented." );
     2565                        $$ = ast::AggregateDecl::NoAggregate;
     2566                }
    24542567        ;
    24552568
     
    24672580                        $$ = fieldDecl( $1, $2 );
    24682581                        // printf( "type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2469                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2582                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    24702583                        //   printf( "\tattr %s\n", attr->name.c_str() );
    24712584                        // } // for
     
    24732586        | EXTENSION type_specifier field_declaring_list_opt ';' // GCC
    24742587                { $$ = fieldDecl( $2, $3 ); distExt( $$ ); }
     2588        | STATIC type_specifier field_declaring_list_opt ';' // CFA
     2589                { SemanticError( yylloc, "STATIC aggregate field qualifier currently unimplemented." ); $$ = nullptr; }
    24752590        | INLINE type_specifier field_abstract_list_opt ';'     // CFA
    24762591                {
     
    24832598                }
    24842599        | INLINE aggregate_control ';'                                          // CFA
    2485                 { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
     2600                { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
    24862601        | typedef_declaration ';'                                                       // CFA
    24872602        | cfa_field_declaring_list ';'                                          // CFA, new style field declaration
     
    25092624                { $$ = $1->addBitfield( $2 ); }
    25102625        | variable_type_redeclarator bit_subrange_size_opt
     2626                // A semantic check is required to ensure bit_subrange only appears on integral types.
     2627                { $$ = $1->addBitfield( $2 ); }
     2628        | function_type_redeclarator bit_subrange_size_opt
    25112629                // A semantic check is required to ensure bit_subrange only appears on integral types.
    25122630                { $$ = $1->addBitfield( $2 ); }
     
    25632681                { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); }
    25642682        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
    2565                 {
    2566                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 )
     2683                {
     2684                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() )
    25672685                        { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    25682686
     
    25752693        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    25762694                {
    2577                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
     2695                        if ( $3->storageClasses.any() || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    25782696                        typedefTable.makeTypedef( *$6 );
    25792697                }
     
    26092727enum_type_nobody:                                                                               // enum - {...}
    26102728        ENUM attribute_list_opt identifier
    2611                 { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, 0, false, false )->addQualifiers( $2 ); }
     2729                { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, nullptr, false, false )->addQualifiers( $2 ); }
    26122730        | ENUM attribute_list_opt type_name
    2613                 { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false, false )->addQualifiers( $2 ); }
     2731                { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, nullptr, false, false )->addQualifiers( $2 ); }
    26142732        ;
    26152733
     
    27512869type_no_function:                                                                               // sizeof, alignof, cast (constructor)
    27522870        cfa_abstract_declarator_tuple                                           // CFA
    2753         | type_specifier
     2871        | type_specifier                                                                        // cannot be type_specifier_nobody, e.g., (struct S {}){} is a thing
    27542872        | type_specifier abstract_declarator
    27552873                { $$ = $2->addType( $1 ); }
     
    27962914        designator_list ':'                                                                     // C99, CFA uses ":" instead of "="
    27972915        | identifier_at ':'                                                                     // GCC, field name
    2798                 { $$ = new ExpressionNode( build_varref( $1 ) ); }
     2916                { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
    27992917        ;
    28002918
     
    28082926designator:
    28092927        '.' identifier_at                                                                       // C99, field name
    2810                 { $$ = new ExpressionNode( build_varref( $2 ) ); }
     2928                { $$ = new ExpressionNode( build_varref( yylloc, $2 ) ); }
    28112929        | '[' push assignment_expression pop ']'                        // C99, single array element
    28122930                // assignment_expression used instead of constant_expression because of shift/reduce conflicts with tuple.
     
    28152933                { $$ = $3; }
    28162934        | '[' push constant_expression ELLIPSIS constant_expression pop ']' // GCC, multiple array elements
    2817                 { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $3 ), maybeMoveBuild<Expression>( $5 ) ) ); }
     2935                { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $3 ), maybeMoveBuild( $5 ) ) ); }
    28182936        | '.' '[' push field_name_list pop ']'                          // CFA, tuple field selector
    28192937                { $$ = $4; }
     
    28552973                {
    28562974                        typedefTable.addToScope( *$2, TYPEDEFname, "9" );
    2857                         if ( $1 == TypeDecl::Otype ) { SemanticError( yylloc, "otype keyword is deprecated, use T " ); }
    2858                         if ( $1 == TypeDecl::Dtype ) { SemanticError( yylloc, "dtype keyword is deprecated, use T &" ); }
    2859                         if ( $1 == TypeDecl::Ttype ) { SemanticError( yylloc, "ttype keyword is deprecated, use T ..." ); }
     2975                        if ( $1 == ast::TypeDecl::Otype ) { SemanticError( yylloc, "otype keyword is deprecated, use T " ); }
     2976                        if ( $1 == ast::TypeDecl::Dtype ) { SemanticError( yylloc, "dtype keyword is deprecated, use T &" ); }
     2977                        if ( $1 == ast::TypeDecl::Ttype ) { SemanticError( yylloc, "ttype keyword is deprecated, use T ..." ); }
    28602978                }
    28612979          type_initializer_opt assertion_list_opt
     
    28682986                {
    28692987                        typedefTable.addToScope( *$2, TYPEDIMname, "9" );
    2870                         $$ = DeclarationNode::newTypeParam( TypeDecl::Dimension, $2 );
     2988                        $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dimension, $2 );
    28712989                }
    28722990        // | type_specifier identifier_parameter_declarator
    28732991        | assertion_list
    2874                 { $$ = DeclarationNode::newTypeParam( TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
     2992                { $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
    28752993        ;
    28762994
    28772995new_type_class:                                                                                 // CFA
    28782996        // empty
    2879                 { $$ = TypeDecl::Otype; }
     2997                { $$ = ast::TypeDecl::Otype; }
    28802998        | '&'
    2881                 { $$ = TypeDecl::Dtype; }
     2999                { $$ = ast::TypeDecl::Dtype; }
    28823000        | '*'
    2883                 { $$ = TypeDecl::DStype; }                                              // dtype + sized
     3001                { $$ = ast::TypeDecl::DStype; }                                         // dtype + sized
    28843002        // | '(' '*' ')'
    2885         //      { $$ = TypeDecl::Ftype; }
     3003        //      { $$ = ast::TypeDecl::Ftype; }
    28863004        | ELLIPSIS
    2887                 { $$ = TypeDecl::Ttype; }
     3005                { $$ = ast::TypeDecl::Ttype; }
    28883006        ;
    28893007
    28903008type_class:                                                                                             // CFA
    28913009        OTYPE
    2892                 { $$ = TypeDecl::Otype; }
     3010                { $$ = ast::TypeDecl::Otype; }
    28933011        | DTYPE
    2894                 { $$ = TypeDecl::Dtype; }
     3012                { $$ = ast::TypeDecl::Dtype; }
    28953013        | FTYPE
    2896                 { $$ = TypeDecl::Ftype; }
     3014                { $$ = ast::TypeDecl::Ftype; }
    28973015        | TTYPE
    2898                 { $$ = TypeDecl::Ttype; }
     3016                { $$ = ast::TypeDecl::Ttype; }
    28993017        ;
    29003018
     
    29223040type_list:                                                                                              // CFA
    29233041        type
    2924                 { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
     3042                { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
    29253043        | assignment_expression
    29263044        | type_list ',' type
    2927                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
     3045                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
    29283046        | type_list ',' assignment_expression
    29293047                { $$ = (ExpressionNode *)( $1->set_last( $3 )); }
     
    29503068                {
    29513069                        typedefTable.addToEnclosingScope( *$1, TYPEDEFname, "10" );
    2952                         $$ = DeclarationNode::newTypeDecl( $1, 0 );
     3070                        $$ = DeclarationNode::newTypeDecl( $1, nullptr );
    29533071                }
    29543072        | identifier_or_type_name '(' type_parameter_list ')'
     
    29613079trait_specifier:                                                                                // CFA
    29623080        TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' '}'
    2963                 { $$ = DeclarationNode::newTrait( $2, $4, 0 ); }
     3081                {
     3082                        SemanticWarning( yylloc, Warning::DeprecTraitSyntax );
     3083                        $$ = DeclarationNode::newTrait( $2, $4, nullptr );
     3084                }
     3085        | forall TRAIT identifier_or_type_name '{' '}'          // alternate
     3086                { $$ = DeclarationNode::newTrait( $3, $1, nullptr ); }
    29643087        | TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' push trait_declaration_list pop '}'
    2965                 { $$ = DeclarationNode::newTrait( $2, $4, $8 ); }
     3088                {
     3089                        SemanticWarning( yylloc, Warning::DeprecTraitSyntax );
     3090                        $$ = DeclarationNode::newTrait( $2, $4, $8 );
     3091                }
     3092        | forall TRAIT identifier_or_type_name '{' push trait_declaration_list pop '}' // alternate
     3093                { $$ = DeclarationNode::newTrait( $3, $1, $6 ); }
    29663094        ;
    29673095
     
    30223150external_definition:
    30233151        DIRECTIVE
    3024                 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); }
     3152                { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( yylloc, $1 ) ) ); }
    30253153        | declaration
     3154                {
     3155                        // Variable declarations of anonymous types requires creating a unique type-name across multiple translation
     3156                        // unit, which is a dubious task, especially because C uses name rather than structural typing; hence it is
     3157                        // disallowed at the moment.
     3158                        if ( $1->linkage == ast::Linkage::Cforall && ! $1->storageClasses.is_static && $1->type && $1->type->kind == TypeData::AggregateInst ) {
     3159                                if ( $1->type->aggInst.aggregate->kind == TypeData::Enum && $1->type->aggInst.aggregate->enumeration.anon ) {
     3160                                        SemanticError( yylloc, "extern anonymous enumeration is currently unimplemented." ); $$ = nullptr;
     3161                                } else if ( $1->type->aggInst.aggregate->aggregate.anon ) { // handles struct or union
     3162                                        SemanticError( yylloc, "extern anonymous struct/union is currently unimplemented." ); $$ = nullptr;
     3163                                }
     3164                        }
     3165                }
    30263166        | IDENTIFIER IDENTIFIER
    30273167                { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; }
     
    30433183                }
    30443184        | ASM '(' string_literal ')' ';'                                        // GCC, global assembler statement
    3045                 { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); }
     3185                { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( yylloc, false, $3, nullptr ) ) ); }
    30463186        | EXTERN STRINGliteral
    30473187                {
    30483188                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    3049                         linkage = LinkageSpec::update( yylloc, linkage, $2 );
     3189                        linkage = ast::Linkage::update( yylloc, linkage, $2 );
    30503190                }
    30513191          up external_definition down
     
    30583198                {
    30593199                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    3060                         linkage = LinkageSpec::update( yylloc, linkage, $2 );
     3200                        linkage = ast::Linkage::update( yylloc, linkage, $2 );
    30613201                }
    30623202          '{' up external_definition_list_opt down '}'
     
    30693209        | type_qualifier_list
    30703210                {
    3071                         if ( $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3211                        if ( $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    30723212                        if ( $1->type->forall ) forall = true;          // remember generic type
    30733213                }
     
    30753215                {
    30763216                        distQual( $5, $1 );
    3077                         forall = false;
     3217                        forall = false;
    30783218                        $$ = $5;
    30793219                }
    30803220        | declaration_qualifier_list
    30813221                {
    3082                         if ( $1->type && $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3222                        if ( $1->type && $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    30833223                        if ( $1->type && $1->type->forall ) forall = true; // remember generic type
    30843224                }
     
    30863226                {
    30873227                        distQual( $5, $1 );
    3088                         forall = false;
     3228                        forall = false;
    30893229                        $$ = $5;
    30903230                }
    30913231        | declaration_qualifier_list type_qualifier_list
    30923232                {
    3093                         if ( ($1->type && $1->type->qualifiers.val) || ($2->type && $2->type->qualifiers.val) ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3233                        if ( ($1->type && $1->type->qualifiers.any()) || ($2->type && $2->type->qualifiers.any()) ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
    30943234                        if ( ($1->type && $1->type->forall) || ($2->type && $2->type->forall) ) forall = true; // remember generic type
    30953235                }
     
    30973237                {
    30983238                        distQual( $6, $1->addQualifiers( $2 ) );
    3099                         forall = false;
     3239                        forall = false;
    31003240                        $$ = $6;
    31013241                }
     
    31413281                        $$ = $2->addFunctionBody( $4, $3 )->addType( $1 );
    31423282                }
    3143         | declaration_specifier variable_type_redeclarator with_clause_opt compound_statement
     3283        | declaration_specifier function_type_redeclarator with_clause_opt compound_statement
    31443284                {
    31453285                        rebindForall( $1, $2 );
     
    31773317        | variable_type_redeclarator
    31783318        | function_declarator
     3319        | function_type_redeclarator
    31793320        ;
    31803321
    31813322subrange:
    31823323        constant_expression '~' constant_expression                     // CFA, integer subrange
    3183                 { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild<Expression>( $1 ), maybeMoveBuild<Expression>( $3 ) ) ); }
     3324                { $$ = new ExpressionNode( new ast::RangeExpr( yylloc, maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    31843325        ;
    31853326
     
    31903331                {
    31913332                        DeclarationNode * name = new DeclarationNode();
    3192                         name->asmName = $3;
     3333                        name->asmName = maybeMoveBuild( $3 );
    31933334                        $$ = name->addQualifiers( $5 );
    31943335                }
     
    32873428variable_ptr:
    32883429        ptrref_operator variable_declarator
    3289                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     3430                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    32903431        | ptrref_operator type_qualifier_list variable_declarator
    32913432                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     
    33033444        | '(' attribute_list variable_ptr ')' array_dimension
    33043445                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3305         | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
     3446        | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
    33063447                { $$ = $2->addArray( $4 ); }
    33073448        | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis
     
    33513492function_ptr:
    33523493        ptrref_operator function_declarator
    3353                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     3494                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    33543495        | ptrref_operator type_qualifier_list function_declarator
    33553496                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     
    34033544KR_function_ptr:
    34043545        ptrref_operator KR_function_declarator
    3405                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     3546                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    34063547        | ptrref_operator type_qualifier_list KR_function_declarator
    34073548                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     
    34273568        ;
    34283569
    3429 // This pattern parses a declaration for a variable or function prototype that redefines a type name, e.g.:
     3570// This pattern parses a declaration for a variable that redefines a type name, e.g.:
    34303571//
    34313572//              typedef int foo;
     
    34333574//                 int foo; // redefine typedef name in new scope
    34343575//              }
    3435 //
    3436 // The pattern precludes declaring an array of functions versus a pointer to an array of functions, and returning arrays
    3437 // and functions versus pointers to arrays and functions.
    34383576
    34393577paren_type:
     
    34503588        paren_type attribute_list_opt
    34513589                { $$ = $1->addQualifiers( $2 ); }
    3452         | type_ptr
    3453         | type_array attribute_list_opt
     3590        | variable_type_ptr
     3591        | variable_type_array attribute_list_opt
    34543592                { $$ = $1->addQualifiers( $2 ); }
    3455         | type_function attribute_list_opt
     3593        | variable_type_function attribute_list_opt
    34563594                { $$ = $1->addQualifiers( $2 ); }
    34573595        ;
    34583596
    3459 type_ptr:
     3597variable_type_ptr:
    34603598        ptrref_operator variable_type_redeclarator
    3461                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     3599                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    34623600        | ptrref_operator type_qualifier_list variable_type_redeclarator
    34633601                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3464         | '(' type_ptr ')' attribute_list_opt                           // redundant parenthesis
     3602        | '(' variable_type_ptr ')' attribute_list_opt          // redundant parenthesis
    34653603                { $$ = $2->addQualifiers( $4 ); }
    3466         | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis
     3604        | '(' attribute_list variable_type_ptr ')' attribute_list_opt // redundant parenthesis
    34673605                { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
    34683606        ;
    34693607
    3470 type_array:
     3608variable_type_array:
    34713609        paren_type array_dimension
    34723610                { $$ = $1->addArray( $2 ); }
    3473         | '(' type_ptr ')' array_dimension
     3611        | '(' variable_type_ptr ')' array_dimension
    34743612                { $$ = $2->addArray( $4 ); }
    3475         | '(' attribute_list type_ptr ')' array_dimension
     3613        | '(' attribute_list variable_type_ptr ')' array_dimension
    34763614                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3477         | '(' type_array ')' multi_array_dimension                      // redundant parenthesis
     3615        | '(' variable_type_array ')' multi_array_dimension     // redundant parenthesis
    34783616                { $$ = $2->addArray( $4 ); }
    3479         | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis
     3617        | '(' attribute_list variable_type_array ')' multi_array_dimension // redundant parenthesis
    34803618                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    3481         | '(' type_array ')'                                                            // redundant parenthesis
     3619        | '(' variable_type_array ')'                                           // redundant parenthesis
    34823620                { $$ = $2; }
    3483         | '(' attribute_list type_array ')'                                     // redundant parenthesis
     3621        | '(' attribute_list variable_type_array ')'            // redundant parenthesis
    34843622                { $$ = $3->addQualifiers( $2 ); }
    34853623        ;
    34863624
    3487 type_function:
     3625variable_type_function:
     3626        '(' variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3627                { $$ = $2->addParamList( $6 ); }
     3628        | '(' attribute_list variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3629                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
     3630        | '(' variable_type_function ')'                                        // redundant parenthesis
     3631                { $$ = $2; }
     3632        | '(' attribute_list variable_type_function ')'         // redundant parenthesis
     3633                { $$ = $3->addQualifiers( $2 ); }
     3634        ;
     3635
     3636// This pattern parses a declaration for a function prototype that redefines a type name.  It precludes declaring an
     3637// array of functions versus a pointer to an array of functions, and returning arrays and functions versus pointers to
     3638// arrays and functions.
     3639
     3640function_type_redeclarator:
     3641        function_type_no_ptr attribute_list_opt
     3642                { $$ = $1->addQualifiers( $2 ); }
     3643        | function_type_ptr
     3644        | function_type_array attribute_list_opt
     3645                { $$ = $1->addQualifiers( $2 ); }
     3646        ;
     3647
     3648function_type_no_ptr:
    34883649        paren_type '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    34893650                { $$ = $1->addParamList( $4 ); }
    3490         | '(' type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3651        | '(' function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
    34913652                { $$ = $2->addParamList( $6 ); }
    3492         | '(' attribute_list type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3653        | '(' attribute_list function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
    34933654                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    3494         | '(' type_function ')'                                                         // redundant parenthesis
     3655        | '(' function_type_no_ptr ')'                                          // redundant parenthesis
    34953656                { $$ = $2; }
    3496         | '(' attribute_list type_function ')'                          // redundant parenthesis
     3657        | '(' attribute_list function_type_no_ptr ')'           // redundant parenthesis
     3658                { $$ = $3->addQualifiers( $2 ); }
     3659        ;
     3660
     3661function_type_ptr:
     3662        ptrref_operator function_type_redeclarator
     3663                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
     3664        | ptrref_operator type_qualifier_list function_type_redeclarator
     3665                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     3666        | '(' function_type_ptr ')' attribute_list_opt
     3667                { $$ = $2->addQualifiers( $4 ); }
     3668        | '(' attribute_list function_type_ptr ')' attribute_list_opt
     3669                { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
     3670        ;
     3671
     3672function_type_array:
     3673        '(' function_type_ptr ')' array_dimension
     3674                { $$ = $2->addArray( $4 ); }
     3675        | '(' attribute_list function_type_ptr ')' array_dimension
     3676                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
     3677        | '(' function_type_array ')' multi_array_dimension     // redundant parenthesis
     3678                { $$ = $2->addArray( $4 ); }
     3679        | '(' attribute_list function_type_array ')' multi_array_dimension // redundant parenthesis
     3680                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
     3681        | '(' function_type_array ')'                                           // redundant parenthesis
     3682                { $$ = $2; }
     3683        | '(' attribute_list function_type_array ')'            // redundant parenthesis
    34973684                { $$ = $3->addQualifiers( $2 ); }
    34983685        ;
     
    35173704identifier_parameter_ptr:
    35183705        ptrref_operator identifier_parameter_declarator
    3519                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     3706                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    35203707        | ptrref_operator type_qualifier_list identifier_parameter_declarator
    35213708                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     
    35743761type_parameter_ptr:
    35753762        ptrref_operator type_parameter_redeclarator
    3576                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     3763                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    35773764        | ptrref_operator type_qualifier_list type_parameter_redeclarator
    35783765                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     
    36173804abstract_ptr:
    36183805        ptrref_operator
    3619                 { $$ = DeclarationNode::newPointer( 0, $1 ); }
     3806                { $$ = DeclarationNode::newPointer( nullptr, $1 ); }
    36203807        | ptrref_operator type_qualifier_list
    36213808                { $$ = DeclarationNode::newPointer( $2, $1 ); }
    36223809        | ptrref_operator abstract_declarator
    3623                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     3810                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    36243811        | ptrref_operator type_qualifier_list abstract_declarator
    36253812                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     
    36503837                // Only the first dimension can be empty.
    36513838        '[' ']'
    3652                 { $$ = DeclarationNode::newArray( 0, 0, false ); }
     3839                { $$ = DeclarationNode::newArray( nullptr, nullptr, false ); }
    36533840        | '[' ']' multi_array_dimension
    3654                 { $$ = DeclarationNode::newArray( 0, 0, false )->addArray( $3 ); }
     3841                { $$ = DeclarationNode::newArray( nullptr, nullptr, false )->addArray( $3 ); }
    36553842                // Cannot use constant_expression because of tuples => semantic check
    36563843        | '[' push assignment_expression pop ',' comma_expression ']' // CFA
    3657                 { $$ = DeclarationNode::newArray( $3, 0, false )->addArray( DeclarationNode::newArray( $6, 0, false ) ); }
     3844                { $$ = DeclarationNode::newArray( $3, nullptr, false )->addArray( DeclarationNode::newArray( $6, nullptr, false ) ); }
    36583845                // { SemanticError( yylloc, "New array dimension is currently unimplemented." ); $$ = nullptr; }
    36593846        | '[' push array_type_list pop ']'                                      // CFA
     
    36643851array_type_list:
    36653852        basic_type_name
    3666                 { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
     3853                { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
    36673854        | type_name
    3668                 { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
     3855                { $$ = new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $1 ) ) ); }
    36693856        | assignment_expression upupeq assignment_expression
    36703857        | array_type_list ',' basic_type_name
    3671                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
    3672         | array_type_list ',' type_name 
    3673                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
     3858                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
     3859        | array_type_list ',' type_name
     3860                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
    36743861        | array_type_list ',' assignment_expression upupeq assignment_expression
    36753862        ;
     
    36803867        | ErangeUpEq
    36813868                { $$ = OperKinds::LEThan; }
    3682         ;
     3869        ;
    36833870
    36843871multi_array_dimension:
    36853872        '[' push assignment_expression pop ']'
    3686                 { $$ = DeclarationNode::newArray( $3, 0, false ); }
     3873                { $$ = DeclarationNode::newArray( $3, nullptr, false ); }
    36873874        | '[' push '*' pop ']'                                                          // C99
    36883875                { $$ = DeclarationNode::newVarArray( 0 ); }
    36893876        | multi_array_dimension '[' push assignment_expression pop ']'
    3690                 { $$ = $1->addArray( DeclarationNode::newArray( $4, 0, false ) ); }
     3877                { $$ = $1->addArray( DeclarationNode::newArray( $4, nullptr, false ) ); }
    36913878        | multi_array_dimension '[' push '*' pop ']'            // C99
    36923879                { $$ = $1->addArray( DeclarationNode::newVarArray( 0 ) ); }
     
    37853972array_parameter_1st_dimension:
    37863973        '[' ']'
    3787                 { $$ = DeclarationNode::newArray( 0, 0, false ); }
     3974                { $$ = DeclarationNode::newArray( nullptr, nullptr, false ); }
    37883975                // multi_array_dimension handles the '[' '*' ']' case
    37893976        | '[' push type_qualifier_list '*' pop ']'                      // remaining C99
    37903977                { $$ = DeclarationNode::newVarArray( $3 ); }
    37913978        | '[' push type_qualifier_list pop ']'
    3792                 { $$ = DeclarationNode::newArray( 0, $3, false ); }
     3979                { $$ = DeclarationNode::newArray( nullptr, $3, false ); }
    37933980                // multi_array_dimension handles the '[' assignment_expression ']' case
    37943981        | '[' push type_qualifier_list assignment_expression pop ']'
     
    38194006variable_abstract_ptr:
    38204007        ptrref_operator
    3821                 { $$ = DeclarationNode::newPointer( 0, $1 ); }
     4008                { $$ = DeclarationNode::newPointer( nullptr, $1 ); }
    38224009        | ptrref_operator type_qualifier_list
    38234010                { $$ = DeclarationNode::newPointer( $2, $1 ); }
    38244011        | ptrref_operator variable_abstract_declarator
    3825                 { $$ = $2->addPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     4012                { $$ = $2->addPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    38264013        | ptrref_operator type_qualifier_list variable_abstract_declarator
    38274014                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
     
    38654052                // No SUE declaration in parameter list.
    38664053        ptrref_operator type_specifier_nobody
    3867                 { $$ = $2->addNewPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     4054                { $$ = $2->addNewPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    38684055        | type_qualifier_list ptrref_operator type_specifier_nobody
    38694056                { $$ = $3->addNewPointer( DeclarationNode::newPointer( $1, $2 ) ); }
    38704057        | ptrref_operator cfa_abstract_function
    3871                 { $$ = $2->addNewPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     4058                { $$ = $2->addNewPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    38724059        | type_qualifier_list ptrref_operator cfa_abstract_function
    38734060                { $$ = $3->addNewPointer( DeclarationNode::newPointer( $1, $2 ) ); }
    38744061        | ptrref_operator cfa_identifier_parameter_declarator_tuple
    3875                 { $$ = $2->addNewPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     4062                { $$ = $2->addNewPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    38764063        | type_qualifier_list ptrref_operator cfa_identifier_parameter_declarator_tuple
    38774064                { $$ = $3->addNewPointer( DeclarationNode::newPointer( $1, $2 ) ); }
     
    38824069                // shift/reduce conflict with new-style empty (void) function return type.
    38834070        '[' ']' type_specifier_nobody
    3884                 { $$ = $3->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
     4071                { $$ = $3->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
    38854072        | cfa_array_parameter_1st_dimension type_specifier_nobody
    38864073                { $$ = $2->addNewArray( $1 ); }
    38874074        | '[' ']' multi_array_dimension type_specifier_nobody
    3888                 { $$ = $4->addNewArray( $3 )->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
     4075                { $$ = $4->addNewArray( $3 )->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
    38894076        | cfa_array_parameter_1st_dimension multi_array_dimension type_specifier_nobody
    38904077                { $$ = $3->addNewArray( $2 )->addNewArray( $1 ); }
     
    38934080
    38944081        | '[' ']' cfa_identifier_parameter_ptr
    3895                 { $$ = $3->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
     4082                { $$ = $3->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
    38964083        | cfa_array_parameter_1st_dimension cfa_identifier_parameter_ptr
    38974084                { $$ = $2->addNewArray( $1 ); }
    38984085        | '[' ']' multi_array_dimension cfa_identifier_parameter_ptr
    3899                 { $$ = $4->addNewArray( $3 )->addNewArray( DeclarationNode::newArray( 0, 0, false ) ); }
     4086                { $$ = $4->addNewArray( $3 )->addNewArray( DeclarationNode::newArray( nullptr, nullptr, false ) ); }
    39004087        | cfa_array_parameter_1st_dimension multi_array_dimension cfa_identifier_parameter_ptr
    39014088                { $$ = $3->addNewArray( $2 )->addNewArray( $1 ); }
     
    39534140cfa_abstract_ptr:                                                                               // CFA
    39544141        ptrref_operator type_specifier
    3955                 { $$ = $2->addNewPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     4142                { $$ = $2->addNewPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    39564143        | type_qualifier_list ptrref_operator type_specifier
    39574144                { $$ = $3->addNewPointer( DeclarationNode::newPointer( $1, $2 ) ); }
    39584145        | ptrref_operator cfa_abstract_function
    3959                 { $$ = $2->addNewPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     4146                { $$ = $2->addNewPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    39604147        | type_qualifier_list ptrref_operator cfa_abstract_function
    39614148                { $$ = $3->addNewPointer( DeclarationNode::newPointer( $1, $2 ) ); }
    39624149        | ptrref_operator cfa_abstract_declarator_tuple
    3963                 { $$ = $2->addNewPointer( DeclarationNode::newPointer( 0, $1 ) ); }
     4150                { $$ = $2->addNewPointer( DeclarationNode::newPointer( nullptr, $1 ) ); }
    39644151        | type_qualifier_list ptrref_operator cfa_abstract_declarator_tuple
    39654152                { $$ = $3->addNewPointer( DeclarationNode::newPointer( $1, $2 ) ); }
  • src/Parser/parserutility.cc

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

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

    r34b4268 r24d6572  
    1414//
    1515
     16#include "AlternativeFinder.h"
     17
    1618#include <algorithm>               // for copy
    1719#include <cassert>                 // for strict_dynamic_cast, assert, assertf
     
    2628
    2729#include "CompilationState.h"      // for resolvep
     30#include "AdjustExprType.hpp"      // for adjustExprType
    2831#include "Alternative.h"           // for AltList, Alternative
    29 #include "AlternativeFinder.h"
    3032#include "AST/Expr.hpp"
    3133#include "AST/SymbolTable.hpp"
    3234#include "AST/Type.hpp"
     35#include "CastCost.hpp"            // for castCost
    3336#include "Common/SemanticError.h"  // for SemanticError
    3437#include "Common/utility.h"        // for deleteAll, printAll, CodeLocation
     38#include "ConversionCost.h"        // for conversionCost
    3539#include "Cost.h"                  // for Cost, Cost::zero, operator<<, Cost...
    3640#include "ExplodedActual.h"        // for ExplodedActual
    3741#include "InitTweak/InitTweak.h"   // for getFunctionName
     42#include "PolyCost.hpp"            // for polyCost
    3843#include "RenameVars.h"            // for RenameVars, global_renamer
    3944#include "ResolveAssertions.h"     // for resolveAssertions
    4045#include "ResolveTypeof.h"         // for resolveTypeof
    4146#include "Resolver.h"              // for resolveStmtExpr
     47#include "SpecCost.hpp"            // for specCost
    4248#include "SymTab/Indexer.h"        // for Indexer
    4349#include "SymTab/Mangler.h"        // for Mangler
     
    5157#include "Tuples/Explode.h"        // for explode
    5258#include "Tuples/Tuples.h"         // for isTtype, handleTupleAssignment
     59#include "typeops.h"               // for combos
    5360#include "Unify.h"                 // for unify
    54 #include "typeops.h"               // for adjustExprType, polyCost, castCost
    5561
    5662#define PRINT( text ) if ( resolvep ) { text }
  • src/ResolvExpr/AlternativeFinder.h

    r34b4268 r24d6572  
    3434namespace ResolvExpr {
    3535        struct ArgPack;
     36
     37        Cost computeConversionCost( Type * actualType, Type * formalType, bool actualIsLvalue,
     38                const SymTab::Indexer & indexer, const TypeEnvironment & env );
     39
     40        void referenceToRvalueConversion( Expression *& expr, Cost & cost );
    3641
    3742        /// First index is which argument, second index is which alternative for that argument,
  • src/ResolvExpr/Candidate.cpp

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

    r34b4268 r24d6572  
    2323#include <vector>
    2424
     25#include "AdjustExprType.hpp"
    2526#include "Candidate.hpp"
    2627#include "CompilationState.h"
    2728#include "Cost.h"
     29#include "CastCost.hpp"
     30#include "PolyCost.hpp"
     31#include "SpecCost.hpp"
     32#include "ConversionCost.h"
    2833#include "ExplodedArg.hpp"
    2934#include "RenameVars.h"           // for renameTyVars
     
    403408                                                        unify(
    404409                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
    405                                                                 newResult.open, symtab )
     410                                                                newResult.open )
    406411                                                ) {
    407412                                                        finalResults.emplace_back( std::move( newResult ) );
     
    474479                                )
    475480
    476                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     481                                if ( unify( paramType, argType, env, need, have, open ) ) {
    477482                                        unsigned nextExpl = results[i].nextExpl + 1;
    478483                                        if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     
    493498                                        ast::OpenVarSet open = results[i].open;
    494499
    495                                         if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
     500                                        if ( unify( paramType, cnst->result, env, need, have, open ) ) {
    496501                                                results.emplace_back(
    497502                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
     
    536541
    537542                                // attempt to unify types
    538                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     543                                if ( unify( paramType, argType, env, need, have, open ) ) {
    539544                                        // add new result
    540545                                        results.emplace_back(
     
    703708                                if ( selfFinder.strictMode ) {
    704709                                        if ( ! unifyExact(
    705                                                 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden(), symtab ) // xxx - is no widening correct?
     710                                                returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct?
    706711                                        ) {
    707712                                                // unification failed, do not pursue this candidate
     
    711716                                else {
    712717                                        if ( ! unify(
    713                                                 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     718                                                returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen )
    714719                                        ) {
    715720                                                // unification failed, do not pursue this candidate
     
    11561161
    11571162                                // unification run for side-effects
    1158                                 unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
     1163                                unify( toType, cand->expr->result, cand->env, need, have, open );
    11591164                                Cost thisCost =
    11601165                                        (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
     
    14971502                                                if (
    14981503                                                        unify(
    1499                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     1504                                                                r2->expr->result, r3->expr->result, env, need, have, open,
    15001505                                                                common )
    15011506                                                ) {
     
    15711576                                        if (
    15721577                                                unify(
    1573                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     1578                                                        r1->expr->result, r2->expr->result, env, need, have, open,
    15741579                                                        common )
    15751580                                        ) {
     
    16771682
    16781683                                        // unification run for side-effects
    1679                                         bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
     1684                                        bool canUnify = unify( toType, cand->expr->result, env, need, have, open );
    16801685                                        (void) canUnify;
    16811686                                        Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
  • src/ResolvExpr/CandidateFinder.hpp

    r34b4268 r24d6572  
    6565        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    6666
     67/// Create an expression that preforms reference to rvalue conversion on
     68/// the given expression and update the cost of the expression.
     69const ast::Expr * referenceToRvalueConversion(
     70        const ast::Expr * expr, Cost & cost );
     71
    6772} // namespace ResolvExpr
    6873
  • src/ResolvExpr/CastCost.cc

    r34b4268 r24d6572  
    1313// Update Count     : 9
    1414//
     15
     16#include "CastCost.hpp"
    1517
    1618#include <cassert>                       // for assert
     
    2224#include "ConversionCost.h"              // for ConversionCost
    2325#include "Cost.h"                        // for Cost, Cost::infinity
     26#include "ResolvExpr/ConversionCost.h"   // for conversionCost
     27#include "ResolvExpr/PtrsCastable.hpp"   // for ptrsCastable
    2428#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment, EqvClass
     29#include "ResolvExpr/typeops.h"          // for ptrsCastable
     30#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    2531#include "SymTab/Indexer.h"              // for Indexer
    2632#include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    2733#include "SynTree/Type.h"                // for PointerType, Type, TypeInstType
    28 #include "typeops.h"                     // for typesCompatibleIgnoreQualifiers
    2934
    3035#if 0
     
    160165                                if (
    161166                                        pointerType->qualifiers <= ptr->qualifiers
    162                                         && typesCompatibleIgnoreQualifiers( pointerType->base, ptr->base, symtab, env )
     167                                        && typesCompatibleIgnoreQualifiers( pointerType->base, ptr->base, env )
    163168                                ) {
    164169                                        cost = Cost::safe;
     
    227232        )
    228233
    229         if ( typesCompatibleIgnoreQualifiers( src, dst, symtab, env ) ) {
     234        if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
    230235                PRINT( std::cerr << "compatible!" << std::endl; )
    231236                if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) {
  • src/ResolvExpr/CommonType.cc

    r34b4268 r24d6572  
    1414//
    1515
     16#include "CommonType.hpp"
     17
    1618#include <cassert>                       // for strict_dynamic_cast
    1719#include <map>                           // for _Rb_tree_const_iterator
     
    1921
    2022#include "AST/Decl.hpp"
     23#include "AST/Pass.hpp"
    2124#include "AST/Type.hpp"
    2225#include "Common/PassVisitor.h"
     
    673676                const ast::Type * type2;
    674677                WidenMode widen;
    675                 const ast::SymbolTable & symtab;
    676678                ast::TypeEnvironment & tenv;
    677679                const ast::OpenVarSet & open;
     
    683685
    684686                CommonType_new(
    685                         const ast::Type * t2, WidenMode w, const ast::SymbolTable & st,
     687                        const ast::Type * t2, WidenMode w,
    686688                        ast::TypeEnvironment & env, const ast::OpenVarSet & o,
    687689                        ast::AssertionSet & need, ast::AssertionSet & have )
    688                 : type2( t2 ), widen( w ), symtab( st ), tenv( env ), open( o ), need (need), have (have) ,result() {}
     690                : type2( t2 ), widen( w ), tenv( env ), open( o ), need (need), have (have) ,result() {}
    689691
    690692                void previsit( const ast::Node * ) { visit_children = false; }
     
    764766                                        ast::AssertionSet need, have;
    765767                                        if ( ! tenv.bindVar(
    766                                                 var, voidPtr->base, entry->second, need, have, open, widen, symtab )
     768                                                var, voidPtr->base, entry->second, need, have, open, widen )
    767769                                        ) return;
    768770                                }
     
    777779                                ast::OpenVarSet newOpen{ open };
    778780                                if (enumInst->base->base
    779                                 && unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen, symtab)) {
     781                                && unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) {
    780782                                        result = type1;
    781783                                        return true;
     
    814816
    815817                                        ast::OpenVarSet newOpen{ open };
    816                                         if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     818                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) {
    817819                                                result = pointer;
    818820                                                if ( q1.val != q2.val ) {
     
    857859                                                                if (unifyExact(
    858860                                                                        arg1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
    859                                                                         noWiden(), symtab )) {
     861                                                                        noWiden() )) {
    860862                                                                                break;
    861863
     
    866868                                                                if (unifyExact(
    867869                                                                        tupleFromTypes( crnt1, end1 ), arg2, tenv, need, have, open,
    868                                                                         noWiden(), symtab )) {
     870                                                                        noWiden() )) {
    869871                                                                                break;
    870872
     
    890892
    891893                                                                                if ( ! unifyExact(
    892                                                                                         base1, base2, tenv, need, have, open, noWiden(), symtab )
     894                                                                                        base1, base2, tenv, need, have, open, noWiden() )
    893895                                                                                ) return;
    894896                                                                        }       
     
    910912
    911913                                                                                if ( ! unifyExact(
    912                                                                                         base1, base2, tenv, need, have, open, noWiden(), symtab )
     914                                                                                        base1, base2, tenv, need, have, open, noWiden() )
    913915                                                                                ) return;
    914916                                                                        }       
     
    918920                                                        }
    919921                                                        else if (! unifyExact(
    920                                                                 arg1, arg2, tenv, need, have, open, noWiden(), symtab )) return;
     922                                                                arg1, arg2, tenv, need, have, open, noWiden() )) return;
    921923
    922924                                                        ++crnt1; ++crnt2;
     
    928930                                                        if (! unifyExact(
    929931                                                                t1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
    930                                                                 noWiden(), symtab )) return;
     932                                                                noWiden() )) return;
    931933                                                } else if ( crnt2 != end2 ) {
    932934                                                        // try unifying empty tuple with ttype
     
    935937                                                        if (! unifyExact(
    936938                                                                tupleFromTypes( crnt1, end1 ), t2, tenv, need, have, open,
    937                                                                 noWiden(), symtab )) return;
     939                                                                noWiden() )) return;
    938940                                                }
    939941                                                if ((f1->returns.size() == 0 && f2->returns.size() == 0)
    940                                                   || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden(), symtab))) {
     942                                                  || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden()))) {
    941943                                                        result = pointer;
    942944
     
    995997
    996998                                        ast::OpenVarSet newOpen{ open };
    997                                         if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     999                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) {
    9981000                                                result = ref;
    9991001                                                if ( q1.val != q2.val ) {
     
    10101012                        } else {
    10111013                                if (!dynamic_cast<const ast::EnumInstType *>(type2))
    1012                                         result = commonType( type2, ref, tenv, need, have, open, widen, symtab );
     1014                                        result = commonType( type2, ref, tenv, need, have, open, widen );
    10131015                        }
    10141016                }
     
    10281030                void postvisit( const ast::EnumInstType * enumInst ) {
    10291031                        if (!dynamic_cast<const ast::EnumInstType *>(type2))
    1030                                 result = commonType( type2, enumInst, tenv, need, have, open, widen, symtab);
     1032                                result = commonType( type2, enumInst, tenv, need, have, open, widen);
    10311033                }
    10321034
    10331035                void postvisit( const ast::TraitInstType * ) {}
    10341036
    1035                 void postvisit( const ast::TypeInstType * inst ) {
    1036                         if ( ! widen.first ) return;
    1037                         if ( const ast::NamedTypeDecl * nt = symtab.lookupType( inst->name ) ) {
    1038                                 if ( const ast::Type * base =
    1039                                                 strict_dynamic_cast< const ast::TypeDecl * >( nt )->base
    1040                                 ) {
    1041                                         ast::CV::Qualifiers q1 = inst->qualifiers, q2 = type2->qualifiers;
    1042 
    1043                                         // force t{1,2} to be cloned if their qualifiers must be mutated
    1044                                         ast::ptr< ast::Type > t1{ base }, t2{ type2 };
    1045                                         reset_qualifiers( t1, q1 );
    1046                                         reset_qualifiers( t2 );
    1047 
    1048                                         ast::OpenVarSet newOpen{ open };
    1049                                         if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
    1050                                                 result = type2;
    1051                                                 reset_qualifiers( result, q1 | q2 );
    1052                                         } else {
    1053                                                 tryResolveWithTypedEnum( t1 );
    1054                                         }
    1055                                 }
    1056                         }
    1057                 }
     1037                void postvisit( const ast::TypeInstType * inst ) {}
    10581038
    10591039                void postvisit( const ast::TupleType * tuple) {
     
    11181098                ast::ptr< ast::Type > handleReference(
    11191099                        const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
    1120                         const ast::SymbolTable & symtab, ast::TypeEnvironment & env,
     1100                        ast::TypeEnvironment & env,
    11211101                        const ast::OpenVarSet & open
    11221102                ) {
     
    11261106
    11271107                        // need unify to bind type variables
    1128                         if ( unify( t1, t2, env, have, need, newOpen, symtab, common ) ) {
     1108                        if ( unify( t1, t2, env, have, need, newOpen, common ) ) {
    11291109                                ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
    11301110                                PRINT(
     
    11501130                        const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
    11511131                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    1152                         const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab
     1132                        const ast::OpenVarSet & open, WidenMode widen
    11531133        ) {
    11541134                unsigned depth1 = type1->referenceDepth();
     
    11651145                        if ( depth1 > depth2 ) {
    11661146                                assert( ref1 );
    1167                                 result = handleReference( ref1->base, type2, widen, symtab, env, open );
     1147                                result = handleReference( ref1->base, type2, widen, env, open );
    11681148                        } else {  // implies depth1 < depth2
    11691149                                assert( ref2 );
    1170                                 result = handleReference( type1, ref2->base, widen, symtab, env, open );
     1150                                result = handleReference( type1, ref2->base, widen, env, open );
    11711151                        }
    11721152
     
    11861166                }
    11871167                // otherwise both are reference types of the same depth and this is handled by the visitor
    1188                 ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open, need, have };
     1168                ast::Pass<CommonType_new> visitor{ type2, widen, env, open, need, have };
    11891169                type1->accept( visitor );
    1190                 ast::ptr< ast::Type > result = visitor.core.result;
    1191 
    1192                 // handling for opaque type declarations (?)
    1193                 if ( ! result && widen.second ) {
    1194                         if ( const ast::TypeInstType * inst = type2.as< ast::TypeInstType >() ) {
    1195                                 if ( const ast::NamedTypeDecl * nt = symtab.lookupType( inst->name ) ) {
    1196                                         auto type = strict_dynamic_cast< const ast::TypeDecl * >( nt );
    1197                                         if ( type->base ) {
    1198                                                 ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
    1199                                                 ast::OpenVarSet newOpen{ open };
    1200 
    1201                                                 // force t{1,2} to be cloned if its qualifiers must be stripped, so that
    1202                                                 // type1 and type->base are left unchanged; calling convention forces
    1203                                                 // {type1,type->base}->strong_ref >= 1
    1204                                                 ast::ptr<ast::Type> t1{ type1 }, t2{ type->base };
    1205                                                 reset_qualifiers( t1 );
    1206                                                 reset_qualifiers( t2, q1 );
    1207 
    1208                                                 if ( unifyExact( t1, t2, env, have, need, newOpen, noWiden(), symtab ) ) {
    1209                                                         result = t1;
    1210                                                         reset_qualifiers( result, q1 | q2 );
    1211                                                 }
    1212                                         }
    1213                                 }
    1214                         }
    1215                 }
    1216 
    1217                 return result;
     1170                // ast::ptr< ast::Type > result = visitor.core.result;
     1171
     1172                return visitor.core.result;
    12181173        }
    12191174
  • src/ResolvExpr/ConversionCost.cc

    r34b4268 r24d6572  
    2222#include "ResolvExpr/Cost.h"             // for Cost
    2323#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    24 #include "ResolvExpr/Unify.h"
     24#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
     25#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    2526#include "SymTab/Indexer.h"              // for Indexer
    2627#include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    2728#include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
    28 #include "typeops.h"                     // for typesCompatibleIgnoreQualifiers
    2929
    3030
     
    532532                }
    533533        }
    534         if ( typesCompatibleIgnoreQualifiers( src, dst, symtab, env ) ) {
     534        if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
    535535                return Cost::zero;
    536536        } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
     
    566566                        ast::CV::Qualifiers tq2 = dstAsRef->base->qualifiers;
    567567                        if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
    568                                         srcAsRef->base, dstAsRef->base, symtab, env ) ) {
     568                                        srcAsRef->base, dstAsRef->base, env ) ) {
    569569                                if ( tq1 == tq2 ) {
    570570                                        return Cost::zero;
     
    587587                const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
    588588                assert( dstAsRef );
    589                 if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
     589                if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, env ) ) {
    590590                        if ( srcIsLvalue ) {
    591591                                if ( src->qualifiers == dstAsRef->base->qualifiers ) {
     
    653653                ast::CV::Qualifiers tq2 = dstAsPtr->base->qualifiers;
    654654                if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
    655                                 pointerType->base, dstAsPtr->base, symtab, env ) ) {
     655                                pointerType->base, dstAsPtr->base, env ) ) {
    656656                        if ( tq1 == tq2 ) {
    657657                                cost = Cost::zero;
  • src/ResolvExpr/ConversionCost.h

    r34b4268 r24d6572  
    3232namespace ResolvExpr {
    3333        class TypeEnvironment;
     34
     35        Cost conversionCost(
     36                const Type * src, const Type * dest, bool srcIsLvalue,
     37                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    3438
    3539        typedef std::function<Cost(const Type *, const Type *, bool,
     
    8084        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    8185
     86Cost conversionCost(
     87        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     88        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     89
     90Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
     91        bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
     92        PtrsCalculation func );
     93
    8294#warning when the old ConversionCost is removed, get ride of the _new suffix.
    8395class ConversionCost_new : public ast::WithShortCircuiting {
     
    119131};
    120132
    121 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
    122         bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
    123         PtrsCalculation func );
    124 
    125133} // namespace ResolvExpr
    126134
  • src/ResolvExpr/CurrentObject.cc

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

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

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

    r34b4268 r24d6572  
    1515
    1616#include "AST/SymbolTable.hpp"
     17#include "AST/Pass.hpp"
    1718#include "AST/Type.hpp"
    1819#include "AST/TypeEnvironment.hpp"
  • src/ResolvExpr/PtrsAssignable.cc

    r34b4268 r24d6572  
    1414//
    1515
    16 #include "typeops.h"
     16#include "PtrsAssignable.hpp"
    1717
    1818#include "AST/Pass.hpp"
  • src/ResolvExpr/PtrsCastable.cc

    r34b4268 r24d6572  
    1414//
    1515
     16#include "PtrsCastable.hpp"
     17
    1618#include "AST/Decl.hpp"
    1719#include "AST/Pass.hpp"
     
    1921#include "AST/TypeEnvironment.hpp"
    2022#include "Common/PassVisitor.h"
     23#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    2124#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2225#include "SymTab/Indexer.h"              // for Indexer
     
    2427#include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    2528#include "SynTree/Visitor.h"             // for Visitor
    26 #include "typeops.h"                     // for ptrsAssignable
    2729
    2830namespace ResolvExpr {
     
    291293                return objectCast( src, env, symtab );
    292294        } else {
    293                 ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab };
    294                 src->accept( ptrs );
    295                 return ptrs.core.result;
     295                return ast::Pass<PtrsCastable_new>::read( src, dst, env, symtab );
    296296        }
    297297}
  • src/ResolvExpr/RenameVars.cc

    r34b4268 r24d6572  
    8383
    8484                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    85                         // rename
    8685                        auto it = idMap.find( type->name );
    87                         if ( it != idMap.end() ) {
    88                                 // unconditionally mutate because map will *always* have different name
    89                                 ast::TypeInstType * mut = ast::shallowCopy( type );
    90                                 // reconcile base node since some copies might have been made
    91                                 mut->base = it->second.base;
    92                                 mut->formal_usage = it->second.formal_usage;
    93                                 mut->expr_id = it->second.expr_id;
    94                     type = mut;
    95                         }
    96 
    97                         return type;
     86                        if ( it == idMap.end() ) return type;
     87
     88                        // Unconditionally mutate because map will *always* have different name.
     89                        ast::TypeInstType * mut = ast::shallowCopy( type );
     90                        // Reconcile base node since some copies might have been made.
     91                        mut->base = it->second.base;
     92                        mut->formal_usage = it->second.formal_usage;
     93                        mut->expr_id = it->second.expr_id;
     94                        return mut;
    9895                }
    9996
     
    187184
    188185const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
    189         // ast::Type *tc = ast::deepCopy(t);
    190186        ast::Pass<RenameVars_new> renamer;
    191187        renamer.core.mode = mode;
  • src/ResolvExpr/ResolveAssertions.cc

    r34b4268 r24d6572  
    2626#include <vector>                   // for vector
    2727
     28#include "AdjustExprType.hpp"       // for adjustExprType
    2829#include "Alternative.h"            // for Alternative, AssertionItem, AssertionList
    2930#include "Common/FilterCombos.h"    // for filterCombos
    3031#include "Common/Indenter.h"        // for Indenter
    31 #include "Common/utility.h"         // for sort_mins
    3232#include "GenPoly/GenPoly.h"        // for getFunctionType
     33#include "ResolvExpr/AlternativeFinder.h"  // for computeConversionCost
    3334#include "ResolvExpr/RenameVars.h"  // for renameTyVars
     35#include "SpecCost.hpp"             // for specCost
    3436#include "SymTab/Indexer.h"         // for Indexer
    3537#include "SymTab/Mangler.h"         // for Mangler
    3638#include "SynTree/Expression.h"     // for InferredParams
    3739#include "TypeEnvironment.h"        // for TypeEnvironment, etc.
    38 #include "typeops.h"                // for adjustExprType, specCost
    3940#include "Unify.h"                  // for unify
    4041
  • src/ResolvExpr/Resolver.cc

    r34b4268 r24d6572  
    3838#include "AST/SymbolTable.hpp"
    3939#include "AST/Type.hpp"
     40#include "Common/Eval.h"                 // for eval
     41#include "Common/Iterate.hpp"            // for group_iterate
    4042#include "Common/PassVisitor.h"          // for PassVisitor
    4143#include "Common/SemanticError.h"        // for SemanticError
    4244#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    43 #include "Common/utility.h"              // for ValueGuard, group_iterate
     45#include "Common/ToString.hpp"           // for toCString
    4446#include "InitTweak/GenInit.h"
    4547#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
     
    11071109                void removeExtraneousCast( ast::ptr<ast::Expr> & expr, const ast::SymbolTable & symtab ) {
    11081110                        if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
    1109                                 if ( typesCompatible( castExpr->arg->result, castExpr->result, symtab ) ) {
     1111                                if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
    11101112                                        // cast is to the same type as its argument, remove it
    11111113                                        swap_and_save_env( expr, castExpr->arg );
     
    17291731
    17301732                        // Find all candidates for a function in canonical form
    1731                         funcFinder.find( clause.target_func, ResolvMode::withAdjustment() );
     1733                        funcFinder.find( clause.target, ResolvMode::withAdjustment() );
    17321734
    17331735                        if ( funcFinder.candidates.empty() ) {
    17341736                                stringstream ss;
    17351737                                ss << "Use of undeclared indentifier '";
    1736                                 ss << clause.target_func.strict_as< ast::NameExpr >()->name;
     1738                                ss << clause.target.strict_as< ast::NameExpr >()->name;
    17371739                                ss << "' in call to waitfor";
    17381740                                SemanticError( stmt->location, ss.str() );
     
    18331835                                                                if (
    18341836                                                                        ! unify(
    1835                                                                                 arg->expr->result, *param, resultEnv, need, have, open,
    1836                                                                                 symtab )
     1837                                                                                arg->expr->result, *param, resultEnv, need, have, open )
    18371838                                                                ) {
    18381839                                                                        // Type doesn't match
     
    19211922                        auto clause2 = new ast::WaitForClause( clause.location );
    19221923
    1923                         clause2->target_func = funcCandidates.front()->expr;
     1924                        clause2->target = funcCandidates.front()->expr;
    19241925
    19251926                        clause2->target_args.reserve( clause.target_args.size() );
     
    19441945
    19451946                        // Resolve the conditions as if it were an IfStmt, statements normally
    1946                         clause2->cond = findSingleExpression( clause.cond, context );
     1947                        clause2->when_cond = findSingleExpression( clause.when_cond, context );
    19471948                        clause2->stmt = clause.stmt->accept( *visitor );
    19481949
  • src/ResolvExpr/Resolver.h

    r34b4268 r24d6572  
    3434        class Decl;
    3535        class DeletedExpr;
     36        class Expr;
    3637        class Init;
    3738        class StmtExpr;
  • src/ResolvExpr/SatisfyAssertions.cpp

    r34b4268 r24d6572  
    2424#include <vector>
    2525
     26#include "AdjustExprType.hpp"
    2627#include "Candidate.hpp"
    2728#include "CandidateFinder.hpp"
     29#include "CommonType.hpp"
    2830#include "Cost.h"
    2931#include "RenameVars.h"
     32#include "SpecCost.hpp"
    3033#include "typeops.h"
    3134#include "Unify.h"
     
    181184                                .strict_as<ast::FunctionType>()->params[0]
    182185                                .strict_as<ast::ReferenceType>()->base;
    183                         sat.cand->env.apply(thisArgType);
     186                        // sat.cand->env.apply(thisArgType);
     187
     188                        if (auto inst = thisArgType.as<ast::TypeInstType>()) {
     189                                auto cls = sat.cand->env.lookup(*inst);
     190                                if (cls && cls->bound) thisArgType = cls->bound;
     191                        }
    184192
    185193                        std::string otypeKey = "";
     
    218226                        ast::TypeEnvironment tempNewEnv {newEnv};
    219227
    220                         if ( unifyExact( toType, adjType, tempNewEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) {
     228                        if ( unifyExact( toType, adjType, tempNewEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) {
    221229                                // set up binding slot for recursive assertions
    222230                                ast::UniqueId crntResnSlot = 0;
     
    234242                                // newEnv = sat.cand->env;
    235243                                // newNeed.clear();
    236                                 if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) {
     244                                if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) {
    237245                                        // set up binding slot for recursive assertions
    238246                                        ast::UniqueId crntResnSlot = 0;
     
    398406                        mergeOpenVars( open, i.match.open );
    399407
    400                         if ( ! env.combine( i.match.env, open, symtab ) ) return false;
     408                        if ( ! env.combine( i.match.env, open ) ) return false;
    401409
    402410                        crnt.emplace_back( i );
  • src/ResolvExpr/Unify.cc

    r34b4268 r24d6572  
    3333#include "AST/TypeEnvironment.hpp"
    3434#include "Common/PassVisitor.h"     // for PassVisitor
     35#include "CommonType.hpp"           // for commonType
    3536#include "FindOpenVars.h"           // for findOpenVars
     37#include "SpecCost.hpp"             // for SpecCost
    3638#include "SynTree/LinkageSpec.h"    // for C
    3739#include "SynTree/Constant.h"       // for Constant
     
    4345#include "Tuples/Tuples.h"          // for isTtype
    4446#include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
    45 #include "typeops.h"                // for flatten, occurs, commonType
     47#include "typeops.h"                // for flatten, occurs
    4648
    4749namespace ast {
     
    5052
    5153namespace SymTab {
    52 class Indexer;
     54        class Indexer;
    5355}  // namespace SymTab
    5456
     
    5658
    5759namespace ResolvExpr {
     60
     61// Template Helpers:
     62template< typename Iterator1, typename Iterator2 >
     63bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {
     64        for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     65                Type *commonType = 0;
     66                if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
     67                        return false;
     68                } // if
     69                commonTypes.push_back( commonType );
     70        } // for
     71        return ( list1Begin == list1End && list2Begin == list2End );
     72}
     73
     74template< typename Iterator1, typename Iterator2 >
     75bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     76        std::list< Type* > commonTypes;
     77        if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions,  openVars, indexer, commonTypes ) ) {
     78                deleteAll( commonTypes );
     79                return true;
     80        } else {
     81                return false;
     82        } // if
     83}
    5884
    5985        struct Unify_old : public WithShortCircuiting {
     
    102128                const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    103129                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    104                 WidenMode widen, const ast::SymbolTable & symtab );
     130                WidenMode widen );
    105131
    106132        bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
     
    124150
    125151        bool typesCompatible(
    126                         const ast::Type * first, const ast::Type * second, const ast::SymbolTable & symtab,
     152                        const ast::Type * first, const ast::Type * second,
    127153                        const ast::TypeEnvironment & env ) {
    128154                ast::TypeEnvironment newEnv;
     
    137163                findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
    138164
    139                 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     165                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
    140166        }
    141167
     
    157183
    158184        bool typesCompatibleIgnoreQualifiers(
    159                         const ast::Type * first, const ast::Type * second, const ast::SymbolTable & symtab,
     185                        const ast::Type * first, const ast::Type * second,
    160186                        const ast::TypeEnvironment & env ) {
    161187                ast::TypeEnvironment newEnv;
     
    190216                        subFirst,
    191217                        subSecond,
    192                         newEnv, need, have, open, noWiden(), symtab );
     218                        newEnv, need, have, open, noWiden() );
    193219        }
    194220
     
    760786                const ast::OpenVarSet & open;
    761787                WidenMode widen;
    762                 const ast::SymbolTable & symtab;
    763788        public:
    764789                static size_t traceId;
     
    767792                Unify_new(
    768793                        const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
    769                         ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen,
    770                         const ast::SymbolTable & symtab )
     794                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
    771795                : type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
    772                   symtab(symtab), result(false) {}
     796                result(false) {}
    773797
    774798                void previsit( const ast::Node * ) { visit_children = false; }
     
    788812                                result = unifyExact(
    789813                                        pointer->base, pointer2->base, tenv, need, have, open,
    790                                         noWiden(), symtab );
     814                                        noWiden());
    791815                        }
    792816                }
     
    811835
    812836                        result = unifyExact(
    813                                 array->base, array2->base, tenv, need, have, open, noWiden(),
    814                                 symtab );
     837                                array->base, array2->base, tenv, need, have, open, noWiden());
    815838                }
    816839
     
    818841                        if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
    819842                                result = unifyExact(
    820                                         ref->base, ref2->base, tenv, need, have, open, noWiden(),
    821                                         symtab );
     843                                        ref->base, ref2->base, tenv, need, have, open, noWiden());
    822844                        }
    823845                }
     
    828850                static bool unifyTypeList(
    829851                        Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
    830                         ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    831                         const ast::SymbolTable & symtab
     852                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
    832853                ) {
    833854                        while ( crnt1 != end1 && crnt2 != end2 ) {
     
    842863                                        return unifyExact(
    843864                                                t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
    844                                                 noWiden(), symtab );
     865                                                noWiden() );
    845866                                } else if ( ! isTuple1 && isTuple2 ) {
    846867                                        // combine remainder of list1, then unify
    847868                                        return unifyExact(
    848869                                                tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
    849                                                 noWiden(), symtab );
     870                                                noWiden() );
    850871                                }
    851872
    852873                                if ( ! unifyExact(
    853                                         t1, t2, env, need, have, open, noWiden(), symtab )
     874                                        t1, t2, env, need, have, open, noWiden() )
    854875                                ) return false;
    855876
     
    865886                                return unifyExact(
    866887                                        t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
    867                                         noWiden(), symtab );
     888                                        noWiden() );
    868889                        } else if ( crnt2 != end2 ) {
    869890                                // try unifying empty tuple with ttype
     
    872893                                return unifyExact(
    873894                                        tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
    874                                         noWiden(), symtab );
     895                                        noWiden() );
    875896                        }
    876897
     
    882903                        const std::vector< ast::ptr< ast::Type > > & list2,
    883904                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    884                         const ast::OpenVarSet & open, const ast::SymbolTable & symtab
     905                        const ast::OpenVarSet & open
    885906                ) {
    886907                        return unifyTypeList(
    887                                 list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open,
    888                                 symtab );
     908                                list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
    889909                }
    890910
     
    927947                        ) return;
    928948
    929                         if ( ! unifyTypeList( params, params2, tenv, need, have, open, symtab ) ) return;
     949                        if ( ! unifyTypeList( params, params2, tenv, need, have, open ) ) return;
    930950                        if ( ! unifyTypeList(
    931                                 func->returns, func2->returns, tenv, need, have, open, symtab ) ) return;
     951                                func->returns, func2->returns, tenv, need, have, open ) ) return;
    932952
    933953                        markAssertions( have, need, func );
     
    944964                        // check that the other type is compatible and named the same
    945965                        auto otherInst = dynamic_cast< const XInstType * >( other );
    946                         if (otherInst && inst->name == otherInst->name) this->result = otherInst;
     966                        if (otherInst && inst->name == otherInst->name)
     967                                this->result = otherInst;
    947968                        return otherInst;
    948969                }
     
    10001021
    10011022                                if ( ! unifyExact(
    1002                                                 pty, pty2, tenv, need, have, open, noWiden(), symtab ) ) {
     1023                                                pty, pty2, tenv, need, have, open, noWiden() ) ) {
    10031024                                        result = false;
    10041025                                        return;
     
    10301051                void postvisit( const ast::TypeInstType * typeInst ) {
    10311052                        // assert( open.find( *typeInst ) == open.end() );
    1032                         handleRefType( typeInst, type2 );
     1053                        auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
     1054                        if (otherInst && typeInst->name == otherInst->name)
     1055                                this->result = otherInst;
     1056                        // return otherInst;
    10331057                }
    10341058
     
    10391063                        const std::vector< ast::ptr< ast::Type > > & list1,
    10401064                        const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
    1041                         ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    1042                         const ast::SymbolTable & symtab
     1065                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
    10431066                ) {
    10441067                        auto crnt1 = list1.begin();
     
    10551078                                        return unifyExact(
    10561079                                                t1, tupleFromTypes( list2 ), env, need, have, open,
    1057                                                 noWiden(), symtab );
     1080                                                noWiden() );
    10581081                                } else if ( ! isTuple1 && isTuple2 ) {
    10591082                                        // combine entirety of list1, then unify
    10601083                                        return unifyExact(
    10611084                                                tupleFromTypes( list1 ), t2, env, need, have, open,
    1062                                                 noWiden(), symtab );
     1085                                                noWiden() );
    10631086                                }
    10641087
    10651088                                if ( ! unifyExact(
    1066                                         t1, t2, env, need, have, open, noWiden(), symtab )
     1089                                        t1, t2, env, need, have, open, noWiden() )
    10671090                                ) return false;
    10681091
     
    10781101                                return unifyExact(
    10791102                                                t1, tupleFromTypes( list2 ), env, need, have, open,
    1080                                                 noWiden(), symtab );
     1103                                                noWiden() );
    10811104                        } else if ( crnt2 != list2.end() ) {
    10821105                                // try unifying empty tuple with ttype
     
    10871110                                return unifyExact(
    10881111                                                tupleFromTypes( list1 ), t2, env, need, have, open,
    1089                                                 noWiden(), symtab );
     1112                                                noWiden() );
    10901113                        }
    10911114
     
    11061129                        auto types2 = flatten( flat2 );
    11071130
    1108                         result = unifyList( types, types2, tenv, need, have, open, symtab );
     1131                        result = unifyList( types, types2, tenv, need, have, open );
    11091132                }
    11101133
     
    11301153                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    11311154                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    1132                         ast::OpenVarSet & open, const ast::SymbolTable & symtab
     1155                        ast::OpenVarSet & open
    11331156        ) {
    11341157                ast::ptr<ast::Type> common;
    1135                 return unify( type1, type2, env, need, have, open, symtab, common );
     1158                return unify( type1, type2, env, need, have, open, common );
    11361159        }
    11371160
     
    11391162                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    11401163                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    1141                         ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common
     1164                        ast::OpenVarSet & open, ast::ptr<ast::Type> & common
    11421165        ) {
    11431166                ast::OpenVarSet closed;
     
    11451168                findOpenVars( type2, open, closed, need, have, env, FirstOpen );
    11461169                return unifyInexact(
    1147                         type1, type2, env, need, have, open, WidenMode{ true, true }, symtab, common );
     1170                        type1, type2, env, need, have, open, WidenMode{ true, true }, common );
    11481171        }
    11491172
     
    11511174                        const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    11521175                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    1153                         WidenMode widen, const ast::SymbolTable & symtab
     1176                        WidenMode widen
    11541177        ) {
    11551178                if ( type1->qualifiers != type2->qualifiers ) return false;
     
    11701193                        return env.bindVarToVar(
    11711194                                var1, var2, ast::TypeData{ entry1->second, entry2->second }, need, have,
    1172                                 open, widen, symtab );
     1195                                open, widen );
    11731196                } else if ( isopen1 ) {
    1174                         return env.bindVar( var1, type2, entry1->second, need, have, open, widen, symtab );
     1197                        return env.bindVar( var1, type2, entry1->second, need, have, open, widen );
    11751198                } else if ( isopen2 ) {
    11761199                        return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
     
    11801203                        return env.bindVarToVar(
    11811204                                var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
    1182                                 open, widen, symtab );
     1205                                open, widen );
    11831206                } else if ( isopen1 ) {
    1184                         return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen, symtab );
     1207                        return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
    11851208                } else if ( isopen2 ) {
    1186                         return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen, symtab );
     1209                        return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
    11871210                }else {
    11881211                        return ast::Pass<Unify_new>::read(
    1189                                 type1, type2, env, need, have, open, widen, symtab );
     1212                                type1, type2, env, need, have, open, widen );
    11901213                }
    11911214               
     
    11951218                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    11961219                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    1197                         const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab,
     1220                        const ast::OpenVarSet & open, WidenMode widen,
    11981221                        ast::ptr<ast::Type> & common
    11991222        ) {
     
    12091232                ast::ptr< ast::Type > t2_(t2);
    12101233
    1211                 if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) {
     1234                if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
    12121235                        // if exact unification on unqualified types, try to merge qualifiers
    12131236                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
     
    12191242                        }
    12201243
    1221                 } else if (( common = commonType( t1, t2, env, need, have, open, widen, symtab ))) {
     1244                } else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
    12221245                        // no exact unification, but common type
    12231246                        auto c = shallowCopy(common.get());
  • src/ResolvExpr/Unify.h

    r34b4268 r24d6572  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 13:09:04 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Mon Jun 18 11:58:00 2018
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Jan 17 11:12:00 2023
     13// Update Count     : 5
    1414//
    1515
     
    3737
    3838namespace ResolvExpr {
    39         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    40         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
    41         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    42         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    4339
    44         template< typename Iterator1, typename Iterator2 >
    45         bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {
    46                 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    47                         Type *commonType = 0;
    48                         if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    49                                 return false;
    50                         } // if
    51                         commonTypes.push_back( commonType );
    52                 } // for
    53                 if ( list1Begin != list1End || list2Begin != list2End ) {
    54                         return false;
    55                 } else {
    56                         return true;
    57                 } // if
    58         }
     40bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
     41bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
     42bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
     43bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    5944
    60         template< typename Iterator1, typename Iterator2 >
    61         bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    62                 std::list< Type* > commonTypes;
    63                 if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions, openVars, indexer, commonTypes ) ) {
    64                         deleteAll( commonTypes );
    65                         return true;
    66                 } else {
    67                         return false;
    68                 } // if
    69         }
     45bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
     46bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    7047
    71         bool unify(
    72                 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    73                 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    74                 ast::OpenVarSet & open, const ast::SymbolTable & symtab );
     48inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
     49        TypeEnvironment env;
     50        return typesCompatible( t1, t2, indexer, env );
     51}
    7552
    76         bool unify(
    77                 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    78                 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    79                 ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common );
     53inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
     54        TypeEnvironment env;
     55        return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
     56}
    8057
    81         bool unifyExact(
    82                 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    83                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    84                 WidenMode widen, const ast::SymbolTable & symtab );
     58bool unify(
     59        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     60        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     61        ast::OpenVarSet & open );
    8562
    86         bool unifyInexact(
    87                 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    88                 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    89                 const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab,
    90                 ast::ptr<ast::Type> & common );
     63bool unify(
     64        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     65        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     66        ast::OpenVarSet & open, ast::ptr<ast::Type> & common );
     67
     68bool unifyExact(
     69        const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
     70        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     71        WidenMode widen );
     72
     73bool unifyInexact(
     74        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     75        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     76        const ast::OpenVarSet & open, WidenMode widen,
     77        ast::ptr<ast::Type> & common );
     78
     79bool typesCompatible(
     80        const ast::Type *, const ast::Type *,
     81        const ast::TypeEnvironment & env = {} );
     82
     83bool typesCompatibleIgnoreQualifiers(
     84        const ast::Type *, const ast::Type *,
     85        const ast::TypeEnvironment & env = {} );
     86
     87/// Creates the type represented by the list of returnVals in a FunctionType.
     88/// The caller owns the return value.
     89Type * extractResultType( FunctionType * functionType );
     90/// Creates or extracts the type represented by returns in a `FunctionType`.
     91ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
     92
     93std::vector<ast::ptr<ast::Type>> flattenList(
     94        const std::vector<ast::ptr<ast::Type>> & src, ast::TypeEnvironment & env
     95);
    9196
    9297} // namespace ResolvExpr
  • src/ResolvExpr/WidenMode.h

    r34b4268 r24d6572  
    1919        struct WidenMode {
    2020                WidenMode( bool first, bool second ): first( first ), second( second ) {}
    21                
     21
    2222                WidenMode &operator|=( const WidenMode &other ) {
    2323                        first |= other.first; second |= other.second; return *this;
     
    3535                        WidenMode newWM( *this ); newWM &= other; return newWM;
    3636                }
    37                
     37
    3838                operator bool() { return first && second; }
    3939
  • src/ResolvExpr/module.mk

    r34b4268 r24d6572  
    1717SRC_RESOLVEXPR = \
    1818      ResolvExpr/AdjustExprType.cc \
     19      ResolvExpr/AdjustExprType.hpp \
    1920      ResolvExpr/Alternative.cc \
    2021      ResolvExpr/AlternativeFinder.cc \
     
    2627      ResolvExpr/Candidate.hpp \
    2728      ResolvExpr/CastCost.cc \
     29      ResolvExpr/CastCost.hpp \
    2830      ResolvExpr/CommonType.cc \
     31      ResolvExpr/CommonType.hpp \
    2932      ResolvExpr/ConversionCost.cc \
    3033      ResolvExpr/ConversionCost.h \
     
    4043      ResolvExpr/Occurs.cc \
    4144      ResolvExpr/PolyCost.cc \
     45      ResolvExpr/PolyCost.hpp \
    4246      ResolvExpr/PtrsAssignable.cc \
     47      ResolvExpr/PtrsAssignable.hpp \
    4348      ResolvExpr/PtrsCastable.cc \
     49      ResolvExpr/PtrsCastable.hpp \
    4450      ResolvExpr/RenameVars.cc \
    4551      ResolvExpr/RenameVars.h \
     
    5460      ResolvExpr/SatisfyAssertions.hpp \
    5561      ResolvExpr/SpecCost.cc \
     62      ResolvExpr/SpecCost.hpp \
    5663      ResolvExpr/TypeEnvironment.cc \
    5764      ResolvExpr/TypeEnvironment.h \
  • src/ResolvExpr/typeops.h

    r34b4268 r24d6572  
    1010// Created On       : Sun May 17 07:28:22 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1 09:45:00 2019
    13 // Update Count     : 6
     12// Last Modified On : Wed Jan 18 11:54:00 2023
     13// Update Count     : 7
    1414//
    1515
     
    1818#include <vector>
    1919
    20 #include "Cost.h"
    21 #include "TypeEnvironment.h"
    22 #include "WidenMode.h"
    23 #include "AST/Fwd.hpp"
    24 #include "AST/Node.hpp"
    25 #include "AST/SymbolTable.hpp"
    2620#include "AST/Type.hpp"
    27 #include "AST/TypeEnvironment.hpp"
    28 #include "SynTree/SynTree.h"
    2921#include "SynTree/Type.h"
    3022
     
    3426
    3527namespace ResolvExpr {
     28        class TypeEnvironment;
     29
    3630        // combos: takes a list of sets and returns a set of lists representing every possible way of forming a list by
    3731        // picking one element out of each set
     
    6155        }
    6256
    63         // in AdjustExprType.cc
    64         /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function
    65         void adjustExprType( Type *& type, const TypeEnvironment & env, const SymTab::Indexer & indexer );
    66 
    67         /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function using empty TypeEnvironment and Indexer
    68         void adjustExprType( Type *& type );
    69 
    70         template< typename ForwardIterator >
    71         void adjustExprTypeList( ForwardIterator begin, ForwardIterator end, const TypeEnvironment & env, const SymTab::Indexer & indexer ) {
    72                 while ( begin != end ) {
    73                         adjustExprType( *begin++, env, indexer );
    74                 } // while
    75         }
    76 
    77         /// Replaces array types with equivalent pointer, and function types with a pointer-to-function
    78         const ast::Type * adjustExprType(
    79                 const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab );
    80 
    81         // in CastCost.cc
    82         Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,
    83                 const SymTab::Indexer & indexer, const TypeEnvironment & env );
    84         Cost castCost(
    85                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    86                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    87 
    88         // in ConversionCost.cc
    89         Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,
    90                 const SymTab::Indexer & indexer, const TypeEnvironment & env );
    91         Cost conversionCost(
    92                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    93                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    94 
    95         // in AlternativeFinder.cc
    96         Cost computeConversionCost( Type * actualType, Type * formalType, bool actualIsLvalue,
    97                 const SymTab::Indexer & indexer, const TypeEnvironment & env );
    98 
    99         // in PtrsAssignable.cc
    100         int ptrsAssignable( const Type * src, const Type * dest, const TypeEnvironment & env );
    101         int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
    102                 const ast::TypeEnvironment & env );
    103 
    104         // in PtrsCastable.cc
    105         int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment & env, const SymTab::Indexer & indexer );
    106         int ptrsCastable(
    107                 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    108                 const ast::TypeEnvironment & env );
    109 
    110         // in Unify.cc
    111         bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    112         bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    113 
    114         inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    115                 TypeEnvironment env;
    116                 return typesCompatible( t1, t2, indexer, env );
    117         }
    118 
    119         inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    120                 TypeEnvironment env;
    121                 return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
    122         }
    123 
    124         bool typesCompatible(
    125                 const ast::Type *, const ast::Type *, const ast::SymbolTable & symtab = {},
    126                 const ast::TypeEnvironment & env = {} );
    127 
    128         bool typesCompatibleIgnoreQualifiers(
    129                 const ast::Type *, const ast::Type *, const ast::SymbolTable &,
    130                 const ast::TypeEnvironment & env = {} );
    131 
    132         /// creates the type represented by the list of returnVals in a FunctionType. The caller owns the return value.
    133         Type * extractResultType( FunctionType * functionType );
    134         /// Creates or extracts the type represented by the list of returns in a `FunctionType`.
    135         ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
    136 
    137         // in CommonType.cc
    138         Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer & indexer, TypeEnvironment & env, const OpenVarSet & openVars );
    139         ast::ptr< ast::Type > commonType(
    140                 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
    141                         ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    142                         const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab
    143         );
    144         // in Unify.cc
    145         std::vector< ast::ptr< ast::Type > > flattenList(
    146                 const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
    147         );
    148 
    149         // in PolyCost.cc
    150         int polyCost( Type * type, const TypeEnvironment & env, const SymTab::Indexer & indexer );
    151         int polyCost(
    152                 const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    153 
    154         // in SpecCost.cc
    155         int specCost( Type * type );
    156         int specCost( const ast::Type * type );
    157 
    15857        // in Occurs.cc
    15958        bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );
     
    16867                return false;
    16968        }
    170 
    171         // in AlternativeFinder.cc
    172         void referenceToRvalueConversion( Expression *& expr, Cost & cost );
    173         // in CandidateFinder.cpp
    174         const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost );
    17569
    17670        /// flatten tuple type into list of types
     
    218112                }
    219113
    220 
    221114                return new ast::TupleType{ std::move(types) };
    222115        }
     
    227120                return tupleFromTypes( tys.begin(), tys.end() );
    228121        }
    229 
    230        
    231122
    232123        // in TypeEnvironment.cc
  • src/SymTab/Autogen.cc

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

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

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

    r34b4268 r24d6572  
    3131#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3232#include "Mangler.h"               // for Mangler
    33 #include "ResolvExpr/typeops.h"    // for typesCompatible
     33#include "ResolvExpr/AlternativeFinder.h"  // for referenceToRvalueConversion
     34#include "ResolvExpr/Unify.h"      // for typesCompatible
    3435#include "SynTree/LinkageSpec.h"   // for isMangled, isOverridable, Spec
    3536#include "SynTree/Constant.h"      // for Constant
  • src/SymTab/Mangler.cc

    r34b4268 r24d6572  
    2424#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
    2525#include "Common/PassVisitor.h"
     26#include "Common/ToString.hpp"           // for toCString
    2627#include "Common/SemanticError.h"        // for SemanticError
    27 #include "Common/utility.h"              // for toString
    2828#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    2929#include "SynTree/LinkageSpec.h"         // for Spec, isOverridable, AutoGen, Int...
     
    439439                  private:
    440440                        void mangleDecl( const ast::DeclWithType *declaration );
    441                         void mangleRef( const ast::BaseInstType *refType, std::string prefix );
     441                        void mangleRef( const ast::BaseInstType *refType, const std::string & prefix );
    442442
    443443                        void printQualifiers( const ast::Type *type );
     
    535535                }
    536536
    537                 __attribute__((unused))
    538                 inline std::vector< ast::ptr< ast::Type > > getTypes( const std::vector< ast::ptr< ast::DeclWithType > > & decls ) {
    539                         std::vector< ast::ptr< ast::Type > > ret;
    540                         std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
    541                                                         std::mem_fun( &ast::DeclWithType::get_type ) );
    542                         return ret;
    543                 }
    544 
    545537                void Mangler_new::postvisit( const ast::FunctionType * functionType ) {
    546538                        printQualifiers( functionType );
     
    558550                }
    559551
    560                 void Mangler_new::mangleRef( const ast::BaseInstType * refType, std::string prefix ) {
     552                void Mangler_new::mangleRef(
     553                                const ast::BaseInstType * refType, const std::string & prefix ) {
    561554                        printQualifiers( refType );
    562555
    563556                        mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
    564557
    565                         if ( mangleGenericParams ) {
    566                                 if ( ! refType->params.empty() ) {
    567                                         mangleName += "_";
    568                                         for ( const ast::Expr * param : refType->params ) {
    569                                                 auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
    570                                                 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    571                                                 maybeAccept( paramType->type.get(), *visitor );
    572                                         }
    573                                         mangleName += "_";
     558                        if ( mangleGenericParams && ! refType->params.empty() ) {
     559                                mangleName += "_";
     560                                for ( const ast::Expr * param : refType->params ) {
     561                                        auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
     562                                        assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
     563                                        maybeAccept( paramType->type.get(), *visitor );
    574564                                }
     565                                mangleName += "_";
    575566                        }
    576567                }
     
    656647                }
    657648
     649                // For debugging:
    658650                __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
    659651                        for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
     
    665657                        // skip if not including qualifiers
    666658                        if ( typeMode ) return;
    667                         if ( auto ptype = dynamic_cast< const ast::FunctionType * >(type) ) {
    668                                 if ( ! ptype->forall.empty() ) {
    669                                         std::list< std::string > assertionNames;
    670                                         int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    671                                         mangleName += Encoding::forall;
    672                                         for ( auto & decl : ptype->forall ) {
    673                                                 switch ( decl->kind ) {
    674                                                   case ast::TypeDecl::Kind::Dtype:
    675                                                         dcount++;
    676                                                         break;
    677                                                   case ast::TypeDecl::Kind::Ftype:
    678                                                         fcount++;
    679                                                         break;
    680                                                   case ast::TypeDecl::Kind::Ttype:
    681                                                         vcount++;
    682                                                         break;
    683                                                   default:
    684                                                         assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[decl->kind].c_str() );
    685                                                 } // switch
    686                                                 varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
    687                                         } // for
    688                                         for ( auto & assert : ptype->assertions ) {
    689                                                 assertionNames.push_back( ast::Pass<Mangler_new>::read(
    690                                                         assert->var.get(),
    691                                                         mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
    692                                                 acount++;
    693                                         } // for
    694                                         mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
    695                                         for(const auto & a : assertionNames) mangleName += a;
    696 //                                      std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    697                                         mangleName += "_";
    698                                 } // if
     659                        auto funcType = dynamic_cast<const ast::FunctionType *>( type );
     660                        if ( funcType && !funcType->forall.empty() ) {
     661                                std::list< std::string > assertionNames;
     662                                int dcount = 0, fcount = 0, vcount = 0, acount = 0;
     663                                mangleName += Encoding::forall;
     664                                for ( auto & decl : funcType->forall ) {
     665                                        switch ( decl->kind ) {
     666                                        case ast::TypeDecl::Dtype:
     667                                                dcount++;
     668                                                break;
     669                                        case ast::TypeDecl::Ftype:
     670                                                fcount++;
     671                                                break;
     672                                        case ast::TypeDecl::Ttype:
     673                                                vcount++;
     674                                                break;
     675                                        default:
     676                                                assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[decl->kind].c_str() );
     677                                        } // switch
     678                                        varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
     679                                } // for
     680                                for ( auto & assert : funcType->assertions ) {
     681                                        assertionNames.push_back( ast::Pass<Mangler_new>::read(
     682                                                assert->var.get(),
     683                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
     684                                        acount++;
     685                                } // for
     686                                mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
     687                                for ( const auto & a : assertionNames ) mangleName += a;
     688                                mangleName += "_";
    699689                        } // if
    700690                        if ( ! inFunctionType ) {
  • src/SymTab/Validate.cc

    r34b4268 r24d6572  
    5555#include "Common/ScopedMap.h"          // for ScopedMap
    5656#include "Common/SemanticError.h"      // for SemanticError
     57#include "Common/ToString.hpp"         // for toCString
    5758#include "Common/UniqueName.h"         // for UniqueName
    58 #include "Common/utility.h"            // for operator+, cloneAll, deleteAll
     59#include "Common/utility.h"            // for cloneAll, deleteAll
    5960#include "CompilationState.h"          // skip some passes in new-ast build
    6061#include "Concurrency/Keywords.h"      // for applyKeywords
     
    6364#include "InitTweak/GenInit.h"         // for fixReturnStatements
    6465#include "InitTweak/InitTweak.h"       // for isCtorDtorAssign
    65 #include "ResolvExpr/typeops.h"        // for typesCompatible
     66#include "ResolvExpr/typeops.h"        // for extractResultType
     67#include "ResolvExpr/Unify.h"          // for typesCompatible
    6668#include "ResolvExpr/Resolver.h"       // for findSingleExpression
    6769#include "ResolvExpr/ResolveTypeof.h"  // for resolveTypeof
     
    862864
    863865        void ReplaceTypedef::premutate( TypeDecl * typeDecl ) {
    864                 TypedefMap::iterator i = typedefNames.find( typeDecl->name );
    865                 if ( i != typedefNames.end() ) {
    866                         typedefNames.erase( i ) ;
    867                 } // if
    868 
     866                typedefNames.erase( typeDecl->name );
    869867                typedeclNames.insert( typeDecl->name, typeDecl );
    870868        }
  • src/SymTab/ValidateType.cc

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

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

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

    r34b4268 r24d6572  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // ApplicationExpr.cc.cc --
     7// ApplicationExpr.cc --
    88//
    99// Author           : Richard C. Bilson
     
    2626#include "Expression.h"          // for ParamEntry, ApplicationExpr, Expression
    2727#include "InitTweak/InitTweak.h" // for getFunction
    28 #include "ResolvExpr/typeops.h"  // for extractResultType
     28#include "ResolvExpr/Unify.h"    // for extractResultType
    2929#include "Type.h"                // for Type, PointerType, FunctionType
    3030
  • src/SynTree/BasicType.cc

    r34b4268 r24d6572  
    2929}
    3030
    31 bool BasicType::isWholeNumber() const {
    32         return kind == Bool ||
    33                 kind ==Char ||
    34                 kind == SignedChar ||
    35                 kind == UnsignedChar ||
    36                 kind == ShortSignedInt ||
    37                 kind == ShortUnsignedInt ||
    38                 kind == SignedInt ||
    39                 kind == UnsignedInt ||
    40                 kind == LongSignedInt ||
    41                 kind == LongUnsignedInt ||
    42                 kind == LongLongSignedInt ||
    43                 kind ==LongLongUnsignedInt ||
    44                 kind == SignedInt128 ||
    45                 kind == UnsignedInt128;
    46 }
    47 
    4831bool BasicType::isInteger() const {
    4932        return kind <= UnsignedInt128;
  • src/SynTree/FunctionDecl.cc

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

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

    r34b4268 r24d6572  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul 14 15:40:00 2021
    13 // Update Count     : 171
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Feb 19 22:37:10 2023
     13// Update Count     : 176
    1414//
    1515
     
    2323
    2424#include "BaseSyntaxNode.h"  // for BaseSyntaxNode
    25 #include "Common/utility.h"  // for operator+
     25#include "Common/Iterate.hpp"// for operator+
    2626#include "Mutator.h"         // for Mutator
    2727#include "SynTree.h"         // for AST nodes
     
    124124                bool operator!=( Qualifiers other ) const { return (val & Mask) != (other.val & Mask); }
    125125                bool operator<=( Qualifiers other ) const {
    126                         return is_const    <= other.is_const        //Any non-const converts to const without cost
    127                                         && is_volatile <= other.is_volatile     //Any non-volatile converts to volatile without cost
    128                                         && is_mutex    >= other.is_mutex        //Any mutex converts to non-mutex without cost
    129                                         && is_atomic   == other.is_atomic;      //No conversion from atomic to non atomic is free
     126                        return is_const    <= other.is_const        // Any non-const converts to const without cost
     127                                && is_volatile <= other.is_volatile             // Any non-volatile converts to volatile without cost
     128                                && is_mutex    >= other.is_mutex                // Any mutex converts to non-mutex without cost
     129                                && is_atomic   == other.is_atomic;              // No conversion from atomic to non atomic is free
    130130                }
    131131                bool operator<( Qualifiers other ) const { return *this != other && *this <= other; }
     
    185185        virtual bool isComplete() const { return true; }
    186186
    187         virtual AggregateDecl * getAggr() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
     187        virtual AggregateDecl * getAggr() const;
    188188
    189189        virtual TypeSubstitution genericSubstitution() const;
    190190
    191         virtual Type *clone() const = 0;
     191        virtual Type * clone() const = 0;
    192192        virtual void accept( Visitor & v ) = 0;
    193193        virtual void accept( Visitor & v ) const = 0;
    194         virtual Type *acceptMutator( Mutator & m ) = 0;
     194        virtual Type * acceptMutator( Mutator & m ) = 0;
    195195        virtual void print( std::ostream & os, Indenter indent = {} ) const;
    196196};
     
    207207        virtual bool isComplete() const override { return false; }
    208208
    209         virtual VoidType *clone() const override { return new VoidType( *this ); }
    210         virtual void accept( Visitor & v ) override { v.visit( this ); }
    211         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    212         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     209        virtual VoidType * clone() const override { return new VoidType( *this ); }
     210        virtual void accept( Visitor & v ) override { v.visit( this ); }
     211        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     212        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    213213        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    214214};
     
    259259        // GENERATED END
    260260
    261         static const char *typeNames[];                                         // string names for basic types, MUST MATCH with Kind
     261        static const char * typeNames[];                                        // string names for basic types, MUST MATCH with Kind
    262262
    263263        BasicType( const Type::Qualifiers & tq, Kind bt, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     
    266266        void set_kind( Kind newValue ) { kind = newValue; }
    267267
    268         virtual BasicType *clone() const override { return new BasicType( *this ); }
    269         virtual void accept( Visitor & v ) override { v.visit( this ); }
    270         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    271         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    272         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    273         bool isWholeNumber() const;
     268        virtual BasicType * clone() const override { return new BasicType( *this ); }
     269        virtual void accept( Visitor & v ) override { v.visit( this ); }
     270        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     271        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     272        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    274273        bool isInteger() const;
    275274};
     
    280279
    281280        // In C99, pointer types can be qualified in many ways e.g., int f( int a[ static 3 ] )
    282         Expression *dimension;
     281        Expression * dimension;
    283282        bool isVarLen;
    284283        bool isStatic;
    285284
    286         PointerType( const Type::Qualifiers & tq, Type *base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    287         PointerType( const Type::Qualifiers & tq, Type *base, Expression *dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     285        PointerType( const Type::Qualifiers & tq, Type * base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     286        PointerType( const Type::Qualifiers & tq, Type * base, Expression * dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    288287        PointerType( const PointerType& );
    289288        virtual ~PointerType();
    290289
    291         Type *get_base() { return base; }
    292         void set_base( Type *newValue ) { base = newValue; }
    293         Expression *get_dimension() { return dimension; }
    294         void set_dimension( Expression *newValue ) { dimension = newValue; }
     290        Type * get_base() { return base; }
     291        void set_base( Type * newValue ) { base = newValue; }
     292        Expression * get_dimension() { return dimension; }
     293        void set_dimension( Expression * newValue ) { dimension = newValue; }
    295294        bool get_isVarLen() { return isVarLen; }
    296295        void set_isVarLen( bool newValue ) { isVarLen = newValue; }
     
    302301        virtual bool isComplete() const override { return ! isVarLen; }
    303302
    304         virtual PointerType *clone() const override { return new PointerType( *this ); }
    305         virtual void accept( Visitor & v ) override { v.visit( this ); }
    306         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    307         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     303        virtual PointerType * clone() const override { return new PointerType( * this ); }
     304        virtual void accept( Visitor & v ) override { v.visit( this ); }
     305        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     306        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    308307        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    309308};
     
    311310class ArrayType : public Type {
    312311  public:
    313         Type *base;
    314         Expression *dimension;
     312        Type * base;
     313        Expression * dimension;
    315314        bool isVarLen;
    316315        bool isStatic;
    317316
    318         ArrayType( const Type::Qualifiers & tq, Type *base, Expression *dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     317        ArrayType( const Type::Qualifiers & tq, Type * base, Expression * dimension, bool isVarLen, bool isStatic, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    319318        ArrayType( const ArrayType& );
    320319        virtual ~ArrayType();
    321320
    322         Type *get_base() { return base; }
    323         void set_base( Type *newValue ) { base = newValue; }
    324         Expression *get_dimension() { return dimension; }
    325         void set_dimension( Expression *newValue ) { dimension = newValue; }
     321        Type * get_base() { return base; }
     322        void set_base( Type * newValue ) { base = newValue; }
     323        Expression * get_dimension() { return dimension; }
     324        void set_dimension( Expression * newValue ) { dimension = newValue; }
    326325        bool get_isVarLen() { return isVarLen; }
    327326        void set_isVarLen( bool newValue ) { isVarLen = newValue; }
     
    334333        virtual bool isComplete() const override { return dimension || isVarLen; }
    335334
    336         virtual ArrayType *clone() const override { return new ArrayType( *this ); }
    337         virtual void accept( Visitor & v ) override { v.visit( this ); }
    338         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    339         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     335        virtual ArrayType * clone() const override { return new ArrayType( *this ); }
     336        virtual void accept( Visitor & v ) override { v.visit( this ); }
     337        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     338        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    340339        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    341340};
     
    349348        virtual ~QualifiedType();
    350349
    351         virtual QualifiedType *clone() const override { return new QualifiedType( *this ); }
    352         virtual void accept( Visitor & v ) override { v.visit( this ); }
    353         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    354         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     350        virtual QualifiedType * clone() const override { return new QualifiedType( *this ); }
     351        virtual void accept( Visitor & v ) override { v.visit( this ); }
     352        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     353        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    355354        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    356355};
     
    358357class ReferenceType : public Type {
    359358public:
    360         Type *base;
    361 
    362         ReferenceType( const Type::Qualifiers & tq, Type *base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     359        Type * base;
     360
     361        ReferenceType( const Type::Qualifiers & tq, Type * base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    363362        ReferenceType( const ReferenceType & );
    364363        virtual ~ReferenceType();
    365364
    366         Type *get_base() { return base; }
    367         void set_base( Type *newValue ) { base = newValue; }
     365        Type * get_base() { return base; }
     366        void set_base( Type * newValue ) { base = newValue; }
    368367
    369368        virtual int referenceDepth() const override;
     
    376375        virtual TypeSubstitution genericSubstitution() const override;
    377376
    378         virtual ReferenceType *clone() const override { return new ReferenceType( *this ); }
    379         virtual void accept( Visitor & v ) override { v.visit( this ); }
    380         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    381         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     377        virtual ReferenceType * clone() const override { return new ReferenceType( *this ); }
     378        virtual void accept( Visitor & v ) override { v.visit( this ); }
     379        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     380        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    382381        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    383382};
     
    406405        bool isUnprototyped() const { return isVarArgs && parameters.size() == 0; }
    407406
    408         virtual FunctionType *clone() const override { return new FunctionType( *this ); }
    409         virtual void accept( Visitor & v ) override { v.visit( this ); }
    410         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    411         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     407        virtual FunctionType * clone() const override { return new FunctionType( *this ); }
     408        virtual void accept( Visitor & v ) override { v.visit( this ); }
     409        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     410        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    412411        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    413412};
     
    415414class ReferenceToType : public Type {
    416415  public:
    417         std::list< Expression* > parameters;
     416        std::list< Expression * > parameters;
    418417        std::string name;
    419418        bool hoistType;
     
    429428        void set_hoistType( bool newValue ) { hoistType = newValue; }
    430429
    431         virtual ReferenceToType *clone() const override = 0;
     430        virtual ReferenceToType * clone() const override = 0;
    432431        virtual void accept( Visitor & v ) override = 0;
    433         virtual Type *acceptMutator( Mutator & m ) override = 0;
     432        virtual Type * acceptMutator( Mutator & m ) override = 0;
    434433        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    435434
     
    444443        // this decl is not "owned" by the struct inst; it is merely a pointer to elsewhere in the tree,
    445444        // where the structure used in this type is actually defined
    446         StructDecl *baseStruct;
     445        StructDecl * baseStruct;
    447446
    448447        StructInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >()  ) : Parent( tq, name, attributes ), baseStruct( 0 ) {}
     
    450449        StructInstType( const StructInstType & other ) : Parent( other ), baseStruct( other.baseStruct ) {}
    451450
    452         StructDecl *get_baseStruct() const { return baseStruct; }
    453         void set_baseStruct( StructDecl *newValue ) { baseStruct = newValue; }
     451        StructDecl * get_baseStruct() const { return baseStruct; }
     452        void set_baseStruct( StructDecl * newValue ) { baseStruct = newValue; }
    454453
    455454        /// Accesses generic parameters of base struct (NULL if none such)
     
    467466        void lookup( const std::string & name, std::list< Declaration* > & foundDecls ) const override;
    468467
    469         virtual StructInstType *clone() const override { return new StructInstType( *this ); }
    470         virtual void accept( Visitor & v ) override { v.visit( this ); }
    471         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    472         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     468        virtual StructInstType * clone() const override { return new StructInstType( *this ); }
     469        virtual void accept( Visitor & v ) override { v.visit( this ); }
     470        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     471        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    473472
    474473        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     
    482481        // this decl is not "owned" by the union inst; it is merely a pointer to elsewhere in the tree,
    483482        // where the union used in this type is actually defined
    484         UnionDecl *baseUnion;
     483        UnionDecl * baseUnion;
    485484
    486485        UnionInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >()  ) : Parent( tq, name, attributes ), baseUnion( 0 ) {}
     
    488487        UnionInstType( const UnionInstType & other ) : Parent( other ), baseUnion( other.baseUnion ) {}
    489488
    490         UnionDecl *get_baseUnion() const { return baseUnion; }
     489        UnionDecl * get_baseUnion() const { return baseUnion; }
    491490        void set_baseUnion( UnionDecl * newValue ) { baseUnion = newValue; }
    492491
     
    505504        void lookup( const std::string & name, std::list< Declaration* > & foundDecls ) const override;
    506505
    507         virtual UnionInstType *clone() const override { return new UnionInstType( *this ); }
    508         virtual void accept( Visitor & v ) override { v.visit( this ); }
    509         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    510         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     506        virtual UnionInstType * clone() const override { return new UnionInstType( *this ); }
     507        virtual void accept( Visitor & v ) override { v.visit( this ); }
     508        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     509        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    511510
    512511        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     
    520519        // this decl is not "owned" by the enum inst; it is merely a pointer to elsewhere in the tree,
    521520        // where the enum used in this type is actually defined
    522         EnumDecl *baseEnum = nullptr;
     521        EnumDecl * baseEnum = nullptr;
    523522
    524523        EnumInstType( const Type::Qualifiers & tq, const std::string & name, const std::list< Attribute * > & attributes = std::list< Attribute * >()  ) : Parent( tq, name, attributes ) {}
     
    526525        EnumInstType( const EnumInstType & other ) : Parent( other ), baseEnum( other.baseEnum ) {}
    527526
    528         EnumDecl *get_baseEnum() const { return baseEnum; }
    529         void set_baseEnum( EnumDecl *newValue ) { baseEnum = newValue; }
     527        EnumDecl * get_baseEnum() const { return baseEnum; }
     528        void set_baseEnum( EnumDecl * newValue ) { baseEnum = newValue; }
    530529
    531530        virtual bool isComplete() const override;
     
    533532        virtual AggregateDecl * getAggr() const override;
    534533
    535         virtual EnumInstType *clone() const override { return new EnumInstType( *this ); }
    536         virtual void accept( Visitor & v ) override { v.visit( this ); }
    537         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    538         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     534        virtual EnumInstType * clone() const override { return new EnumInstType( *this ); }
     535        virtual void accept( Visitor & v ) override { v.visit( this ); }
     536        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     537        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    539538
    540539        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     
    557556        virtual bool isComplete() const override;
    558557
    559         virtual TraitInstType *clone() const override { return new TraitInstType( *this ); }
    560         virtual void accept( Visitor & v ) override { v.visit( this ); }
    561         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    562         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     558        virtual TraitInstType * clone() const override { return new TraitInstType( *this ); }
     559        virtual void accept( Visitor & v ) override { v.visit( this ); }
     560        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     561        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    563562  private:
    564563        virtual std::string typeString() const override;
     
    570569        // this decl is not "owned" by the type inst; it is merely a pointer to elsewhere in the tree,
    571570        // where the type used here is actually defined
    572         TypeDecl *baseType;
     571        TypeDecl * baseType;
    573572        bool isFtype;
    574573
    575         TypeInstType( const Type::Qualifiers & tq, const std::string & name, TypeDecl *baseType, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
     574        TypeInstType( const Type::Qualifiers & tq, const std::string & name, TypeDecl * baseType, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    576575        TypeInstType( const Type::Qualifiers & tq, const std::string & name, bool isFtype, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    577576        TypeInstType( const TypeInstType & other );
    578577        ~TypeInstType();
    579578
    580         TypeDecl *get_baseType() const { return baseType; }
    581         void set_baseType( TypeDecl *newValue );
     579        TypeDecl * get_baseType() const { return baseType; }
     580        void set_baseType( TypeDecl * newValue );
    582581        bool get_isFtype() const { return isFtype; }
    583582        void set_isFtype( bool newValue ) { isFtype = newValue; }
     
    585584        virtual bool isComplete() const override;
    586585
    587         virtual TypeInstType *clone() const override { return new TypeInstType( *this ); }
    588         virtual void accept( Visitor & v ) override { v.visit( this ); }
    589         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    590         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     586        virtual TypeInstType * clone() const override { return new TypeInstType( *this ); }
     587        virtual void accept( Visitor & v ) override { v.visit( this ); }
     588        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     589        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    591590        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    592591  private:
     
    623622        // virtual bool isComplete() const override { return true; } // xxx - not sure if this is right, might need to recursively check complete-ness
    624623
    625         virtual TupleType *clone() const override { return new TupleType( *this ); }
    626         virtual void accept( Visitor & v ) override { v.visit( this ); }
    627         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    628         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     624        virtual TupleType * clone() const override { return new TupleType( *this ); }
     625        virtual void accept( Visitor & v ) override { v.visit( this ); }
     626        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     627        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    629628        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    630629};
     
    632631class TypeofType : public Type {
    633632  public:
    634         Expression *expr;    ///< expression to take the type of
    635         bool is_basetypeof;  ///< true iff is basetypeof type
    636 
    637         TypeofType( const Type::Qualifiers & tq, Expression *expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    638         TypeofType( const Type::Qualifiers & tq, Expression *expr, bool is_basetypeof,
     633        Expression * expr;              ///< expression to take the type of
     634        bool is_basetypeof;             ///< true iff is basetypeof type
     635
     636        TypeofType( const Type::Qualifiers & tq, Expression * expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     637        TypeofType( const Type::Qualifiers & tq, Expression * expr, bool is_basetypeof,
    639638                const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    640639        TypeofType( const TypeofType& );
    641640        virtual ~TypeofType();
    642641
    643         Expression *get_expr() const { return expr; }
    644         void set_expr( Expression *newValue ) { expr = newValue; }
     642        Expression * get_expr() const { return expr; }
     643        void set_expr( Expression * newValue ) { expr = newValue; }
    645644
    646645        virtual bool isComplete() const override { assert( false ); return false; }
    647646
    648         virtual TypeofType *clone() const override { return new TypeofType( *this ); }
    649         virtual void accept( Visitor & v ) override { v.visit( this ); }
    650         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    651         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     647        virtual TypeofType * clone() const override { return new TypeofType( *this ); }
     648        virtual void accept( Visitor & v ) override { v.visit( this ); }
     649        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     650        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    652651        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    653652};
     
    655654class VTableType : public Type {
    656655public:
    657         Type *base;
    658 
    659         VTableType( const Type::Qualifiers & tq, Type *base,
     656        Type * base;
     657
     658        VTableType( const Type::Qualifiers & tq, Type * base,
    660659                const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    661660        VTableType( const VTableType & );
    662661        virtual ~VTableType();
    663662
    664         Type *get_base() { return base; }
    665         void set_base( Type *newValue ) { base = newValue; }
    666 
    667         virtual VTableType *clone() const override { return new VTableType( *this ); }
    668         virtual void accept( Visitor & v ) override { v.visit( this ); }
    669         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    670         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     663        Type * get_base() { return base; }
     664        void set_base( Type * newValue ) { base = newValue; }
     665
     666        virtual VTableType * clone() const override { return new VTableType( *this ); }
     667        virtual void accept( Visitor & v ) override { v.visit( this ); }
     668        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     669        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    671670        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    672671};
     
    675674  public:
    676675        std::string name;
    677         Expression *expr;
    678         Type *type;
     676        Expression * expr;
     677        Type * type;
    679678        bool isType;
    680679
    681         AttrType( const Type::Qualifiers & tq, const std::string & name, Expression *expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
    682         AttrType( const Type::Qualifiers & tq, const std::string & name, Type *type, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
     680        AttrType( const Type::Qualifiers & tq, const std::string & name, Expression * expr, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
     681        AttrType( const Type::Qualifiers & tq, const std::string & name, Type * type, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    683682        AttrType( const AttrType& );
    684683        virtual ~AttrType();
     
    686685        const std::string & get_name() const { return name; }
    687686        void set_name( const std::string & newValue ) { name = newValue; }
    688         Expression *get_expr() const { return expr; }
    689         void set_expr( Expression *newValue ) { expr = newValue; }
    690         Type *get_type() const { return type; }
    691         void set_type( Type *newValue ) { type = newValue; }
     687        Expression * get_expr() const { return expr; }
     688        void set_expr( Expression * newValue ) { expr = newValue; }
     689        Type * get_type() const { return type; }
     690        void set_type( Type * newValue ) { type = newValue; }
    692691        bool get_isType() const { return isType; }
    693692        void set_isType( bool newValue ) { isType = newValue; }
     
    695694        virtual bool isComplete() const override { assert( false ); } // xxx - not sure what to do here
    696695
    697         virtual AttrType *clone() const override { return new AttrType( *this ); }
    698         virtual void accept( Visitor & v ) override { v.visit( this ); }
    699         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    700         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     696        virtual AttrType * clone() const override { return new AttrType( *this ); }
     697        virtual void accept( Visitor & v ) override { v.visit( this ); }
     698        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     699        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    701700        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    702701};
     
    710709        virtual bool isComplete() const override{ return true; } // xxx - is this right?
    711710
    712         virtual VarArgsType *clone() const override { return new VarArgsType( *this ); }
    713         virtual void accept( Visitor & v ) override { v.visit( this ); }
    714         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    715         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     711        virtual VarArgsType * clone() const override { return new VarArgsType( *this ); }
     712        virtual void accept( Visitor & v ) override { v.visit( this ); }
     713        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     714        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    716715        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    717716};
     
    723722        ZeroType( Type::Qualifiers tq, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    724723
    725         virtual ZeroType *clone() const override { return new ZeroType( *this ); }
    726         virtual void accept( Visitor & v ) override { v.visit( this ); }
    727         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    728         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     724        virtual ZeroType * clone() const override { return new ZeroType( *this ); }
     725        virtual void accept( Visitor & v ) override { v.visit( this ); }
     726        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     727        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    729728        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    730729};
     
    736735        OneType( Type::Qualifiers tq, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
    737736
    738         virtual OneType *clone() const override { return new OneType( *this ); }
    739         virtual void accept( Visitor & v ) override { v.visit( this ); }
    740         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    741         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     737        virtual OneType * clone() const override { return new OneType( *this ); }
     738        virtual void accept( Visitor & v ) override { v.visit( this ); }
     739        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     740        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    742741        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    743742};
     
    747746        GlobalScopeType();
    748747
    749         virtual GlobalScopeType *clone() const override { return new GlobalScopeType( *this ); }
    750         virtual void accept( Visitor & v ) override { v.visit( this ); }
    751         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    752         virtual Type *acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     748        virtual GlobalScopeType * clone() const override { return new GlobalScopeType( *this ); }
     749        virtual void accept( Visitor & v ) override { v.visit( this ); }
     750        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     751        virtual Type * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    753752        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    754753};
  • src/Tuples/Explode.cc

    r34b4268 r24d6572  
    1717#include <list>                  // for list
    1818
     19#include "AST/Pass.hpp"          // for Pass
    1920#include "SynTree/Mutator.h"     // for Mutator
    2021#include "Common/PassVisitor.h"  // for PassVisitor
  • src/Validate/Autogen.cpp

    r34b4268 r24d6572  
    2525
    2626#include "AST/Attribute.hpp"
     27#include "AST/Copy.hpp"
    2728#include "AST/Create.hpp"
    2829#include "AST/Decl.hpp"
     
    3940#include "InitTweak/GenInit.h"     // for fixReturnStatements
    4041#include "InitTweak/InitTweak.h"   // for isAssignment, isCopyConstructor
     42#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4143#include "SymTab/Mangler.h"        // for Mangler
    4244#include "CompilationState.h"
    43 
    44 // TODO: The other new ast function should be moved over to this file.
    45 #include "SymTab/Autogen.h"
    4645
    4746namespace Validate {
     
    9493
    9594        const CodeLocation& getLocation() const { return getDecl()->location; }
    96         ast::FunctionDecl * genProto( const std::string& name,
     95        ast::FunctionDecl * genProto( std::string&& name,
    9796                std::vector<ast::ptr<ast::DeclWithType>>&& params,
    9897                std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const;
     
    322321void FuncGenerator::produceDecl( const ast::FunctionDecl * decl ) {
    323322        assert( nullptr != decl->stmts );
     323        const auto & oldParams = getGenericParams(type);
     324        assert( decl->type_params.size() == oldParams.size());
     325
     326        /*
     327        ast::DeclReplacer::TypeMap typeMap;
     328        for (auto it = oldParams.begin(), jt = decl->type_params.begin(); it != oldParams.end(); ++it, ++jt) {
     329                typeMap.emplace(*it, *jt);
     330        }
     331
     332        const ast::FunctionDecl * mut = strict_dynamic_cast<const ast::FunctionDecl *>(ast::DeclReplacer::replace(decl, typeMap));
     333        assert (mut == decl);
     334        */
    324335
    325336        definitions.push_back( decl );
     
    335346}
    336347
     348void replaceAll( std::vector<ast::ptr<ast::DeclWithType>> & dwts,
     349                const ast::DeclReplacer::TypeMap & map ) {
     350        for ( auto & dwt : dwts ) {
     351                dwt = strict_dynamic_cast<const ast::DeclWithType *>(
     352                                ast::DeclReplacer::replace( dwt, map ) );
     353        }
     354}
     355
    337356/// Generates a basic prototype function declaration.
    338 ast::FunctionDecl * FuncGenerator::genProto( const std::string& name,
     357ast::FunctionDecl * FuncGenerator::genProto( std::string&& name,
    339358                std::vector<ast::ptr<ast::DeclWithType>>&& params,
    340359                std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const {
     
    342361        // Handle generic prameters and assertions, if any.
    343362        auto const & old_type_params = getGenericParams( type );
     363        ast::DeclReplacer::TypeMap oldToNew;
    344364        std::vector<ast::ptr<ast::TypeDecl>> type_params;
    345365        std::vector<ast::ptr<ast::DeclWithType>> assertions;
     366
     367        ast::DeclReplacer::TypeMap typeMap;
    346368        for ( auto & old_param : old_type_params ) {
    347369                ast::TypeDecl * decl = ast::deepCopy( old_param );
    348                 for ( auto assertion : decl->assertions ) {
    349                         assertions.push_back( assertion );
    350                 }
    351                 decl->assertions.clear();
     370                decl->init = nullptr;
     371                splice( assertions, decl->assertions );
     372                oldToNew.emplace( std::make_pair( old_param, decl ) );
    352373                type_params.push_back( decl );
    353         }
    354         // TODO: The values in params and returns still may point at the old
    355         // generic params, that does not appear to be an issue but perhaps it
    356         // should be addressed.
     374                typeMap.emplace(old_param, decl);
     375        }
     376
     377        for (auto & param : params) {
     378                param = ast::DeclReplacer::replace(param, typeMap);
     379        }
     380        for (auto & param : returns) {
     381                param = ast::DeclReplacer::replace(param, typeMap);
     382        }
     383        replaceAll( params, oldToNew );
     384        replaceAll( returns, oldToNew );
     385        replaceAll( assertions, oldToNew );
    357386
    358387        ast::FunctionDecl * decl = new ast::FunctionDecl(
    359388                // Auto-generated routines use the type declaration's location.
    360389                getLocation(),
    361                 name,
     390                std::move( name ),
    362391                std::move( type_params ),
    363392                std::move( assertions ),
     
    423452        for ( unsigned int index = 0 ; index < fields ; ++index ) {
    424453                auto member = aggr->members[index].strict_as<ast::DeclWithType>();
    425                 if ( SymTab::isUnnamedBitfield(
     454                if ( ast::isUnnamedBitfield(
    426455                                dynamic_cast<const ast::ObjectDecl *>( member ) ) ) {
    427456                        if ( index == fields - 1 ) {
     
    515544        InitTweak::InitExpander_new srcParam( src );
    516545        // Assign to destination.
    517         ast::Expr * dstSelect = new ast::MemberExpr(
     546        ast::MemberExpr * dstSelect = new ast::MemberExpr(
    518547                location,
    519548                field,
     
    567596                }
    568597
    569                 ast::Expr * srcSelect = (srcParam) ? new ast::MemberExpr(
     598                ast::MemberExpr * srcSelect = (srcParam) ? new ast::MemberExpr(
    570599                        location, field, new ast::VariableExpr( location, srcParam )
    571600                ) : nullptr;
     
    599628                // Not sure why it could be null.
    600629                // Don't make a function for a parameter that is an unnamed bitfield.
    601                 if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {
     630                if ( nullptr == field || ast::isUnnamedBitfield( field ) ) {
    602631                        continue;
    603632                // Matching Parameter: Initialize the field by copy.
  • src/Validate/FixQualifiedTypes.cpp

    r34b4268 r24d6572  
    1616#include "Validate/FixQualifiedTypes.hpp"
    1717
     18#include "AST/Copy.hpp"
     19#include "AST/LinkageSpec.hpp"             // for Linkage
    1820#include "AST/Pass.hpp"
    1921#include "AST/TranslationUnit.hpp"
     22#include "Common/ToString.hpp"             // for toString
     23#include "SymTab/Mangler.h"                // for Mangler
    2024#include "Validate/NoIdSymbolTable.hpp"
    21 #include "SymTab/Mangler.h"            // for Mangler
    22 #include "AST/LinkageSpec.hpp"                     // for Linkage
    2325
    2426namespace Validate {
  • src/Validate/FixReturnTypes.cpp

    r34b4268 r24d6572  
    2020#include "AST/Type.hpp"
    2121#include "CodeGen/CodeGenerator.h"
    22 #include "ResolvExpr/typeops.h"
     22#include "ResolvExpr/Unify.h"
    2323
    2424namespace ast {
  • src/Validate/ForallPointerDecay.cpp

    r34b4268 r24d6572  
    2222#include "CodeGen/OperatorTable.h"
    2323#include "Common/CodeLocation.h"
     24#include "Common/ToString.hpp"
    2425#include "SymTab/FixFunction.h"
    2526
  • src/Validate/GenericParameter.cpp

    r34b4268 r24d6572  
    1616#include "GenericParameter.hpp"
    1717
     18#include "AST/Copy.hpp"
    1819#include "AST/Decl.hpp"
    1920#include "AST/Expr.hpp"
  • src/Validate/HandleAttributes.cc

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

    r34b4268 r24d6572  
    1616#include "Validate/HoistStruct.hpp"
    1717
     18#include <sstream>
     19
    1820#include "AST/Pass.hpp"
    1921#include "AST/TranslationUnit.hpp"
    20 #include "Common/utility.h"
    2122
    2223namespace Validate {
  • src/Validate/ReplaceTypedef.cpp

    r34b4268 r24d6572  
    1616#include "ReplaceTypedef.hpp"
    1717
     18#include "AST/Copy.hpp"
    1819#include "AST/Pass.hpp"
    1920#include "Common/ScopedMap.h"
    2021#include "Common/UniqueName.h"
    2122#include "Common/utility.h"
    22 #include "ResolvExpr/typeops.h"
     23#include "ResolvExpr/Unify.h"
    2324
    2425namespace Validate {
     
    149150                // constant/enumerator. The effort required to fix this corner case
    150151                // likely outweighs the utility of allowing it.
    151                 if ( !ResolvExpr::typesCompatible( t0, t1, ast::SymbolTable() )
     152                if ( !ResolvExpr::typesCompatible( t0, t1 )
    152153                                || ast::Pass<VarLenChecker>::read( t0 )
    153154                                || ast::Pass<VarLenChecker>::read( t1 ) ) {
     
    186187
    187188void ReplaceTypedefCore::previsit( ast::TypeDecl const * decl ) {
    188         TypedefMap::iterator iter = typedefNames.find( decl->name );
    189         if ( iter != typedefNames.end() ) {
    190                 typedefNames.erase( iter );
    191         }
     189        typedefNames.erase( decl->name );
    192190        typedeclNames.insert( decl->name, decl );
    193191}
  • src/Virtual/ExpandCasts.cc

    r34b4268 r24d6572  
    2020#include <string>                  // for string, allocator, operator==, ope...
    2121
     22#include "AST/Copy.hpp"
    2223#include "AST/Decl.hpp"
    2324#include "AST/Expr.hpp"
  • src/Virtual/module.mk

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

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

    r34b4268 r24d6572  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Oct  5 12:06:00 2022
    13 // Update Count     : 679
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 21:12:17 2023
     13// Update Count     : 682
    1414//
    1515
     
    3232
    3333#include "AST/Convert.hpp"
     34#include "AST/Pass.hpp"                     // for pass_visitor_stats
     35#include "AST/TranslationUnit.hpp"          // for TranslationUnit
     36#include "AST/Util.hpp"                     // for checkInvariants
    3437#include "CompilationState.h"
    3538#include "../config.h"                      // for CFA_LIBDIR
     
    4043#include "CodeTools/TrackLoc.h"             // for fillLocations
    4144#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    42 #include "Common/CompilerError.h"           // for CompilerError
    4345#include "Common/DeclStats.hpp"             // for printDeclStats
    4446#include "Common/ResolvProtoDump.hpp"       // for dumpAsResolverProto
    4547#include "Common/Stats.h"                   // for Stats
    46 #include "Common/UnimplementedError.h"      // for UnimplementedError
    4748#include "Common/utility.h"                 // for deleteAll, filter, printAll
     49#include "Concurrency/Actors.hpp"           // for implementActors
    4850#include "Concurrency/Keywords.h"           // for implementMutex, implement...
    4951#include "Concurrency/Waitfor.h"            // for generateWaitfor
     52#include "Concurrency/Waituntil.hpp"        // for generateWaitUntil
    5053#include "ControlStruct/ExceptDecl.h"       // for translateExcept
    5154#include "ControlStruct/ExceptTranslate.h"  // for translateThrows, translat...
     
    5962#include "InitTweak/GenInit.h"              // for genInit
    6063#include "MakeLibCfa.h"                     // for makeLibCfa
    61 #include "Parser/ParseNode.h"               // for DeclarationNode, buildList
    62 #include "Parser/TypedefTable.h"            // for TypedefTable
     64#include "Parser/RunParser.hpp"             // for buildList, dumpParseTree,...
    6365#include "ResolvExpr/CandidatePrinter.hpp"  // for printCandidates
    6466#include "ResolvExpr/Resolver.h"            // for resolve
     
    8486#include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign
    8587#include "Virtual/ExpandCasts.h"            // for expandCasts
     88#include "Virtual/VirtualDtor.hpp"           // for implementVirtDtors
    8689
    8790static void NewPass( const char * const name ) {
     
    102105}
    103106
    104 #define PASS( name, pass )                  \
     107// Helpers for checkInvariant:
     108void checkInvariants( std::list< Declaration * > & ) {}
     109using ast::checkInvariants;
     110
     111#define PASS( name, pass, unit, ... )       \
    105112        if ( errorp ) { cerr << name << endl; } \
    106113        NewPass(name);                          \
    107114        Stats::Time::StartBlock(name);          \
    108         pass;                                   \
    109         Stats::Time::StopBlock();
    110 
    111 LinkageSpec::Spec linkage = LinkageSpec::Cforall;
    112 TypedefTable typedefTable;
    113 DeclarationNode * parseTree = nullptr;                                  // program parse tree
     115        pass(unit,##__VA_ARGS__);               \
     116        Stats::Time::StopBlock();               \
     117        if ( invariant ) {                      \
     118                checkInvariants(unit);              \
     119        }
     120
     121#define DUMP( cond, unit )                  \
     122        if ( cond ) {                           \
     123                dump(unit);                         \
     124                return EXIT_SUCCESS;                \
     125        }
    114126
    115127static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
     
    118130
    119131static void parse_cmdline( int argc, char * argv[] );
    120 static void parse( FILE * input, LinkageSpec::Spec linkage, bool shouldExit = false );
    121132static void dump( list< Declaration * > & translationUnit, ostream & out = cout );
    122133static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
     
    234245        ostream * output = & cout;
    235246        list< Declaration * > translationUnit;
     247        ast::TranslationUnit transUnit;
    236248
    237249        Signal( SIGSEGV, sigSegvBusHandler, SA_SIGINFO );
     
    278290                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" );
    279291                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
    280                         parse( gcc_builtins, LinkageSpec::Compiler );
     292                        parse( gcc_builtins, ast::Linkage::Compiler );
    281293
    282294                        // read the extra prelude in, if not generating the cfa library
    283295                        FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" );
    284296                        assertf( extras, "cannot open extras.cf\n" );
    285                         parse( extras, LinkageSpec::BuiltinC );
     297                        parse( extras, ast::Linkage::BuiltinC );
    286298
    287299                        if ( ! libcfap ) {
     
    289301                                FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" );
    290302                                assertf( prelude, "cannot open prelude.cfa\n" );
    291                                 parse( prelude, LinkageSpec::Intrinsic );
     303                                parse( prelude, ast::Linkage::Intrinsic );
    292304
    293305                                // Read to cfa builtins, if not generating the cfa library
    294306                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" );
    295307                                assertf( builtins, "cannot open builtins.cf\n" );
    296                                 parse( builtins, LinkageSpec::BuiltinCFA );
    297                         } // if
    298                 } // if
    299 
    300                 parse( input, libcfap ? LinkageSpec::Intrinsic : LinkageSpec::Cforall, yydebug );
    301 
    302                 if ( parsep ) {
    303                         parseTree->printList( cout );
    304                         delete parseTree;
    305                         return EXIT_SUCCESS;
    306                 } // if
    307 
    308                 buildList( parseTree, translationUnit );
    309                 delete parseTree;
    310                 parseTree = nullptr;
    311 
    312                 if ( astp ) {
    313                         dump( translationUnit );
    314                         return EXIT_SUCCESS;
    315                 } // if
    316 
    317                 // Temporary: fill locations after parsing so that every node has a location, for early error messages.
    318                 // Eventually we should pass the locations from the parser to every node, but this quick and dirty solution
    319                 // works okay for now.
    320                 CodeTools::fillLocations( translationUnit );
     308                                parse( builtins, ast::Linkage::BuiltinCFA );
     309                        } // if
     310                } // if
     311
     312                parse( input, libcfap ? ast::Linkage::Intrinsic : ast::Linkage::Cforall, yydebug );
     313
     314                transUnit = buildUnit();
     315
     316                DUMP( astp, std::move( transUnit ) );
     317
    321318                Stats::Time::StopBlock();
    322319
     
    325322                        ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");
    326323                }
    327                 auto transUnit = convert( std::move( translationUnit ) );
    328 
    329                 forceFillCodeLocations( transUnit );
    330 
    331                 PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) );
    332                 if ( exdeclp ) {
    333                         dump( std::move( transUnit ) );
    334                         return EXIT_SUCCESS;
    335                 }
    336 
    337                 PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) );
    338                 PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) );
    339                 // Hoist Type Decls pulls some declarations out of contexts where
    340                 // locations are not tracked. Perhaps they should be, but for now
    341                 // the full fill solves it.
    342                 forceFillCodeLocations( transUnit );
    343 
    344                 PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) );
    345                 PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
    346                 PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
    347 
    348                 PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) );
    349 
    350                 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
    351                 PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
    352                 PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
    353                 PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) );
    354                 PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) );
    355                 PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) );
    356                 PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) );
    357                 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
    358                 PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
    359                 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
    360 
    361                 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
    362 
    363                 PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
    364                 PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
    365                 PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) );
    366                 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
    367                 PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
    368                 PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) );
     324
     325                PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
     326
     327                PASS( "Translate Exception Declarations", ControlStruct::translateExcept, transUnit );
     328                DUMP( exdeclp, std::move( transUnit ) );
     329                PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign, transUnit );
     330                PASS( "Replace Typedefs", Validate::replaceTypedef, transUnit );
     331                PASS( "Fix Return Types", Validate::fixReturnTypes, transUnit );
     332                PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers, transUnit );
     333
     334                PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit );
     335
     336                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
     337                PASS( "Hoist Struct", Validate::hoistStruct, transUnit );
     338                PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
     339                PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit );
     340                PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit );
     341                PASS( "Check Function Returns", Validate::checkReturnStatements, transUnit );
     342                PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit );
     343                PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
     344                PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
     345        PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
     346                PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
     347
     348                PASS( "Generate Autogen Routines", Validate::autogenerateRoutines, transUnit );
     349
     350                PASS( "Implement Actors", Concurrency::implementActors, transUnit );
     351                PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors, transUnit );
     352                PASS( "Implement Mutex", Concurrency::implementMutex, transUnit );
     353                PASS( "Implement Thread Start", Concurrency::implementThreadStarter, transUnit );
     354                PASS( "Compound Literal", Validate::handleCompoundLiterals, transUnit );
     355                PASS( "Set Length From Initializer", Validate::setLengthFromInitializer, transUnit );
     356                PASS( "Find Global Decls", Validate::findGlobalDecls, transUnit );
     357                PASS( "Fix Label Address", Validate::fixLabelAddresses, transUnit );
    369358
    370359                if ( symtabp ) {
     
    377366                } // if
    378367
    379                 if ( validp ) {
    380                         dump( std::move( transUnit ) );
    381                         return EXIT_SUCCESS;
    382                 } // if
    383 
    384                 PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
    385                 PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
    386                 PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
    387                 PASS( "Gen Init", InitTweak::genInit( transUnit ) );
    388                 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
     368                DUMP( validp, std::move( transUnit ) );
     369
     370                PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
     371                PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
     372                PASS( "Fix Names", CodeGen::fixNames, transUnit );
     373                PASS( "Gen Init", InitTweak::genInit, transUnit );
     374                PASS( "Expand Member Tuples" , Tuples::expandMemberTuples, transUnit );
    389375
    390376                if ( libcfap ) {
     
    398384                } // if
    399385
    400                 if ( bresolvep ) {
    401                         dump( std::move( transUnit ) );
    402                         return EXIT_SUCCESS;
    403                 } // if
     386                DUMP( bresolvep, std::move( transUnit ) );
    404387
    405388                if ( resolvprotop ) {
     
    408391                } // if
    409392
    410                 PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    411                 if ( exprp ) {
    412                         dump( std::move( transUnit ) );
    413                         return EXIT_SUCCESS;
    414                 } // if
    415 
    416                 forceFillCodeLocations( transUnit );
    417 
    418                 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
     393                PASS( "Resolve", ResolvExpr::resolve, transUnit );
     394                DUMP( exprp, std::move( transUnit ) );
     395
     396                PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
    419397
    420398                // fix ObjectDecl - replaces ConstructorInit nodes
    421                 if ( ctorinitp ) {
    422                         dump( std::move( transUnit ) );
    423                         return EXIT_SUCCESS;
    424                 } // if
     399                DUMP( ctorinitp, std::move( transUnit ) );
    425400
    426401                // Currently not working due to unresolved issues with UniqueExpr
    427                 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    428 
    429                 PASS( "Translate Tries", ControlStruct::translateTries( transUnit ) );
    430                 PASS( "Gen Waitfor", Concurrency::generateWaitFor( transUnit ) );
     402                PASS( "Expand Unique Expr", Tuples::expandUniqueExpr, transUnit ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
     403
     404                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
     405                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
    431406
    432407                // Needs to happen before tuple types are expanded.
    433                 PASS( "Convert Specializations",  GenPoly::convertSpecializations( transUnit ) );
    434 
    435                 PASS( "Expand Tuples", Tuples::expandTuples( transUnit ) );
    436 
    437                 if ( tuplep ) {
    438                         dump( std::move( transUnit ) );
    439                         return EXIT_SUCCESS;
    440                 } // if
     408                PASS( "Convert Specializations",  GenPoly::convertSpecializations, transUnit );
     409
     410                PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
     411                DUMP( tuplep, std::move( transUnit ) );
    441412
    442413                // Must come after Translate Tries.
    443                 PASS( "Virtual Expand Casts", Virtual::expandCasts( transUnit ) );
    444 
    445                 PASS( "Instantiate Generics", GenPoly::instantiateGeneric( transUnit ) );
    446                 if ( genericsp ) {
    447                         dump( std::move( transUnit ) );
    448                         return EXIT_SUCCESS;
    449                 } // if
    450 
    451                 PASS( "Convert L-Value", GenPoly::convertLvalue( transUnit ) );
     414                PASS( "Virtual Expand Casts", Virtual::expandCasts, transUnit );
     415
     416                PASS( "Instantiate Generics", GenPoly::instantiateGeneric, transUnit );
     417                DUMP( genericsp, std::move( transUnit ) );
     418
     419                PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit );
    452420
    453421                translationUnit = convert( std::move( transUnit ) );
    454422
    455                 if ( bboxp ) {
    456                         dump( translationUnit );
    457                         return EXIT_SUCCESS;
    458                 } // if
    459                 PASS( "Box", GenPoly::box( translationUnit ) );
    460 
    461                 PASS( "Link-Once", CodeGen::translateLinkOnce( translationUnit ) );
     423                DUMP( bboxp, translationUnit );
     424                PASS( "Box", GenPoly::box, translationUnit );
     425
     426                PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit );
    462427
    463428                // Code has been lowered to C, now we can start generation.
    464429
    465                 if ( bcodegenp ) {
    466                         dump( translationUnit );
    467                         return EXIT_SUCCESS;
    468                 } // if
     430                DUMP( bcodegenp, translationUnit );
    469431
    470432                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    473435
    474436                CodeTools::fillLocations( translationUnit );
    475                 PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
     437                PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
    476438
    477439                CodeGen::FixMain::fix( translationUnit, *output,
     
    483445                if ( errorp ) {
    484446                        cerr << "---AST at error:---" << endl;
    485                         dump( translationUnit, cerr );
     447                        // We check which section the errors came from without looking at
     448                        // transUnit because std::move means it could look like anything.
     449                        if ( !translationUnit.empty() ) {
     450                                dump( translationUnit, cerr );
     451                        } else {
     452                                dump( std::move( transUnit ), cerr );
     453                        }
    486454                        cerr << endl << "---End of AST, begin error message:---\n" << endl;
    487455                } // if
    488456                e.print();
    489                 if ( output != &cout ) {
    490                         delete output;
    491                 } // if
    492                 return EXIT_FAILURE;
    493         } catch ( UnimplementedError & e ) {
    494                 cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl;
    495                 if ( output != &cout ) {
    496                         delete output;
    497                 } // if
    498                 return EXIT_FAILURE;
    499         } catch ( CompilerError & e ) {
    500                 cerr << "Compiler Error: " << e.get_what() << endl;
    501                 cerr << "(please report bugs to [REDACTED])" << endl;
    502457                if ( output != &cout ) {
    503458                        delete output;
     
    528483
    529484
    530 static const char optstring[] = ":c:ghlLmNnpdP:S:twW:D:";
     485static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
    531486
    532487enum { PreludeDir = 128 };
     
    535490        { "gdb", no_argument, nullptr, 'g' },
    536491        { "help", no_argument, nullptr, 'h' },
     492        { "invariant", no_argument, nullptr, 'i' },
    537493        { "libcfa", no_argument, nullptr, 'l' },
    538494        { "linemarks", no_argument, nullptr, 'L' },
    539         { "no-main", no_argument, 0, 'm' },
     495        { "no-main", no_argument, nullptr, 'm' },
    540496        { "no-linemarks", no_argument, nullptr, 'N' },
    541497        { "no-prelude", no_argument, nullptr, 'n' },
     
    556512        "wait for gdb to attach",                                                       // -g
    557513        "print translator help message",                                        // -h
     514        "invariant checking during AST passes",                         // -i
    558515        "generate libcfa.c",                                                            // -l
    559516        "generate line marks",                                                          // -L
     
    587544        { "rproto", resolvprotop, true, "resolver-proto instance" },
    588545        { "rsteps", resolvep, true, "print resolver steps" },
    589         { "tree", parsep, true, "print parse tree" },
    590546        // code dumps
    591547        { "ast", astp, true, "print AST after parsing" },
     
    650606                        usage( argv );                                                          // no return
    651607                        break;
     608                  case 'i':                                                                             // invariant checking
     609                        invariant = true;
     610                        break;
    652611                  case 'l':                                                                             // generate libcfa.c
    653612                        libcfap = true;
     
    748707} // parse_cmdline
    749708
    750 static void parse( FILE * input, LinkageSpec::Spec linkage, bool shouldExit ) {
    751         extern int yyparse( void );
    752         extern FILE * yyin;
    753         extern int yylineno;
    754 
    755         ::linkage = linkage;                                                            // set globals
    756         yyin = input;
    757         yylineno = 1;
    758         int parseStatus = yyparse();
    759 
    760         fclose( input );
    761         if ( shouldExit || parseStatus != 0 ) {
    762                 exit( parseStatus );
    763         } // if
    764 } // parse
    765 
    766709static bool notPrelude( Declaration * decl ) {
    767710        return ! LinkageSpec::isBuiltin( decl->get_linkage() );
  • tests/.expect/PRNG.x64.txt

    r34b4268 r24d6572  
    11
    2        PRNG()   PRNG(5)    PRNG(0,5)
    3           861         3            0
    4 10137507171299805328         1            2
    5 12205946788447993741         4            0
    6 16222929371023265189         2            5
    7 11921944259646500358         1            1
    8 9511863719043198063         2            0
    9 18170109536749574203         0            1
    10 15896208456307578543         0            3
    11 4171113079117645375         1            4
    12 5535309872453329531         1            1
    13 13293369315461644140         2            2
    14 855811942427900360         1            1
    15 9125507373316195824         1            5
    16 6942856496042419510         1            5
    17 16774706561877323900         2            4
    18 17765436951300330249         4            0
    19 3766082030894719812         1            2
    20 15818141700523398820         3            5
    21 1244962761353699441         0            5
    22 4506898200126256218         1            2
     2CFA xoshiro256pp
     3
     4                    PRNG()     PRNG(5)   PRNG(0,5)
     5      13944458589275087071           3           2
     6        129977468648444256           0           4
     7       2357727400298891021           2           2
     8       8855179187835660146           3           3
     9       9957620185645882382           4           1
     10      13396406983727409795           0           5
     11       3342782395220265920           0           5
     12       1707651271867677937           1           0
     13      16402561450140881681           0           1
     14      17838519215740313729           4           2
     15       7425936020594490136           4           0
     16       4174865704721714670           3           5
     17      16055269689200152092           0           2
     18      15091270195803594018           1           5
     19      11807315541476180798           1           1
     20      10697186588988060306           4           1
     21      14665526411527044929           3           2
     22      11289342279096164771           2           5
     23      16126980828050300615           1           4
     24       7821578301767524260           4           1
    2325seed 1009
    2426
    2527Sequential
    26 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
     28trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    2729
    2830Concurrent
    29 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    30 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    31 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    32 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
     31trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     32trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     33trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     34trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    3335
    34        prng()   prng(5)    prng(0,5)
    35           861         3            0
    36 10137507171299805328         1            2
    37 12205946788447993741         4            0
    38 16222929371023265189         2            5
    39 11921944259646500358         1            1
    40 9511863719043198063         2            0
    41 18170109536749574203         0            1
    42 15896208456307578543         0            3
    43 4171113079117645375         1            4
    44 5535309872453329531         1            1
    45 13293369315461644140         2            2
    46 855811942427900360         1            1
    47 9125507373316195824         1            5
    48 6942856496042419510         1            5
    49 16774706561877323900         2            4
    50 17765436951300330249         4            0
    51 3766082030894719812         1            2
    52 15818141700523398820         3            5
    53 1244962761353699441         0            5
    54 4506898200126256218         1            2
     36                    prng()     prng(5)   prng(0,5)
     37      13944458589275087071           3           2
     38        129977468648444256           0           4
     39       2357727400298891021           2           2
     40       8855179187835660146           3           3
     41       9957620185645882382           4           1
     42      13396406983727409795           0           5
     43       3342782395220265920           0           5
     44       1707651271867677937           1           0
     45      16402561450140881681           0           1
     46      17838519215740313729           4           2
     47       7425936020594490136           4           0
     48       4174865704721714670           3           5
     49      16055269689200152092           0           2
     50      15091270195803594018           1           5
     51      11807315541476180798           1           1
     52      10697186588988060306           4           1
     53      14665526411527044929           3           2
     54      11289342279096164771           2           5
     55      16126980828050300615           1           4
     56       7821578301767524260           4           1
    5557seed 1009
    5658
    5759Sequential
    58 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
     60trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    5961
    6062Concurrent
    61 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    62 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    63 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    64 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
     63trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     64trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     65trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     66trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    6567
    66       prng(t) prng(t,5) prng(t,0,5)
    67           861         3            0
    68 10137507171299805328         1            2
    69 12205946788447993741         4            0
    70 16222929371023265189         2            5
    71 11921944259646500358         1            1
    72 9511863719043198063         2            0
    73 18170109536749574203         0            1
    74 15896208456307578543         0            3
    75 4171113079117645375         1            4
    76 5535309872453329531         1            1
    77 13293369315461644140         2            2
    78 855811942427900360         1            1
    79 9125507373316195824         1            5
    80 6942856496042419510         1            5
    81 16774706561877323900         2            4
    82 17765436951300330249         4            0
    83 3766082030894719812         1            2
    84 15818141700523398820         3            5
    85 1244962761353699441         0            5
    86 4506898200126256218         1            2
     68                   prng(t)   prng(t,5) prng(t,0,5)
     69      13944458589275087071           3           2
     70        129977468648444256           0           4
     71       2357727400298891021           2           2
     72       8855179187835660146           3           3
     73       9957620185645882382           4           1
     74      13396406983727409795           0           5
     75       3342782395220265920           0           5
     76       1707651271867677937           1           0
     77      16402561450140881681           0           1
     78      17838519215740313729           4           2
     79       7425936020594490136           4           0
     80       4174865704721714670           3           5
     81      16055269689200152092           0           2
     82      15091270195803594018           1           5
     83      11807315541476180798           1           1
     84      10697186588988060306           4           1
     85      14665526411527044929           3           2
     86      11289342279096164771           2           5
     87      16126980828050300615           1           4
     88       7821578301767524260           4           1
    8789seed 1009
    8890
    8991Sequential
    90 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
     92trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    9193
    9294Concurrent
    93 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    94 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    95 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
    96 trials 100000000 buckets 100000 min 875 max 1138 avg 1000.0 std 31.8 rstd 3.2%
     95trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     96trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     97trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     98trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
  • tests/.expect/PRNG.x86.txt

    r34b4268 r24d6572  
    11
    2        PRNG()   PRNG(5)    PRNG(0,5)
    3       8333105         1            2
    4    1989339636         4            5
    5     266970699         3            2
    6    1928130121         3            4
    7    1351003938         4            5
    8    1624164922         4            3
    9     363429604         1            2
    10    3355083174         1            1
    11     214422584         1            1
    12    2266729947         1            2
    13    3649702519         2            4
    14    2250875012         2            4
    15    4184653025         1            3
    16    2640851227         2            5
    17     206468178         2            3
    18    2600873108         1            3
    19    3007574582         3            3
    20     394476790         0            2
    21    1312145388         1            5
    22    2989081290         2            4
     2CFA xoshiro128pp
     3
     4                    PRNG()     PRNG(5)   PRNG(0,5)
     5                2884683541           0           0
     6                3465286746           2           4
     7                3268922916           0           1
     8                2396374907           3           0
     9                2135076892           4           1
     10                 944377718           3           1
     11                2204845346           3           3
     12                3736609533           0           4
     13                4063231336           0           2
     14                1075394776           0           2
     15                 712844808           4           0
     16                4246343110           3           1
     17                3793873837           2           1
     18                3690340337           1           4
     19                 319207944           1           4
     20                1815791072           3           5
     21                2581617261           1           5
     22                3873329448           1           3
     23                 832631329           4           0
     24                 651551615           3           5
    2325seed 1009
    2426
    2527Sequential
    26 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
     28trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    2729
    2830Concurrent
    29 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    30 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    31 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    32 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
     31trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     32trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     33trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     34trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    3335
    34        prng()   prng(5)    prng(0,5)
    35       8333105         1            2
    36    1989339636         4            5
    37     266970699         3            2
    38    1928130121         3            4
    39    1351003938         4            5
    40    1624164922         4            3
    41     363429604         1            2
    42    3355083174         1            1
    43     214422584         1            1
    44    2266729947         1            2
    45    3649702519         2            4
    46    2250875012         2            4
    47    4184653025         1            3
    48    2640851227         2            5
    49     206468178         2            3
    50    2600873108         1            3
    51    3007574582         3            3
    52     394476790         0            2
    53    1312145388         1            5
    54    2989081290         2            4
     36                    prng()     prng(5)   prng(0,5)
     37                2884683541           0           0
     38                3465286746           2           4
     39                3268922916           0           1
     40                2396374907           3           0
     41                2135076892           4           1
     42                 944377718           3           1
     43                2204845346           3           3
     44                3736609533           0           4
     45                4063231336           0           2
     46                1075394776           0           2
     47                 712844808           4           0
     48                4246343110           3           1
     49                3793873837           2           1
     50                3690340337           1           4
     51                 319207944           1           4
     52                1815791072           3           5
     53                2581617261           1           5
     54                3873329448           1           3
     55                 832631329           4           0
     56                 651551615           3           5
    5557seed 1009
    5658
    5759Sequential
    58 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
     60trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    5961
    6062Concurrent
    61 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    62 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    63 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    64 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
     63trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     64trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     65trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     66trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    6567
    66       prng(t) prng(t,5) prng(t,0,5)
    67       8333105         1            2
    68    1989339636         4            5
    69     266970699         3            2
    70    1928130121         3            4
    71    1351003938         4            5
    72    1624164922         4            3
    73     363429604         1            2
    74    3355083174         1            1
    75     214422584         1            1
    76    2266729947         1            2
    77    3649702519         2            4
    78    2250875012         2            4
    79    4184653025         1            3
    80    2640851227         2            5
    81     206468178         2            3
    82    2600873108         1            3
    83    3007574582         3            3
    84     394476790         0            2
    85    1312145388         1            5
    86    2989081290         2            4
     68                   prng(t)   prng(t,5) prng(t,0,5)
     69                2884683541           0           0
     70                3465286746           2           4
     71                3268922916           0           1
     72                2396374907           3           0
     73                2135076892           4           1
     74                 944377718           3           1
     75                2204845346           3           3
     76                3736609533           0           4
     77                4063231336           0           2
     78                1075394776           0           2
     79                 712844808           4           0
     80                4246343110           3           1
     81                3793873837           2           1
     82                3690340337           1           4
     83                 319207944           1           4
     84                1815791072           3           5
     85                2581617261           1           5
     86                3873329448           1           3
     87                 832631329           4           0
     88                 651551615           3           5
    8789seed 1009
    8890
    8991Sequential
    90 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
     92trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    9193
    9294Concurrent
    93 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    94 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    95 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
    96 trials 100000000 buckets 100000 min 873 max 1140 avg 1000.0 std 31.3 rstd 3.1%
     95trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     96trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     97trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     98trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
  • tests/.expect/array.txt

    r34b4268 r24d6572  
    1 array.cfa:52:25: warning: Compiled
     1array.cfa:119:25: warning: Preprocessor started
  • tests/.expect/attributes.arm64.txt

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

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

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

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

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

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

    r34b4268 r24d6572  
    1 forall.cfa:244:25: warning: Compiled
     11
     2f
     397
     4f
     5g
     6f
     7f
     8g
     9fT
     10fT
     11fT
     12fTU
     13fTU
     14fTU
     151 2
     162 1
     171, 2
     18@ 0 2 0 4 6.4 6.4 6.4 6.4+3.i 4
     193. 3.
     2045
     2112 3
  • tests/.expect/nested_function.x64.txt

    r34b4268 r24d6572  
    1 total 80
     1total 145
  • tests/.expect/nested_function.x86.txt

    r34b4268 r24d6572  
    1 total 55
     1total 245
  • tests/Makefile.am

    r34b4268 r24d6572  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Jun  5 14:49:25 2021
    14 ## Update Count     : 92
     13## Last Modified On : Sun May 28 08:15:43 2023
     14## Update Count     : 196
    1515###############################################################################
    1616
     
    2222DEFAULT_INCLUDES = -I${abs_srcdir}
    2323
    24 debug=yes
    25 installed=no
    26 archiveerrors=
    27 
    28 DEBUG_FLAGS=-debug -g -O0
    29 
    30 quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes meta/dumpable
    31 
    32 concurrent=
    33 timeouts=
     24debug ?= yes
     25installed ?= no
     26ARCH = ${if ${arch},"--arch=${arch}"}
     27arch_support = "x86/x64/arm"
     28TIMEOUT = ${if ${timeout},"--timeout=${timeout}"}
     29GLOBAL_TIMEOUT = ${if ${global-timeout},"--global-timeout=${global-timeout}"}
     30ARCHIVE_ERRORS = ${if ${archive-errors},"--archive-errors=${archive-errors}"}
     31
     32DEBUG_FLAGS = -debug -g -O0
     33
     34quick_test = avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes meta/dumpable
    3435
    3536TEST_PY = python3 ${builddir}/test.py
     
    3738# applies to both programs
    3839# since automake doesn't have support for CFA we have to
    39 AM_CFLAGS = $(if $(test), 2> $(test), ) \
    40         -fdebug-prefix-map=$(abspath ${abs_srcdir})= \
     40AM_CFLAGS = ${if ${test}, 2> ${test}, } \
     41        -fdebug-prefix-map=${abspath ${abs_srcdir}}= \
    4142        -fdebug-prefix-map=/tmp= \
    4243        -fno-diagnostics-show-caret \
     
    5152
    5253# get the desired cfa to test
    53 TARGET_CFA = $(if $(filter $(installed),yes), @CFACC_INSTALL@, @CFACC@)
     54TARGET_CFA = ${if ${filter ${installed},yes}, @CFACC_INSTALL@, @CFACC@}
    5455
    5556# adjust CC to current flags
    56 CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS} ,$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    57 CFACC = $(CC)
     57CC = LC_ALL=C ${if ${DISTCC_CFA_PATH},distcc ${DISTCC_CFA_PATH} ${ARCH_FLAGS} ,${TARGET_CFA} ${DEBUG_FLAGS} ${ARCH_FLAGS}}
     58CFACC = ${CC}
    5859
    5960# get local binary for depedencies
     
    6162
    6263# adjusted CC but without the actual distcc call
    63 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS} ,$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    64 CFACCLINK = $(CFACCLOCAL) -quiet $(if $(test), 2> $(test), ) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g'))
    65 
    66 PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    67 
    68 .PHONY: list .validate .test_makeflags
    69 .INTERMEDIATE: .validate .validate.cfa .test_makeflags
     64CFACCLOCAL = ${if ${DISTCC_CFA_PATH},${DISTCC_CFA_PATH} ${ARCH_FLAGS} ,${TARGET_CFA} ${DEBUG_FLAGS} ${ARCH_FLAGS}}
     65CFACCLINK = ${CFACCLOCAL} -quiet ${if ${test}, 2> ${test}, } ${${shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g'}}
     66
     67PRETTY_PATH = mkdir -p ${dir ${abspath ${@}}} && cd ${srcdir} &&
     68
     69.PHONY : concurrency list .validate .test_makeflags
     70.INTERMEDIATE : .validate .validate.cfa .test_makeflags
    7071EXTRA_PROGRAMS = avl_test linkonce linking/mangling/anon .dummy_hack # build but do not install
    7172EXTRA_DIST = test.py \
     
    7879        avltree/avl-private.h \
    7980        avltree/avl.h \
    80         concurrent/clib_tls.c \
    81         concurrent/clib.c \
    8281        configs/.in/parseconfig-all.txt \
    8382        configs/.in/parseconfig-errors.txt \
     
    8887        io/.in/many_read.data \
    8988        meta/fork+exec.hfa \
    90         unified_locking/mutex_test.hfa
     89        concurrency/clib_tls.c \
     90        concurrency/clib.c \
     91        concurrency/unified_locking/mutex_test.hfa \
     92        concurrency/channels/parallel_harness.hfa
    9193
    9294dist-hook:
     
    9496        for file in `${TEST_PY} --list-dist`; do \
    9597                if test -f ${srcdir}/$${file}; then \
    96                         $(MKDIR_P) $$(dirname ${distdir}/$${file}); \
     98                        ${MKDIR_P} $$(dirname ${distdir}/$${file}); \
    9799                        cp -df ${srcdir}/$${file} ${distdir}/$${file}; \
    98100                fi; \
     
    106108
    107109#----------------------------------------------------------------------------------------------------------------
    108 all-local :
    109         @+${TEST_PY} --debug=${debug} --install=${installed} --archive-errors=${archiveerrors} ${concurrent} ${timeouts} ${quick_test}
    110 
    111 all-tests :
    112         @+${TEST_PY} --debug=${debug} --install=${installed} --archive-errors=${archiveerrors} ${concurrent} ${timeouts} --all # '@' => do not echo command (SILENT), '+' => allows recursive make from within python program
     110
     111# '@' => do not echo command (SILENT), '+' => allows recursive make from within python program
     112all-local : # This name is important to automake and implies the default build target.
     113        @+${TEST_PY} --debug=${debug} --install=${installed} --invariant ${ARCHIVE_ERRORS} ${TIMEOUT} ${GLOBAL_TIMEOUT} ${ARCH} --all
     114
     115tests : all-local # synonym
     116
     117install : all-local  # synonym, PAB only
     118
     119quick :
     120        @+${TEST_PY} --debug=${debug} --install=${installed} ${ARCHIVE_ERRORS} ${ARCH} ${quick_test}
     121
     122concurrency :
     123        @+${TEST_PY} --debug=${debug} --install=${installed} ${ARCHIVE_ERRORS} ${TIMEOUT} ${GLOBAL_TIMEOUT} ${ARCH} -Iconcurrency
     124
     125list :
     126        @+${TEST_PY} --list
     127
     128help :
     129        @echo "user targets:"
     130        @echo "    Run the complete test suite."
     131        @echo "    $$ make (null) / tests [debug=yes/no] [installed=yes/no] [archive-errors=dump-dir] [timeout=seconds] [global-timeout=seconds] [arch=${arch_support}]"
     132        @echo ""
     133        @echo "    Run the short (quick) test suite."
     134        @echo "    $$ make quick [debug=yes/no] [installed=yes/no] [archive-errors=dump-dir] [arch=${arch_support}]"
     135        @echo ""
     136        @echo "    Run the concurrency test suite."
     137        @echo "    $$ make concurrency [debug=yes/no] [installed=yes/no] [archive-errors=dump-dir] [timeout=seconds] [global-timeout=seconds] [arch=${arch_support}]"
     138        @echo ""
     139        @echo "    List all tests in the test suite."
     140        @echo "    $$ make list"
    113141
    114142mostlyclean-local :
     
    122150        find ${builddir} -path '*.Po' -delete
    123151
    124 list :
    125         @+${TEST_PY} --list ${concurrent}
    126 
    127152.test_makeflags:
    128153        @echo "${MAKEFLAGS}"
    129154
    130155.validate: .validate.cfa
    131         $(CFACOMPILE) .validate.cfa -fsyntax-only -Wall -Wextra -Werror
     156        ${CFACOMPILE} .validate.cfa -fsyntax-only -Wall -Wextra -Werror
    132157
    133158.validate.cfa:
     
    141166        @echo "int bar() { return 0; }" > ${@}
    142167
    143 concurrency :
    144         @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
    145 
    146168#----------------------------------------------------------------------------------------------------------------
    147169
    148170# Use for all tests, make sure the path are correct and all flags are added
    149 CFACOMPILETEST=$(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGSCFA" | sed 's/-\|\//_/g'))
     171CFACOMPILETEST=${PRETTY_PATH} ${CFACOMPILE} ${shell realpath --relative-to=${srcdir} ${<}} ${${shell echo "${@}_FLAGSCFA" | sed 's/-\|\//_/g'}}
    150172
    151173#----------------------------------------------------------------------------------------------------------------
     
    154176# split into two steps to support compiling remotely using distcc
    155177# don't use distcc to do the linking because distcc doesn't do linking
    156 % : %.cfa $(CFACCBIN)
    157         $(CFACOMPILETEST) -c -o $(abspath ${@}).o -DIN_DIR="$(abspath $(dir ${<}))/.in/"
    158         $(CFACCLINK) ${@}.o -o $(abspath ${@})
    159         rm $(abspath ${@}).o
     178% : %.cfa ${CFACCBIN}
     179        ${CFACOMPILETEST} -c -o ${abspath ${@}}.o -DIN_DIR="${abspath ${dir ${<}}}/.in/"
     180        ${CFACCLINK} ${@}.o -o ${abspath ${@}}
     181        rm ${abspath ${@}}.o
    160182
    161183# implicit rule for c++ test
    162184# convient for testing the testsuite itself but not actuall used
    163185% : %.cpp
    164         $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     186        ${PRETTY_PATH} ${CXXCOMPILE} ${shell realpath --relative-to=${srcdir} ${<}} -o ${abspath ${@}}
    165187
    166188#------------------------------------------------------------------------------
     
    173195# Generated code
    174196GENERATED_CODE = declarationSpecifier gccExtensions extension attributes functions KRfunctions
    175 $(GENERATED_CODE): % : %.cfa $(CFACCBIN)
    176         $(CFACOMPILETEST) -CFA -XCFA -p -c -fsyntax-only -o $(abspath ${@})
     197${GENERATED_CODE} : % : %.cfa ${CFACCBIN}
     198        ${CFACOMPILETEST} -CFA -XCFA -p -c -fsyntax-only -o ${abspath ${@}}
    177199
    178200#------------------------------------------------------------------------------
     
    180202#------------------------------------------------------------------------------
    181203# tests that just validate syntax and compiler output should be compared to stderr
    182 CFACOMPILE_SYNTAX = $(CFACOMPILETEST) -Wno-unused-variable -Wno-unused-label -c -fsyntax-only -o $(abspath ${@})
    183 
    184 SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator forall \
    185         init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment
    186 $(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    187         $(CFACOMPILE_SYNTAX)
    188         $(if $(test), cp $(test) $(abspath ${@}), )
     204CFACOMPILE_SYNTAX = ${CFACOMPILETEST} -Wno-unused-variable -Wno-unused-label -c -fsyntax-only -o ${abspath ${@}}
     205
     206SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator \
     207        init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment concurrency/waitfor/parse
     208${SYNTAX_ONLY_CODE} : % : %.cfa ${CFACCBIN}
     209        ${CFACOMPILE_SYNTAX}
     210        ${if ${test}, cp ${test} ${abspath ${@}}, }
    189211
    190212# expected failures
    191213# use custom target since they require a custom define *and* have a name that doesn't match the file
    192 alloc-ERROR : alloc.cfa $(CFACCBIN)
    193         $(CFACOMPILE_SYNTAX) -DERR1
    194         -cp $(test) $(abspath ${@})
    195 
    196 init1-ERROR : init1.cfa $(CFACCBIN)
    197         $(CFACOMPILE_SYNTAX) -DERR1
    198         -cp $(test) $(abspath ${@})
    199 
    200 typedefRedef-ERR1 : typedefRedef.cfa $(CFACCBIN)
    201         $(CFACOMPILE_SYNTAX) -DERR1
    202         -cp $(test) $(abspath ${@})
    203 
    204 nested-types-ERR1 : nested-types.cfa $(CFACCBIN)
    205         $(CFACOMPILE_SYNTAX) -DERR1
    206         -cp $(test) $(abspath ${@})
    207 
    208 nested-types-ERR2 : nested-types.cfa $(CFACCBIN)
    209         $(CFACOMPILE_SYNTAX) -DERR2
    210         -cp $(test) $(abspath ${@})
    211 
    212 raii/memberCtors-ERR1 : raii/memberCtors.cfa $(CFACCBIN)
    213         $(CFACOMPILE_SYNTAX) -DERR1
    214         -cp $(test) $(abspath ${@})
    215 
    216 raii/ctor-autogen-ERR1 : raii/ctor-autogen.cfa $(CFACCBIN)
    217         $(CFACOMPILE_SYNTAX) -DERR1
    218         -cp $(test) $(abspath ${@})
    219 
    220 raii/dtor-early-exit-ERR1 : raii/dtor-early-exit.cfa $(CFACCBIN)
    221         $(CFACOMPILE_SYNTAX) -DERR1
    222         -cp $(test) $(abspath ${@})
    223 
    224 raii/dtor-early-exit-ERR2 : raii/dtor-early-exit.cfa $(CFACCBIN)
    225         $(CFACOMPILE_SYNTAX) -DERR2
    226         -cp $(test) $(abspath ${@})
     214
     215array-ERR1 : array.cfa ${CFACCBIN}
     216        ${CFACOMPILE_SYNTAX} -DERR1
     217        -cp ${test} ${abspath ${@}}
     218
     219array-ERR2 : array.cfa ${CFACCBIN}
     220        ${CFACOMPILE_SYNTAX} -DERR2
     221        -cp ${test} ${abspath ${@}}
     222
     223array-ERR3 : array.cfa ${CFACCBIN}
     224        ${CFACOMPILE_SYNTAX} -DERR3
     225        -cp ${test} ${abspath ${@}}
     226
     227alloc-ERROR : alloc.cfa ${CFACCBIN}
     228        ${CFACOMPILE_SYNTAX} -DERR1
     229        -cp ${test} ${abspath ${@}}
     230
     231init1-ERROR : init1.cfa ${CFACCBIN}
     232        ${CFACOMPILE_SYNTAX} -DERR1
     233        -cp ${test} ${abspath ${@}}
     234
     235typedefRedef-ERR1 : typedefRedef.cfa ${CFACCBIN}
     236        ${CFACOMPILE_SYNTAX} -DERR1
     237        -cp ${test} ${abspath ${@}}
     238
     239nested-types-ERR1 : nested-types.cfa ${CFACCBIN}
     240        ${CFACOMPILE_SYNTAX} -DERR1
     241        -cp ${test} ${abspath ${@}}
     242
     243nested-types-ERR2 : nested-types.cfa ${CFACCBIN}
     244        ${CFACOMPILE_SYNTAX} -DERR2
     245        -cp ${test} ${abspath ${@}}
     246
     247raii/memberCtors-ERR1 : raii/memberCtors.cfa ${CFACCBIN}
     248        ${CFACOMPILE_SYNTAX} -DERR1
     249        -cp ${test} ${abspath ${@}}
     250
     251raii/ctor-autogen-ERR1 : raii/ctor-autogen.cfa ${CFACCBIN}
     252        ${CFACOMPILE_SYNTAX} -DERR1
     253        -cp ${test} ${abspath ${@}}
     254
     255raii/dtor-early-exit-ERR1 : raii/dtor-early-exit.cfa ${CFACCBIN}
     256        ${CFACOMPILE_SYNTAX} -DERR1
     257        -cp ${test} ${abspath ${@}}
     258
     259raii/dtor-early-exit-ERR2 : raii/dtor-early-exit.cfa ${CFACCBIN}
     260        ${CFACOMPILE_SYNTAX} -DERR2
     261        -cp ${test} ${abspath ${@}}
    227262
    228263# Exception Tests
    229264# Test with libcfathread; it changes how storage works.
    230265
    231 exceptions/%-threads : exceptions/%.cfa $(CFACCBIN)
    232         $(CFACOMPILETEST) -include exceptions/with-threads.hfa -c -o $(abspath ${@}).o
    233         $(CFACCLOCAL) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) $(abspath ${@}).o -o $(abspath ${@})
     266exceptions/%-threads : exceptions/%.cfa ${CFACCBIN}
     267        ${CFACOMPILETEST} -include exceptions/with-threads.hfa -c -o ${abspath ${@}}.o
     268        ${CFACCLOCAL} ${${shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g'}} ${abspath ${@}}.o -o ${abspath ${@}}
    234269
    235270# Linking tests
    236271# Meta tests to make sure we see linking errors (can't compile with -O2 since it may multiply number of calls)
    237 linking/linkerror : linking/linkerror.cfa $(CFACCBIN)
    238         $(CFACOMPILETEST) -O0 -c -o $(abspath ${@}).o
    239         $(CFACCLINK)  -O0 ${@}.o -o $(abspath ${@})
    240         rm $(abspath ${@}).o
     272linking/linkerror : linking/linkerror.cfa ${CFACCBIN}
     273        ${CFACOMPILETEST} -O0 -c -o ${abspath ${@}}.o
     274        ${CFACCLINK}  -O0 ${@}.o -o ${abspath ${@}}
     275        rm ${abspath ${@}}.o
    241276
    242277#------------------------------------------------------------------------------
  • tests/PRNG.cfa

    r34b4268 r24d6572  
    1 //                               -*- Mode: C -*-
    2 //
     1//
    32// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    4 //
    5 // PRNG.c --
    6 //
     3//
     4// PRNG.c -- high-perforamnce pseudo-random numbers
     5//
     6// The contents of this file are covered under the licence agreement in the
     7// file "LICENCE" distributed with Cforall.
     8//
    79// Author           : Peter A. Buhr
    810// Created On       : Wed Dec 29 09:38:12 2021
    911// Last Modified By : Peter A. Buhr
    10 // Last Modified On : Tue Nov 22 22:51:12 2022
    11 // Update Count     : 381
     12// Last Modified On : Thu May 25 15:39:52 2023
     13// Update Count     : 422
    1214//
    1315
     
    1517#include <stdlib.hfa>                                                                   // PRNG
    1618#include <clock.hfa>
    17 #include <thread.hfa>
    1819#include <limits.hfa>                                                                   // MAX
    1920#include <math.hfa>                                                                             // sqrt
    2021#include <malloc.h>                                                                             // malloc_stats
    2122#include <locale.h>                                                                             // setlocale
     23#include <thread.hfa>
    2224#include <mutex_stmt.hfa>
    2325
    24 #ifdef __x86_64__                                                                               // 64-bit architecture
     26#define xstr(s) str(s)
     27#define str(s) #s
     28
     29#if defined( __x86_64__ ) || defined( __aarch64__ )             // 64-bit architecture
    2530#define PRNG PRNG64
    2631#else                                                                                                   // 32-bit architecture
    2732#define PRNG PRNG32
    2833#endif // __x86_64__
     34
     35//#define TIME
    2936
    3037#ifdef TIME                                                                                             // use -O2 -nodebug
     
    3845#endif // TIME
    3946
    40 void avgstd( unsigned int buckets[] ) {
    41         unsigned int min = MAX, max = 0;
     47static void avgstd( size_t trials, size_t buckets[] ) {
     48        size_t min = MAX, max = 0;
    4249        double sum = 0.0, diff;
    4350        for ( i; BUCKETS ) {
     
    5461        } // for
    5562        double std = sqrt( sum / BUCKETS );
    56         mutex( sout ) sout | "trials"  | TRIALS | "buckets" | BUCKETS
     63        mutex( sout ) sout | "trials"  | trials | "buckets" | BUCKETS
    5764                | "min" | min | "max" | max
    5865                | "avg" | wd(0,1, avg) | "std" | wd(0,1, std) | "rstd" | wd(0,1, (avg == 0 ? 0.0 : std / avg * 100)) | "%";
     
    6067
    6168
    62 unsigned int seed = 1009;
     69size_t seed = 1009;
    6370
    6471thread T1 {};
    6572void main( T1 & ) {
    66         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    67         for ( TRIALS / 100 ) {
     73        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     74        for ( TRIALS / 50 ) {
    6875                buckets[rand() % BUCKETS] += 1;                                 // concurrent
    6976        } // for
    70         avgstd( buckets );
     77        avgstd( TRIALS / 50, buckets );
    7178        free( buckets );
    7279} // main
     
    7683        PRNG prng;
    7784        if ( seed != 0 ) set_seed( prng, seed );
    78         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     85        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    7986        for ( TRIALS ) {
    8087                buckets[prng( prng ) % BUCKETS] += 1;                   // concurrent
    8188        } // for
    82         avgstd( buckets );
     89        avgstd( TRIALS, buckets );
    8390        free( buckets );
    8491} // main
     
    8693thread T3 {};
    8794void main( T3 & th ) {
    88         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    89         for ( TRIALS ) {
     95        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     96        for ( TRIALS / 5 ) {
    9097                buckets[prng() % BUCKETS] += 1;                                 // concurrent
    9198        } // for
    92         avgstd( buckets );
     99        avgstd( TRIALS / 5, buckets );
    93100        free( buckets );
    94101} // main
     
    96103thread T4 {};
    97104void main( T4 & th ) {
    98         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     105        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    99106        for ( TRIALS ) {
    100                 buckets[prng( th ) % BUCKETS] += 1;     // concurrent
    101         } // for
    102         avgstd( buckets );
     107                buckets[prng( th ) % BUCKETS] += 1;                             // concurrent
     108        } // for
     109        avgstd( TRIALS, buckets );
    103110        free( buckets );
    104111} // main
     
    108115static void dummy( thread$ & th ) __attribute__(( noinline ));
    109116static void dummy( thread$ & th ) {
    110         unsigned int * buckets = (unsigned int *)calloc( BUCKETS, sizeof(unsigned int) ); // too big for task stack
    111         for ( unsigned int i = 0; i < TRIALS; i += 1 ) {
     117        size_t * buckets = (size_t *)calloc( BUCKETS, sizeof(size_t) ); // too big for task stack
     118        for ( size_t i = 0; i < TRIALS; i += 1 ) {
    112119                buckets[prng( th ) % BUCKETS] += 1;                             // sequential
    113120        } // for
    114         avgstd( buckets );
     121        avgstd( TRIALS, buckets );
    115122        free( buckets );
    116123} // dummy
    117124
     125
    118126int main() {
    119         // causes leaked storage message
    120 //      setlocale( LC_NUMERIC, getenv( "LANG" ) );                      // print digit separator
     127        // setlocale( LC_NUMERIC, getenv( "LANG" ) );           // causes leaked storage message
     128
     129        // only works on the current pthread thread
     130        // locale_t loc = newlocale( LC_NUMERIC_MASK, getenv( "LANG" ), (locale_t)0p );
     131        // if ( loc == (locale_t)0p ) abort( "newlocale" );
     132        // uselocale( loc );
    121133
    122134        enum { TASKS = 4 };
    123135        Time start;
     136
    124137#ifdef TIME                                                                                             // too slow for test and generates non-repeatable results
    125138#if 1
    126         unsigned int rseed;
     139        sout | "glib rand" | nl | nl;
     140
     141        size_t rseed;
    127142        if ( seed != 0 ) rseed = seed;
    128143        else rseed = rdtscl();
     
    130145
    131146        sout | sepDisable;
    132         sout | wd(13, "rand()" ) | wd(10, "rand(5)") | wd(13, "rand(0,5)" );
    133         for ( 20 ) {
    134                 sout | wd(13, rand()) | nonl;
    135                 sout | wd(10, rand() % 5) | nonl;
    136                 sout | wd(13, rand() % (5 - 0 + 1) + 0);
     147        sout | nl | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
     148        for ( 20 ) {
     149                sout | wd(26, rand()) | nonl;
     150                sout | wd(12, rand() % 5) | nonl;
     151                sout | wd(12, rand() % (5 - 0 + 1) + 0);
    137152        } // for
    138153        sout | sepEnable;
     
    142157        STARTTIME;
    143158        {
    144                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    145                 for ( i; TRIALS / 10 ) {
     159                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     160                for ( i; TRIALS / 5 ) {
    146161                        buckets[rand() % BUCKETS] += 1;                         // sequential
    147162                } // for
    148                 avgstd( buckets );
     163                avgstd( TRIALS / 5, buckets );
    149164                free( buckets );
    150165        }
    151         ENDTIME( " x 10 " );
     166        ENDTIME( " x 5 " );
    152167
    153168        sout | nl | "Concurrent";
     
    159174                } // wait for threads to complete
    160175        }
    161         ENDTIME( " x 100 " );
     176        ENDTIME( " x 50 " );
    162177#endif // 0
    163178#endif // TIME
     179
     180        sout | nl | "CFA " xstr(PRNG_NAME);
     181
    164182#if 1
    165183        PRNG prng;
     
    168186
    169187        sout | sepDisable;
    170         sout | nl | wd(13, "PRNG()" ) | wd(10, "PRNG(5)") | wd(13, "PRNG(0,5)" );
    171         for ( 20 ) {
    172                 sout | wd(13, prng( prng )) | nonl;                             // cascading => side-effect functions called in arbitary order
    173                 sout | wd(10, prng( prng, 5 )) | nonl;
    174                 sout | wd(13, prng( prng, 0, 5 ));
     188        sout | nl | wd(26, "PRNG()" ) | wd(12, "PRNG(5)") | wd(12, "PRNG(0,5)" );
     189        for ( 20 ) {
     190                sout | wd(26, prng( prng )) | nonl;                             // cascading => side-effect functions called in arbitary order
     191                sout | wd(12, prng( prng, 5 )) | nonl;
     192                sout | wd(12, prng( prng, 0, 5 ));
    175193        } // for
    176194        sout | sepEnable;
     
    180198        STARTTIME;
    181199        {
    182                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
     200                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
    183201                for ( TRIALS ) {
    184202                        buckets[prng( prng ) % BUCKETS] += 1;           // sequential
    185203                } // for
    186                 avgstd( buckets );
     204                avgstd( TRIALS, buckets );
    187205                free( buckets );
    188206        }
     
    203221
    204222        sout | sepDisable;
    205         sout | nl | wd(13, "prng()" ) | wd(10, "prng(5)") | wd(13, "prng(0,5)" );
    206         for ( 20 ) {
    207                 sout | wd(13, prng()) | nonl;                                   // cascading => side-effect functions called in arbitary order
    208                 sout | wd(10, prng( 5 )) | nonl;
    209                 sout | wd(13, prng( 0, 5 ));
     223        sout | nl | wd(26, "prng()" ) | wd(12, "prng(5)") | wd(12, "prng(0,5)" );
     224        for ( 20 ) {
     225                sout | wd(26, prng()) | nonl;                                   // cascading => side-effect functions called in arbitary order
     226                sout | wd(12, prng( 5 )) | nonl;
     227                sout | wd(12, prng( 0, 5 ));
    210228        } // for
    211229        sout | sepEnable;
     
    215233        STARTTIME;
    216234        {
    217                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    218                 for ( TRIALS ) {
     235                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     236                for ( TRIALS / 5 ) {
    219237                        buckets[prng() % BUCKETS] += 1;
    220238                } // for
    221                 avgstd( buckets );
     239                avgstd( TRIALS / 5, buckets );
    222240                free( buckets );
    223241        }
    224         ENDTIME();
     242        ENDTIME( " x 5 " );
    225243
    226244        sout | nl | "Concurrent";
     
    232250                } // wait for threads to complete
    233251        }
    234         ENDTIME();
     252        ENDTIME( " x 5 " );
    235253#endif // 0
    236254#if 1
     
    239257
    240258        sout | sepDisable;
    241         sout | nl | wd(13, "prng(t)" ) | wd(10, "prng(t,5)") | wd(13, "prng(t,0,5)" );
    242         for ( 20 ) {
    243                 sout | wd(13, prng( th )) | nonl;                               // cascading => side-effect functions called in arbitary order
    244                 sout | wd(10, prng( th, 5 )) | nonl;
    245                 sout | wd(13, prng( th, 0, 5 ));
     259        sout | nl | wd(26, "prng(t)" ) | wd(12, "prng(t,5)") | wd(12, "prng(t,0,5)" );
     260        for ( 20 ) {
     261                sout | wd(26, prng( th )) | nonl;                               // cascading => side-effect functions called in arbitary order
     262                sout | wd(12, prng( th, 5 )) | nonl;
     263                sout | wd(12, prng( th, 0, 5 ));
    246264        } // for
    247265        sout | sepEnable;
     
    266284#endif // 0
    267285//      malloc_stats();
     286        // freelocale( loc );
    268287} // main
    269288
  • tests/array.cfa

    r34b4268 r24d6572  
    1515//
    1616
    17 int a1[0];
    18 //int a2[*];
    19 //double a4[3.0];
     17// Tests syntax.  Comments explain semantics.  Test does not show semantics.
     18// Mostly illustrates facts about C (with which CFA is being tested to agree).
     19// Is a test oracle under `gcc -x c`.
    2020
    21 int m1[0][3];
    22 //int m2[*][*];
    23 int m4[3][3];
     21#ifdef ERR1
     22#define E1(...) __VA_ARGS__
     23#else
     24#define E1(...)
     25#endif
    2426
    25 typedef int T;
     27#ifdef ERR2
     28#define E2(...) __VA_ARGS__
     29#else
     30#define E2(...)
     31#endif
    2632
    27 int fred() {
    28 //      int a1[];
    29 //      int a2[*];
    30         int a4[3];
    31         int T[3];
    32 }
     33#ifdef ERR3
     34#define E3(...) __VA_ARGS__
     35#else
     36#define E3(...)
     37#endif
    3338
    34 int mary( int T[3],
    35                   int p1[const 3],
    36                   int p2[static 3],
    37                   int p3[static const 3]
    38         ) {
    39 }
     39    int a1[0];
     40E1( int a2[*];       )
     41                                                        #ifndef __cforall
     42E1( double a4[3.0];  )                                  // BUG 275: CFA accepts but should reject
     43                                                        #endif
    4044
    41 int (*tom())[3] {
    42 }
     45    int m1[0][3];
     46E1( int m2[*][*];    )
     47    int m4[3][3];
    4348
    44 int (*(jane)())( int T[3],
    45                                  int p1[const 3],
    46                                  int p2[static 3],
    47                                  int p3[static const 3]
    48         ) {
    49 }
     49    typedef int T;
     50
     51    int fred(int n) {
     52E1(     int a1[];    )
     53E1(     int a2[*];   )
     54        int a4[3];
     55        int T[3];
     56        int a5[n];
     57    }
     58
     59    int mary( int T[3],                                 // same as: int *T
     60              int p1[const 3],                          // same as: int const *p1
     61              int p2[static 3],                         // same as T, but length >=3 checked
     62              int p3[static const 3]                    // both above: 3 is static, p3 is const
     63        ) {
     64    }
     65
     66    // function taking (), returning pointer to array of ints
     67    int (*tom())[3] {
     68    }
     69
     70    // function taking (), returning pointer to function of same type as mary
     71    int (*(jane)())( int T[3],
     72                     int p1[const 3],
     73                     int p2[static 3],
     74                     int p3[static const 3]
     75        ) {
     76    }
     77
     78    // functions returning same exotic pointers, in CFA's non-onion syntax
     79    #ifdef __cforall
     80    [ * [3] int ] toms_twin(...) {
     81    }
     82    [ * [int]( [3] int T,
     83               [const 3] int p1,
     84               [static 3] int p2,
     85               [static const 3] int p3
     86             )
     87    ] janes_twin(...) {
     88    }
     89    #endif
     90
     91    // GCC 11+ gives a false warning (-Wvla-parameter) on the valid (C11 ARM p134-135) combination:
     92    // declare with type int[*], define with type int[n].
     93    // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=100420 suggests the internal representation of
     94    // of a[*] is the same as a[0].
     95    // https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wno-vla-parameter explains
     96    // the purpose of -Wvla-parameter is to report conflicts between int[] and int[n], which would
     97    // understandably also include those between int[42] and int[n].
     98    // https://stackoverflow.com/questions/17371645/why-use-an-asterisk-instead-of-an-integer-for-a-vla-array-parameter-of-a-f
     99    // explains the declare-*, define-n pattern.
     100
     101    // To work around the false warning, and keep to this test's purpose of exercising CFA's
     102    // handling of exotic C array syntax, what would ideally be demonstrated as a declaration of
     103    // fm1, followed by its definition, is instead split into fm1x and fm1y.  And similarly for
     104    // fm5.
     105
     106    int fm1x( int, int, int[][*] );
     107    int fm1y( int r, int c, int m[][c] ) {}
     108    int fm2( int r, int c, int (*m)[c] ) {}             // same as fm1
     109E2( int fm3( int r, int c, int m[][static c] ) {}  )    // that's not static
     110E3( int fm4( int r, int c, int m[][] );            )    // m's immediate element type is incomplete
     111    int fm5x( int, int, int[*][*] );                    // same as fm1 decl
     112                                                        #ifndef __cforall
     113    int fm5y( int r, int c, int m[r][c] ) {}            // BUG 276: CFA chokes but should accept
     114                                                        // C: same as fm1 defn
     115                                                        #endif
     116
    50117
    51118int main() {
    52     #pragma GCC warning "Compiled"                      // force non-empty .expect file, NO TABS!!!
     119    #pragma GCC warning "Preprocessor started"          // force non-empty .expect file, NO TABS!!!
    53120}
    54121
  • tests/attributes.cfa

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

    r34b4268 r24d6572  
    99// #include <lib.h>
    1010
    11 trait Comparable(T) {
     11forall(T)
     12trait Comparable {
    1213  int ?<?(T, T);
    1314};
  • tests/collections/vector-demo.cfa

    r34b4268 r24d6572  
    143143    assert( v`capacity >  5 && v`length == 5 );
    144144
    145     v[2] = -0.1;  // v is [0.0, 98.6, -0.1, 0.2, 0.3]; iter at -0.1, where only the new memory had that change
     145    v[2] = -0.1f;  // v is [0.0, 98.6, -0.1, 0.2, 0.3]; iter at -0.1, where only the new memory had that change
    146146
    147147    float val3 = iter`val;
  • tests/declarationSpecifier.cfa

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

    r34b4268 r24d6572  
    1 0
    2 1
    3 1000
    4 1001
    5 2000
    6 2001
    7 2002
     10=0
     21=1
     31000=1000
     41001=1001
     52000=2000
     62001=2001
     72002=2002
  • tests/enum_tests/pointerEnum.cfa

    r34b4268 r24d6572  
    1111int main() {
    1212    E * v = First;
    13     sout | "v: " | e.x;
     13    // sout | "v: " | e.x;
    1414}
  • tests/enum_tests/typedIntEnum.cfa

    r34b4268 r24d6572  
    1212
    1313int main() {
    14     printf("%d\n", zero);
    15     printf("%d\n", one);
    16     printf("%d\n", thousand);
    17     printf("%d\n", thousand_one);
    18     printf("%d\n", two_thousand);
    19     printf("%d\n", two_thousand_one);
    20     printf("%d\n", two_thousand_two);
     14    printf("0=%d\n", zero);
     15    printf("1=%d\n", one);
     16    printf("1000=%d\n", thousand);
     17    printf("1001=%d\n", thousand_one);
     18    printf("2000=%d\n", two_thousand);
     19    printf("2001=%d\n", two_thousand_one);
     20    printf("2002=%d\n", two_thousand_two);
    2121    return 0;
    2222}
  • tests/errors/.expect/declaration.txt

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

    r34b4268 r24d6572  
    1010// Created On       : Wed May  9 08:48:15 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jun  5 10:06:08 2021
    13 // Update Count     : 36
    14 //
     12// Last Modified On : Thu Feb 23 20:29:59 2023
     13// Update Count     : 91
     14//
     15
     16#include <fstream.hfa>
    1517
    1618void g1() {
    17         forall( T ) T f( T ) {};
    18         void f( int ) {};
    19         void h( void (*p)(void) ) {};
    20 
    21         int x;
    22         void (*y)(void);
    23         char z;
    24         float w;
     19        forall( T ) T f( T p ) { sout | 'f'; return p;  };
     20        void f( int p ) { sout | p; };
     21        void g( void ) { sout | 'g'; };
     22        void h( void (*p)(void) ) { p(); };
     23
     24        int x = 1;
     25        void (*y)(void) = g;
     26        char z = 'a';
     27        float w = 3.5;
    2528
    2629        f( x );
     
    2831        f( z );
    2932        f( w );
     33        h( y );
     34        f( y );
    3035        h( f( y ) );
    3136}
    3237
    3338void g2() {
    34         forall( T ) void f( T, T ) {}
    35         forall( T, U ) void f( T, U ) {}
     39        forall( T ) void f( T, T ) { sout | "fT"; }
     40        forall( T, U ) void f( T, U ) { sout | "fTU"; }
    3641
    3742        int x;
    3843        float y;
    39         int *z;
    40         float *w;
    41 
     44        int * z;
     45        float * w;
     46
     47        f( x, x );
     48        f( y, y );
     49        f( w, w );
    4250        f( x, y );
    4351        f( z, w );
     
    5058
    5159forall( T )
    52 void swap( T left, T right ) {
    53         T temp = left;
    54         left = right;
    55         right = temp;
    56 }
    57 
    58 trait sumable( T ) {
     60void swap( T & left, T & right ) {                                              // by reference
     61    T temp = left;
     62    left = right;
     63    right = temp;
     64}
     65
     66forall( T )
     67[ T, T ] swap( T i, T j ) {                                                             // by value
     68    return [ j, i ];
     69}
     70
     71forall( T ) trait sumable {
    5972        void ?{}( T &, zero_t );                                                        // 0 literal constructor
    6073        T ?+?( T, T );                                                                          // assortment of additions
     
    6477}; // sumable
    6578
    66 forall( T | sumable( T ) )                                              // use trait
     79forall( T | sumable( T ) )                                                              // use trait
    6780T sum( size_t size, T a[] ) {
    6881        T total = 0;                                                                            // initialize by 0 constructor
     
    7285} // sum
    7386
    74 forall( T | { T ?+?( T, T ); T ?++( T & ); [T] ?+=?( T &,T ); } )
     87forall( T | { T ?+?( T, T ); T ?++( T & ); [T] ?+=?( T &, T ); } )
    7588T twice( T t ) {
    7689        return t + t;
     
    8295}
    8396
    84 int fred() {
    85         int x = 1, y = 2, a[10];
     97void fred() {
     98        int x = 1, y = 2, a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    8699        float f;
    87100
     101        sout | x | y;
    88102        swap( x, y );
    89         twice( x );
     103        sout | x | y | nl | swap( x, y );
     104        // [ x, y ] = swap( y, x );
     105        sout | twice( ' ' ) | ' ' | twice( 0hh ) | twice( 1h ) | twice( 0n ) | twice( 2 )
     106                 | twice( 3.2f ) | twice( 3.2 ) | twice( 3.2d ) | twice( 3.2+1.5i ) | twice( x );
    90107        f = min( 4.0, 3.0 );
    91         sum( 10, a );
     108        sout | f | min( 4.0, 3.0 );
     109        sout | sum( 10, a );
    92110}
    93111
     
    177195
    178196forall( T ) struct S { T t; } (int) x, y, z;
    179 forall( T ) struct { T t; } (int) a, b, c;
     197static forall( T ) struct { T t; } (int) a, b, c;
    180198
    181199forall( T ) static forall( S ) {
     
    186204
    187205forall( T ) {
    188         extern "C" {
     206//      extern "C" {
    189207                struct SS { T t; };
    190                 T foo( T ) {}
    191         }
     208                T foo( T p ) { return p; }
     209//      }
    192210}
    193211
     
    195213W(int,int) w;
    196214
    197 int jane() {
     215void jane() {
    198216//      int j = bar( 3, 4 );
    199217        int k = baz( 3, 4, 5 );
    200218        int i = foo( 3 );
     219        sout | k | i;
    201220}
    202221
     
    211230        T t;
    212231        T t2 = t;
     232        sout | &tr | tp;
    213233}
    214234
     
    242262
    243263int main( void ) {
    244     #pragma GCC warning "Compiled"                      // force non-empty .expect file, NO TABS!!!
     264        g1();
     265        g2();
     266        fred();
     267        jane();
    245268}
    246269
  • tests/function-operator.cfa

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

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

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

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

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

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

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

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

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

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

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