Changes in / [e67a82d:67ca73e]


Ignore:
Files:
2 added
21 deleted
120 edited

Legend:

Unmodified
Added
Removed
  • benchmark/benchcltr.hfa

    re67a82d r67ca73e  
    11#pragma once
     2
    23#include <assert.h>
    3 #include <stdint.h>
    4 
    5 #ifdef __cforall
    6         #include <kernel.hfa>
    7         #include <thread.hfa>
    8         #include <stats.hfa>
    9 #else
    10 #include <time.h>                                                                               // timespec
    11 #include <sys/time.h>                                                                   // timeval
    12 
    13 enum { TIMEGRAN = 1000000000LL };                                       // nanosecond granularity, except for timeval
    14 #endif
     4#include <kernel.hfa>
     5#include <thread.hfa>
     6#include <stats.hfa>
    157
    168#define BENCH_OPT_SHORT "d:p:t:SPV"
     
    2214        {"procstat",     no_argument      , 0, 'P'}, \
    2315        {"viewhalts",    no_argument      , 0, 'V'},
     16
     17#define BENCH_DECL \
     18        double duration = 5; \
     19        int nprocs = 1; \
     20        int nthreads = 1;
    2421
    2522#define BENCH_OPT_CASE \
     
    5552                break;
    5653
    57 double duration = 5;
    58 int nprocs = 1;
    59 int nthreads = 1;
    6054bool silent = false;
    61 bool continuous = false;
    6255bool procstats = false;
    6356bool viewhalts = false;
    64 
    65 #define BENCH_OPT_CFA \
    66         {'d', "duration",  "Duration of the experiments in seconds", duration }, \
    67         {'t', "nthreads",  "Number of threads to use", nthreads }, \
    68         {'p', "nprocs",    "Number of processors to use", nprocs }, \
    69         {'S', "nostats",   "Don't print statistics", silent, parse_settrue }, \
    70         {'C', "constats",  "Regularly print statistics", continuous, parse_settrue }, \
    71         {'P', "procstat",  "Print statistics for each processors", procstats, parse_settrue }, \
    72         {'V', "viewhalts", "Visualize halts, prints timestamp and Processor id for each halt.", viewhalts, parse_settrue },
    73 
    74 #ifdef __cforall
    75 #include <parseargs.hfa>
    76 
    7757struct cluster * the_benchmark_cluster = 0p;
    7858struct BenchCluster {
     
    8060};
    8161
    82 void ?{}( BenchCluster & this, int num_io, const io_context_params & io_params, int stats ) {
    83         (this.self){ "Benchmark Cluster", num_io, io_params };
     62void ?{}( BenchCluster & this, int flags, int stats ) {
     63        (this.self){ "Benchmark Cluster", flags };
    8464
    8565        assert( the_benchmark_cluster == 0p );
     
    125105        }
    126106}
    127 #else
    128 uint64_t getTimeNsec() {
    129         timespec curr;
    130         clock_gettime( CLOCK_REALTIME, &curr );
    131         return (int64_t)curr.tv_sec * TIMEGRAN + curr.tv_nsec;
    132 }
    133 
    134 uint64_t to_miliseconds( uint64_t durtn ) { return durtn / (TIMEGRAN / 1000LL); }
    135 double to_fseconds(uint64_t durtn ) { return durtn / (double)TIMEGRAN; }
    136 uint64_t from_fseconds(double sec) { return sec * TIMEGRAN; }
    137 
    138 
    139 void wait_duration(double duration, uint64_t & start, uint64_t & end, bool is_tty) {
    140         for(;;) {
    141                 usleep(100000);
    142                 end = getTimeNsec();
    143                 uint64_t delta = end - start;
    144                 /*if(is_tty)*/ {
    145                         printf(" %.1f\r", to_fseconds(delta));
    146                         fflush(stdout);
    147                 }
    148                 if( delta >= from_fseconds(duration) ) {
    149                         break;
    150                 }
    151         }
    152 }
    153 #endif
    154 
    155107
    156108void bench_usage( char * argv [] ) {
  • benchmark/io/http/options.cfa

    re67a82d r67ca73e  
    1010
    1111#include <kernel.hfa>
    12 #include <parseargs.hfa>
     12
     13#include "parseargs.hfa"
     14
    1315
    1416Options options @= {
  • benchmark/io/readv.cfa

    re67a82d r67ca73e  
    4040int do_read(int fd, struct iovec * iov) {
    4141        // extern ssize_t cfa_preadv2(int, const struct iovec *, int, off_t, int, int = 0, Duration = -1`s, io_cancellation * = 0p, io_context * = 0p);
    42         int sflags = 0
    43         #if defined(CFA_HAVE_IOSQE_ASYNC)
    44                 | CFA_IO_ASYNC
    45         #else
    46         #warning no CFA_IO_ASYNC support
    47         #endif
    48         ;
     42        int sflags = 0;
    4943        if(fixed_file) {
    5044                sflags |= CFA_IO_FIXED_FD1;
     
    6963
    7064int main(int argc, char * argv[]) {
     65        BENCH_DECL
     66        unsigned num_io = 1;
     67        io_context_params params;
    7168        int file_flags = 0;
    72         unsigned num_io = 1;
    7369        unsigned sublen = 16;
    74         unsigned nentries = 0;
    7570
    76         bool subthrd = false;
    77         bool subeagr = false;
    78         bool odirect = false;
    79         bool kpollsb = false;
    80         bool kpollcp = false;
     71        arg_loop:
     72        for(;;) {
     73                static struct option options[] = {
     74                        BENCH_OPT_LONG
     75                        {"bufsize",       required_argument, 0, 'b'},
     76                        {"submitthread",  no_argument      , 0, 's'},
     77                        {"eagersubmit",   no_argument      , 0, 'e'},
     78                        {"kpollsubmit",   no_argument      , 0, 'k'},
     79                        {"kpollcomplete", no_argument      , 0, 'i'},
     80                        {"fixed-files",   no_argument      , 0, 'f'},
     81                        {"open-direct",   no_argument      , 0, 'o'},
     82                        {"submitlength",  required_argument, 0, 'l'},
     83                        {0, 0, 0, 0}
     84                };
    8185
    82         cfa_option opt[] = {
    83                 BENCH_OPT_CFA
    84                 {'b', "bufsize",       "Number of bytes to read per request", buflen},
    85                 {'s', "submitthread",  "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue},
    86                 {'e', "eagersubmit",   "If set, cluster submits I/O eagerly but still aggregates submits", subeagr, parse_settrue},
    87                 {'f', "fixed-files",   "Pre-register files with the io_contexts", fixed_file, parse_settrue},
    88                 {'o', "open-direct",   "Open files with O_DIRECT flag, bypassing the file cache", odirect, parse_settrue},
    89                 {'k', "kpollsubmit",   "If set, cluster uses an in kernel thread to poll submission, implies -f, requires elevated permissions", kpollsb, parse_settrue},
    90                 {'i', "kpollcomplete", "If set, cluster polls fds for completions instead of relying on interrupts to get notifications, implies -o", kpollcp, parse_settrue},
    91                 {'l', "submitlength",  "Size of the buffer that stores ready submissions", sublen},
    92                 {'r', "numentries",    "Number of entries each of the io_context have", nentries},
    93                 {'n', "numcontexts",   "Number of io_contexts to the cluster", num_io},
    94         };
    95         int opt_cnt = sizeof(opt) / sizeof(cfa_option);
     86                int idx = 0;
     87                int opt = getopt_long(argc, argv, BENCH_OPT_SHORT "b:sekil:", options, &idx);
    9688
    97         char **left;
    98         parse_args( opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
    99 
    100         if(kpollcp || odirect) {
    101                 if( (buflen % 512) != 0 ) {
    102                         fprintf(stderr, "Buffer length must be a multiple of 512 when using O_DIRECT, was %lu\n\n", buflen);
    103                         print_args_usage(opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", true);
     89                const char * arg = optarg ? optarg : "";
     90                char * end;
     91                switch(opt) {
     92                        // Exit Case
     93                        case -1:
     94                                break arg_loop;
     95                        BENCH_OPT_CASE
     96                        case 'b':
     97                                buflen = strtoul(arg, &end, 10);
     98                                if(*end != '\0' && buflen < 10) {
     99                                        fprintf(stderr, "Buffer size must be at least 10, was %s\n", arg);
     100                                        goto usage;
     101                                }
     102                                break;
     103                        case 's':
     104                                params.poller_submits = true;
     105                                break;
     106                        case 'e':
     107                                params.eager_submits = true;
     108                                break;
     109                        case 'k':
     110                                params.poll_submit = true;
     111                        case 'f':
     112                                fixed_file = true;
     113                                break;
     114                        case 'i':
     115                                params.poll_complete = true;
     116                        case 'o':
     117                                file_flags |= O_DIRECT;
     118                                break;
     119                        case 'l':
     120                                sublen = strtoul(arg, &end, 10);
     121                                if(*end != '\0' && sublen < 16) {
     122                                        fprintf(stderr, "Submit length must be at least 16, was %s\n", arg);
     123                                        goto usage;
     124                                }
     125                                // flags |= (sublen << CFA_CLUSTER_IO_BUFFLEN_OFFSET);
     126                                break;
     127                        default: /* ? */
     128                                fprintf(stderr, "%d\n", opt);
     129                        usage:
     130                                bench_usage( argv );
     131                                fprintf( stderr, "  -b, --buflen=SIZE        Number of bytes to read per request\n" );
     132                                fprintf( stderr, "  -u, --userthread         If set, cluster uses user-thread to poll I/O\n" );
     133                                fprintf( stderr, "  -s, --submitthread       If set, cluster uses polling thread to submit I/O\n" );
     134                                fprintf( stderr, "  -e, --eagersubmit        If set, cluster submits I/O eagerly but still aggregates submits\n" );
     135                                fprintf( stderr, "  -k, --kpollsubmit        If set, cluster uses IORING_SETUP_SQPOLL\n" );
     136                                fprintf( stderr, "  -i, --kpollcomplete      If set, cluster uses IORING_SETUP_IOPOLL\n" );
     137                                fprintf( stderr, "  -l, --submitlength=LEN   Max number of submitions that can be submitted together\n" );
     138                                exit(EXIT_FAILURE);
    104139                }
    105140        }
    106 
    107         io_context_params params;
    108 
    109         if( subthrd ) params.poller_submits = true;
    110         if( subeagr ) params.eager_submits  = true;
    111         if( kpollsb ) params.poll_submit    = true;
    112         if( kpollcp ) params.poll_complete  = true;
    113 
    114         if(params.poll_submit  ) fixed_file = true;
    115         if(params.poll_complete) odirect    = true;
    116 
    117         params.num_ready = sublen;
    118         params.num_entries = nentries;
    119 
    120         if(odirect) file_flags |= O_DIRECT;
    121141
    122142        int lfd = open(__FILE__, file_flags);
  • benchmark/readyQ/yield.cfa

    re67a82d r67ca73e  
    4343
    4444int main(int argc, char * argv[]) {
    45         unsigned num_io = 1;
    46         io_context_params params;
     45        BENCH_DECL
    4746
    48         cfa_option opt[] = {
    49                 BENCH_OPT_CFA
    50         };
    51         int opt_cnt = sizeof(opt) / sizeof(cfa_option);
     47        for(;;) {
     48                static struct option options[] = {
     49                        BENCH_OPT_LONG
     50                        {0, 0, 0, 0}
     51                };
    5252
    53         char **left;
    54         parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
     53                int idx = 0;
     54                int opt = getopt_long(argc, argv, BENCH_OPT_SHORT, options, &idx);
     55
     56                const char * arg = optarg ? optarg : "";
     57                char * end;
     58                switch(opt) {
     59                        case -1:
     60                                goto run;
     61                        BENCH_OPT_CASE
     62                        default: /* ? */
     63                                fprintf( stderr, "Unkown option '%c'\n", opt);
     64                        usage:
     65                                bench_usage( argv );
     66                                exit(1);
     67                }
     68        }
     69        run:
    5570
    5671        {
     
    5873
    5974                Time start, end;
    60                 BenchCluster cl = { num_io, params, CFA_STATS_READY_Q };
     75                BenchCluster cl = { 0, CFA_STATS_READY_Q };
    6176                {
    6277                        BenchProc procs[nprocs];
  • configure.ac

    re67a82d r67ca73e  
    2424#Trasforming cc1 will break compilation
    2525M4CFA_PROGRAM_NAME
    26 
    27 #==============================================================================
    28 # New AST toggling support
    29 AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast])
    30 AC_ARG_ENABLE(new-ast,
    31         [  --enable-new-ast     whether or not to use new ast as the default AST algorithm],
    32         [case "${enableval}" in
    33                 yes) newast=true ;;
    34                 no)  newast=false ;;
    35                 *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;;
    36         esac],[newast=false])
    37 AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
    3826
    3927#==============================================================================
  • driver/cc1.cc

    re67a82d r67ca73e  
    1010// Created On       : Fri Aug 26 14:23:51 2005
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug 16 21:03:02 2020
    13 // Update Count     : 413
     12// Last Modified On : Sat May 30 18:09:05 2020
     13// Update Count     : 404
    1414//
    1515
     
    2424#include <unistd.h>                                                                             // execvp, fork, unlink
    2525#include <sys/wait.h>                                                                   // wait
    26 #include <fcntl.h>                                                                              // creat
     26#include <fcntl.h>
    2727
    2828
     
    5959
    6060
    61 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "__CFA_FLAG__=" suffix
     61static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "N__=" suffix
    6262
    6363static void checkEnv1( const char * args[], int & nargs ) { // stage 1
     
    111111} // checkEnv2
    112112
    113 #define CFA_SUFFIX ".ifa"
    114 
    115 static char tmpname[] = P_tmpdir "/CFAXXXXXX" CFA_SUFFIX;
     113
     114static char tmpname[] = P_tmpdir "/CFAXXXXXX.ifa";
    116115static int tmpfilefd = -1;
    117116static bool startrm = false;
     
    171170                        if ( arg == "-quiet" ) {
    172171                        } else if ( arg == "-imultilib" || arg == "-imultiarch" ) {
    173                                 i += 1;                                                                 // and argument
     172                                i += 1;                                                                 // and the argument
    174173                        } else if ( prefix( arg, "-A" ) ) {
    175174                        } else if ( prefix( arg, "-D__GNU" ) ) {
     
    178177                                //********
    179178                        } else if ( arg == "-D" && prefix( argv[i + 1], "__GNU" ) ) {
    180                                 i += 1;                                                                 // and argument
     179                                i += 1;                                                                 // and the argument
    181180
    182181                                // strip flags controlling cpp step
     
    185184                                cpp_flag = true;
    186185                        } else if ( arg == "-D" && string( argv[i + 1] ) == "__CPP__" ) {
    187                                 i += 1;                                                                 // and argument
     186                                i += 1;                                                                 // and the argument
    188187                                cpp_flag = true;
    189188
     
    195194                                cpp_out = argv[i];
    196195                        } else {
    197                                 args[nargs++] = argv[i];                                // pass flag along
     196                                args[nargs++] = argv[i];                                // pass the flag along
    198197                                // CPP flags with an argument
    199198                                if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
     
    201200                                         arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
    202201                                        i += 1;
    203                                         args[nargs++] = argv[i];                        // pass argument along
     202                                        args[nargs++] = argv[i];                        // pass the argument along
    204203                                        #ifdef __DEBUG_H__
    205204                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
    206205                                        #endif // __DEBUG_H__
    207206                                } else if ( arg == "-MD" || arg == "-MMD" ) {
    208                                         // gcc frontend generates the dependency file-name after the -MD/-MMD flag, but it is necessary to
    209                                         // prefix that file name with -MF.
    210207                                        args[nargs++] = "-MF";                          // insert before file
    211208                                        i += 1;
    212                                         args[nargs++] = argv[i];                        // pass argument along
     209                                        args[nargs++] = argv[i];                        // pass the argument along
    213210                                        #ifdef __DEBUG_H__
    214211                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
     
    282279        // Run the C preprocessor and save the output in the given file.
    283280
    284         if ( fork() == 0 ) {                                                            // child process ?
     281        if ( fork() == 0 ) {                                                             // child process ?
    285282                // -o xxx.ii cannot be used to write the output file from cpp because no output file is created if cpp detects
    286283                // an error (e.g., cannot find include file). Whereas, output is always generated, even when there is an error,
     
    322319
    323320        if ( WIFSIGNALED(code) ) {                                                      // child failed ?
    324                 rmtmpfile();                                                                    // remove tmpname
    325321                cerr << "CC1 Translator error: stage 1, child failed " << WTERMSIG(code) << endl;
    326322                exit( EXIT_FAILURE );
    327323        } // if
    328324
    329         exit( WEXITSTATUS( code ) );                                            // bad cpp result stops top-level gcc
     325        exit( WEXITSTATUS(code) );                                                      // bad cpp result stops top-level gcc
    330326} // Stage1
    331327
     
    375371                        } else if ( arg == "-fno-diagnostics-color" ) {
    376372                                color_arg = Color_Auto;
    377                         } // if
     373                        }
    378374
    379375                        if ( arg == "-quiet" || arg == "-version" || arg == "-fpreprocessed" ||
    380                                  // Currently CFA does not suppose precompiled .h files.
    381                                  prefix( arg, "--output-pch" ) ) {
     376                                // Currently CFA does not suppose precompiled .h files.
     377                                prefix( arg, "--output-pch" ) ) {
    382378
    383379                                // strip inappropriate flags with an argument
     
    392388
    393389                        } else {
    394                                 args[nargs++] = argv[i];                                // pass flag along
     390                                args[nargs++] = argv[i];                                // pass the flag along
    395391                                if ( arg == "-o" ) {
    396392                                        i += 1;
    397393                                        cpp_out = argv[i];
    398                                         args[nargs++] = argv[i];                        // pass argument along
     394                                        args[nargs++] = argv[i];                        // pass the argument along
    399395                                        #ifdef __DEBUG_H__
    400396                                        cerr << "arg:\"" << argv[i] << "\"" << endl;
     
    443439                        } // if
    444440
    445                         cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + CFA_SUFFIX;
     441                        cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + ".ifa";
    446442                        if ( creat( cfa_cpp_out.c_str(), 0666 ) == -1 ) {
    447443                                perror( "CC1 Translator error: stage 2, creat" );
     
    464460        // output.  Otherwise, run the cfa-cpp preprocessor on the temporary file and save the result into the output file.
    465461
    466         if ( fork() == 0 ) {                                                            // child runs CFA preprocessor
     462        if ( fork() == 0 ) {                                                            // child runs CFA
    467463                cargs[0] = ( *new string( bprefix + "cfa-cpp" ) ).c_str();
    468464                cargs[ncargs++] = cpp_in;
     
    522518        #endif // __DEBUG_H__
    523519
    524         if ( fork() == 0 ) {                                                            // child runs gcc
     520        if ( fork() == 0 ) {                                                            // child runs CFA
    525521                args[0] = compiler_path.c_str();
    526522                args[nargs++] = "-S";                                                   // only compile and put assembler output in specified file
  • driver/cfa.cc

    re67a82d r67ca73e  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 20 23:43:59 2020
    13 // Update Count     : 436
     12// Last Modified On : Tue Aug 18 16:40:22 2020
     13// Update Count     : 435
    1414//
    1515
    1616#include <iostream>
    17 #include <cstdio>                                                                               // perror
    18 #include <cstdlib>                                                                              // putenv, exit
    19 #include <climits>                                                                              // PATH_MAX
    20 #include <string>                                                                               // STL version
    21 #include <algorithm>                                                                    // find
    22 
    23 #include <unistd.h>                                                                             // execvp
     17#include <cstdio>      // perror
     18#include <cstdlib>     // putenv, exit
     19#include <climits>     // PATH_MAX
     20#include <unistd.h>    // execvp
     21#include <string>      // STL version
     22#include <string.h>    // strcmp
     23#include <algorithm>   // find
     24
    2425#include <sys/types.h>
    2526#include <sys/stat.h>
     
    3334using std::to_string;
    3435
    35 //#define __DEBUG_H__
    36 
    37 #define xstr(s) str(s)
    38 #define str(s) #s
    39 
    40 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "__CFA_FLAG__=" suffix
    41 
    42 static void Putenv( char * argv[], string arg ) {
     36// #define __DEBUG_H__
     37
     38// "N__=" suffix
     39static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );
     40
     41void Putenv( char * argv[], string arg ) {
    4342        // environment variables must have unique names
    4443        static int flags = 0;
     
    5049} // Putenv
    5150
    52 static bool prefix( const string & arg, const string & pre ) { // check if string has prefix
     51// check if string has prefix
     52bool prefix( const string & arg, const string & pre ) {
    5353        return arg.substr( 0, pre.size() ) == pre;
    5454} // prefix
    5555
    56 static inline bool ends_with(const string & str, const string & sfix) {
     56inline bool ends_with(const string & str, const string & sfix) {
    5757        if (sfix.size() > str.size()) return false;
    5858        return std::equal(str.rbegin(), str.rbegin() + sfix.size(), sfix.rbegin(), sfix.rend());
     
    6060
    6161// check if string has suffix
    62 static bool suffix( const string & arg ) {
     62bool suffix( const string & arg ) {
    6363        enum { NumSuffixes = 3 };
    6464        static const string suffixes[NumSuffixes] = { "cfa", "hfa", "ifa" };
     
    7070} // suffix
    7171
     72
    7273static inline bool dirExists( const string & path ) {   // check if directory exists
    7374    struct stat info;
     
    7879static inline string dir(const string & path) {
    7980        return path.substr(0, path.find_last_of('/'));
    80 } // dir
     81}
    8182
    8283// Different path modes
     
    117118}
    118119
     120
     121#define xstr(s) str(s)
     122#define str(s) #s
    119123
    120124int main( int argc, char * argv[] ) {
     
    154158        PathMode path = FromProc();
    155159
    156         const char * args[argc + 100];                                          // cfa command line values, plus some space for additional flags
     160        const char *args[argc + 100];                                           // cfa command line values, plus some space for additional flags
    157161        int sargs = 1;                                                                          // starting location for arguments in args list
    158162        int nargs = sargs;                                                                      // number of arguments in args list; 0 => command name
    159163
    160         const char * libs[argc + 20];                                           // non-user libraries must come separately, plus some added libraries and flags
     164        const char *libs[argc + 20];                                            // non-user libraries must come separately, plus some added libraries and flags
    161165        int nlibs = 0;
    162166
     
    176180
    177181                        if ( arg == "-Xlinker" || arg == "-o" ) {
    178                                 args[nargs++] = argv[i];                                // pass flag along
     182                                args[nargs++] = argv[i];                                // pass argument along
    179183                                i += 1;
    180184                                if ( i == argc ) continue;                              // next argument available ?
    181185                                args[nargs++] = argv[i];                                // pass argument along
    182186                                if ( arg == "-o" ) o_file = i;                  // remember file
    183 
    184                                 // CFA specific arguments
    185 
    186                         } else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) { // CFA pass through
    187                                 if ( arg.size() == 5 ) {
     187                        } else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) {                           // CFA pass through
     188                                if(arg.size() == 5) {
    188189                                        i += 1;
    189                                         if ( i == argc ) continue;                      // next argument available ?
     190                                        if ( i == argc ) continue;                              // next argument available ?
    190191                                        Putenv( argv, argv[i] );
    191                                 } else if ( arg[5] == ',' ) {                   // CFA specific arguments
     192
     193                                        // CFA specific arguments
     194                                }
     195                                else if(arg[5] == ',') {
    192196                                        Putenv( argv, argv[i] + 6 );
    193                                 } else {                                                                // CFA specific arguments
     197
     198                                        // CFA specific arguments
     199                                }
     200                                else {
    194201                                        args[nargs++] = argv[i];
    195                                 } // if
     202                                }
     203
    196204                        } else if ( arg == "-CFA" ) {
    197205                                CFA_flag = true;                                                // strip the -CFA flag
     
    202210                        } else if ( arg == "-nodebug" ) {
    203211                                debug = false;                                                  // strip the nodebug flag
     212                        } else if ( arg == "-nolib" ) {
     213                                nolib = true;                                                   // strip the nodebug flag
    204214                        } else if ( arg == "-quiet" ) {
    205215                                quiet = true;                                                   // strip the quiet flag
    206216                        } else if ( arg == "-noquiet" ) {
    207217                                quiet = false;                                                  // strip the noquiet flag
    208                         } else if ( arg == "-no-include-stdhdr" ) {
    209                                 noincstd_flag = true;                                   // strip the no-include-stdhdr flag
    210                         } else if ( arg == "-nolib" ) {
    211                                 nolib = true;                                                   // strip the nolib flag
    212218                        } else if ( arg == "-help" ) {
    213219                                help = true;                                                    // strip the help flag
    214220                        } else if ( arg == "-nohelp" ) {
    215221                                help = false;                                                   // strip the nohelp flag
     222                        } else if ( arg == "-no-include-stdhdr" ) {
     223                                noincstd_flag = true;                                   // strip the no-include-stdhdr flag
    216224                        } else if ( arg == "-cfalib") {
    217225                                compiling_libs = true;
     
    227235                        } else if ( arg == "-v" ) {
    228236                                verbose = true;                                                 // verbosity required
    229                                 args[nargs++] = argv[i];                                // pass flag along
     237                                args[nargs++] = argv[i];                                // pass argument along
    230238                        } else if ( arg == "-g" ) {
    231239                                debugging = true;                                               // symbolic debugging required
    232                                 args[nargs++] = argv[i];                                // pass flag along
     240                                args[nargs++] = argv[i];                                // pass argument along
    233241                        } else if ( arg == "-save-temps" ) {
    234                                 args[nargs++] = argv[i];                                // pass flag along
     242                                args[nargs++] = argv[i];                                // pass argument along
    235243                                Putenv( argv, arg );                                    // save cfa-cpp output
    236244                        } else if ( prefix( arg, "-x" ) ) {                     // file suffix ?
    237245                                string lang;
    238                                 args[nargs++] = argv[i];                                // pass flag along
     246                                args[nargs++] = argv[i];                                // pass argument along
    239247                                if ( arg.length() == 2 ) {                              // separate argument ?
    240248                                        i += 1;
     
    253261                        } else if ( prefix( arg, "-std=" ) || prefix( arg, "--std=" ) ) {
    254262                                std_flag = true;                                                // -std=XX provided
    255                                 args[nargs++] = argv[i];                                // pass flag along
     263                                args[nargs++] = argv[i];                                // pass argument along
    256264                        } else if ( arg == "-w" ) {
    257                                 args[nargs++] = argv[i];                                // pass flag along
     265                                args[nargs++] = argv[i];                                // pass argument along
    258266                                Putenv( argv, arg );
    259267                        } else if ( prefix( arg, "-W" ) ) {                     // check before next tests
    260268                                if ( arg == "-Werror" || arg == "-Wall" ) {
    261                                         args[nargs++] = argv[i];                        // pass flag along
     269                                        args[nargs++] = argv[i];                        // pass argument along
    262270                                        Putenv( argv, argv[i] );
    263271                                } else {
     
    273281                                bprefix = arg.substr(2);                                // strip the -B flag
    274282                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    275                                 args[nargs++] = argv[i];                                // pass flag along
     283                                args[nargs++] = argv[i];                                // pass argument along
    276284                                if ( arg == "-E" || arg == "-M" || arg == "-MM" ) {
    277285                                        cpp_flag = true;                                        // cpp only
    278286                                } // if
    279287                                link = false;                           // no linkage required
    280                         } else if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
    281                                                 arg == "-include" || arg == "-imacros" || arg == "-idirafter" || arg == "-iprefix" ||
    282                                                 arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
    283                                 args[nargs++] = argv[i];                                // pass flag along
    284                                 i += 1;
    285                                 args[nargs++] = argv[i];                                // pass argument along
    286288                        } else if ( arg[1] == 'l' ) {
    287289                                // if the user specifies a library, load it after user code
     
    335337        string libbase;
    336338        switch(path) {
    337           case Installed:
     339        case Installed:
    338340                args[nargs++] = "-I" CFA_INCDIR;
    339341                // do not use during build
     
    345347                libbase = CFA_LIBDIR;
    346348                break;
    347           case BuildTree:
    348           case Distributed:
     349        case BuildTree:
     350        case Distributed:
    349351                args[nargs++] = "-I" TOP_SRCDIR "libcfa/src";
    350352                // do not use during build
     
    380382        string libdir = libbase + arch + "-" + config;
    381383
    382         if ( path != Distributed ) {
     384        if (path != Distributed) {
    383385                if ( ! nolib && ! dirExists( libdir ) ) {
    384386                        cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl;
     
    400402        string preludedir;
    401403        switch(path) {
    402           case Installed   : preludedir = libdir; break;
    403           case BuildTree   : preludedir = libdir + "/prelude"; break;
    404           case Distributed : preludedir = dir(argv[0]); break;
    405         } // switch
     404        case Installed   : preludedir = libdir; break;
     405        case BuildTree   : preludedir = libdir + "/prelude"; break;
     406        case Distributed : preludedir = dir(argv[0]); break;
     407        }
    406408
    407409        Putenv( argv, "--prelude-dir=" + preludedir );
     
    475477        if ( bprefix.length() == 0 ) {
    476478                switch(path) {
    477                   case Installed   : bprefix = installlibdir; break;
    478                   case BuildTree   : bprefix = srcdriverdir ; break;
    479                   case Distributed : bprefix = dir(argv[0]) ; break;
    480                 } // switch
    481         } // if
    482         if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
    483         Putenv( argv, string("-B=") + bprefix );
     479                case Installed   : bprefix = installlibdir; break;
     480                case BuildTree   : bprefix = srcdriverdir ; break;
     481                case Distributed : bprefix = dir(argv[0]) ; break;
     482                }
     483                if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
     484                Putenv( argv, string("-B=") + bprefix );
     485        } // if
    484486
    485487        args[nargs++] = "-Xlinker";                                                     // used by backtrace
     
    503505                args[nargs++] = "-Wno-cast-function-type";
    504506                #endif // HAVE_CAST_FUNCTION_TYPE
    505                 if ( ! std_flag && ! x_flag ) {
    506                         args[nargs++] = "-std=gnu11";                           // default c11, if none specified
     507                if ( ! std_flag ) {                                                             // default c11, if none specified
     508                        args[nargs++] = "-std=gnu11";
    507509                } // if
    508510                args[nargs++] = "-fgnu89-inline";
     
    554556        // execute the command and return the result
    555557
    556         execvp( args[0], (char * const *)args );                        // should not return
     558        execvp( args[0], (char *const *)args );                         // should not return
    557559        perror( "CFA Translator error: execvp" );
    558560        exit( EXIT_FAILURE );
  • libcfa/prelude/bootloader.cf

    re67a82d r67ca73e  
    11extern "C" { static inline int invoke_main(int argc, char* argv[], char* envp[]); }
    2 int cfa_args_argc;
    3 char ** cfa_args_argv;
    4 char ** cfa_args_envp;
    52
    63int main(int argc, char* argv[], char* envp[]) {
    7         cfa_args_argc = argc;
    8         cfa_args_argv = argv;
    9         cfa_args_envp = envp;
    104        return invoke_main(argc, argv, envp);
    115}
  • libcfa/src/Makefile.am

    re67a82d r67ca73e  
    4444
    4545headers = common.hfa fstream.hfa heap.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa \
    46                 time.hfa stdlib.hfa parseargs.hfa \
     46                time.hfa stdlib.hfa memory.hfa \
    4747                containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
    4848
  • libcfa/src/bits/locks.hfa

    re67a82d r67ca73e  
    217217                }
    218218        }
    219 
    220         // Semaphore which only supports a single thread and one post
    221         // Semaphore which only supports a single thread
    222         struct oneshot {
    223                 struct $thread * volatile ptr;
    224         };
    225 
    226         static inline {
    227                 void  ?{}(oneshot & this) {
    228                         this.ptr = 0p;
    229                 }
    230 
    231                 void ^?{}(oneshot & this) {}
    232 
    233                 bool wait(oneshot & this) {
    234                         for() {
    235                                 struct $thread * expected = this.ptr;
    236                                 if(expected == 1p) return false;
    237                                 /* paranoid */ verify( expected == 0p );
    238                                 if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    239                                         park( __cfaabi_dbg_ctx );
    240                                         /* paranoid */ verify( this.ptr == 1p );
    241                                         return true;
    242                                 }
    243                         }
    244                 }
    245 
    246                 bool post(oneshot & this) {
    247                         struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    248                         if( got == 0p ) return false;
    249                         unpark( got __cfaabi_dbg_ctx2 );
    250                         return true;
    251                 }
    252         }
    253219#endif
  • libcfa/src/common.hfa

    re67a82d r67ca73e  
    1010// Created On       : Wed Jul 11 17:54:36 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 15 08:51:29 2020
    13 // Update Count     : 14
     12// Last Modified On : Thu Jul 12 08:02:18 2018
     13// Update Count     : 5
    1414//
    1515
     
    6767
    6868static inline {
    69         char min( char t1, char t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    70         intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    71         uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    7269        forall( otype T | { int ?<?( T, T ); } )
    7370        T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; }
    7471
    75         char max( char t1, char t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    76         intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    77         uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    7872        forall( otype T | { int ?>?( T, T ); } )
    7973        T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; }
  • libcfa/src/concurrency/alarm.hfa

    re67a82d r67ca73e  
    2323#include "time.hfa"
    2424
    25 #include "containers/list.hfa"
     25#include <containers/list.hfa>
    2626
    2727struct $thread;
  • libcfa/src/concurrency/coroutine.cfa

    re67a82d r67ca73e  
    215215                return cor;
    216216        }
    217 
    218         struct $coroutine * __cfactx_cor_active(void) {
    219                 return active_coroutine();
    220         }
    221217}
    222218
  • libcfa/src/concurrency/invoke.c

    re67a82d r67ca73e  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 20 23:43:23 2020
    13 // Update Count     : 31
     12// Last Modified On : Thu Aug 20 18:54:34 2020
     13// Update Count     : 30
    1414//
    1515
     
    2929// Called from the kernel when starting a coroutine or task so must switch back to user mode.
    3030
    31 extern struct $coroutine * __cfactx_cor_active(void);
    3231extern struct $coroutine * __cfactx_cor_finish(void);
    3332extern void __cfactx_cor_leave ( struct $coroutine * );
     
    3635extern void disable_interrupts() OPTIONAL_THREAD;
    3736extern void enable_interrupts( __cfaabi_dbg_ctx_param );
    38 
    39 struct exception_context_t * this_exception_context() {
    40         return &__get_stack( __cfactx_cor_active() )->exception_context;
    41 }
    4237
    4338void __cfactx_invoke_coroutine(
     
    151146
    152147#elif defined( __ARM_ARCH_32 )
    153 #error ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
    154         // More details about the error:
    155         // To avoid the thunk problem, I changed the invoke routine to pass the main explicitly
    156         // instead of relying on an assertion. This effectively hoists any required thunk one level
    157         // which was enough to get to global scope in most cases.
    158         // This means that __cfactx_invoke_... now takes two parameters and the FakeStack needs
    159         // to be adjusted as a consequence of that.
    160         // I don't know how to do that for ARM, hence the #error
    161 
     148#warning ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
    162149        struct FakeStack {
    163150                float fpRegs[16];                                                               // floating point registers
  • libcfa/src/concurrency/invoke.h

    re67a82d r67ca73e  
    2626#ifndef _INVOKE_H_
    2727#define _INVOKE_H_
    28 
    29         struct __cfaehm_try_resume_node;
    30         struct __cfaehm_base_exception_t;
    31         struct exception_context_t {
    32                 struct __cfaehm_try_resume_node * top_resume;
    33                 struct __cfaehm_base_exception_t * current_exception;
    34         };
    3528
    3629        struct __stack_context_t {
     
    5851                // base of stack
    5952                void * base;
    60 
    61                 // Information for exception handling.
    62                 struct exception_context_t exception_context;
    6353        };
    6454
     
    9484        };
    9585
    96         static inline struct __stack_t * __get_stack( struct $coroutine * cor ) {
    97                 return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2));
    98         }
    99 
    100         struct exception_context_t * this_exception_context();
     86        static inline struct __stack_t * __get_stack( struct $coroutine * cor ) { return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2)); }
    10187
    10288        // struct which calls the monitor is accepting
  • libcfa/src/concurrency/io.cfa

    re67a82d r67ca73e  
    4141        #include "kernel/fwd.hfa"
    4242        #include "io/types.hfa"
    43 
    44         // returns true of acquired as leader or second leader
    45         static inline bool try_lock( __leaderlock_t & this ) {
    46                 const uintptr_t thrd = 1z | (uintptr_t)active_thread();
    47                 bool block;
    48                 disable_interrupts();
    49                 for() {
    50                         struct $thread * expected = this.value;
    51                         if( 1p != expected && 0p != expected ) {
    52                                 /* paranoid */ verify( thrd != (uintptr_t)expected ); // We better not already be the next leader
    53                                 enable_interrupts( __cfaabi_dbg_ctx );
    54                                 return false;
    55                         }
    56                         struct $thread * desired;
    57                         if( 0p == expected ) {
    58                                 // If the lock isn't locked acquire it, no need to block
    59                                 desired = 1p;
    60                                 block = false;
    61                         }
    62                         else {
    63                                 // If the lock is already locked try becomming the next leader
    64                                 desired = (struct $thread *)thrd;
    65                                 block = true;
    66                         }
    67                         if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
    68                 }
    69                 if( block ) {
    70                         enable_interrupts( __cfaabi_dbg_ctx );
    71                         park( __cfaabi_dbg_ctx );
    72                         disable_interrupts();
    73                 }
    74                 return true;
    75         }
    76 
    77         static inline bool next( __leaderlock_t & this ) {
    78                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    79                 struct $thread * nextt;
    80                 for() {
    81                         struct $thread * expected = this.value;
    82                         /* paranoid */ verify( (1 & (uintptr_t)expected) == 1 ); // The lock better be locked
    83 
    84                         struct $thread * desired;
    85                         if( 1p == expected ) {
    86                                 // No next leader, just unlock
    87                                 desired = 0p;
    88                                 nextt   = 0p;
    89                         }
    90                         else {
    91                                 // There is a next leader, remove but keep locked
    92                                 desired = 1p;
    93                                 nextt   = (struct $thread *)(~1z & (uintptr_t)expected);
    94                         }
    95                         if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
    96                 }
    97 
    98                 if(nextt) {
    99                         unpark( nextt __cfaabi_dbg_ctx2 );
    100                         enable_interrupts( __cfaabi_dbg_ctx );
    101                         return true;
    102                 }
    103                 enable_interrupts( __cfaabi_dbg_ctx );
    104                 return false;
    105         }
    10643
    10744//=============================================================================================
     
    15693//=============================================================================================
    15794        static unsigned __collect_submitions( struct __io_data & ring );
    158         static __u32 __release_consumed_submission( struct __io_data & ring );
     95        static uint32_t __release_consumed_submission( struct __io_data & ring );
    15996
    16097        static inline void process(struct io_uring_cqe & cqe ) {
     
    163100
    164101                data->result = cqe.res;
    165                 post( data->sem );
     102                unpark( data->thrd __cfaabi_dbg_ctx2 );
    166103        }
    167104
     
    199136                unsigned head = *ring.completion_q.head;
    200137                unsigned tail = *ring.completion_q.tail;
    201                 const __u32 mask = *ring.completion_q.mask;
     138                const uint32_t mask = *ring.completion_q.mask;
    202139
    203140                // Nothing was new return 0
     
    206143                }
    207144
    208                 __u32 count = tail - head;
     145                uint32_t count = tail - head;
    209146                /* paranoid */ verify( count != 0 );
    210147                for(i; count) {
     
    245182                                __STATS__( true,
    246183                                        io.complete_q.completed_avg.val += count;
    247                                         io.complete_q.completed_avg.cnt += 1;
     184                                        io.complete_q.completed_avg.fast_cnt += 1;
    248185                                )
    249186                        enable_interrupts( __cfaabi_dbg_ctx );
     
    255192                        // We didn't get anything baton pass to the slow poller
    256193                        else {
    257                                 __STATS__( false,
    258                                         io.complete_q.blocks += 1;
    259                                 )
    260194                                __cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %p\n", &this.self);
    261195                                reset = 0;
     
    290224//
    291225
    292         [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) {
     226        [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
    293227                /* paranoid */ verify( data != 0 );
    294228
     
    296230                __attribute((unused)) int len   = 0;
    297231                __attribute((unused)) int block = 0;
    298                 __u32 cnt = *ring.submit_q.num;
    299                 __u32 mask = *ring.submit_q.mask;
     232                uint32_t cnt = *ring.submit_q.num;
     233                uint32_t mask = *ring.submit_q.mask;
    300234
    301235                disable_interrupts();
    302                         __u32 off = __tls_rand();
     236                        uint32_t off = __tls_rand();
    303237                enable_interrupts( __cfaabi_dbg_ctx );
    304238
     
    307241                        // Look through the list starting at some offset
    308242                        for(i; cnt) {
    309                                 __u64 expected = 0;
    310                                 __u32 idx = (i + off) & mask;
     243                                uint64_t expected = 0;
     244                                uint32_t idx = (i + off) & mask;
    311245                                struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
    312                                 volatile __u64 * udata = &sqe->user_data;
     246                                volatile uint64_t * udata = (volatile uint64_t *)&sqe->user_data;
    313247
    314248                                if( *udata == expected &&
     
    336270        }
    337271
    338         static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) {
     272        static inline uint32_t __submit_to_ready_array( struct __io_data & ring, uint32_t idx, const uint32_t mask ) {
    339273                /* paranoid */ verify( idx <= mask   );
    340274                /* paranoid */ verify( idx != -1ul32 );
     
    343277                __attribute((unused)) int len   = 0;
    344278                __attribute((unused)) int block = 0;
    345                 __u32 ready_mask = ring.submit_q.ready_cnt - 1;
     279                uint32_t ready_mask = ring.submit_q.ready_cnt - 1;
    346280
    347281                disable_interrupts();
    348                         __u32 off = __tls_rand();
     282                        uint32_t off = __tls_rand();
    349283                enable_interrupts( __cfaabi_dbg_ctx );
    350284
    351                 __u32 picked;
     285                uint32_t picked;
    352286                LOOKING: for() {
    353287                        for(i; ring.submit_q.ready_cnt) {
    354288                                picked = (i + off) & ready_mask;
    355                                 __u32 expected = -1ul32;
     289                                uint32_t expected = -1ul32;
    356290                                if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) {
    357291                                        break LOOKING;
     
    363297
    364298                        block++;
    365 
    366                         __u32 released = __release_consumed_submission( ring );
    367                         if( released == 0 ) {
     299                        if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
     300                                __release_consumed_submission( ring );
     301                                unlock( ring.submit_q.lock );
     302                        }
     303                        else {
    368304                                yield();
    369305                        }
     
    380316        }
    381317
    382         void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) {
     318        void __submit( struct io_context * ctx, uint32_t idx ) __attribute__((nonnull (1))) {
    383319                __io_data & ring = *ctx->thrd.ring;
    384320                // Get now the data we definetely need
    385                 volatile __u32 * const tail = ring.submit_q.tail;
    386                 const __u32 mask  = *ring.submit_q.mask;
     321                volatile uint32_t * const tail = ring.submit_q.tail;
     322                const uint32_t mask  = *ring.submit_q.mask;
    387323
    388324                // There are 2 submission schemes, check which one we are using
     
    396332                }
    397333                else if( ring.eager_submits ) {
    398                         __u32 picked = __submit_to_ready_array( ring, idx, mask );
    399 
    400                         #if defined(LEADER_LOCK)
    401                                 if( !try_lock(ring.submit_q.submit_lock) ) {
     334                        uint32_t picked = __submit_to_ready_array( ring, idx, mask );
     335
     336                        for() {
     337                                yield();
     338
     339                                // If some one else collected our index, we are done
     340                                #warning ABA problem
     341                                if( ring.submit_q.ready[picked] != idx ) {
    402342                                        __STATS__( false,
    403343                                                io.submit_q.helped += 1;
     
    405345                                        return;
    406346                                }
    407                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    408                                 __STATS__( true,
    409                                         io.submit_q.leader += 1;
     347
     348                                if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
     349                                        __STATS__( false,
     350                                                io.submit_q.leader += 1;
     351                                        )
     352                                        break;
     353                                }
     354
     355                                __STATS__( false,
     356                                        io.submit_q.busy += 1;
    410357                                )
    411                         #else
    412                                 for() {
    413                                         yield();
    414 
    415                                         if( try_lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2) ) {
    416                                                 __STATS__( false,
    417                                                         io.submit_q.leader += 1;
    418                                                 )
    419                                                 break;
    420                                         }
    421 
    422                                         // If some one else collected our index, we are done
    423                                         #warning ABA problem
    424                                         if( ring.submit_q.ready[picked] != idx ) {
    425                                                 __STATS__( false,
    426                                                         io.submit_q.helped += 1;
    427                                                 )
    428                                                 return;
    429                                         }
    430 
    431                                         __STATS__( false,
    432                                                 io.submit_q.busy += 1;
    433                                         )
    434                                 }
    435                         #endif
     358                        }
    436359
    437360                        // We got the lock
    438                         // Collect the submissions
    439361                        unsigned to_submit = __collect_submitions( ring );
    440 
    441                         // Actually submit
    442362                        int ret = __io_uring_enter( ring, to_submit, false );
    443 
    444                         #if defined(LEADER_LOCK)
    445                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    446                                 next(ring.submit_q.submit_lock);
    447                         #else
    448                                 unlock(ring.submit_q.submit_lock);
    449                         #endif
    450                         if( ret < 0 ) return;
     363                        if( ret < 0 ) {
     364                                unlock(ring.submit_q.lock);
     365                                return;
     366                        }
     367
     368                        /* paranoid */ verify( ret > 0 || to_submit == 0 || (ring.ring_flags & IORING_SETUP_SQPOLL) );
    451369
    452370                        // Release the consumed SQEs
     
    454372
    455373                        // update statistics
    456                         __STATS__( false,
     374                        __STATS__( true,
    457375                                io.submit_q.submit_avg.rdy += to_submit;
    458376                                io.submit_q.submit_avg.csm += ret;
    459377                                io.submit_q.submit_avg.cnt += 1;
    460378                        )
     379
     380                        unlock(ring.submit_q.lock);
    461381                }
    462382                else {
    463383                        // get mutual exclusion
    464                         #if defined(LEADER_LOCK)
    465                                 while(!try_lock(ring.submit_q.submit_lock));
    466                         #else
    467                                 lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2);
    468                         #endif
     384                        lock(ring.submit_q.lock __cfaabi_dbg_ctx2);
    469385
    470386                        /* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 0,
     
    504420                        __release_consumed_submission( ring );
    505421
    506                         #if defined(LEADER_LOCK)
    507                                 next(ring.submit_q.submit_lock);
    508                         #else
    509                                 unlock(ring.submit_q.submit_lock);
    510                         #endif
     422                        unlock(ring.submit_q.lock);
    511423
    512424                        __cfadbg_print_safe( io, "Kernel I/O : Performed io_submit for %p, returned %d\n", active_thread(), ret );
     
    514426        }
    515427
    516         // #define PARTIAL_SUBMIT 32
    517428        static unsigned __collect_submitions( struct __io_data & ring ) {
    518429                /* paranoid */ verify( ring.submit_q.ready != 0p );
     
    520431
    521432                unsigned to_submit = 0;
    522                 __u32 tail = *ring.submit_q.tail;
    523                 const __u32 mask = *ring.submit_q.mask;
    524                 #if defined(PARTIAL_SUBMIT)
    525                         #if defined(LEADER_LOCK)
    526                                 #error PARTIAL_SUBMIT and LEADER_LOCK cannot co-exist
    527                         #endif
    528                         const __u32 cnt = ring.submit_q.ready_cnt > PARTIAL_SUBMIT ? PARTIAL_SUBMIT : ring.submit_q.ready_cnt;
    529                         const __u32 offset = ring.submit_q.prev_ready;
    530                         ring.submit_q.prev_ready += cnt;
    531                 #else
    532                         const __u32 cnt = ring.submit_q.ready_cnt;
    533                         const __u32 offset = 0;
    534                 #endif
     433                uint32_t tail = *ring.submit_q.tail;
     434                const uint32_t mask = *ring.submit_q.mask;
    535435
    536436                // Go through the list of ready submissions
    537                 for( c; cnt ) {
    538                         __u32 i = (offset + c) % ring.submit_q.ready_cnt;
    539 
     437                for( i; ring.submit_q.ready_cnt ) {
    540438                        // replace any submission with the sentinel, to consume it.
    541                         __u32 idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
     439                        uint32_t idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
    542440
    543441                        // If it was already the sentinel, then we are done
     
    555453        }
    556454
    557         static __u32 __release_consumed_submission( struct __io_data & ring ) {
    558                 const __u32 smask = *ring.submit_q.mask;
     455        static uint32_t __release_consumed_submission( struct __io_data & ring ) {
     456                const uint32_t smask = *ring.submit_q.mask;
    559457
    560458                if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0;
    561                 __u32 chead = *ring.submit_q.head;
    562                 __u32 phead = ring.submit_q.prev_head;
     459                uint32_t chead = *ring.submit_q.head;
     460                uint32_t phead = ring.submit_q.prev_head;
    563461                ring.submit_q.prev_head = chead;
    564462                unlock(ring.submit_q.release_lock);
    565463
    566                 __u32 count = chead - phead;
     464                uint32_t count = chead - phead;
    567465                for( i; count ) {
    568                         __u32 idx = ring.submit_q.array[ (phead + i) & smask ];
     466                        uint32_t idx = ring.submit_q.array[ (phead + i) & smask ];
    569467                        ring.submit_q.sqes[ idx ].user_data = 0;
    570468                }
  • libcfa/src/concurrency/io/setup.cfa

    re67a82d r67ca73e  
    228228                if( cluster_context ) {
    229229                        cluster & cltr = *thrd.curr_cluster;
    230                         /* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster );
     230                        /* paranoid */ verify( cltr.nprocessors == 0 || &cltr == mainCluster );
    231231                        /* paranoid */ verify( !ready_mutate_islocked() );
    232232
     
    298298                if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;
    299299
    300                 __u32 nentries = params_in.num_entries != 0 ? params_in.num_entries : 256;
    301                 if( !is_pow2(nentries) ) {
    302                         abort("ERROR: I/O setup 'num_entries' must be a power of 2\n");
    303                 }
    304                 if( params_in.poller_submits && params_in.eager_submits ) {
    305                         abort("ERROR: I/O setup 'poller_submits' and 'eager_submits' cannot be used together\n");
    306                 }
     300                uint32_t nentries = params_in.num_entries;
    307301
    308302                int fd = syscall(__NR_io_uring_setup, nentries, &params );
     
    362356                // Get the pointers from the kernel to fill the structure
    363357                // submit queue
    364                 sq.head    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
    365                 sq.tail    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
    366                 sq.mask    = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
    367                 sq.num     = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
    368                 sq.flags   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
    369                 sq.dropped = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
    370                 sq.array   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
     358                sq.head    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
     359                sq.tail    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
     360                sq.mask    = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
     361                sq.num     = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
     362                sq.flags   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
     363                sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
     364                sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
    371365                sq.prev_head = *sq.head;
    372366
    373367                {
    374                         const __u32 num = *sq.num;
     368                        const uint32_t num = *sq.num;
    375369                        for( i; num ) {
    376370                                sq.sqes[i].user_data = 0ul64;
     
    378372                }
    379373
    380                 (sq.submit_lock){};
     374                (sq.lock){};
    381375                (sq.release_lock){};
    382376
     
    388382                                sq.ready[i] = -1ul32;
    389383                        }
    390                         sq.prev_ready = 0;
    391384                }
    392385                else {
    393386                        sq.ready_cnt = 0;
    394387                        sq.ready = 0p;
    395                         sq.prev_ready = 0;
    396388                }
    397389
    398390                // completion queue
    399                 cq.head      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
    400                 cq.tail      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
    401                 cq.mask      = (   const __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
    402                 cq.num       = (   const __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
    403                 cq.overflow  = (         __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
    404                 cq.cqes = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
     391                cq.head     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
     392                cq.tail     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
     393                cq.mask     = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
     394                cq.num      = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
     395                cq.overflow = (         uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
     396                cq.cqes   = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
    405397
    406398                // some paranoid checks
     
    450442        void __ioctx_register($io_ctx_thread & ctx, struct epoll_event & ev) {
    451443                ev.events = EPOLLIN | EPOLLONESHOT;
    452                 ev.data.u64 = (__u64)&ctx;
     444                ev.data.u64 = (uint64_t)&ctx;
    453445                int ret = epoll_ctl(iopoll.epollfd, EPOLL_CTL_ADD, ctx.ring->fd, &ev);
    454446                if (ret < 0) {
  • libcfa/src/concurrency/io/types.hfa

    re67a82d r67ca73e  
    1717
    1818#if defined(CFA_HAVE_LINUX_IO_URING_H)
    19         extern "C" {
    20                 #include <linux/types.h>
    21         }
    22 
    2319      #include "bits/locks.hfa"
    24 
    25         #define LEADER_LOCK
    26         struct __leaderlock_t {
    27                 struct $thread * volatile value;        // ($thread) next_leader | (bool:1) is_locked
    28         };
    29 
    30         static inline void ?{}( __leaderlock_t & this ) { this.value = 0p; }
    3120
    3221        //-----------------------------------------------------------------------
     
    3423      struct __submition_data {
    3524                // Head and tail of the ring (associated with array)
    36                 volatile __u32 * head;
    37                 volatile __u32 * tail;
    38                 volatile __u32 prev_head;
     25                volatile uint32_t * head;
     26                volatile uint32_t * tail;
     27                volatile uint32_t prev_head;
    3928
    4029                // The actual kernel ring which uses head/tail
    4130                // indexes into the sqes arrays
    42                 __u32 * array;
     31                uint32_t * array;
    4332
    4433                // number of entries and mask to go with it
    45                 const __u32 * num;
    46                 const __u32 * mask;
     34                const uint32_t * num;
     35                const uint32_t * mask;
    4736
    4837                // Submission flags (Not sure what for)
    49                 __u32 * flags;
     38                uint32_t * flags;
    5039
    5140                // number of sqes not submitted (whatever that means)
    52                 __u32 * dropped;
     41                uint32_t * dropped;
    5342
    5443                // Like head/tail but not seen by the kernel
    55                 volatile __u32 * ready;
    56                 __u32 ready_cnt;
    57                 __u32 prev_ready;
     44                volatile uint32_t * ready;
     45                uint32_t ready_cnt;
    5846
    59                 #if defined(LEADER_LOCK)
    60                         __leaderlock_t submit_lock;
    61                 #else
    62                         __spinlock_t submit_lock;
    63                 #endif
    64                 __spinlock_t  release_lock;
     47                __spinlock_t lock;
     48                __spinlock_t release_lock;
    6549
    6650                // A buffer of sqes (not the actual ring)
     
    7458        struct __completion_data {
    7559                // Head and tail of the ring
    76                 volatile __u32 * head;
    77                 volatile __u32 * tail;
     60                volatile uint32_t * head;
     61                volatile uint32_t * tail;
    7862
    7963                // number of entries and mask to go with it
    80                 const __u32 * mask;
    81                 const __u32 * num;
     64                const uint32_t * mask;
     65                const uint32_t * num;
    8266
    8367                // number of cqes not submitted (whatever that means)
    84                 __u32 * overflow;
     68                uint32_t * overflow;
    8569
    8670                // the kernel ring
     
    9579                struct __submition_data submit_q;
    9680                struct __completion_data completion_q;
    97                 __u32 ring_flags;
     81                uint32_t ring_flags;
    9882                int fd;
    9983                bool eager_submits:1;
     
    10589        // IO user data
    10690        struct __io_user_data_t {
    107                 __s32 result;
    108                 oneshot sem;
     91                int32_t result;
     92                $thread * thrd;
    10993        };
    11094
  • libcfa/src/concurrency/iocall.cfa

    re67a82d r67ca73e  
    3232        #include "io/types.hfa"
    3333
    34         extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
    35         extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1)));
    36 
    37         static inline void ?{}(struct io_uring_sqe & this, __u8 opcode, int fd) {
     34        extern [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data );
     35        extern void __submit( struct io_context * ctx, uint32_t idx ) __attribute__((nonnull (1)));
     36
     37        static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd) {
    3838                this.opcode = opcode;
    3939                #if !defined(IOSQE_ASYNC)
     
    5151        }
    5252
    53         static inline void ?{}(struct io_uring_sqe & this, __u8 opcode, int fd, void * addr, __u32 len, __u64 off ) {
     53        static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_t off ) {
    5454                (this){ opcode, fd };
    5555                this.off = off;
    56                 this.addr = (__u64)(uintptr_t)addr;
     56                this.addr = (uint64_t)(uintptr_t)addr;
    5757                this.len = len;
    5858        }
     
    101101        #endif
    102102
     103
    103104        #define __submit_prelude \
    104105                if( 0 != (submit_flags & LINK_FLAGS) ) { errno = ENOTSUP; return -1; } \
    105106                (void)timeout; (void)cancellation; \
    106107                if( !context ) context = __get_io_context(); \
    107                 __io_user_data_t data = { 0 }; \
     108                __io_user_data_t data = { 0, active_thread() }; \
    108109                struct __io_data & ring = *context->thrd.ring; \
    109110                struct io_uring_sqe * sqe; \
    110                 __u32 idx; \
    111                 __u8 sflags = REGULAR_FLAGS & submit_flags; \
    112                 [sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&data ); \
    113                 sqe->flags = sflags;
     111                uint32_t idx; \
     112                [sqe, idx] = __submit_alloc( ring, (uint64_t)(uintptr_t)&data ); \
     113                sqe->flags = REGULAR_FLAGS & submit_flags;
    114114
    115115        #define __submit_wait \
    116116                /*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \
    117                 verify( sqe->user_data == (__u64)(uintptr_t)&data ); \
     117                verify( sqe->user_data == (uint64_t)(uintptr_t)&data ); \
    118118                __submit( context, idx ); \
    119                 wait( data.sem ); \
     119                park( __cfaabi_dbg_ctx ); \
    120120                if( data.result < 0 ) { \
    121121                        errno = -data.result; \
     
    149149
    150150        extern int fsync(int fd);
    151 
    152         #if __OFF_T_MATCHES_OFF64_T
    153                 typedef __off64_t off_t;
    154         #else
    155                 typedef __off_t off_t;
    156         #endif
    157         typedef __off64_t off64_t;
    158         extern int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags);
     151        extern int sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags);
    159152
    160153        struct msghdr;
     
    167160        extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    168161
    169         extern int fallocate(int fd, int mode, off_t offset, off_t len);
    170         extern int posix_fadvise(int fd, off_t offset, off_t len, int advice);
     162        extern int fallocate(int fd, int mode, uint64_t offset, uint64_t len);
     163        extern int posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice);
    171164        extern int madvise(void *addr, size_t length, int advice);
    172165
     
    193186                        __submit_prelude
    194187
    195                         sqe->opcode = IORING_OP_READV;
    196                         sqe->ioprio = 0;
    197                         sqe->fd = fd;
    198                         sqe->off = offset;
    199                         sqe->addr = (__u64)iov;
    200                         sqe->len = iovcnt;
    201                         sqe->rw_flags = 0;
    202                         sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
     188                        (*sqe){ IORING_OP_READV, fd, iov, iovcnt, offset };
    203189
    204190                        __submit_wait
     
    214200                        __submit_prelude
    215201
    216                         sqe->opcode = IORING_OP_WRITEV;
    217                         sqe->ioprio = 0;
    218                         sqe->fd = fd;
    219                         sqe->off = offset;
    220                         sqe->addr = (__u64)iov;
    221                         sqe->len = iovcnt;
    222                         sqe->rw_flags = 0;
    223                         sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
     202                        (*sqe){ IORING_OP_WRITEV, fd, iov, iovcnt, offset };
    224203
    225204                        __submit_wait
     
    234213                __submit_prelude
    235214
    236                 sqe->opcode = IORING_OP_FSYNC;
    237                 sqe->ioprio = 0;
    238                 sqe->fd = fd;
    239                 sqe->off = 0;
    240                 sqe->addr = 0;
    241                 sqe->len = 0;
    242                 sqe->rw_flags = 0;
    243                 sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
    244 
    245                 __submit_wait
    246         #endif
    247 }
    248 
    249 int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
     215                (*sqe){ IORING_OP_FSYNC, fd };
     216
     217                __submit_wait
     218        #endif
     219}
     220
     221int cfa_sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
    250222        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_SYNC_FILE_RANGE)
    251223                return sync_file_range(fd, offset, nbytes, flags);
     
    296268
    297269                (*sqe){ IORING_OP_SEND, sockfd };
    298                 sqe->addr = (__u64)buf;
     270                sqe->addr = (uint64_t)buf;
    299271                sqe->len = len;
    300272                sqe->msg_flags = flags;
     
    311283
    312284                (*sqe){ IORING_OP_RECV, sockfd };
    313                 sqe->addr = (__u64)buf;
     285                sqe->addr = (uint64_t)buf;
    314286                sqe->len = len;
    315287                sqe->msg_flags = flags;
     
    326298
    327299                (*sqe){ IORING_OP_ACCEPT, sockfd };
    328                 sqe->addr  = (__u64)addr;
    329                 sqe->addr2 = (__u64)addrlen;
     300                sqe->addr = (uint64_t)(uintptr_t)addr;
     301                sqe->addr2 = (uint64_t)(uintptr_t)addrlen;
    330302                sqe->accept_flags = flags;
    331303
     
    341313
    342314                (*sqe){ IORING_OP_CONNECT, sockfd };
    343                 sqe->addr = (__u64)addr;
    344                 sqe->off  = (__u64)addrlen;
    345 
    346                 __submit_wait
    347         #endif
    348 }
    349 
    350 int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
     315                sqe->addr = (uint64_t)(uintptr_t)addr;
     316                sqe->off  = (uint64_t)(uintptr_t)addrlen;
     317
     318                __submit_wait
     319        #endif
     320}
     321
     322int cfa_fallocate(int fd, int mode, uint64_t offset, uint64_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
    351323        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FALLOCATE)
    352324                return fallocate( fd, mode, offset, len );
     
    365337}
    366338
    367 int cfa_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
     339int cfa_fadvise(int fd, uint64_t offset, uint64_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
    368340        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FADVISE)
    369341                return posix_fadvise( fd, offset, len, advice );
     
    372344
    373345                (*sqe){ IORING_OP_FADVISE, fd };
    374                 sqe->off = (__u64)offset;
     346                sqe->off = (uint64_t)offset;
    375347                sqe->len = len;
    376348                sqe->fadvise_advice = advice;
     
    387359
    388360                (*sqe){ IORING_OP_MADVISE, 0 };
    389                 sqe->addr = (__u64)addr;
     361                sqe->addr = (uint64_t)addr;
    390362                sqe->len = length;
    391363                sqe->fadvise_advice = advice;
     
    402374
    403375                (*sqe){ IORING_OP_OPENAT, dirfd };
    404                 sqe->addr = (__u64)pathname;
     376                sqe->addr = (uint64_t)pathname;
    405377                sqe->open_flags = flags;
    406378                sqe->len = mode;
     
    435407                __submit_prelude
    436408
    437                 (*sqe){ IORING_OP_STATX, dirfd, pathname, mask, (__u64)statxbuf };
     409                (*sqe){ IORING_OP_STATX, dirfd, pathname, mask, (uint64_t)statxbuf };
    438410                sqe->statx_flags = flags;
    439411
     
    477449                }
    478450                else {
    479                         sqe->off = (__u64)-1;
     451                        sqe->off = (uint64_t)-1;
    480452                }
    481453                sqe->len = len;
     
    485457                }
    486458                else {
    487                         sqe->splice_off_in = (__u64)-1;
     459                        sqe->splice_off_in = (uint64_t)-1;
    488460                }
    489461                sqe->splice_flags  = flags | (SPLICE_FLAGS & submit_flags);
  • libcfa/src/concurrency/kernel.cfa

    re67a82d r67ca73e  
    102102// Kernel Scheduling logic
    103103static $thread * __next_thread(cluster * this);
    104 static $thread * __next_thread_slow(cluster * this);
     104static bool __has_next_thread(cluster * this);
    105105static void __run_thread(processor * this, $thread * dst);
    106 static void __wake_one(struct __processor_id_t * id, cluster * cltr);
    107 
    108 static void push  (__cluster_idles & idles, processor & proc);
    109 static void remove(__cluster_idles & idles, processor & proc);
    110 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
    111 
     106static bool __wake_one(struct __processor_id_t * id, cluster * cltr);
     107static void __halt(processor * this);
     108bool __wake_proc(processor *);
    112109
    113110//=============================================================================================
     
    119116        // Do it here
    120117        kernelTLS.rand_seed ^= rdtscl();
    121         kernelTLS.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&runner);
    122         __tls_rand_advance_bck();
    123118
    124119        processor * this = runner.proc;
     
    139134
    140135                $thread * readyThread = 0p;
    141                 MAIN_LOOP:
    142                 for() {
     136                for( unsigned int spin_count = 0;; spin_count++ ) {
    143137                        // Try to get the next thread
    144138                        readyThread = __next_thread( this->cltr );
    145139
     140                        // Check if we actually found a thread
     141                        if( readyThread ) {
     142                                /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     143                                /* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted);
     144                                /* paranoid */ verifyf( readyThread->link.next == 0p, "Expected null got %p", readyThread->link.next );
     145                                __builtin_prefetch( readyThread->context.SP );
     146
     147                                // We found a thread run it
     148                                __run_thread(this, readyThread);
     149
     150                                /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     151                        }
     152
     153                        if(__atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST)) break;
     154
    146155                        if( !readyThread ) {
    147                                 readyThread = __next_thread_slow( this->cltr );
     156                                // Block until a thread is ready
     157                                __halt(this);
    148158                        }
    149 
    150                         HALT:
    151                         if( !readyThread ) {
    152                                 // Don't block if we are done
    153                                 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    154 
    155                                 #if !defined(__CFA_NO_STATISTICS__)
    156                                         __tls_stats()->ready.sleep.halts++;
    157                                 #endif
    158 
    159                                 // Push self to idle stack
    160                                 push(this->cltr->idles, * this);
    161 
    162                                 // Confirm the ready-queue is empty
    163                                 readyThread = __next_thread_slow( this->cltr );
    164                                 if( readyThread ) {
    165                                         // A thread was found, cancel the halt
    166                                         remove(this->cltr->idles, * this);
    167 
    168                                         #if !defined(__CFA_NO_STATISTICS__)
    169                                                 __tls_stats()->ready.sleep.cancels++;
    170                                         #endif
    171 
    172                                         // continue the mai loop
    173                                         break HALT;
    174                                 }
    175 
    176                                 #if !defined(__CFA_NO_STATISTICS__)
    177                                         if(this->print_halts) {
    178                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
    179                                         }
    180                                 #endif
    181 
    182                                 wait( this->idle );
    183 
    184                                 #if !defined(__CFA_NO_STATISTICS__)
    185                                         if(this->print_halts) {
    186                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
    187                                         }
    188                                 #endif
    189 
    190                                 // We were woken up, remove self from idle
    191                                 remove(this->cltr->idles, * this);
    192 
    193                                 // DON'T just proceed, start looking again
    194                                 continue MAIN_LOOP;
    195                         }
    196 
    197                         /* paranoid */ verify( readyThread );
    198 
    199                         // We found a thread run it
    200                         __run_thread(this, readyThread);
    201 
    202                         // Are we done?
    203                         if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    204159                }
    205160
     
    226181// from the processor coroutine to the target thread
    227182static void __run_thread(processor * this, $thread * thrd_dst) {
    228         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    229         /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
    230         /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
    231         __builtin_prefetch( thrd_dst->context.SP );
    232 
    233183        $coroutine * proc_cor = get_coroutine(this->runner);
    234184
     
    310260        proc_cor->state = Active;
    311261        kernelTLS.this_thread = 0p;
    312 
    313         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    314262}
    315263
     
    368316        ready_schedule_lock  ( id );
    369317                push( thrd->curr_cluster, thrd );
    370                 __wake_one(id, thrd->curr_cluster);
     318
     319                #if !defined(__CFA_NO_STATISTICS__)
     320                        bool woke =
     321                #endif
     322                        __wake_one(id, thrd->curr_cluster);
     323
     324                #if !defined(__CFA_NO_STATISTICS__)
     325                        if(woke) __tls_stats()->ready.sleep.wakes++;
     326                #endif
    371327        ready_schedule_unlock( id );
    372328
     
    375331
    376332// KERNEL ONLY
    377 static inline $thread * __next_thread(cluster * this) with( *this ) {
     333static $thread * __next_thread(cluster * this) with( *this ) {
    378334        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    379335
    380336        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    381                 $thread * thrd = pop( this );
     337                $thread * head = pop( this );
    382338        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    383339
    384340        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    385         return thrd;
     341        return head;
    386342}
    387343
    388344// KERNEL ONLY
    389 static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
     345static bool __has_next_thread(cluster * this) with( *this ) {
    390346        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    391347
    392348        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    393                 $thread * thrd = pop_slow( this );
     349                bool not_empty = query( this );
    394350        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    395351
    396352        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    397         return thrd;
     353        return not_empty;
    398354}
    399355
     
    485441//=============================================================================================
    486442// Wake a thread from the front if there are any
    487 static void __wake_one(struct __processor_id_t * id, cluster * this) {
    488         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     443static bool __wake_one(struct __processor_id_t * id, cluster * this) {
    489444        /* paranoid */ verify( ready_schedule_islocked( id ) );
    490445
    491446        // Check if there is a sleeping processor
    492         processor * p;
    493         unsigned idle;
    494         unsigned total;
    495         [idle, total, p] = query(this->idles);
     447        processor * p = pop(this->idles);
    496448
    497449        // If no one is sleeping, we are done
    498         if( idle == 0 ) return;
     450        if( 0p == p ) return false;
    499451
    500452        // We found a processor, wake it up
    501453        post( p->idle );
    502454
    503         #if !defined(__CFA_NO_STATISTICS__)
    504                 __tls_stats()->ready.sleep.wakes++;
    505         #endif
    506 
    507         /* paranoid */ verify( ready_schedule_islocked( id ) );
    508         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    509 
    510         return;
     455        return true;
    511456}
    512457
    513458// Unconditionnaly wake a thread
    514 void __wake_proc(processor * this) {
     459bool __wake_proc(processor * this) {
    515460        __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    516461
     
    519464                bool ret = post( this->idle );
    520465        enable_interrupts( __cfaabi_dbg_ctx );
    521 }
    522 
    523 static void push  (__cluster_idles & this, processor & proc) {
    524         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    525         lock( this );
    526                 this.idle++;
    527                 /* paranoid */ verify( this.idle <= this.total );
    528 
    529                 insert_first(this.list, proc);
    530         unlock( this );
    531         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    532 }
    533 
    534 static void remove(__cluster_idles & this, processor & proc) {
    535         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    536         lock( this );
    537                 this.idle--;
    538                 /* paranoid */ verify( this.idle >= 0 );
    539 
    540                 remove(proc);
    541         unlock( this );
    542         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    543 }
    544 
    545 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
    546         for() {
    547                 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
    548                 if( 1 == (l % 2) ) { Pause(); continue; }
    549                 unsigned idle    = this.idle;
    550                 unsigned total   = this.total;
    551                 processor * proc = &this.list`first;
    552                 // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
    553                 asm volatile("": : :"memory");
    554                 if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; }
    555                 return [idle, total, proc];
    556         }
     466
     467        return ret;
     468}
     469
     470static void __halt(processor * this) with( *this ) {
     471        if( do_terminate ) return;
     472
     473        #if !defined(__CFA_NO_STATISTICS__)
     474                __tls_stats()->ready.sleep.halts++;
     475        #endif
     476        // Push self to queue
     477        push(cltr->idles, *this);
     478
     479        // Makre sure we don't miss a thread
     480        if( __has_next_thread(cltr) ) {
     481                // A thread was posted, make sure a processor is woken up
     482                struct __processor_id_t *id = (struct __processor_id_t *) this;
     483                ready_schedule_lock  ( id );
     484                        __wake_one( id, cltr );
     485                ready_schedule_unlock( id );
     486                #if !defined(__CFA_NO_STATISTICS__)
     487                        __tls_stats()->ready.sleep.cancels++;
     488                #endif
     489        }
     490
     491        #if !defined(__CFA_NO_STATISTICS__)
     492                if(this->print_halts) {
     493                        __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
     494                }
     495        #endif
     496
     497        wait( idle );
     498
     499        #if !defined(__CFA_NO_STATISTICS__)
     500                if(this->print_halts) {
     501                        __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
     502                }
     503        #endif
    557504}
    558505
  • libcfa/src/concurrency/kernel.hfa

    re67a82d r67ca73e  
    2020#include "coroutine.hfa"
    2121
    22 #include "containers/list.hfa"
     22#include "containers/stackLockFree.hfa"
    2323
    2424extern "C" {
     
    9999
    100100        // Link lists fields
    101         DLISTED_MGD_IMPL_IN(processor)
     101        Link(processor) link;
    102102
    103103        #if !defined(__CFA_NO_STATISTICS__)
     
    119119static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
    120120
    121 DLISTED_MGD_IMPL_OUT(processor)
     121static inline Link(processor) * ?`next( processor * this ) { return &this->link; }
    122122
    123123//-----------------------------------------------------------------------------
     
    206206void ^?{}(__ready_queue_t & this);
    207207
    208 // Idle Sleep
    209 struct __cluster_idles {
    210         // Spin lock protecting the queue
    211         volatile uint64_t lock;
    212 
    213         // Total number of processors
    214         unsigned total;
    215 
    216         // Total number of idle processors
    217         unsigned idle;
    218 
    219         // List of idle processors
    220         dlist(processor, processor) list;
    221 };
    222 
    223208//-----------------------------------------------------------------------------
    224209// Cluster
     
    234219
    235220        // List of idle processors
    236         __cluster_idles idles;
     221        StackLF(processor) idles;
     222        volatile unsigned int nprocessors;
    237223
    238224        // List of threads
  • libcfa/src/concurrency/kernel/fwd.hfa

    re67a82d r67ca73e  
    5050                                uint64_t rand_seed;
    5151                        #endif
    52                         struct {
    53                                 uint64_t fwd_seed;
    54                                 uint64_t bck_seed;
    55                         } ready_rng;
    5652                } kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
    57 
    58 
    5953
    6054                static inline uint64_t __tls_rand() {
     
    6458                                return __xorshift64( kernelTLS.rand_seed );
    6559                        #endif
    66                 }
    67 
    68                 #define M  (1_l64u << 48_l64u)
    69                 #define A  (25214903917_l64u)
    70                 #define AI (18446708753438544741_l64u)
    71                 #define C  (11_l64u)
    72                 #define D  (16_l64u)
    73 
    74                 static inline unsigned __tls_rand_fwd() {
    75 
    76                         kernelTLS.ready_rng.fwd_seed = (A * kernelTLS.ready_rng.fwd_seed + C) & (M - 1);
    77                         return kernelTLS.ready_rng.fwd_seed >> D;
    78                 }
    79 
    80                 static inline unsigned __tls_rand_bck() {
    81                         unsigned int r = kernelTLS.ready_rng.bck_seed >> D;
    82                         kernelTLS.ready_rng.bck_seed = AI * (kernelTLS.ready_rng.bck_seed - C) & (M - 1);
    83                         return r;
    84                 }
    85 
    86                 #undef M
    87                 #undef A
    88                 #undef AI
    89                 #undef C
    90                 #undef D
    91 
    92                 static inline void __tls_rand_advance_bck(void) {
    93                         kernelTLS.ready_rng.bck_seed = kernelTLS.ready_rng.fwd_seed;
    9460                }
    9561        }
  • libcfa/src/concurrency/kernel/startup.cfa

    re67a82d r67ca73e  
    7878static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info);
    7979
    80 #if defined(__CFA_WITH_VERIFY__)
    81         static bool verify_fwd_bck_rng(void);
    82 #endif
    83 
    8480//-----------------------------------------------------------------------------
    8581// Forward Declarations for other modules
     
    9187//-----------------------------------------------------------------------------
    9288// Other Forward Declarations
    93 extern void __wake_proc(processor *);
     89extern bool __wake_proc(processor *);
    9490
    9591//-----------------------------------------------------------------------------
     
    162158        __cfa_dbg_global_clusters.list{ __get };
    163159        __cfa_dbg_global_clusters.lock{};
    164 
    165         /* paranoid */ verify( verify_fwd_bck_rng() );
    166160
    167161        // Initialize the global scheduler lock
     
    481475        #endif
    482476
    483         lock( this.cltr->idles );
    484                 int target = this.cltr->idles.total += 1u;
    485         unlock( this.cltr->idles );
     477        int target = __atomic_add_fetch( &cltr->nprocessors, 1u, __ATOMIC_SEQ_CST );
    486478
    487479        id = doregister((__processor_id_t*)&this);
     
    501493// Not a ctor, it just preps the destruction but should not destroy members
    502494static void deinit(processor & this) {
    503         lock( this.cltr->idles );
    504                 int target = this.cltr->idles.total -= 1u;
    505         unlock( this.cltr->idles );
     495
     496        int target = __atomic_sub_fetch( &this.cltr->nprocessors, 1u, __ATOMIC_SEQ_CST );
    506497
    507498        // Lock the RWlock so no-one pushes/pops while we are changing the queue
     
    510501                // Adjust the ready queue size
    511502                ready_queue_shrink( this.cltr, target );
     503
     504                // Make sure we aren't on the idle queue
     505                unsafe_remove( this.cltr->idles, &this );
    512506
    513507        // Unlock the RWlock
     
    522516        ( this.terminated ){ 0 };
    523517        ( this.runner ){};
    524 
    525         disable_interrupts();
    526                 init( this, name, _cltr );
    527         enable_interrupts( __cfaabi_dbg_ctx );
     518        init( this, name, _cltr );
    528519
    529520        __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this);
     
    549540        free( this.stack );
    550541
    551         disable_interrupts();
    552                 deinit( this );
    553         enable_interrupts( __cfaabi_dbg_ctx );
     542        deinit( this );
    554543}
    555544
    556545//-----------------------------------------------------------------------------
    557546// Cluster
    558 static void ?{}(__cluster_idles & this) {
    559         this.lock  = 0;
    560         this.idle  = 0;
    561         this.total = 0;
    562         (this.list){};
    563 }
    564 
    565547void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) with( this ) {
    566548        this.name = name;
    567549        this.preemption_rate = preemption_rate;
     550        this.nprocessors = 0;
    568551        ready_queue{};
    569552
     
    683666        return stack;
    684667}
    685 
    686 #if defined(__CFA_WITH_VERIFY__)
    687 static bool verify_fwd_bck_rng(void) {
    688         kernelTLS.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&verify_fwd_bck_rng);
    689 
    690         unsigned values[10];
    691         for(i; 10) {
    692                 values[i] = __tls_rand_fwd();
    693         }
    694 
    695         __tls_rand_advance_bck();
    696 
    697         for ( i; 9 -~= 0 ) {
    698                 if(values[i] != __tls_rand_bck()) {
    699                         return false;
    700                 }
    701         }
    702 
    703         return true;
    704 }
    705 #endif
  • libcfa/src/concurrency/kernel_private.hfa

    re67a82d r67ca73e  
    121121void     unregister( struct __processor_id_t * proc );
    122122
    123 //-----------------------------------------------------------------------
    124 // Cluster idle lock/unlock
    125 static inline void lock(__cluster_idles & this) {
    126         for() {
    127                 uint64_t l = this.lock;
    128                 if(
    129                         (0 == (l % 2))
    130                         && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
    131                 ) return;
    132                 Pause();
    133         }
    134 }
    135 
    136 static inline void unlock(__cluster_idles & this) {
    137         /* paranoid */ verify( 1 == (this.lock % 2) );
    138         __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
    139 }
    140 
    141123//=======================================================================
    142124// Reader-writer lock implementation
     
    266248// pop thread from the ready queue of a cluster
    267249// returns 0p if empty
    268 // May return 0p spuriously
    269250__attribute__((hot)) struct $thread * pop(struct cluster * cltr);
    270 
    271 //-----------------------------------------------------------------------
    272 // pop thread from the ready queue of a cluster
    273 // returns 0p if empty
    274 // guaranteed to find any threads added before this call
    275 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
    276251
    277252//-----------------------------------------------------------------------
  • libcfa/src/concurrency/ready_queue.cfa

    re67a82d r67ca73e  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
    19 // #define USE_SNZI
    20 
    2119#include "bits/defs.hfa"
    2220#include "kernel_private.hfa"
     
    150148//  queues or removing them.
    151149uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
    152         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    153 
    154150        // Step 1 : lock global lock
    155151        // It is needed to avoid processors that register mid Critical-Section
     
    166162        }
    167163
    168         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    169164        return s;
    170165}
    171166
    172167void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
    173         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    174 
    175168        // Step 1 : release local locks
    176169        // This must be done while the global lock is held to avoid
     
    187180        /*paranoid*/ assert(true == lock);
    188181        __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
    189 
    190         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    191182}
    192183
     
    201192void ^?{}(__ready_queue_t & this) with (this) {
    202193        verify( 1 == lanes.count );
    203         #ifdef USE_SNZI
    204                 verify( !query( snzi ) );
    205         #endif
     194        verify( !query( snzi ) );
    206195        free(lanes.data);
    207196}
     
    209198//-----------------------------------------------------------------------
    210199__attribute__((hot)) bool query(struct cluster * cltr) {
    211         #ifdef USE_SNZI
    212                 return query(cltr->ready_queue.snzi);
    213         #endif
    214         return true;
     200        return query(cltr->ready_queue.snzi);
    215201}
    216202
     
    276262        bool lane_first = push(lanes.data[i], thrd);
    277263
    278         #ifdef USE_SNZI
    279                 // If this lane used to be empty we need to do more
    280                 if(lane_first) {
    281                         // Check if the entire queue used to be empty
    282                         first = !query(snzi);
    283 
    284                         // Update the snzi
    285                         arrive( snzi, i );
    286                 }
    287         #endif
     264        // If this lane used to be empty we need to do more
     265        if(lane_first) {
     266                // Check if the entire queue used to be empty
     267                first = !query(snzi);
     268
     269                // Update the snzi
     270                arrive( snzi, i );
     271        }
    288272
    289273        // Unlock and return
     
    310294__attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
    311295        /* paranoid */ verify( lanes.count > 0 );
    312         unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    313296        #if defined(BIAS)
    314297                // Don't bother trying locally too much
     
    317300
    318301        // As long as the list is not empty, try finding a lane that isn't empty and pop from it
    319         #ifdef USE_SNZI
    320                 while( query(snzi) ) {
    321         #else
    322                 for(25) {
    323         #endif
     302        while( query(snzi) ) {
    324303                // Pick two lists at random
    325304                unsigned i,j;
     
    357336                #endif
    358337
    359                 i %= count;
    360                 j %= count;
     338                i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     339                j %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    361340
    362341                // try popping from the 2 picked lists
     
    374353}
    375354
    376 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
    377         /* paranoid */ verify( lanes.count > 0 );
    378         unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    379         unsigned offset = __tls_rand();
    380         for(i; count) {
    381                 unsigned idx = (offset + i) % count;
    382                 struct $thread * thrd = try_pop(cltr, idx);
    383                 if(thrd) {
    384                         return thrd;
    385                 }
    386         }
    387 
    388         // All lanes where empty return 0p
    389         return 0p;
    390 }
    391 
    392 
    393355//-----------------------------------------------------------------------
    394356// Given 2 indexes, pick the list with the oldest push an try to pop from it
     
    426388        // Actually pop the list
    427389        struct $thread * thrd;
    428         thrd = pop(lane);
     390        bool emptied;
     391        [thrd, emptied] = pop(lane);
    429392
    430393        /* paranoid */ verify(thrd);
    431394        /* paranoid */ verify(lane.lock);
    432395
    433         #ifdef USE_SNZI
    434                 // If this was the last element in the lane
    435                 if(emptied) {
    436                         depart( snzi, w );
    437                 }
    438         #endif
     396        // If this was the last element in the lane
     397        if(emptied) {
     398                depart( snzi, w );
     399        }
    439400
    440401        // Unlock and return
     
    463424                        if(head(lane)->link.next == thrd) {
    464425                                $thread * pthrd;
    465                                 pthrd = pop(lane);
     426                                bool emptied;
     427                                [pthrd, emptied] = pop(lane);
    466428
    467429                                /* paranoid */ verify( pthrd == thrd );
    468430
    469431                                removed = true;
    470                                 #ifdef USE_SNZI
    471                                         if(emptied) {
    472                                                 depart( snzi, i );
    473                                         }
    474                                 #endif
     432                                if(emptied) {
     433                                        depart( snzi, i );
     434                                }
    475435                        }
    476436                __atomic_unlock(&lane.lock);
     
    534494        // grow the ready queue
    535495        with( cltr->ready_queue ) {
    536                 #ifdef USE_SNZI
    537                         ^(snzi){};
    538                 #endif
     496                ^(snzi){};
    539497
    540498                // Find new count
     
    558516                lanes.count = ncount;
    559517
    560                 #ifdef USE_SNZI
    561                         // Re-create the snzi
    562                         snzi{ log2( lanes.count / 8 ) };
    563                         for( idx; (size_t)lanes.count ) {
    564                                 if( !is_empty(lanes.data[idx]) ) {
    565                                         arrive(snzi, idx);
    566                                 }
    567                         }
    568                 #endif
     518                // Re-create the snzi
     519                snzi{ log2( lanes.count / 8 ) };
     520                for( idx; (size_t)lanes.count ) {
     521                        if( !is_empty(lanes.data[idx]) ) {
     522                                arrive(snzi, idx);
     523                        }
     524                }
    569525        }
    570526
     
    586542
    587543        with( cltr->ready_queue ) {
    588                 #ifdef USE_SNZI
    589                         ^(snzi){};
    590                 #endif
     544                ^(snzi){};
    591545
    592546                // Remember old count
     
    613567                        while(!is_empty(lanes.data[idx])) {
    614568                                struct $thread * thrd;
    615                                 thrd = pop(lanes.data[idx]);
     569                                __attribute__((unused)) bool _;
     570                                [thrd, _] = pop(lanes.data[idx]);
    616571
    617572                                push(cltr, thrd);
     
    641596                }
    642597
    643                 #ifdef USE_SNZI
    644                         // Re-create the snzi
    645                         snzi{ log2( lanes.count / 8 ) };
    646                         for( idx; (size_t)lanes.count ) {
    647                                 if( !is_empty(lanes.data[idx]) ) {
    648                                         arrive(snzi, idx);
    649                                 }
    650                         }
    651                 #endif
     598                // Re-create the snzi
     599                snzi{ log2( lanes.count / 8 ) };
     600                for( idx; (size_t)lanes.count ) {
     601                        if( !is_empty(lanes.data[idx]) ) {
     602                                arrive(snzi, idx);
     603                        }
     604                }
    652605        }
    653606
  • libcfa/src/concurrency/ready_subqueue.hfa

    re67a82d r67ca73e  
    144144// returns popped
    145145// returns true of lane was empty before push, false otherwise
    146 $thread * pop(__intrusive_lane_t & this) {
     146[$thread *, bool] pop(__intrusive_lane_t & this) {
    147147        /* paranoid */ verify(this.lock);
    148148        /* paranoid */ verify(this.before.link.ts != 0ul);
     
    162162        head->link.next = next;
    163163        next->link.prev = head;
    164         node->link.next = 0p;
    165         node->link.prev = 0p;
     164        node->link.[next, prev] = 0p;
    166165
    167166        // Update head time stamp
     
    181180                /* paranoid */ verify(tail(this)->link.prev == head(this));
    182181                /* paranoid */ verify(head(this)->link.next == tail(this));
    183                 return node;
     182                return [node, true];
    184183        }
    185184        else {
     
    188187                /* paranoid */ verify(head(this)->link.next != tail(this));
    189188                /* paranoid */ verify(this.before.link.ts != 0);
    190                 return node;
     189                return [node, false];
    191190        }
    192191}
  • libcfa/src/concurrency/stats.cfa

    re67a82d r67ca73e  
    3838                        stats->io.submit_q.busy   = 0;
    3939                        stats->io.complete_q.completed_avg.val = 0;
    40                         stats->io.complete_q.completed_avg.cnt = 0;
    41                         stats->io.complete_q.blocks = 0;
     40                        stats->io.complete_q.completed_avg.slow_cnt = 0;
     41                        stats->io.complete_q.completed_avg.fast_cnt = 0;
    4242                #endif
    4343        }
     
    6060
    6161                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    62                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy     , proc->io.submit_q.submit_avg.rdy     , __ATOMIC_SEQ_CST );
    63                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm     , proc->io.submit_q.submit_avg.csm     , __ATOMIC_SEQ_CST );
    64                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl     , proc->io.submit_q.submit_avg.avl     , __ATOMIC_SEQ_CST );
    65                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt     , proc->io.submit_q.submit_avg.cnt     , __ATOMIC_SEQ_CST );
    66                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.val       , proc->io.submit_q.look_avg.val       , __ATOMIC_SEQ_CST );
    67                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt       , proc->io.submit_q.look_avg.cnt       , __ATOMIC_SEQ_CST );
    68                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.block     , proc->io.submit_q.look_avg.block     , __ATOMIC_SEQ_CST );
    69                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val      , proc->io.submit_q.alloc_avg.val      , __ATOMIC_SEQ_CST );
    70                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt      , proc->io.submit_q.alloc_avg.cnt      , __ATOMIC_SEQ_CST );
    71                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block    , proc->io.submit_q.alloc_avg.block    , __ATOMIC_SEQ_CST );
    72                         __atomic_fetch_add( &cltr->io.submit_q.helped             , proc->io.submit_q.helped             , __ATOMIC_SEQ_CST );
    73                         __atomic_fetch_add( &cltr->io.submit_q.leader             , proc->io.submit_q.leader             , __ATOMIC_SEQ_CST );
    74                         __atomic_fetch_add( &cltr->io.submit_q.busy               , proc->io.submit_q.busy               , __ATOMIC_SEQ_CST );
    75                         __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val, proc->io.complete_q.completed_avg.val, __ATOMIC_SEQ_CST );
    76                         __atomic_fetch_add( &cltr->io.complete_q.completed_avg.cnt, proc->io.complete_q.completed_avg.cnt, __ATOMIC_SEQ_CST );
    77                         __atomic_fetch_add( &cltr->io.complete_q.blocks           , proc->io.complete_q.blocks           , __ATOMIC_SEQ_CST );
     62                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy          , proc->io.submit_q.submit_avg.rdy          , __ATOMIC_SEQ_CST );
     63                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm          , proc->io.submit_q.submit_avg.csm          , __ATOMIC_SEQ_CST );
     64                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl          , proc->io.submit_q.submit_avg.avl          , __ATOMIC_SEQ_CST );
     65                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt          , proc->io.submit_q.submit_avg.cnt          , __ATOMIC_SEQ_CST );
     66                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.val            , proc->io.submit_q.look_avg.val            , __ATOMIC_SEQ_CST );
     67                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt            , proc->io.submit_q.look_avg.cnt            , __ATOMIC_SEQ_CST );
     68                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.block          , proc->io.submit_q.look_avg.block          , __ATOMIC_SEQ_CST );
     69                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val           , proc->io.submit_q.alloc_avg.val           , __ATOMIC_SEQ_CST );
     70                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt           , proc->io.submit_q.alloc_avg.cnt           , __ATOMIC_SEQ_CST );
     71                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block         , proc->io.submit_q.alloc_avg.block         , __ATOMIC_SEQ_CST );
     72                        __atomic_fetch_add( &cltr->io.submit_q.helped                  , proc->io.submit_q.helped                  , __ATOMIC_SEQ_CST );
     73                        __atomic_fetch_add( &cltr->io.submit_q.leader                  , proc->io.submit_q.leader                  , __ATOMIC_SEQ_CST );
     74                        __atomic_fetch_add( &cltr->io.submit_q.busy                    , proc->io.submit_q.busy                    , __ATOMIC_SEQ_CST );
     75                        __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val     , proc->io.complete_q.completed_avg.val     , __ATOMIC_SEQ_CST );
     76                        __atomic_fetch_add( &cltr->io.complete_q.completed_avg.slow_cnt, proc->io.complete_q.completed_avg.slow_cnt, __ATOMIC_SEQ_CST );
     77                        __atomic_fetch_add( &cltr->io.complete_q.completed_avg.fast_cnt, proc->io.complete_q.completed_avg.fast_cnt, __ATOMIC_SEQ_CST );
    7878                #endif
    7979        }
     
    154154                                        "- avg alloc search len   : %'18.2lf\n"
    155155                                        "- avg alloc search block : %'18.2lf\n"
    156                                         "- total wait calls       : %'15" PRIu64 "\n"
     156                                        "- total wait calls       : %'15" PRIu64 "   (%'" PRIu64 " slow, %'" PRIu64 " fast)\n"
    157157                                        "- avg completion/wait    : %'18.2lf\n"
    158                                         "- total completion blocks: %'15" PRIu64 "\n"
    159158                                        "\n"
    160159                                        , cluster ? "Cluster" : "Processor",  name, id
     
    166165                                        , io.submit_q.alloc_avg.cnt
    167166                                        , aavgv, aavgb
    168                                         , io.complete_q.completed_avg.cnt
    169                                         , ((double)io.complete_q.completed_avg.val) / io.complete_q.completed_avg.cnt
    170                                         , io.complete_q.blocks
     167                                        , io.complete_q.completed_avg.slow_cnt + io.complete_q.completed_avg.fast_cnt
     168                                        , io.complete_q.completed_avg.slow_cnt,  io.complete_q.completed_avg.fast_cnt
     169                                        , ((double)io.complete_q.completed_avg.val) / (io.complete_q.completed_avg.slow_cnt + io.complete_q.completed_avg.fast_cnt)
    171170                                );
    172171                        }
  • libcfa/src/concurrency/stats.hfa

    re67a82d r67ca73e  
    9090                                struct {
    9191                                        volatile uint64_t val;
    92                                         volatile uint64_t cnt;
     92                                        volatile uint64_t slow_cnt;
     93                                        volatile uint64_t fast_cnt;
    9394                                } completed_avg;
    94                                 volatile uint64_t blocks;
    9595                        } complete_q;
    9696                };
  • libcfa/src/containers/list.hfa

    re67a82d r67ca73e  
    1313// Update Count     : 1
    1414//
    15 
    16 #pragma once
    1715
    1816#include <assert.h>
  • libcfa/src/exception.c

    re67a82d r67ca73e  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 20 23:45:45 2020
    13 // Update Count     : 27
     12// Last Modified On : Sat Aug 15 07:17:19 2020
     13// Update Count     : 26
    1414//
    1515
     
    3131#include <unwind.h>
    3232#include <bits/debug.hfa>
    33 #include "concurrency/invoke.h"
    3433#include "stdhdr/assert.h"
    3534
     
    6261
    6362
     63// Temperary global exception context. Does not work with concurency.
     64struct exception_context_t {
     65        struct __cfaehm_try_resume_node * top_resume;
     66
     67        exception_t * current_exception;
     68        int current_handler_index;
     69} static shared_stack = {NULL, NULL, 0};
     70
    6471// Get the current exception context.
    6572// There can be a single global until multithreading occurs, then each stack
    66 // needs its own. We get this from libcfathreads (no weak attribute).
    67 __attribute__((weak)) struct exception_context_t * this_exception_context() {
    68         static struct exception_context_t shared_stack = {NULL, NULL};
     73// needs its own. It will have to be updated to handle that.
     74struct exception_context_t * this_exception_context() {
    6975        return &shared_stack;
    7076}
     
    119125
    120126// MEMORY MANAGEMENT =========================================================
    121 
    122 struct __cfaehm_node {
    123         struct _Unwind_Exception unwind_exception;
    124         struct __cfaehm_node * next;
    125         int handler_index;
    126 };
    127 
    128 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    129 #define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
    130 #define UNWIND_TO_NODE(unwind) ((struct __cfaehm_node *)(unwind))
    131 #define NULL_MAP(map, ptr) ((ptr) ? (map(ptr)) : NULL)
    132127
    133128// How to clean up an exception in various situations.
     
    145140}
    146141
     142// We need a piece of storage to raise the exception, for now its a single
     143// piece.
     144static struct _Unwind_Exception this_exception_storage;
     145
     146struct __cfaehm_node {
     147        struct __cfaehm_node * next;
     148};
     149
     150#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
     151#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
     152
    147153// Creates a copy of the indicated exception and sets current_exception to it.
    148154static void __cfaehm_allocate_exception( exception_t * except ) {
     
    158164        }
    159165
    160         // Initialize the node:
    161         exception_t * except_store = NODE_TO_EXCEPT(store);
    162         store->unwind_exception.exception_class = __cfaehm_exception_class;
    163         store->unwind_exception.exception_cleanup = __cfaehm_exception_cleanup;
    164         store->handler_index = 0;
    165         except->virtual_table->copy( except_store, except );
    166 
    167166        // Add the node to the list:
    168         store->next = NULL_MAP(EXCEPT_TO_NODE, context->current_exception);
    169         context->current_exception = except_store;
     167        store->next = EXCEPT_TO_NODE(context->current_exception);
     168        context->current_exception = NODE_TO_EXCEPT(store);
     169
     170        // Copy the exception to storage.
     171        except->virtual_table->copy( context->current_exception, except );
     172
     173        // Set up the exception storage.
     174        this_exception_storage.exception_class = __cfaehm_exception_class;
     175        this_exception_storage.exception_cleanup = __cfaehm_exception_cleanup;
    170176}
    171177
     
    182188        if ( context->current_exception == except ) {
    183189                node = to_free->next;
    184                 context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node);
     190                context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;
    185191        } else {
    186192                node = EXCEPT_TO_NODE(context->current_exception);
     
    210216        // Verify actions follow the rules we expect.
    211217        verify((actions & _UA_CLEANUP_PHASE) && (actions & _UA_FORCE_UNWIND));
    212         verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME)));
     218        verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDER_FRAME)));
    213219
    214220        if ( actions & _UA_END_OF_STACK ) {
     
    219225}
    220226
    221 static struct _Unwind_Exception cancel_exception_storage;
    222 
    223227// Cancel the current stack, prefroming approprate clean-up and messaging.
    224228void __cfaehm_cancel_stack( exception_t * exception ) {
    225229        // TODO: Detect current stack and pick a particular stop-function.
    226230        _Unwind_Reason_Code ret;
    227         ret = _Unwind_ForcedUnwind( &cancel_exception_storage, _Stop_Fn, (void*)0x22 );
     231        ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
    228232        printf("UNWIND ERROR %d after force unwind\n", ret);
    229233        abort();
     
    246250static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) {
    247251        struct exception_context_t * context = this_exception_context();
     252        struct _Unwind_Exception * storage = &this_exception_storage;
    248253        if ( NULL == context->current_exception ) {
    249254                printf("UNWIND ERROR missing exception in begin unwind\n");
    250255                abort();
    251256        }
    252         struct _Unwind_Exception * storage =
    253                 &EXCEPT_TO_NODE(context->current_exception)->unwind_exception;
    254257
    255258        // Call stdlibc to raise the exception
     
    423426                                _Unwind_Reason_Code ret = (0 == index)
    424427                                        ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    425                                 UNWIND_TO_NODE(unwind_exception)->handler_index = index;
     428                                context->current_handler_index = index;
    426429
    427430                                // Based on the return value, check if we matched the exception
     
    429432                                        __cfadbg_print_safe(exception, " handler found\n");
    430433                                } else {
    431                                         // TODO: Continue the search if there is more in the table.
    432434                                        __cfadbg_print_safe(exception, " no handler\n");
    433435                                }
     
    521523        // Exception handler
    522524        // Note: Saving the exception context on the stack breaks termination exceptions.
    523         catch_block( EXCEPT_TO_NODE( this_exception_context()->current_exception )->handler_index,
     525        catch_block( this_exception_context()->current_handler_index,
    524526                     this_exception_context()->current_exception );
    525527}
  • libcfa/src/heap.cfa

    re67a82d r67ca73e  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Aug 12 16:43:38 2020
    13 // Update Count     : 902
     12// Last Modified On : Sun Aug  9 12:23:20 2020
     13// Update Count     : 894
    1414//
    1515
     
    650650                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    651651                #else
    652                 // for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
    653                 for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
    654                         typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works
    655                         p = temp;
     652                for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
    656653                #endif // BUCKETLOCK
    657654                        total += size;
     
    11651162                choose( option ) {
    11661163                  case M_TOP_PAD:
    1167                         heapExpand = ceiling2( value, pageSize ); return 1;
     1164                        heapExpand = ceiling( value, pageSize ); return 1;
    11681165                  case M_MMAP_THRESHOLD:
    11691166                        if ( setMmapStart( value ) ) return 1;
  • libcfa/src/iostream.cfa

    re67a82d r67ca73e  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Aug 11 22:16:33 2020
    13 // Update Count     : 1128
     12// Last Modified On : Mon Aug 10 09:32:14 2020
     13// Update Count     : 1126
    1414//
    1515
     
    3737
    3838forall( dtype ostype | ostream( ostype ) ) {
     39        ostype & ?|?( ostype & os, zero_t ) {
     40                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     41                fmt( os, "%d", 0n );
     42                return os;
     43        } // ?|?
     44        void ?|?( ostype & os, zero_t z ) {
     45                (ostype &)(os | z); ends( os );
     46        } // ?|?
     47
     48        ostype & ?|?( ostype & os, one_t ) {
     49                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     50                fmt( os, "%d", 1n );
     51                return os;
     52        } // ?|?
     53        void ?|?( ostype & os, one_t o ) {
     54                (ostype &)(os | o); ends( os );
     55        } // ?|?
     56
    3957        ostype & ?|?( ostype & os, bool b ) {
    4058                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
  • libcfa/src/iostream.hfa

    re67a82d r67ca73e  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Aug 11 22:16:14 2020
    13 // Update Count     : 350
     12// Last Modified On : Thu Jul 16 07:43:32 2020
     13// Update Count     : 348
    1414//
    1515
     
    6767
    6868forall( dtype ostype | ostream( ostype ) ) {
     69        ostype & ?|?( ostype &, zero_t );
     70        void ?|?( ostype &, zero_t );
     71        ostype & ?|?( ostype &, one_t );
     72        void ?|?( ostype &, one_t );
     73
    6974        ostype & ?|?( ostype &, bool );
    7075        void ?|?( ostype &, bool );
  • libcfa/src/stdlib.hfa

    re67a82d r67ca73e  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 14 23:38:50 2020
    13 // Update Count     : 504
     12// Last Modified On : Thu Jul 30 16:14:58 2020
     13// Update Count     : 490
    1414//
    1515
     
    3939//---------------------------------------
    4040
    41 #include "common.hfa"
    42 
    43 //---------------------------------------
    44 
    4541// Macro because of returns
    4642#define $VAR_ALLOC( allocation, alignment ) \
     
    140136        T * alloc_set( char fill ) {
    141137                return (T *)memset( (T *)alloc(), (int)fill, sizeof(T) ); // initialize with fill value
    142         } // alloc_set
    143 
    144         T * alloc_set( const T & fill ) {
     138        } // alloc
     139
     140        T * alloc_set( T fill ) {
    145141                return (T *)memcpy( (T *)alloc(), &fill, sizeof(T) ); // initialize with fill value
    146         } // alloc_set
     142        } // alloc
    147143
    148144        T * alloc_set( size_t dim, char fill ) {
    149145                return (T *)memset( (T *)alloc( dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
    150         } // alloc_set
    151 
    152         T * alloc_set( size_t dim, const T & fill ) {
     146        } // alloc
     147
     148        T * alloc_set( size_t dim, T fill ) {
    153149                T * r = (T *)alloc( dim );
    154150                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
    155151                return r;
    156         } // alloc_set
    157 
    158         T * alloc_set( size_t dimNew, const T fill[], size_t dimOld ) {
    159                 return (T *)memcpy( (T *)alloc( dimNew ), fill, min( dimNew, dimOld ) * sizeof(T) ); // initialize with fill value
    160         } // alloc_set
     152        } // alloc
     153
     154        T * alloc_set( size_t dim, const T fill[] ) {
     155                return (T *)memcpy( (T *)alloc( dim ), fill, dim * sizeof(T) ); // initialize with fill value
     156        } // alloc
    161157
    162158        T * alloc_set( T ptr[], size_t dim, char fill ) {       // realloc array with fill
     
    170166        } // alloc_set
    171167
    172         T * alloc_set( T ptr[], size_t dim, const T & fill ) {  // realloc array with fill
     168        T * alloc_set( T ptr[], size_t dim, T & fill ) {        // realloc array with fill
    173169                size_t odim = malloc_size( ptr ) / sizeof(T);   // current dimension
    174170                size_t nsize = dim * sizeof(T);                                 // new allocation
     
    181177                } // if
    182178                return nptr;
    183         } // alloc_set
     179        } // alloc_align_set
    184180} // distribution
    185181
     
    208204        T * alloc_align_set( size_t align, char fill ) {
    209205                return (T *)memset( (T *)alloc_align( align ), (int)fill, sizeof(T) ); // initialize with fill value
    210         } // alloc_align_set
    211 
    212         T * alloc_align_set( size_t align, const T & fill ) {
     206        } // alloc_align
     207
     208        T * alloc_align_set( size_t align, T fill ) {
    213209                return (T *)memcpy( (T *)alloc_align( align ), &fill, sizeof(T) ); // initialize with fill value
    214         } // alloc_align_set
     210        } // alloc_align
    215211
    216212        T * alloc_align_set( size_t align, size_t dim, char fill ) {
    217213                return (T *)memset( (T *)alloc_align( align, dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
    218         } // alloc_align_set
    219 
    220         T * alloc_align_set( size_t align, size_t dim, const T & fill ) {
     214        } // alloc_align
     215
     216        T * alloc_align_set( size_t align, size_t dim, T fill ) {
    221217                T * r = (T *)alloc_align( align, dim );
    222218                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
    223219                return r;
    224         } // alloc_align_set
    225 
    226         T * alloc_align_set( size_t align, size_t dimNew, const T fill[], size_t dimOld ) {
    227                 return (T *)memcpy( (T *)alloc_align( align, dimNew ), fill, min( dimNew, dimOld ) * sizeof(T) );
    228         } // alloc_align_set
     220        } // alloc_align
     221
     222        T * alloc_align_set( size_t align, size_t dim, const T fill[] ) {
     223                return (T *)memcpy( (T *)alloc_align( align, dim ), fill, dim * sizeof(T) );
     224        } // alloc_align
    229225
    230226        T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ) {
     
    238234        } // alloc_align_set
    239235
    240         T * alloc_align_set( T ptr[], size_t align, size_t dim, const T & fill ) {
     236        T * alloc_align_set( T ptr[], size_t align, size_t dim, T & fill ) {
    241237                size_t odim = malloc_size( ptr ) / sizeof(T);   // current dimension
    242238                size_t nsize = dim * sizeof(T);                                 // new allocation
     
    378374//---------------------------------------
    379375
     376#include "common.hfa"
     377
     378//---------------------------------------
     379
    380380extern bool threading_enabled(void) OPTIONAL_THREAD;
    381381
  • src/AST/Attribute.hpp

    re67a82d r67ca73e  
    5151        template<typename node_t>
    5252        friend node_t * mutate(const node_t * node);
    53         template<typename node_t>
    54     friend node_t * shallowCopy(const node_t * node);
    5553};
    5654
  • src/AST/CVQualifiers.hpp

    re67a82d r67ca73e  
    2727                Restrict = 1 << 1,
    2828                Volatile = 1 << 2,
    29                 Mutex    = 1 << 3,
    30                 Atomic   = 1 << 4,
    31                 NumQualifiers = 5
     29                Lvalue   = 1 << 3,
     30                Mutex    = 1 << 4,
     31                Atomic   = 1 << 5,
     32                NumQualifiers = 6
    3233        };
    3334
    3435        /// Mask for equivalence-preserving qualfiers
    35         enum { EquivQualifiers = ~Restrict };
     36        enum { EquivQualifiers = ~(Restrict | Lvalue) };
    3637
    3738        /// Underlying data for qualifiers
     
    4344                                bool is_restrict : 1;
    4445                                bool is_volatile : 1;
     46                                bool is_lvalue   : 1;
    4547                                bool is_mutex    : 1;
    4648                                bool is_atomic   : 1;
  • src/AST/Convert.cpp

    re67a82d r67ca73e  
    2020
    2121#include "AST/Attribute.hpp"
    22 #include "AST/Copy.hpp"
    2322#include "AST/Decl.hpp"
    2423#include "AST/Expr.hpp"
     
    167166                        LinkageSpec::Spec( node->linkage.val ),
    168167                        bfwd,
    169                         type->clone(),
     168                        type,
    170169                        init,
    171170                        attr,
     
    588587                assert( tgtResnSlots.empty() );
    589588
    590                 if ( srcInferred.data.inferParams ) {
     589                if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
    591590                        const ast::InferredParams &srcParams = srcInferred.inferParams();
    592591                        for (auto & srcParam : srcParams) {
     
    594593                                        srcParam.second.decl,
    595594                                        get<Declaration>().accept1(srcParam.second.declptr),
    596                                         get<Type>().accept1(srcParam.second.actualType)->clone(),
    597                                         get<Type>().accept1(srcParam.second.formalType)->clone(),
    598                                         get<Expression>().accept1(srcParam.second.expr)->clone()
     595                                        get<Type>().accept1(srcParam.second.actualType),
     596                                        get<Type>().accept1(srcParam.second.formalType),
     597                                        get<Expression>().accept1(srcParam.second.expr)
    599598                                ));
    600599                                assert(res.second);
    601600                        }
    602                 }
    603                 if ( srcInferred.data.resnSlots ) {
     601                } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
    604602                        const ast::ResnSlots &srcSlots = srcInferred.resnSlots();
    605603                        for (auto srcSlot : srcSlots) {
     
    622620
    623621                tgt->result = get<Type>().accept1(src->result);
    624                 // Unconditionally use a clone of the result type.
    625                 // We know this will leak some objects: much of the immediate conversion result.
    626                 // In some cases, using the conversion result directly gives unintended object sharing.
    627                 // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache.
    628                 // But tgt->result must be fully owned privately by tgt.
    629                 // Applying these conservative copies here means
    630                 // - weak references point at the declaration's copy, not these expr.result copies (good)
    631                 // - we copy more objects than really needed (bad, tolerated)
    632                 if (tgt->result) {
    633                         tgt->result = tgt->result->clone();
    634                 }
    635622                return visitBaseExpr_skipResultType(src, tgt);
    636623        }
     
    992979
    993980        const ast::Expr * visit( const ast::StmtExpr * node ) override final {
    994                 auto stmts = node->stmts;
    995                 // disable sharing between multiple StmtExprs explicitly.
    996                 if (inCache(stmts)) {
    997                         stmts = ast::deepCopy(stmts.get());
    998                 }
    999981                auto rslt = new StmtExpr(
    1000                         get<CompoundStmt>().accept1(stmts)
     982                        get<CompoundStmt>().accept1(node->stmts)
    1001983                );
    1002984
     
    20041986
    20051987                assert( oldInferParams.empty() || oldResnSlots.empty() );
    2006                 // assert( newInferred.mode == ast::Expr::InferUnion::Empty );
     1988                assert( newInferred.mode == ast::Expr::InferUnion::Empty );
    20071989
    20081990                if ( !oldInferParams.empty() ) {
     
    21352117                                old->location,
    21362118                                GET_ACCEPT_1(member, DeclWithType),
    2137                                 GET_ACCEPT_1(aggregate, Expr),
    2138                                 ast::MemberExpr::NoOpConstructionChosen
     2119                                GET_ACCEPT_1(aggregate, Expr)
    21392120                        )
    21402121                );
  • src/AST/Decl.cpp

    re67a82d r67ca73e  
    5050
    5151const Type * FunctionDecl::get_type() const { return type.get(); }
    52 void FunctionDecl::set_type( const Type * t ) {
    53         type = strict_dynamic_cast< const FunctionType * >( t );
    54 }
     52void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
    5553
    5654// --- TypeDecl
  • src/AST/Decl.hpp

    re67a82d r67ca73e  
    3333
    3434// Must be included in *all* AST classes; should be #undef'd at the end of the file
    35 #define MUTATE_FRIEND \
    36     template<typename node_t> friend node_t * mutate(const node_t * node); \
    37         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     35#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3836
    3937namespace ast {
     
    9088        virtual const Type * get_type() const = 0;
    9189        /// Set type of this declaration. May be verified by subclass
    92         virtual void set_type( const Type * ) = 0;
     90        virtual void set_type(Type *) = 0;
    9391
    9492        const DeclWithType * accept( Visitor & v ) const override = 0;
     
    113111
    114112        const Type* get_type() const override { return type; }
    115         void set_type( const Type * ty ) override { type = ty; }
     113        void set_type( Type * ty ) override { type = ty; }
    116114
    117115        const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
     
    135133
    136134        const Type * get_type() const override;
    137         void set_type( const Type * t ) override;
     135        void set_type(Type * t) override;
    138136
    139137        bool has_body() const { return stmts; }
     
    152150        std::vector<ptr<DeclWithType>> assertions;
    153151
    154         NamedTypeDecl(
    155                 const CodeLocation & loc, const std::string & name, Storage::Classes storage,
    156                 const Type * b, Linkage::Spec spec = Linkage::Cforall )
     152        NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
     153                Type* b, Linkage::Spec spec = Linkage::Cforall )
    157154        : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
    158155
     
    189186        };
    190187
    191         TypeDecl(
    192                 const CodeLocation & loc, const std::string & name, Storage::Classes storage,
    193                 const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr )
    194         : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ),
    195           init( i ) {}
     188        TypeDecl( const CodeLocation & loc, const std::string & name, Storage::Classes storage, Type * b,
     189                          Kind k, bool s, Type * i = nullptr )
     190                : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ),
     191                init( i ) {}
    196192
    197193        const char * typeString() const override;
  • src/AST/Expr.cpp

    re67a82d r67ca73e  
    2020#include <vector>
    2121
    22 #include "Copy.hpp"                // for shallowCopy
    23 #include "Eval.hpp"                // for call
    2422#include "GenericSubstitution.hpp"
    25 #include "LinkageSpec.hpp"
    2623#include "Stmt.hpp"
    2724#include "Type.hpp"
     
    3027#include "Common/SemanticError.h"
    3128#include "GenPoly/Lvalue.h"        // for referencesPermissable
    32 #include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
     29#include "InitTweak/InitTweak.h"   // for getPointerBase
    3330#include "ResolvExpr/typeops.h"    // for extractResultType
    3431#include "Tuples/Tuples.h"         // for makeTupleType
    3532
    3633namespace ast {
    37 
    38 namespace {
    39         std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
    40 }
    41 
    42 // --- Expr
    43 bool Expr::get_lvalue() const {
    44         return false;
    45 }
    4634
    4735// --- ApplicationExpr
     
    5846}
    5947
    60 bool ApplicationExpr::get_lvalue() const {
    61         if ( const DeclWithType * func = InitTweak::getFunction( this ) ) {
    62                 return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
    63         }
    64         return false;
    65 }
    66 
    6748// --- UntypedExpr
    6849
     
    7051        assert( arg );
    7152
    72         UntypedExpr * ret = call( loc, "*?", arg );
     53        UntypedExpr * ret = new UntypedExpr{
     54                loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
     55        };
    7356        if ( const Type * ty = arg->result ) {
    7457                const Type * base = InitTweak::getPointerBase( ty );
     
    8265                        // base type
    8366                        ret->result = base;
     67                        add_qualifiers( ret->result, CV::Lvalue );
    8468                }
    8569        }
    8670        return ret;
    87 }
    88 
    89 bool UntypedExpr::get_lvalue() const {
    90         std::string fname = InitTweak::getFunctionName( this );
    91         return lvalueFunctionNames.count( fname );
    9271}
    9372
     
    9574        assert( lhs && rhs );
    9675
    97         UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
     76        UntypedExpr * ret = new UntypedExpr{
     77                loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
     78        };
    9879        if ( lhs->result && rhs->result ) {
    9980                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    127108AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
    128109        if ( arg->result ) {
    129                 if ( arg->get_lvalue() ) {
     110                if ( arg->result->is_lvalue() ) {
    130111                        // lvalue, retains all levels of reference, and gains a pointer inside the references
    131112                        Type * res = addrType( arg->result );
     113                        res->set_lvalue( false ); // result of & is never an lvalue
    132114                        result = res;
    133115                } else {
     
    136118                                        dynamic_cast< const ReferenceType * >( arg->result.get() ) ) {
    137119                                Type * res = addrType( refType->base );
     120                                res->set_lvalue( false ); // result of & is never an lvalue
    138121                                result = res;
    139122                        } else {
     
    156139: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
    157140
    158 bool CastExpr::get_lvalue() const {
    159         // This is actually wrong by C, but it works with our current set-up.
    160         return arg->get_lvalue();
    161 }
    162 
    163141// --- KeywordCastExpr
    164142
    165143const char * KeywordCastExpr::targetString() const {
    166144        return AggregateDecl::aggrString( target );
    167 }
    168 
    169 // --- UntypedMemberExpr
    170 
    171 bool UntypedMemberExpr::get_lvalue() const {
    172         return aggregate->get_lvalue();
    173145}
    174146
     
    181153        assert( aggregate->result );
    182154
    183         // Deep copy on result type avoids mutation on transitively multiply referenced object.
    184         //
    185         // Example, adapted from parts of builtins and bootloader:
    186         //
    187         // forall(dtype T)
    188         // struct __Destructor {
    189         //   T * object;
    190         //   void (*dtor)(T *);
    191         // };
    192         //
    193         // forall(dtype S)
    194         // void foo(__Destructor(S) &d) {
    195         //   if (d.dtor) {  // here
    196         //   }
    197         // }
    198         //
    199         // Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
    200         // declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
    201         // declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
    202         // is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
    203         // object.
    204         //
    205         // e.result: PointerType
    206         // .base: FunctionType
    207         // .params.front(): ObjectDecl, the anonymous parameter of type T*
    208         // .type: PointerType
    209         // .base: TypeInstType
    210         // let x = that
    211         // let y = similar, except start from d.type
    212         //
    213         // Consider two code lines down, genericSubstitution(...).apply(result).
    214         //
    215         // Applying this chosen-candidate's type substitution means modifying x, substituting
    216         // S for T.  This mutation should affect x and not y.
    217 
    218         result = deepCopy(mem->get_type());
    219 
     155        // take ownership of member type
     156        result = mem->get_type();
    220157        // substitute aggregate generic parameters into member type
    221158        genericSubstitution( aggregate->result ).apply( result );
    222         // ensure appropriate restrictions from aggregate type
    223         add_qualifiers( result, aggregate->result->qualifiers );
    224 }
    225 
    226 MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
    227     MemberExpr::NoOpConstruction overloadSelector )
    228 : Expr( loc ), member( mem ), aggregate( agg ) {
    229         assert( member );
    230         assert( aggregate );
    231         assert( aggregate->result );
    232         (void) overloadSelector;
    233 }
    234 
    235 bool MemberExpr::get_lvalue() const {
    236         // This is actually wrong by C, but it works with our current set-up.
    237         return true;
     159        // ensure lvalue and appropriate restrictions from aggregate type
     160        add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue );
    238161}
    239162
     
    247170        assert( var );
    248171        assert( var->get_type() );
    249         result = shallowCopy( var->get_type() );
    250 }
    251 
    252 bool VariableExpr::get_lvalue() const {
    253         // It isn't always an lvalue, but it is never an rvalue.
    254         return true;
     172        result = var->get_type();
     173        add_qualifiers( result, CV::Lvalue );
    255174}
    256175
     
    338257        const CodeLocation & loc, const Expr * a1, const Expr * a2, LogicalFlag ia )
    339258: Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
    340 
    341 // --- CommaExpr
    342 bool CommaExpr::get_lvalue() const {
    343         // This is wrong by C, but the current implementation uses it.
    344         // (ex: Specialize, Lvalue and Box)
    345         return arg2->get_lvalue();
    346 }
    347259
    348260// --- ConstructorExpr
     
    364276        assert( t && i );
    365277        result = t;
    366 }
    367 
    368 bool CompoundLiteralExpr::get_lvalue() const {
    369         return true;
     278        add_qualifiers( result, CV::Lvalue );
    370279}
    371280
     
    384293        // like MemberExpr, TupleIndexExpr is always an lvalue
    385294        result = type->types[ index ];
    386 }
    387 
    388 bool TupleIndexExpr::get_lvalue() const {
    389         return tuple->get_lvalue();
     295        add_qualifiers( result, CV::Lvalue );
    390296}
    391297
  • src/AST/Expr.hpp

    re67a82d r67ca73e  
    3131
    3232// Must be included in *all* AST classes; should be #undef'd at the end of the file
    33 #define MUTATE_FRIEND \
    34     template<typename node_t> friend node_t * mutate(const node_t * node); \
    35         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    36 
     33#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3734
    3835class ConverterOldToNew;
     
    4542struct ParamEntry {
    4643        UniqueId decl;
    47         readonly<Decl> declptr;
     44        ptr<Decl> declptr;
    4845        ptr<Type> actualType;
    4946        ptr<Type> formalType;
     
    6562class Expr : public ParseNode {
    6663public:
    67         /*
    68          * NOTE: the union approach is incorrect until the case of
    69          * partial resolution in InferMatcher is eliminated.
    70          * it is reverted to allow unresolved and resolved parameters
    71          * to coexist in an expression node.
    72          */
     64        /// Saves space (~16 bytes) by combining ResnSlots and InferredParams
    7365        struct InferUnion {
    74                 // mode is now unused
    7566                enum { Empty, Slots, Params } mode;
    76                 struct data_t {
    77                         // char def;
    78                         ResnSlots * resnSlots;
    79                         InferredParams * inferParams;
    80 
    81                         data_t(): resnSlots(nullptr), inferParams(nullptr) {}
    82                         data_t(const data_t &other) = delete;
    83                         ~data_t() {
    84                                 delete resnSlots;
    85                                 delete inferParams;
    86                         }
     67                union data_t {
     68                        char def;
     69                        ResnSlots resnSlots;
     70                        InferredParams inferParams;
     71
     72                        data_t() : def('\0') {}
     73                        ~data_t() {}
    8774                } data;
    8875
    8976                /// initializes from other InferUnion
    9077                void init_from( const InferUnion& o ) {
    91                         if (o.data.resnSlots) {
    92                                 data.resnSlots = new ResnSlots(*o.data.resnSlots);
    93                         }
    94                         if (o.data.inferParams) {
    95                                 data.inferParams = new InferredParams(*o.data.inferParams);
     78                        switch ( o.mode ) {
     79                        case Empty:  return;
     80                        case Slots:  new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return;
     81                        case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return;
    9682                        }
    9783                }
     
    9985                /// initializes from other InferUnion (move semantics)
    10086                void init_from( InferUnion&& o ) {
    101                         data.resnSlots = o.data.resnSlots;
    102                         data.inferParams = o.data.inferParams;
    103                         o.data.resnSlots = nullptr;
    104                         o.data.inferParams = nullptr;
     87                        switch ( o.mode ) {
     88                        case Empty:  return;
     89                        case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
     90                        case Params:
     91                                new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
     92                        }
     93                }
     94
     95                /// clears variant fields
     96                void reset() {
     97                        switch( mode ) {
     98                        case Empty:  return;
     99                        case Slots:  data.resnSlots.~ResnSlots(); return;
     100                        case Params: data.inferParams.~InferredParams(); return;
     101                        }
    105102                }
    106103
     
    110107                InferUnion& operator= ( const InferUnion& ) = delete;
    111108                InferUnion& operator= ( InferUnion&& ) = delete;
    112 
    113                 bool hasSlots() const { return data.resnSlots; }
     109                ~InferUnion() { reset(); }
    114110
    115111                ResnSlots& resnSlots() {
    116                         if (!data.resnSlots) {
    117                                 data.resnSlots = new ResnSlots();
     112                        switch (mode) {
     113                        case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough
     114                        case Slots: return data.resnSlots;
     115                        case Params: assertf(false, "Cannot return to resnSlots from Params"); abort();
    118116                        }
    119                         return *data.resnSlots;
     117                        assertf(false, "unreachable");
    120118                }
    121119
    122120                const ResnSlots& resnSlots() const {
    123                         if (data.resnSlots) {
    124                                 return *data.resnSlots;
     121                        if (mode == Slots) {
     122                                return data.resnSlots;
    125123                        }
    126124                        assertf(false, "Mode was not already resnSlots");
     
    129127
    130128                InferredParams& inferParams() {
    131                         if (!data.inferParams) {
    132                                 data.inferParams = new InferredParams();
     129                        switch (mode) {
     130                        case Slots: data.resnSlots.~ResnSlots(); // fallthrough
     131                        case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough
     132                        case Params: return data.inferParams;
    133133                        }
    134                         return *data.inferParams;
     134                        assertf(false, "unreachable");
    135135                }
    136136
    137137                const InferredParams& inferParams() const {
    138                         if (data.inferParams) {
    139                                 return *data.inferParams;
     138                        if (mode == Params) {
     139                                return data.inferParams;
    140140                        }
    141141                        assertf(false, "Mode was not already Params");
     
    143143                }
    144144
    145                 void set_inferParams( InferredParams * ps ) {
    146                         delete data.resnSlots;
    147                         data.resnSlots = nullptr;
    148                         delete data.inferParams;
    149                         data.inferParams = ps;
     145                void set_inferParams( InferredParams && ps ) {
     146                        switch(mode) {
     147                        case Slots:
     148                                data.resnSlots.~ResnSlots();
     149                                // fallthrough
     150                        case Empty:
     151                                new(&data.inferParams) InferredParams{ std::move( ps ) };
     152                                mode = Params;
     153                                break;
     154                        case Params:
     155                                data.inferParams = std::move( ps );
     156                                break;
     157                        }
    150158                }
    151159
     
    153161                /// and the other is in `Params`.
    154162                void splice( InferUnion && o ) {
    155                         if (o.data.resnSlots) {
    156                                 if (data.resnSlots) {
    157                                         data.resnSlots->insert(
    158                                                 data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() );
    159                                         delete o.data.resnSlots;
     163                        if ( o.mode == Empty ) return;
     164                        if ( mode == Empty ) { init_from( o ); return; }
     165                        assert( mode == o.mode && "attempt to splice incompatible InferUnion" );
     166
     167                        if ( mode == Slots ){
     168                                data.resnSlots.insert(
     169                                        data.resnSlots.end(), o.data.resnSlots.begin(), o.data.resnSlots.end() );
     170                        } else if ( mode == Params ) {
     171                                for ( const auto & p : o.data.inferParams ) {
     172                                        data.inferParams[p.first] = std::move(p.second);
    160173                                }
    161                                 else {
    162                                         data.resnSlots = o.data.resnSlots;
    163                                 }
    164                                 o.data.resnSlots = nullptr;
    165                         }
    166 
    167                         if (o.data.inferParams) {
    168                                 if (data.inferParams) {
    169                                         for ( const auto & p : *o.data.inferParams ) {
    170                                                 (*data.inferParams)[p.first] = std::move(p.second);
    171                                         }
    172                                         delete o.data.inferParams;
    173                                 }
    174                                 else {
    175                                         data.inferParams = o.data.inferParams;
    176                                 }
    177                                 o.data.inferParams = nullptr;
    178                         }
     174                        } else assertf(false, "invalid mode");
    179175                }
    180176        };
     
    189185
    190186        Expr * set_extension( bool ex ) { extension = ex; return this; }
    191         virtual bool get_lvalue() const;
    192187
    193188        virtual const Expr * accept( Visitor & v ) const override = 0;
     
    206201        ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} );
    207202
    208         bool get_lvalue() const final;
    209 
    210203        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    211204private:
     
    222215        UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} )
    223216        : Expr( loc ), func( f ), args( std::move(as) ) {}
    224 
    225         bool get_lvalue() const final;
    226217
    227218        /// Creates a new dereference expression
     
    300291        CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
    301292
    302         bool get_lvalue() const final;
    303 
    304293        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    305294private:
     
    349338        : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); }
    350339
    351         bool get_lvalue() const final;
    352 
    353340        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    354341private:
     
    365352        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg );
    366353
    367         bool get_lvalue() const final;
    368 
    369354        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    370355private:
    371356        MemberExpr * clone() const override { return new MemberExpr{ *this }; }
    372357        MUTATE_FRIEND
    373 
    374         // Custructor overload meant only for AST conversion
    375         enum NoOpConstruction { NoOpConstructionChosen };
    376         MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
    377             NoOpConstruction overloadSelector );
    378         friend class ::ConverterOldToNew;
    379         friend class ::ConverterNewToOld;
    380358};
    381359
     
    387365        VariableExpr( const CodeLocation & loc );
    388366        VariableExpr( const CodeLocation & loc, const DeclWithType * v );
    389 
    390         bool get_lvalue() const final;
    391367
    392368        /// generates a function pointer for a given function
     
    556532
    557533        CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 )
    558         : Expr( loc ), arg1( a1 ), arg2( a2 ) {
    559                 this->result = a2->result;
    560         }
    561 
    562         bool get_lvalue() const final;
     534        : Expr( loc ), arg1( a1 ), arg2( a2 ) {}
    563535
    564536        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    633605        CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
    634606
    635         bool get_lvalue() const final;
    636 
    637607        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    638608private:
     
    690660
    691661        TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
    692 
    693         bool get_lvalue() const final;
    694662
    695663        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

    re67a82d r67ca73e  
    1010// Created On       : Wed May  8 16:05:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Jul 23 14:15:00 2020
    13 // Update Count     : 2
     12// Last Modified On : Mon Jun 24 09:48:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    108108class FunctionType;
    109109class ReferenceToType;
    110 template<typename decl_t> class SueInstType;
    111 using StructInstType = SueInstType<StructDecl>;
    112 using UnionInstType = SueInstType<UnionDecl>;
    113 using EnumInstType = SueInstType<EnumDecl>;
     110class StructInstType;
     111class UnionInstType;
     112class EnumInstType;
    114113class TraitInstType;
    115114class TypeInstType;
  • src/AST/GenericSubstitution.cpp

    re67a82d r67ca73e  
    6262        Pass<GenericSubstitutionBuilder> builder;
    6363        maybe_accept( ty, builder );
    64         return std::move(builder.core.sub);
     64        return std::move(builder.pass.sub);
    6565}
    6666
  • src/AST/Init.hpp

    re67a82d r67ca73e  
    2525
    2626// Must be included in *all* AST classes; should be #undef'd at the end of the file
    27 #define MUTATE_FRIEND \
    28     template<typename node_t> friend node_t * mutate(const node_t * node); \
    29         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     27#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3028
    3129namespace ast {
  • src/AST/Node.cpp

    re67a82d r67ca73e  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun  5 10:21:00 2020
    13 // Update Count     : 1
     11// Last Modified By :
     12// Last Modified On :
     13// Update Count     :
    1414//
    1515
     
    1717#include "Fwd.hpp"
    1818
    19 #include <csignal>  // MEMORY DEBUG -- for raise
    2019#include <iostream>
    2120
     
    3029#include "Print.hpp"
    3130
    32 /// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
    33 /// Process to use in GDB:
    34 ///   break ast::Node::_trap()
    35 ///   run
    36 ///   set variable MEM_TRAP_OBJ = <target>
    37 ///   disable <first breakpoint>
    38 ///   continue
    39 void * MEM_TRAP_OBJ = nullptr;
    40 
    41 void _trap( const void * node ) {
    42         if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
    43 }
    44 
    45 [[noreturn]] static inline void strict_fail(const ast::Node * node) {
    46         assertf(node, "strict_as had nullptr input.");
    47         const ast::ParseNode * parse = dynamic_cast<const ast::ParseNode *>( node );
    48         if ( nullptr == parse ) {
    49                 assertf(nullptr, "%s (no location)", toString(node).c_str());
    50         } else if ( parse->location.isUnset() ) {
    51                 assertf(nullptr, "%s (unset location)", toString(node).c_str());
    52         } else {
    53                 assertf(nullptr, "%s (at %s:%d)", toString(node).c_str(),
    54                         parse->location.filename.c_str(), parse->location.first_line);
    55         }
    56 }
    57 
    58 template< typename node_t, enum ast::Node::ref_type ref_t >
    59 void ast::ptr_base<node_t, ref_t>::_strict_fail() const {
    60         strict_fail(node);
    61 }
    62 
    63 template< typename node_t, enum ast::Node::ref_type ref_t >
    64 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
    65         node->increment(ref_t);
    66         _trap( node );
    67 }
    68 
    69 template< typename node_t, enum ast::Node::ref_type ref_t >
    70 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
    71         _trap( node );
    72         node->decrement( ref_t, do_delete );
    73 }
    74 
    75 template< typename node_t, enum ast::Node::ref_type ref_t >
    76 void ast::ptr_base<node_t, ref_t>::_check() const {
    77         // if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
    78 }
     31template< typename node_t, enum ast::Node::ref_type ref_t >
     32void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
     33
     34template< typename node_t, enum ast::Node::ref_type ref_t >
     35void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
     36
     37template< typename node_t, enum ast::Node::ref_type ref_t >
     38void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
    7939
    8040template< typename node_t, enum ast::Node::ref_type ref_t >
  • src/AST/Node.hpp

    re67a82d r67ca73e  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun 5 9:47:00 2020
    13 // Update Count     : 6
     12// Last Modified On : Mon Jun  3 13:26:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    3838        Node& operator= (const Node&) = delete;
    3939        Node& operator= (Node&&) = delete;
    40         virtual ~Node() {}
     40        virtual ~Node() = default;
    4141
    4242        virtual const Node * accept( Visitor & v ) const = 0;
     
    5757        template<typename node_t>
    5858        friend node_t * mutate(const node_t * node);
    59         template<typename node_t>
    60         friend node_t * shallowCopy(const node_t * node);
    6159
    6260        mutable size_t strong_count = 0;
     
    7169        }
    7270
    73         void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
     71        void decrement(ast::Node::ref_type ref) const {
    7472                switch (ref) {
    7573                        case ref_type::strong: strong_count--; break;
     
    7775                }
    7876
    79                 if( do_delete && !strong_count && !weak_count) {
     77                if(!strong_count && !weak_count) {
    8078                        delete this;
    8179                }
     
    9694        assertf(
    9795                node->weak_count == 0,
    98                 "Error: mutating node with weak references to it will invalidate some references"
     96                "Error: mutating node with weak references to it will invalided some references"
    9997        );
    10098        return node->clone();
     
    106104        // skip mutate if equivalent
    107105        if ( node->*field == val ) return node;
    108 
     106       
    109107        // mutate and return
    110108        node_t * ret = mutate( node );
     
    125123        (ret->*field)[i] = std::forward< field_t >( val );
    126124        return ret;
    127 }
    128 
    129 /// Mutate an entire indexed collection by cloning to accepted value
    130 template<typename node_t, typename parent_t, typename coll_t>
    131 const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
    132         for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
    133                 node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
    134         }
    135         return node;
    136125}
    137126
     
    230219        operator const node_t * () const { _check(); return node; }
    231220
    232         const node_t * release() {
    233                 const node_t * ret = node;
    234                 if ( node ) {
    235                         _dec(node, false);
    236                         node = nullptr;
    237                 }
    238                 return ret;
    239         }
    240 
    241221        /// wrapper for convenient access to dynamic_cast
    242222        template<typename o_node_t>
    243223        const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); }
    244224
    245         /// Wrapper that makes sure dynamic_cast returns non-null.
     225        /// wrapper for convenient access to strict_dynamic_cast
    246226        template<typename o_node_t>
    247         const o_node_t * strict_as() const {
    248                 if (const o_node_t * ret = as<o_node_t>()) return ret;
    249                 _strict_fail();
    250         }
    251 
    252         /// Wrapper that makes sure dynamic_cast does not fail.
    253         template<typename o_node_t, decltype(nullptr) null>
    254         const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; }
     227        const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); }
    255228
    256229        /// Returns a mutable version of the pointer in this node.
     
    271244
    272245        void _inc( const node_t * other );
    273         void _dec( const node_t * other, bool do_delete = true );
     246        void _dec( const node_t * other );
    274247        void _check() const;
    275         void _strict_fail() const __attribute__((noreturn));
    276248
    277249        const node_t * node;
  • src/AST/Pass.hpp

    re67a82d r67ca73e  
    88//
    99// Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15:37:05 2019
     10// Created On       : Thu May 09 15::37::05 2019
    1111// Last Modified By :
    1212// Last Modified On :
     
    3535#include "AST/SymbolTable.hpp"
    3636
    37 #include "AST/ForallSubstitutionTable.hpp"
    38 
    3937// Private prelude header, needed for some of the magic tricks this class pulls off
    4038#include "AST/Pass.proto.hpp"
     
    4846//
    4947// Several additional features are available through inheritance
    50 // | WithTypeSubstitution  - provides polymorphic const TypeSubstitution * env for the
    51 //                           current expression
    52 // | WithStmtsToAdd        - provides the ability to insert statements before or after the current
    53 //                           statement by adding new statements into stmtsToAddBefore or
    54 //                           stmtsToAddAfter respectively.
    55 // | WithDeclsToAdd        - provides the ability to insert declarations before or after the
    56 //                           current declarations by adding new DeclStmt into declsToAddBefore or
    57 //                           declsToAddAfter respectively.
    58 // | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
    59 //                           to false in pre{visit,visit} to skip visiting children
    60 // | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
    61 //                           call GuardValue with the variable to save, the variable will
    62 //                           automatically be restored to its previous value after the
    63 //                           corresponding postvisit/postmutate teminates.
    64 // | WithVisitorRef        - provides an pointer to the templated visitor wrapper
    65 // | WithSymbolTable       - provides symbol table functionality
    66 // | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
     48// | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
     49//                          current expression
     50// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
     51//                          statement by adding new statements into stmtsToAddBefore or
     52//                          stmtsToAddAfter respectively.
     53// | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
     54//                          declarations by adding new DeclStmt into declsToAddBefore or
     55//                          declsToAddAfter respectively.
     56// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
     57//                          to false in pre{visit,visit} to skip visiting children
     58// | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
     59//                          call GuardValue with the variable to save, the variable will
     60//                          automatically be restored to its previous value after the corresponding
     61//                          postvisit/postmutate teminates.
     62// | WithVisitorRef       - provides an pointer to the templated visitor wrapper
     63// | WithSymbolTable      - provides symbol table functionality
    6764//-------------------------------------------------------------------------------------------------
    68 template< typename core_t >
     65template< typename pass_t >
    6966class Pass final : public ast::Visitor {
    7067public:
    71         using core_type = core_t;
    72         using type = Pass<core_t>;
    73 
    7468        /// Forward any arguments to the pass constructor
    7569        /// Propagate 'this' if necessary
    7670        template< typename... Args >
    7771        Pass( Args &&... args)
    78                 : core( std::forward<Args>( args )... )
     72                : pass( std::forward<Args>( args )... )
    7973        {
    8074                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    81                 type * const * visitor = __pass::visitor(core, 0);
     75                typedef Pass<pass_t> this_t;
     76                this_t * const * visitor = __pass::visitor(pass, 0);
    8277                if(visitor) {
    83                         *const_cast<type **>( visitor ) = this;
     78                        *const_cast<this_t **>( visitor ) = this;
    8479                }
    8580        }
     
    8782        virtual ~Pass() = default;
    8883
    89         /// Construct and run a pass on a translation unit.
    90         template< typename... Args >
    91         static void run( std::list< ptr<Decl> > & decls, Args &&... args ) {
    92                 Pass<core_t> visitor( std::forward<Args>( args )... );
    93                 accept_all( decls, visitor );
    94         }
    95 
    96         template< typename... Args >
    97         static void run( std::list< ptr<Decl> > & decls ) {
    98                 Pass<core_t> visitor;
    99                 accept_all( decls, visitor );
    100         }
    101 
    10284        /// Storage for the actual pass
    103         core_t core;
     85        pass_t pass;
    10486
    10587        /// Visit function declarations
     
    197179        const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
    198180
    199         template<typename core_type>
    200         friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
     181        template<typename pass_type>
     182        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
    201183private:
    202184
    203         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; }
     185        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
    204186
    205187private:
     
    220202        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    221203
    222         /// Mutate forall-list, accounting for presence of type substitution map
    223         template<typename node_t>
    224         void mutate_forall( const node_t *& );
    225 
    226204public:
    227205        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
     
    232210        /// Internal RAII guard for symbol table features
    233211        struct guard_symtab {
    234                 guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); }
    235                 ~guard_symtab()                                   { __pass::symtab::leave(pass.core, 0); }
    236                 Pass<core_t> & pass;
     212                guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
     213                ~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
     214                Pass<pass_t> & pass;
    237215        };
    238216
    239217        /// Internal RAII guard for scope features
    240218        struct guard_scope {
    241                 guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); }
    242                 ~guard_scope()                                   { __pass::scope::leave(pass.core, 0); }
    243                 Pass<core_t> & pass;
    244         };
    245 
    246         /// Internal RAII guard for forall substitutions
    247         struct guard_forall_subs {
    248                 guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type )
    249                 : pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
    250                 ~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
    251                 Pass<core_t> & pass;
    252                 const ParameterizedType * type;
     219                guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
     220                ~guard_scope()                                   { __pass::scope::leave(pass, 0); }
     221                Pass<pass_t> & pass;
    253222        };
    254223
     
    258227
    259228/// Apply a pass to an entire translation unit
    260 template<typename core_t>
    261 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
     229template<typename pass_t>
     230void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
    262231
    263232//-------------------------------------------------------------------------------------------------
     
    299268        };
    300269
    301         template< typename core_t>
    302         friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup );
     270        template< typename pass_t>
     271        friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );
    303272public:
    304273
     
    336305
    337306/// Used to get a pointer to the pass with its wrapped type
    338 template<typename core_t>
     307template<typename pass_t>
    339308struct WithVisitorRef {
    340         Pass<core_t> * const visitor = nullptr;
     309        Pass<pass_t> * const visitor = nullptr;
    341310};
    342311
     
    345314        SymbolTable symtab;
    346315};
    347 
    348 /// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
    349 struct WithForallSubstitutor {
    350         ForallSubstitutionTable subs;
    351 };
    352 
    353316}
    354317
     
    358321extern struct PassVisitorStats {
    359322        size_t depth = 0;
    360         Stats::Counters::MaxCounter<double> * max;
    361         Stats::Counters::AverageCounter<double> * avg;
     323        Stats::Counters::MaxCounter<double> * max = nullptr;
     324        Stats::Counters::AverageCounter<double> * avg = nullptr;
    362325} pass_visitor_stats;
    363326}
  • src/AST/Pass.impl.hpp

    re67a82d r67ca73e  
    2525        using namespace ast; \
    2626        /* back-up the visit children */ \
    27         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \
     27        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
    2828        /* setup the scope for passes that want to run code at exit */ \
    29         __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (core, 0) ); \
    30         /* begin tracing memory allocation if requested by this pass */ \
    31         __pass::beginTrace( core, 0 ); \
     29        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
    3230        /* call the implementation of the previsit of this pass */ \
    33         __pass::previsit( core, node, 0 );
     31        __pass::previsit( pass, node, 0 );
    3432
    3533#define VISIT( code... ) \
     
    4240#define VISIT_END( type, node ) \
    4341        /* call the implementation of the postvisit of this pass */ \
    44         auto __return = __pass::postvisit( core, node, 0 ); \
     42        auto __return = __pass::postvisit( pass, node, 0 ); \
    4543        assertf(__return, "post visit should never return null"); \
    46         /* end tracing memory allocation if requested by this pass */ \
    47         __pass::endTrace( core, 0 ); \
    4844        return __return;
    4945
     
    123119        }
    124120
    125         template< typename core_t >
     121        template< typename pass_t >
    126122        template< typename node_t >
    127         auto ast::Pass< core_t >::call_accept( const node_t * node )
     123        auto ast::Pass< pass_t >::call_accept( const node_t * node )
    128124                -> typename std::enable_if<
    129125                                !std::is_base_of<ast::Expr, node_t>::value &&
     
    131127                        , decltype( node->accept(*this) )
    132128                >::type
     129
    133130        {
    134131                __pedantic_pass_assert( __visit_children() );
    135                 __pedantic_pass_assert( node );
     132                __pedantic_pass_assert( expr );
    136133
    137134                static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
     
    141138        }
    142139
    143         template< typename core_t >
    144         const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
     140        template< typename pass_t >
     141        const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
    145142                __pedantic_pass_assert( __visit_children() );
    146143                __pedantic_pass_assert( expr );
    147144
    148                 const ast::TypeSubstitution ** env_ptr = __pass::env( core, 0);
     145                const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
    149146                if ( env_ptr && expr->env ) {
    150147                        *env_ptr = expr->env;
     
    154151        }
    155152
    156         template< typename core_t >
    157         const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
     153        template< typename pass_t >
     154        const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
    158155                __pedantic_pass_assert( __visit_children() );
    159156                __pedantic_pass_assert( stmt );
     
    163160
    164161                // get the stmts/decls that will need to be spliced in
    165                 auto stmts_before = __pass::stmtsToAddBefore( core, 0);
    166                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    167                 auto decls_before = __pass::declsToAddBefore( core, 0);
    168                 auto decls_after  = __pass::declsToAddAfter ( core, 0);
     162                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
     163                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     164                auto decls_before = __pass::declsToAddBefore( pass, 0);
     165                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
    169166
    170167                // These may be modified by subnode but most be restored once we exit this statemnet.
    171                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( core, 0) );
     168                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
    172169                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    173170                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    205202        }
    206203
    207         template< typename core_t >
     204        template< typename pass_t >
    208205        template< template <class...> class container_t >
    209         container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     206        container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    210207                __pedantic_pass_assert( __visit_children() );
    211208                if( statements.empty() ) return {};
     
    218215
    219216                // get the stmts/decls that will need to be spliced in
    220                 auto stmts_before = __pass::stmtsToAddBefore( core, 0);
    221                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    222                 auto decls_before = __pass::declsToAddBefore( core, 0);
    223                 auto decls_after  = __pass::declsToAddAfter ( core, 0);
     217                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
     218                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     219                auto decls_before = __pass::declsToAddBefore( pass, 0);
     220                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
    224221
    225222                // These may be modified by subnode but most be restored once we exit this statemnet.
     
    271268        }
    272269
    273         template< typename core_t >
     270        template< typename pass_t >
    274271        template< template <class...> class container_t, typename node_t >
    275         container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     272        container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    276273                __pedantic_pass_assert( __visit_children() );
    277274                if( container.empty() ) return {};
     
    302299        }
    303300
    304         template< typename core_t >
     301        template< typename pass_t >
    305302        template<typename node_t, typename parent_t, typename child_t>
    306         void ast::Pass< core_t >::maybe_accept(
     303        void ast::Pass< pass_t >::maybe_accept(
    307304                const node_t * & parent,
    308305                child_t parent_t::*child
     
    326323        }
    327324
    328 
    329         template< typename core_t >
    330         template< typename node_t >
    331         void ast::Pass< core_t >::mutate_forall( const node_t *& node ) {
    332                 if ( auto subs = __pass::forall::subs( core, 0 ) ) {
    333                         // tracking TypeDecl substitution, full clone
    334                         if ( node->forall.empty() ) return;
    335 
    336                         node_t * mut = mutate( node );
    337                         mut->forall = subs->clone( node->forall, *this );
    338                         node = mut;
    339                 } else {
    340                         // not tracking TypeDecl substitution, just mutate
    341                         maybe_accept( node, &node_t::forall );
    342                 }
    343         }
    344325}
    345326
     
    352333//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    353334
    354 template< typename core_t >
    355 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) {
     335template< typename pass_t >
     336inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
    356337        // We are going to aggregate errors for all these statements
    357338        SemanticErrorException errors;
     
    361342
    362343        // get the stmts/decls that will need to be spliced in
    363         auto decls_before = __pass::declsToAddBefore( visitor.core, 0);
    364         auto decls_after  = __pass::declsToAddAfter ( visitor.core, 0);
     344        auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
     345        auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
    365346
    366347        // update pass statitistics
     
    411392//--------------------------------------------------------------------------
    412393// ObjectDecl
    413 template< typename core_t >
    414 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) {
     394template< typename pass_t >
     395const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
    415396        VISIT_START( node );
    416397
     
    425406        )
    426407
    427         __pass::symtab::addId( core, 0, node );
     408        __pass::symtab::addId( pass, 0, node );
    428409
    429410        VISIT_END( DeclWithType, node );
     
    432413//--------------------------------------------------------------------------
    433414// FunctionDecl
    434 template< typename core_t >
    435 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) {
    436         VISIT_START( node );
    437 
    438         __pass::symtab::addId( core, 0, node );
     415template< typename pass_t >
     416const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
     417        VISIT_START( node );
     418
     419        __pass::symtab::addId( pass, 0, node );
    439420
    440421        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
     
    444425                // shadow with exprs and not the other way around.
    445426                guard_symtab guard { *this };
    446                 __pass::symtab::addWith( core, 0, node->withExprs, node );
     427                __pass::symtab::addWith( pass, 0, node->withExprs, node );
    447428                {
    448429                        guard_symtab guard { *this };
    449430                        // implicit add __func__ identifier as specified in the C manual 6.4.2.2
    450                         static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{
    451                                 CodeLocation{}, "__func__",
    452                                 new ast::ArrayType{
    453                                         new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
     431                        static ast::ObjectDecl func(
     432                                node->location, "__func__",
     433                                new ast::ArrayType(
     434                                        new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
    454435                                        nullptr, VariableLen, DynamicDim
    455                                 }
    456                         } };
    457                         __pass::symtab::addId( core, 0, func );
     436                                )
     437                        );
     438                        __pass::symtab::addId( pass, 0, &func );
    458439                        VISIT(
    459440                                maybe_accept( node, &FunctionDecl::type );
     
    473454//--------------------------------------------------------------------------
    474455// StructDecl
    475 template< typename core_t >
    476 const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) {
     456template< typename pass_t >
     457const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
    477458        VISIT_START( node );
    478459
    479460        // make up a forward declaration and add it before processing the members
    480461        // needs to be on the heap because addStruct saves the pointer
    481         __pass::symtab::addStructFwd( core, 0, node );
     462        __pass::symtab::addStructFwd( pass, 0, node );
    482463
    483464        VISIT({
     
    488469
    489470        // this addition replaces the forward declaration
    490         __pass::symtab::addStruct( core, 0, node );
     471        __pass::symtab::addStruct( pass, 0, node );
    491472
    492473        VISIT_END( Decl, node );
     
    495476//--------------------------------------------------------------------------
    496477// UnionDecl
    497 template< typename core_t >
    498 const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) {
     478template< typename pass_t >
     479const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
    499480        VISIT_START( node );
    500481
    501482        // make up a forward declaration and add it before processing the members
    502         __pass::symtab::addUnionFwd( core, 0, node );
     483        __pass::symtab::addUnionFwd( pass, 0, node );
    503484
    504485        VISIT({
     
    508489        })
    509490
    510         __pass::symtab::addUnion( core, 0, node );
     491        __pass::symtab::addUnion( pass, 0, node );
    511492
    512493        VISIT_END( Decl, node );
     
    515496//--------------------------------------------------------------------------
    516497// EnumDecl
    517 template< typename core_t >
    518 const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) {
    519         VISIT_START( node );
    520 
    521         __pass::symtab::addEnum( core, 0, node );
     498template< typename pass_t >
     499const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
     500        VISIT_START( node );
     501
     502        __pass::symtab::addEnum( pass, 0, node );
    522503
    523504        VISIT(
     
    532513//--------------------------------------------------------------------------
    533514// TraitDecl
    534 template< typename core_t >
    535 const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) {
     515template< typename pass_t >
     516const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
    536517        VISIT_START( node );
    537518
     
    542523        })
    543524
    544         __pass::symtab::addTrait( core, 0, node );
     525        __pass::symtab::addTrait( pass, 0, node );
    545526
    546527        VISIT_END( Decl, node );
     
    549530//--------------------------------------------------------------------------
    550531// TypeDecl
    551 template< typename core_t >
    552 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) {
     532template< typename pass_t >
     533const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
    553534        VISIT_START( node );
    554535
     
    562543        // note that assertions come after the type is added to the symtab, since they are not part of the type proper
    563544        // and may depend on the type itself
    564         __pass::symtab::addType( core, 0, node );
     545        __pass::symtab::addType( pass, 0, node );
    565546
    566547        VISIT(
     
    578559//--------------------------------------------------------------------------
    579560// TypedefDecl
    580 template< typename core_t >
    581 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) {
     561template< typename pass_t >
     562const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
    582563        VISIT_START( node );
    583564
     
    588569        })
    589570
    590         __pass::symtab::addType( core, 0, node );
     571        __pass::symtab::addType( pass, 0, node );
    591572
    592573        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
     
    597578//--------------------------------------------------------------------------
    598579// AsmDecl
    599 template< typename core_t >
    600 const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) {
     580template< typename pass_t >
     581const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
    601582        VISIT_START( node );
    602583
     
    610591//--------------------------------------------------------------------------
    611592// StaticAssertDecl
    612 template< typename core_t >
    613 const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) {
     593template< typename pass_t >
     594const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
    614595        VISIT_START( node );
    615596
     
    624605//--------------------------------------------------------------------------
    625606// CompoundStmt
    626 template< typename core_t >
    627 const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
     607template< typename pass_t >
     608const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
    628609        VISIT_START( node );
    629610        VISIT({
    630611                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    631                 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {
    632                         if ( ! inFunctionCpy ) __pass::symtab::enter(core, 0);
    633                 }, [this, inFunctionCpy = this->inFunction]() {
    634                         if ( ! inFunctionCpy ) __pass::symtab::leave(core, 0);
     612                auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
     613                        if ( ! inFunction ) __pass::symtab::enter(pass, 0);
     614                }, [this, inFunction = this->inFunction]() {
     615                        if ( ! inFunction ) __pass::symtab::leave(pass, 0);
    635616                });
    636617                ValueGuard< bool > guard2( inFunction );
     
    644625//--------------------------------------------------------------------------
    645626// ExprStmt
    646 template< typename core_t >
    647 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) {
     627template< typename pass_t >
     628const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
    648629        VISIT_START( node );
    649630
     
    657638//--------------------------------------------------------------------------
    658639// AsmStmt
    659 template< typename core_t >
    660 const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) {
     640template< typename pass_t >
     641const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
    661642        VISIT_START( node )
    662643
     
    673654//--------------------------------------------------------------------------
    674655// DirectiveStmt
    675 template< typename core_t >
    676 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) {
     656template< typename pass_t >
     657const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
    677658        VISIT_START( node )
    678659
     
    682663//--------------------------------------------------------------------------
    683664// IfStmt
    684 template< typename core_t >
    685 const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) {
     665template< typename pass_t >
     666const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
    686667        VISIT_START( node );
    687668
     
    700681//--------------------------------------------------------------------------
    701682// WhileStmt
    702 template< typename core_t >
    703 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
     683template< typename pass_t >
     684const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
    704685        VISIT_START( node );
    705686
     
    717698//--------------------------------------------------------------------------
    718699// ForStmt
    719 template< typename core_t >
    720 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) {
     700template< typename pass_t >
     701const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {
    721702        VISIT_START( node );
    722703
     
    735716//--------------------------------------------------------------------------
    736717// SwitchStmt
    737 template< typename core_t >
    738 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) {
     718template< typename pass_t >
     719const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {
    739720        VISIT_START( node );
    740721
     
    749730//--------------------------------------------------------------------------
    750731// CaseStmt
    751 template< typename core_t >
    752 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) {
     732template< typename pass_t >
     733const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {
    753734        VISIT_START( node );
    754735
     
    763744//--------------------------------------------------------------------------
    764745// BranchStmt
    765 template< typename core_t >
    766 const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) {
     746template< typename pass_t >
     747const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {
    767748        VISIT_START( node );
    768749        VISIT_END( Stmt, node );
     
    771752//--------------------------------------------------------------------------
    772753// ReturnStmt
    773 template< typename core_t >
    774 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) {
     754template< typename pass_t >
     755const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {
    775756        VISIT_START( node );
    776757
     
    784765//--------------------------------------------------------------------------
    785766// ThrowStmt
    786 template< typename core_t >
    787 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) {
     767template< typename pass_t >
     768const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {
    788769        VISIT_START( node );
    789770
     
    798779//--------------------------------------------------------------------------
    799780// TryStmt
    800 template< typename core_t >
    801 const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) {
     781template< typename pass_t >
     782const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {
    802783        VISIT_START( node );
    803784
     
    813794//--------------------------------------------------------------------------
    814795// CatchStmt
    815 template< typename core_t >
    816 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) {
     796template< typename pass_t >
     797const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
    817798        VISIT_START( node );
    818799
     
    830811//--------------------------------------------------------------------------
    831812// FinallyStmt
    832 template< typename core_t >
    833 const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) {
     813template< typename pass_t >
     814const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
    834815        VISIT_START( node );
    835816
     
    843824//--------------------------------------------------------------------------
    844825// FinallyStmt
    845 template< typename core_t >
    846 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) {
     826template< typename pass_t >
     827const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {
    847828        VISIT_START( node );
    848829
     
    856837//--------------------------------------------------------------------------
    857838// WaitForStmt
    858 template< typename core_t >
    859 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) {
     839template< typename pass_t >
     840const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
    860841        VISIT_START( node );
    861842                // for( auto & clause : node->clauses ) {
     
    925906//--------------------------------------------------------------------------
    926907// WithStmt
    927 template< typename core_t >
    928 const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) {
     908template< typename pass_t >
     909const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
    929910        VISIT_START( node );
    930911
     
    934915                        // catch statements introduce a level of scope (for the caught exception)
    935916                        guard_symtab guard { *this };
    936                         __pass::symtab::addWith( core, 0, node->exprs, node );
     917                        __pass::symtab::addWith( pass, 0, node->exprs, node );
    937918                        maybe_accept( node, &WithStmt::stmt );
    938919                }
     
    943924//--------------------------------------------------------------------------
    944925// NullStmt
    945 template< typename core_t >
    946 const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) {
     926template< typename pass_t >
     927const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
    947928        VISIT_START( node );
    948929        VISIT_END( NullStmt, node );
     
    951932//--------------------------------------------------------------------------
    952933// DeclStmt
    953 template< typename core_t >
    954 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) {
     934template< typename pass_t >
     935const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
    955936        VISIT_START( node );
    956937
     
    964945//--------------------------------------------------------------------------
    965946// ImplicitCtorDtorStmt
    966 template< typename core_t >
    967 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
     947template< typename pass_t >
     948const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
    968949        VISIT_START( node );
    969950
    970951        // For now this isn't visited, it is unclear if this causes problem
    971952        // if all tests are known to pass, remove this code
    972         VISIT(
    973                 maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    974         )
     953        // VISIT(
     954        //      maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
     955        // )
    975956
    976957        VISIT_END( Stmt, node );
     
    979960//--------------------------------------------------------------------------
    980961// ApplicationExpr
    981 template< typename core_t >
    982 const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) {
     962template< typename pass_t >
     963const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
    983964        VISIT_START( node );
    984965
     
    997978//--------------------------------------------------------------------------
    998979// UntypedExpr
    999 template< typename core_t >
    1000 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) {
     980template< typename pass_t >
     981const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
    1001982        VISIT_START( node );
    1002983
     
    1015996//--------------------------------------------------------------------------
    1016997// NameExpr
    1017 template< typename core_t >
    1018 const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) {
     998template< typename pass_t >
     999const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
    10191000        VISIT_START( node );
    10201001
     
    10291010//--------------------------------------------------------------------------
    10301011// CastExpr
    1031 template< typename core_t >
    1032 const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) {
     1012template< typename pass_t >
     1013const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
    10331014        VISIT_START( node );
    10341015
     
    10451026//--------------------------------------------------------------------------
    10461027// KeywordCastExpr
    1047 template< typename core_t >
    1048 const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) {
     1028template< typename pass_t >
     1029const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
    10491030        VISIT_START( node );
    10501031
     
    10611042//--------------------------------------------------------------------------
    10621043// VirtualCastExpr
    1063 template< typename core_t >
    1064 const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) {
     1044template< typename pass_t >
     1045const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
    10651046        VISIT_START( node );
    10661047
     
    10771058//--------------------------------------------------------------------------
    10781059// AddressExpr
    1079 template< typename core_t >
    1080 const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) {
     1060template< typename pass_t >
     1061const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
    10811062        VISIT_START( node );
    10821063
     
    10931074//--------------------------------------------------------------------------
    10941075// LabelAddressExpr
    1095 template< typename core_t >
    1096 const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) {
     1076template< typename pass_t >
     1077const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
    10971078        VISIT_START( node );
    10981079
     
    11071088//--------------------------------------------------------------------------
    11081089// UntypedMemberExpr
    1109 template< typename core_t >
    1110 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) {
     1090template< typename pass_t >
     1091const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
    11111092        VISIT_START( node );
    11121093
     
    11241105//--------------------------------------------------------------------------
    11251106// MemberExpr
    1126 template< typename core_t >
    1127 const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) {
     1107template< typename pass_t >
     1108const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
    11281109        VISIT_START( node );
    11291110
     
    11401121//--------------------------------------------------------------------------
    11411122// VariableExpr
    1142 template< typename core_t >
    1143 const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) {
     1123template< typename pass_t >
     1124const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
    11441125        VISIT_START( node );
    11451126
     
    11541135//--------------------------------------------------------------------------
    11551136// ConstantExpr
    1156 template< typename core_t >
    1157 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) {
     1137template< typename pass_t >
     1138const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
    11581139        VISIT_START( node );
    11591140
     
    11681149//--------------------------------------------------------------------------
    11691150// SizeofExpr
    1170 template< typename core_t >
    1171 const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) {
     1151template< typename pass_t >
     1152const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
    11721153        VISIT_START( node );
    11731154
     
    11881169//--------------------------------------------------------------------------
    11891170// AlignofExpr
    1190 template< typename core_t >
    1191 const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) {
     1171template< typename pass_t >
     1172const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
    11921173        VISIT_START( node );
    11931174
     
    12081189//--------------------------------------------------------------------------
    12091190// UntypedOffsetofExpr
    1210 template< typename core_t >
    1211 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) {
     1191template< typename pass_t >
     1192const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
    12121193        VISIT_START( node );
    12131194
     
    12241205//--------------------------------------------------------------------------
    12251206// OffsetofExpr
    1226 template< typename core_t >
    1227 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) {
     1207template< typename pass_t >
     1208const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
    12281209        VISIT_START( node );
    12291210
     
    12401221//--------------------------------------------------------------------------
    12411222// OffsetPackExpr
    1242 template< typename core_t >
    1243 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) {
     1223template< typename pass_t >
     1224const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
    12441225        VISIT_START( node );
    12451226
     
    12561237//--------------------------------------------------------------------------
    12571238// LogicalExpr
    1258 template< typename core_t >
    1259 const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) {
     1239template< typename pass_t >
     1240const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
    12601241        VISIT_START( node );
    12611242
     
    12731254//--------------------------------------------------------------------------
    12741255// ConditionalExpr
    1275 template< typename core_t >
    1276 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) {
     1256template< typename pass_t >
     1257const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
    12771258        VISIT_START( node );
    12781259
     
    12911272//--------------------------------------------------------------------------
    12921273// CommaExpr
    1293 template< typename core_t >
    1294 const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) {
     1274template< typename pass_t >
     1275const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
    12951276        VISIT_START( node );
    12961277
     
    13081289//--------------------------------------------------------------------------
    13091290// TypeExpr
    1310 template< typename core_t >
    1311 const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) {
     1291template< typename pass_t >
     1292const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
    13121293        VISIT_START( node );
    13131294
     
    13241305//--------------------------------------------------------------------------
    13251306// AsmExpr
    1326 template< typename core_t >
    1327 const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) {
     1307template< typename pass_t >
     1308const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
    13281309        VISIT_START( node );
    13291310
     
    13411322//--------------------------------------------------------------------------
    13421323// ImplicitCopyCtorExpr
    1343 template< typename core_t >
    1344 const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
     1324template< typename pass_t >
     1325const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
    13451326        VISIT_START( node );
    13461327
     
    13571338//--------------------------------------------------------------------------
    13581339// ConstructorExpr
    1359 template< typename core_t >
    1360 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) {
     1340template< typename pass_t >
     1341const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
    13611342        VISIT_START( node );
    13621343
     
    13731354//--------------------------------------------------------------------------
    13741355// CompoundLiteralExpr
    1375 template< typename core_t >
    1376 const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) {
     1356template< typename pass_t >
     1357const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
    13771358        VISIT_START( node );
    13781359
     
    13891370//--------------------------------------------------------------------------
    13901371// RangeExpr
    1391 template< typename core_t >
    1392 const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) {
     1372template< typename pass_t >
     1373const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
    13931374        VISIT_START( node );
    13941375
     
    14061387//--------------------------------------------------------------------------
    14071388// UntypedTupleExpr
    1408 template< typename core_t >
    1409 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) {
     1389template< typename pass_t >
     1390const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
    14101391        VISIT_START( node );
    14111392
     
    14221403//--------------------------------------------------------------------------
    14231404// TupleExpr
    1424 template< typename core_t >
    1425 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) {
     1405template< typename pass_t >
     1406const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
    14261407        VISIT_START( node );
    14271408
     
    14381419//--------------------------------------------------------------------------
    14391420// TupleIndexExpr
    1440 template< typename core_t >
    1441 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) {
     1421template< typename pass_t >
     1422const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
    14421423        VISIT_START( node );
    14431424
     
    14541435//--------------------------------------------------------------------------
    14551436// TupleAssignExpr
    1456 template< typename core_t >
    1457 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) {
     1437template< typename pass_t >
     1438const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
    14581439        VISIT_START( node );
    14591440
     
    14701451//--------------------------------------------------------------------------
    14711452// StmtExpr
    1472 template< typename core_t >
    1473 const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) {
     1453template< typename pass_t >
     1454const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
    14741455        VISIT_START( node );
    14751456
    14761457        VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
    14771458                // get the stmts that will need to be spliced in
    1478                 auto stmts_before = __pass::stmtsToAddBefore( core, 0);
    1479                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     1459                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
     1460                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    14801461
    14811462                // These may be modified by subnode but most be restored once we exit this statemnet.
    1482                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( core, 0) );
     1463                ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );
    14831464                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    14841465                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    14981479//--------------------------------------------------------------------------
    14991480// UniqueExpr
    1500 template< typename core_t >
    1501 const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) {
     1481template< typename pass_t >
     1482const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
    15021483        VISIT_START( node );
    15031484
     
    15141495//--------------------------------------------------------------------------
    15151496// UntypedInitExpr
    1516 template< typename core_t >
    1517 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) {
     1497template< typename pass_t >
     1498const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
    15181499        VISIT_START( node );
    15191500
     
    15311512//--------------------------------------------------------------------------
    15321513// InitExpr
    1533 template< typename core_t >
    1534 const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) {
     1514template< typename pass_t >
     1515const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
    15351516        VISIT_START( node );
    15361517
     
    15481529//--------------------------------------------------------------------------
    15491530// DeletedExpr
    1550 template< typename core_t >
    1551 const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) {
     1531template< typename pass_t >
     1532const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
    15521533        VISIT_START( node );
    15531534
     
    15651546//--------------------------------------------------------------------------
    15661547// DefaultArgExpr
    1567 template< typename core_t >
    1568 const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) {
     1548template< typename pass_t >
     1549const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
    15691550        VISIT_START( node );
    15701551
     
    15811562//--------------------------------------------------------------------------
    15821563// GenericExpr
    1583 template< typename core_t >
    1584 const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) {
     1564template< typename pass_t >
     1565const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
    15851566        VISIT_START( node );
    15861567
     
    16211602//--------------------------------------------------------------------------
    16221603// VoidType
    1623 template< typename core_t >
    1624 const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) {
     1604template< typename pass_t >
     1605const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
    16251606        VISIT_START( node );
    16261607
     
    16301611//--------------------------------------------------------------------------
    16311612// BasicType
    1632 template< typename core_t >
    1633 const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) {
     1613template< typename pass_t >
     1614const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
    16341615        VISIT_START( node );
    16351616
     
    16391620//--------------------------------------------------------------------------
    16401621// PointerType
    1641 template< typename core_t >
    1642 const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) {
     1622template< typename pass_t >
     1623const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
    16431624        VISIT_START( node );
    16441625
     
    16531634//--------------------------------------------------------------------------
    16541635// ArrayType
    1655 template< typename core_t >
    1656 const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) {
     1636template< typename pass_t >
     1637const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
    16571638        VISIT_START( node );
    16581639
     
    16671648//--------------------------------------------------------------------------
    16681649// ReferenceType
    1669 template< typename core_t >
    1670 const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) {
     1650template< typename pass_t >
     1651const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
    16711652        VISIT_START( node );
    16721653
     
    16801661//--------------------------------------------------------------------------
    16811662// QualifiedType
    1682 template< typename core_t >
    1683 const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) {
     1663template< typename pass_t >
     1664const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
    16841665        VISIT_START( node );
    16851666
     
    16941675//--------------------------------------------------------------------------
    16951676// FunctionType
    1696 template< typename core_t >
    1697 const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) {
    1698         VISIT_START( node );
    1699 
    1700         VISIT({
    1701                 guard_forall_subs forall_guard { *this, node };
    1702                 mutate_forall( node );
     1677template< typename pass_t >
     1678const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
     1679        VISIT_START( node );
     1680
     1681        VISIT(
     1682                maybe_accept( node, &FunctionType::forall  );
    17031683                maybe_accept( node, &FunctionType::returns );
    17041684                maybe_accept( node, &FunctionType::params  );
    1705         })
     1685        )
    17061686
    17071687        VISIT_END( Type, node );
     
    17101690//--------------------------------------------------------------------------
    17111691// StructInstType
    1712 template< typename core_t >
    1713 const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) {
    1714         VISIT_START( node );
    1715 
    1716         __pass::symtab::addStruct( core, 0, node->name );
     1692template< typename pass_t >
     1693const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
     1694        VISIT_START( node );
     1695
     1696        __pass::symtab::addStruct( pass, 0, node->name );
    17171697
    17181698        VISIT({
    17191699                guard_symtab guard { *this };
    1720                 guard_forall_subs forall_guard { *this, node };
    1721                 mutate_forall( node );
     1700                maybe_accept( node, &StructInstType::forall );
    17221701                maybe_accept( node, &StructInstType::params );
    17231702        })
     
    17281707//--------------------------------------------------------------------------
    17291708// UnionInstType
    1730 template< typename core_t >
    1731 const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) {
    1732         VISIT_START( node );
    1733 
    1734         __pass::symtab::addUnion( core, 0, node->name );
    1735 
    1736         VISIT({
     1709template< typename pass_t >
     1710const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {
     1711        VISIT_START( node );
     1712
     1713        __pass::symtab::addStruct( pass, 0, node->name );
     1714
     1715        {
    17371716                guard_symtab guard { *this };
    1738                 guard_forall_subs forall_guard { *this, node };
    1739                 mutate_forall( node );
     1717                maybe_accept( node, &UnionInstType::forall );
    17401718                maybe_accept( node, &UnionInstType::params );
    1741         })
     1719        }
    17421720
    17431721        VISIT_END( Type, node );
     
    17461724//--------------------------------------------------------------------------
    17471725// EnumInstType
    1748 template< typename core_t >
    1749 const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) {
    1750         VISIT_START( node );
    1751 
    1752         VISIT({
    1753                 guard_forall_subs forall_guard { *this, node };
    1754                 mutate_forall( node );
     1726template< typename pass_t >
     1727const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
     1728        VISIT_START( node );
     1729
     1730        VISIT(
     1731                maybe_accept( node, &EnumInstType::forall );
    17551732                maybe_accept( node, &EnumInstType::params );
    1756         })
     1733        )
    17571734
    17581735        VISIT_END( Type, node );
     
    17611738//--------------------------------------------------------------------------
    17621739// TraitInstType
    1763 template< typename core_t >
    1764 const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) {
    1765         VISIT_START( node );
    1766 
    1767         VISIT({
    1768                 guard_forall_subs forall_guard { *this, node };
    1769                 mutate_forall( node );
     1740template< typename pass_t >
     1741const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
     1742        VISIT_START( node );
     1743
     1744        VISIT(
     1745                maybe_accept( node, &TraitInstType::forall );
    17701746                maybe_accept( node, &TraitInstType::params );
    1771         })
     1747        )
    17721748
    17731749        VISIT_END( Type, node );
     
    17761752//--------------------------------------------------------------------------
    17771753// TypeInstType
    1778 template< typename core_t >
    1779 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) {
    1780         VISIT_START( node );
    1781 
    1782         VISIT(
    1783                 {
    1784                         guard_forall_subs forall_guard { *this, node };
    1785                         mutate_forall( node );
    1786                         maybe_accept( node, &TypeInstType::params );
    1787                 }
    1788                 // ensure that base re-bound if doing substitution
    1789                 __pass::forall::replace( core, 0, node );
     1754template< typename pass_t >
     1755const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) {
     1756        VISIT_START( node );
     1757
     1758        VISIT(
     1759                maybe_accept( node, &TypeInstType::forall );
     1760                maybe_accept( node, &TypeInstType::params );
    17901761        )
    17911762
     
    17951766//--------------------------------------------------------------------------
    17961767// TupleType
    1797 template< typename core_t >
    1798 const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) {
     1768template< typename pass_t >
     1769const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
    17991770        VISIT_START( node );
    18001771
     
    18091780//--------------------------------------------------------------------------
    18101781// TypeofType
    1811 template< typename core_t >
    1812 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) {
     1782template< typename pass_t >
     1783const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
    18131784        VISIT_START( node );
    18141785
     
    18221793//--------------------------------------------------------------------------
    18231794// VarArgsType
    1824 template< typename core_t >
    1825 const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) {
     1795template< typename pass_t >
     1796const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
    18261797        VISIT_START( node );
    18271798
     
    18311802//--------------------------------------------------------------------------
    18321803// ZeroType
    1833 template< typename core_t >
    1834 const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) {
     1804template< typename pass_t >
     1805const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
    18351806        VISIT_START( node );
    18361807
     
    18401811//--------------------------------------------------------------------------
    18411812// OneType
    1842 template< typename core_t >
    1843 const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) {
     1813template< typename pass_t >
     1814const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
    18441815        VISIT_START( node );
    18451816
     
    18491820//--------------------------------------------------------------------------
    18501821// GlobalScopeType
    1851 template< typename core_t >
    1852 const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) {
     1822template< typename pass_t >
     1823const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
    18531824        VISIT_START( node );
    18541825
     
    18591830//--------------------------------------------------------------------------
    18601831// Designation
    1861 template< typename core_t >
    1862 const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) {
     1832template< typename pass_t >
     1833const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
    18631834        VISIT_START( node );
    18641835
     
    18701841//--------------------------------------------------------------------------
    18711842// SingleInit
    1872 template< typename core_t >
    1873 const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) {
     1843template< typename pass_t >
     1844const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
    18741845        VISIT_START( node );
    18751846
     
    18831854//--------------------------------------------------------------------------
    18841855// ListInit
    1885 template< typename core_t >
    1886 const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) {
     1856template< typename pass_t >
     1857const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
    18871858        VISIT_START( node );
    18881859
     
    18971868//--------------------------------------------------------------------------
    18981869// ConstructorInit
    1899 template< typename core_t >
    1900 const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) {
     1870template< typename pass_t >
     1871const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
    19011872        VISIT_START( node );
    19021873
     
    19121883//--------------------------------------------------------------------------
    19131884// Attribute
    1914 template< typename core_t >
    1915 const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node  )  {
     1885template< typename pass_t >
     1886const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
    19161887        VISIT_START( node );
    19171888
     
    19251896//--------------------------------------------------------------------------
    19261897// TypeSubstitution
    1927 template< typename core_t >
    1928 const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) {
     1898template< typename pass_t >
     1899const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
    19291900        VISIT_START( node );
    19301901
     
    19361907                                guard_symtab guard { *this };
    19371908                                auto new_node = p.second->accept( *this );
    1938                                 if (new_node != p.second) mutated = true;
     1909                                if (new_node != p.second) mutated = false;
    19391910                                new_map.insert({ p.first, new_node });
    19401911                        }
     
    19521923                                guard_symtab guard { *this };
    19531924                                auto new_node = p.second->accept( *this );
    1954                                 if (new_node != p.second) mutated = true;
     1925                                if (new_node != p.second) mutated = false;
    19551926                                new_map.insert({ p.first, new_node });
    19561927                        }
  • src/AST/Pass.proto.hpp

    re67a82d r67ca73e  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
    19 #include "Common/Stats/Heap.h"
    20 
    2119namespace ast {
    22 template<typename core_t>
     20template<typename pass_type>
    2321class Pass;
    2422
     
    8482                };
    8583
    86                 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
     84                std::stack< cleanup_t > cleanups;
    8785        };
    8886
     
    113111        /// "Short hand" to check if this is a valid previsit function
    114112        /// Mostly used to make the static_assert look (and print) prettier
    115         template<typename core_t, typename node_t>
     113        template<typename pass_t, typename node_t>
    116114        struct is_valid_previsit {
    117                 using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) );
     115                using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
    118116
    119117                static constexpr bool value = std::is_void< ret_t >::value ||
     
    129127        template<>
    130128        struct __assign<true> {
    131                 template<typename core_t, typename node_t>
    132                 static inline void result( core_t & core, const node_t * & node ) {
    133                         core.previsit( node );
     129                template<typename pass_t, typename node_t>
     130                static inline void result( pass_t & pass, const node_t * & node ) {
     131                        pass.previsit( node );
    134132                }
    135133        };
     
    137135        template<>
    138136        struct __assign<false> {
    139                 template<typename core_t, typename node_t>
    140                 static inline void result( core_t & core, const node_t * & node ) {
    141                         node = core.previsit( node );
     137                template<typename pass_t, typename node_t>
     138                static inline void result( pass_t & pass, const node_t * & node ) {
     139                        node = pass.previsit( node );
    142140                        assertf(node, "Previsit must not return NULL");
    143141                }
     
    152150        template<>
    153151        struct __return<true> {
    154                 template<typename core_t, typename node_t>
    155                 static inline const node_t * result( core_t & core, const node_t * & node ) {
    156                         core.postvisit( node );
     152                template<typename pass_t, typename node_t>
     153                static inline const node_t * result( pass_t & pass, const node_t * & node ) {
     154                        pass.postvisit( node );
    157155                        return node;
    158156                }
     
    161159        template<>
    162160        struct __return<false> {
    163                 template<typename core_t, typename node_t>
    164                 static inline auto result( core_t & core, const node_t * & node ) {
    165                         return core.postvisit( node );
     161                template<typename pass_t, typename node_t>
     162                static inline auto result( pass_t & pass, const node_t * & node ) {
     163                        return pass.postvisit( node );
    166164                }
    167165        };
     
    182180        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    183181        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    184         template<typename core_t, typename node_t>
    185         static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
     182        template<typename pass_t, typename node_t>
     183        static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
    186184                static_assert(
    187                         is_valid_previsit<core_t, node_t>::value,
     185                        is_valid_previsit<pass_t, node_t>::value,
    188186                        "Previsit may not change the type of the node. It must return its paremeter or void."
    189187                );
     
    191189                __assign<
    192190                        std::is_void<
    193                                 decltype( core.previsit( node ) )
     191                                decltype( pass.previsit( node ) )
    194192                        >::value
    195                 >::result( core, node );
     193                >::result( pass, node );
    196194        }
    197195
    198         template<typename core_t, typename node_t>
    199         static inline auto previsit( core_t &, const node_t *, long ) {}
     196        template<typename pass_t, typename node_t>
     197        static inline auto previsit( pass_t &, const node_t *, long ) {}
    200198
    201199        // PostVisit : never mutates the passed pointer but may return a different node
    202         template<typename core_t, typename node_t>
    203         static inline auto postvisit( core_t & core, const node_t * node, int ) ->
    204                 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
     200        template<typename pass_t, typename node_t>
     201        static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->
     202                decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    205203        {
    206204                return __return<
    207205                        std::is_void<
    208                                 decltype( core.postvisit( node ) )
     206                                decltype( pass.postvisit( node ) )
    209207                        >::value
    210                 >::result( core, node );
     208                >::result( pass, node );
    211209        }
    212210
    213         template<typename core_t, typename node_t>
    214         static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
     211        template<typename pass_t, typename node_t>
     212        static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
    215213
    216214        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    227225        // The type is not strictly enforced but does match the accessory
    228226        #define FIELD_PTR( name, default_type ) \
    229         template< typename core_t > \
    230         static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
     227        template< typename pass_t > \
     228        static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
    231229        \
    232         template< typename core_t > \
    233         static inline default_type * name( core_t &, long ) { return nullptr; }
     230        template< typename pass_t > \
     231        static inline default_type * name( pass_t &, long ) { return nullptr; }
    234232
    235233        // List of fields and their expected types
     
    241239        FIELD_PTR( visit_children, __pass::bool_ref )
    242240        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    243         FIELD_PTR( visitor, ast::Pass<core_t> * const )
     241        FIELD_PTR( visitor, ast::Pass<pass_t> * const )
    244242
    245243        // Remove the macro to make sure we don't clash
    246244        #undef FIELD_PTR
    247 
    248         template< typename core_t >
    249         static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    250                 // Stats::Heap::stacktrace_push(core_t::traceId);
    251         }
    252 
    253         template< typename core_t >
    254         static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    255                 // Stats::Heap::stacktrace_pop();
    256         }
    257 
    258         template< typename core_t >
    259         static void beginTrace(core_t &, long) {}
    260 
    261         template< typename core_t >
    262         static void endTrace(core_t &, long) {}
    263245
    264246        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     
    266248        // detect it using the same strategy
    267249        namespace scope {
    268                 template<typename core_t>
    269                 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
    270                         core.beginScope();
    271                 }
    272 
    273                 template<typename core_t>
    274                 static inline void enter( core_t &, long ) {}
    275 
    276                 template<typename core_t>
    277                 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
    278                         core.endScope();
    279                 }
    280 
    281                 template<typename core_t>
    282                 static inline void leave( core_t &, long ) {}
    283         } // namespace scope
    284 
    285         // Certain passes desire an up to date symbol table automatically
     250                template<typename pass_t>
     251                static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
     252                        pass.beginScope();
     253                }
     254
     255                template<typename pass_t>
     256                static inline void enter( pass_t &, long ) {}
     257
     258                template<typename pass_t>
     259                static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
     260                        pass.endScope();
     261                }
     262
     263                template<typename pass_t>
     264                static inline void leave( pass_t &, long ) {}
     265        };
     266
     267        // Finally certain pass desire an up to date symbol table automatically
    286268        // detect the presence of a member name `symtab` and call all the members appropriately
    287269        namespace symtab {
    288270                // Some simple scoping rules
    289                 template<typename core_t>
    290                 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
    291                         core.symtab.enterScope();
    292                 }
    293 
    294                 template<typename core_t>
    295                 static inline auto enter( core_t &, long ) {}
    296 
    297                 template<typename core_t>
    298                 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
    299                         core.symtab.leaveScope();
    300                 }
    301 
    302                 template<typename core_t>
    303                 static inline auto leave( core_t &, long ) {}
     271                template<typename pass_t>
     272                static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
     273                        pass.symtab.enterScope();
     274                }
     275
     276                template<typename pass_t>
     277                static inline auto enter( pass_t &, long ) {}
     278
     279                template<typename pass_t>
     280                static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
     281                        pass.symtab.leaveScope();
     282                }
     283
     284                template<typename pass_t>
     285                static inline auto leave( pass_t &, long ) {}
    304286
    305287                // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    306288                // Create macro to condense these common patterns
    307289                #define SYMTAB_FUNC1( func, type ) \
    308                 template<typename core_t> \
    309                 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
    310                         core.symtab.func( arg ); \
     290                template<typename pass_t> \
     291                static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\
     292                        pass.symtab.func( arg ); \
    311293                } \
    312294                \
    313                 template<typename core_t> \
    314                 static inline void func( core_t &, long, type ) {}
     295                template<typename pass_t> \
     296                static inline void func( pass_t &, long, type ) {}
    315297
    316298                #define SYMTAB_FUNC2( func, type1, type2 ) \
    317                 template<typename core_t> \
    318                 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
    319                         core.symtab.func( arg1, arg2 ); \
     299                template<typename pass_t> \
     300                static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\
     301                        pass.symtab.func( arg1, arg2 ); \
    320302                } \
    321303                        \
    322                 template<typename core_t> \
    323                 static inline void func( core_t &, long, type1, type2 ) {}
     304                template<typename pass_t> \
     305                static inline void func( pass_t &, long, type1, type2 ) {}
    324306
    325307                SYMTAB_FUNC1( addId     , const DeclWithType *  );
     
    329311                SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    330312                SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    331                 SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
     313                SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
    332314
    333315                // A few extra functions have more complicated behaviour, they are hand written
    334                 template<typename core_t>
    335                 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
     316                template<typename pass_t>
     317                static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {
    336318                        ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    337319                        fwd->params = decl->params;
    338                         core.symtab.addStruct( fwd );
    339                 }
    340 
    341                 template<typename core_t>
    342                 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
    343 
    344                 template<typename core_t>
    345                 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
     320                        pass.symtab.addStruct( fwd );
     321                }
     322
     323                template<typename pass_t>
     324                static inline void addStructFwd( pass_t &, long, const ast::StructDecl * ) {}
     325
     326                template<typename pass_t>
     327                static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.symtab.addUnion( decl ), void() ) {
    346328                        UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
    347329                        fwd->params = decl->params;
    348                         core.symtab.addUnion( fwd );
    349                 }
    350 
    351                 template<typename core_t>
    352                 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
    353 
    354                 template<typename core_t>
    355                 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
    356                         if ( ! core.symtab.lookupStruct( str ) ) {
    357                                 core.symtab.addStruct( str );
    358                         }
    359                 }
    360 
    361                 template<typename core_t>
    362                 static inline void addStruct( core_t &, long, const std::string & ) {}
    363 
    364                 template<typename core_t>
    365                 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
    366                         if ( ! core.symtab.lookupUnion( str ) ) {
    367                                 core.symtab.addUnion( str );
    368                         }
    369                 }
    370 
    371                 template<typename core_t>
    372                 static inline void addUnion( core_t &, long, const std::string & ) {}
     330                        pass.symtab.addUnion( fwd );
     331                }
     332
     333                template<typename pass_t>
     334                static inline void addUnionFwd( pass_t &, long, const ast::UnionDecl * ) {}
     335
     336                template<typename pass_t>
     337                static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addStruct( str ), void() ) {
     338                        if ( ! pass.symtab.lookupStruct( str ) ) {
     339                                pass.symtab.addStruct( str );
     340                        }
     341                }
     342
     343                template<typename pass_t>
     344                static inline void addStruct( pass_t &, long, const std::string & ) {}
     345
     346                template<typename pass_t>
     347                static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addUnion( str ), void() ) {
     348                        if ( ! pass.symtab.lookupUnion( str ) ) {
     349                                pass.symtab.addUnion( str );
     350                        }
     351                }
     352
     353                template<typename pass_t>
     354                static inline void addUnion( pass_t &, long, const std::string & ) {}
    373355
    374356                #undef SYMTAB_FUNC1
    375357                #undef SYMTAB_FUNC2
    376         } // namespace symtab
    377 
    378         // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
    379         // Detect the presence of a member name `subs` and call all members appropriately
    380         namespace forall {
    381                 // Some simple scoping rules
    382                 template<typename core_t>
    383                 static inline auto enter( core_t & core, int, const ast::ParameterizedType * type )
    384                 -> decltype( core.subs, void() ) {
    385                         if ( ! type->forall.empty() ) core.subs.beginScope();
    386                 }
    387 
    388                 template<typename core_t>
    389                 static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {}
    390 
    391                 template<typename core_t>
    392                 static inline auto leave( core_t & core, int, const ast::ParameterizedType * type )
    393                 -> decltype( core.subs, void() ) {
    394                         if ( ! type->forall.empty() ) { core.subs.endScope(); }
    395                 }
    396 
    397                 template<typename core_t>
    398                 static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {}
    399 
    400                 // Get the substitution table, if present
    401                 template<typename core_t>
    402                 static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) {
    403                         return &core.subs;
    404                 }
    405 
    406                 template<typename core_t>
    407                 static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; }
    408 
    409                 // Replaces a TypeInstType's base TypeDecl according to the table
    410                 template<typename core_t>
    411                 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
    412                 -> decltype( core.subs, void() ) {
    413                         inst = ast::mutate_field(
    414                                 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
    415                 }
    416 
    417                 template<typename core_t>
    418                 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
    419 
    420         } // namespace forall
    421 } // namespace __pass
    422 } // namespace ast
     358        };
     359};
     360};
  • src/AST/Print.cpp

    re67a82d r67ca73e  
    2929
    3030template <typename C, typename... T>
    31 constexpr array<C,sizeof...(T)> make_array(T&&... values)
     31constexpr auto make_array(T&&... values) ->
     32        array<C,sizeof...(T)>
    3233{
    3334        return array<C,sizeof...(T)>{
     
    128129
    129130        void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
    130                 if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) {
    131                         os << indent << "with " << inferred.data.resnSlots->size()
     131                switch ( inferred.mode ) {
     132                case ast::Expr::InferUnion::Empty: return;
     133                case ast::Expr::InferUnion::Slots: {
     134                        os << indent << "with " << inferred.data.resnSlots.size()
    132135                           << " pending inference slots" << endl;
    133                 }
    134                 if (inferred.data.inferParams && !inferred.data.inferParams->empty()) {
     136                        return;
     137                }
     138                case ast::Expr::InferUnion::Params: {
    135139                        os << indent << "with inferred parameters " << level << ":" << endl;
    136140                        ++indent;
    137                         for ( const auto & i : *inferred.data.inferParams ) {
     141                        for ( const auto & i : inferred.data.inferParams ) {
    138142                                os << indent;
    139                                 short_print( i.second.declptr );
     143                                short_print( Decl::fromId( i.second.decl ) );
    140144                                os << endl;
    141145                                print( i.second.expr->inferred, level+1 );
    142146                        }
    143147                        --indent;
     148                        return;
     149                }
    144150                }
    145151        }
     
    227233                }
    228234
    229                 if ( ! node->assertions.empty() ) {
     235                if ( ! short_mode && ! node->assertions.empty() ) {
    230236                        os << endl << indent << "... with assertions" << endl;
    231237                        ++indent;
     
    237243        void postprint( const ast::Expr * node ) {
    238244                print( node->inferred );
    239 
    240                 if ( node->result ) {
    241                         os << endl << indent << "... with resolved type:" << endl;
    242                         ++indent;
    243                         os << indent;
    244                         node->result->accept( *this );
    245                         --indent;
    246                 }
    247245
    248246                if ( node->env ) {
     
    844842        virtual const ast::Expr * visit( const ast::CastExpr * node ) override final {
    845843                ++indent;
    846                 os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent;
     844                os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
    847845                safe_print( node->arg );
    848846                os << endl << indent-1 << "... to:";
  • src/AST/Stmt.hpp

    re67a82d r67ca73e  
    2727
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    29 #define MUTATE_FRIEND \
    30     template<typename node_t> friend node_t * mutate(const node_t * node); \
    31         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     29#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3230
    3331namespace ast {
     
    414412class ImplicitCtorDtorStmt final : public Stmt {
    415413public:
    416         ptr<Stmt> callStmt;
     414        readonly<Stmt> callStmt;
    417415
    418416        ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
  • src/AST/Type.cpp

    re67a82d r67ca73e  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jul 23 14:16:00 2020
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Dec 15 16:56:28 2019
     13// Update Count     : 4
    1414//
    1515
     
    2121
    2222#include "Decl.hpp"
    23 #include "ForallSubstitutor.hpp" // for substituteForall
    2423#include "Init.hpp"
    25 #include "Common/utility.h"      // for copy, move
    2624#include "InitTweak/InitTweak.h" // for getPointerBase
    2725#include "Tuples/Tuples.h"       // for isTtype
     
    9290// GENERATED END
    9391
    94 // --- ParameterizedType
    95 
    96 void ParameterizedType::initWithSub(
    97         const ParameterizedType & o, Pass< ForallSubstitutor > & sub
    98 ) {
    99         forall = sub.core( o.forall );
    100 }
    101 
    10292// --- FunctionType
    103 
    104 FunctionType::FunctionType( const FunctionType & o )
    105 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(),
    106   isVarArgs( o.isVarArgs ) {
    107         Pass< ForallSubstitutor > sub;
    108         initWithSub( o, sub );           // initialize substitution map
    109         returns = sub.core( o.returns ); // apply to return and parameter types
    110         params = sub.core( o.params );
    111 }
    11293
    11394namespace {
     
    125106
    126107// --- ReferenceToType
    127 
    128 void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) {
    129         ParameterizedType::initWithSub( o, sub ); // initialize substitution
    130         params = sub.core( o.params );            // apply to parameters
    131 }
    132 
    133 ReferenceToType::ReferenceToType( const ReferenceToType & o )
    134 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ),
    135   hoistType( o.hoistType ) {
    136         Pass< ForallSubstitutor > sub;
    137         initWithSub( o, sub );
    138 }
    139 
    140108std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
    141109        assertf( aggr(), "Must have aggregate to perform lookup" );
     
    148116}
    149117
    150 // --- SueInstType (StructInstType, UnionInstType, EnumInstType)
     118// --- StructInstType
    151119
    152 template<typename decl_t>
    153 SueInstType<decl_t>::SueInstType(
    154         const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    155 : ReferenceToType( b->name, q, move(as) ), base( b ) {}
     120StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
     121        std::vector<ptr<Attribute>>&& as )
     122: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    156123
    157 template<typename decl_t>
    158 bool SueInstType<decl_t>::isComplete() const {
    159         return base ? base->body : false;
    160 }
     124bool StructInstType::isComplete() const { return base ? base->body : false; }
    161125
    162 template class SueInstType<StructDecl>;
    163 template class SueInstType<UnionDecl>;
    164 template class SueInstType<EnumDecl>;
     126// --- UnionInstType
     127
     128UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
     129        std::vector<ptr<Attribute>>&& as )
     130: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     131
     132bool UnionInstType::isComplete() const { return base ? base->body : false; }
     133
     134// --- EnumInstType
     135
     136EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
     137        std::vector<ptr<Attribute>>&& as )
     138: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     139
     140bool EnumInstType::isComplete() const { return base ? base->body : false; }
    165141
    166142// --- TraitInstType
    167143
    168 TraitInstType::TraitInstType(
    169         const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    170 : ReferenceToType( b->name, q, move(as) ), base( b ) {}
     144TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
     145        std::vector<ptr<Attribute>>&& as )
     146: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    171147
    172148// --- TypeInstType
    173 
    174 TypeInstType::TypeInstType( const TypeInstType & o )
    175 : ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
    176         Pass< ForallSubstitutor > sub;
    177         initWithSub( o, sub );      // initialize substitution
    178         base = sub.core( o.base );  // apply to base type
    179 }
    180149
    181150void TypeInstType::set_base( const TypeDecl * b ) {
     
    189158
    190159TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    191 : Type( q ), types( move(ts) ), members() {
     160: Type( q ), types( std::move(ts) ), members() {
    192161        // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    193162        // named, but members without initializer nodes end up getting constructors, which breaks
  • src/AST/Type.hpp

    re67a82d r67ca73e  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jul 23 14:15:00 2020
    13 // Update Count     : 6
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Dec 11 21:56:46 2019
     13// Update Count     : 5
    1414//
    1515
     
    2929
    3030// Must be included in *all* AST classes; should be #undef'd at the end of the file
    31 #define MUTATE_FRIEND \
    32     template<typename node_t> friend node_t * mutate(const node_t * node); \
    33         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     31#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3432
    3533namespace ast {
    36 
    37 template< typename T > class Pass;
    38 
    39 struct ForallSubstitutor;
    4034
    4135class Type : public Node {
     
    5044        bool is_volatile() const { return qualifiers.is_volatile; }
    5145        bool is_restrict() const { return qualifiers.is_restrict; }
     46        bool is_lvalue() const { return qualifiers.is_lvalue; }
    5247        bool is_mutex() const { return qualifiers.is_mutex; }
    5348        bool is_atomic() const { return qualifiers.is_atomic; }
     
    5651        Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
    5752        Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
     53        Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
    5854        Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
    5955        Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
     
    167163        static const char *typeNames[];
    168164
    169         BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     165        BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
    170166        : Type(q, std::move(as)), kind(k) {}
    171167
     
    269265/// Base type for potentially forall-qualified types
    270266class ParameterizedType : public Type {
    271 protected:
    272         /// initializes forall with substitutor
    273         void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
    274267public:
    275268        using ForallList = std::vector<ptr<TypeDecl>>;
     
    283276        ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
    284277        : Type(q, std::move(as)), forall() {}
    285 
    286         // enforce use of ForallSubstitutor to copy parameterized type
    287         ParameterizedType( const ParameterizedType & ) = delete;
    288 
    289         ParameterizedType( ParameterizedType && ) = default;
    290 
    291         // no need to change destructor, and operator= deleted in Node
    292278
    293279private:
     
    315301        : ParameterizedType(q), returns(), params(), isVarArgs(va) {}
    316302
    317         FunctionType( const FunctionType & o );
    318 
    319303        /// true if either the parameters or return values contain a tttype
    320304        bool isTtype() const;
     
    330314/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
    331315class ReferenceToType : public ParameterizedType {
    332 protected:
    333         /// Initializes forall and parameters based on substitutor
    334         void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub );
    335316public:
    336317        std::vector<ptr<Expr>> params;
     
    338319        bool hoistType = false;
    339320
    340         ReferenceToType(
    341                 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     321        ReferenceToType( const std::string& n, CV::Qualifiers q = {},
     322                std::vector<ptr<Attribute>> && as = {} )
    342323        : ParameterizedType(q, std::move(as)), params(), name(n) {}
    343 
    344         ReferenceToType( const ReferenceToType & o );
    345324
    346325        /// Gets aggregate declaration this type refers to
     
    354333};
    355334
    356 // Common implementation for the SUE instance types. Not to be used directly.
    357 template<typename decl_t>
    358 class SueInstType final : public ReferenceToType {
    359 public:
    360         using base_type = decl_t;
    361         readonly<decl_t> base;
    362 
    363         SueInstType(
    364                 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     335/// instance of struct type
     336class StructInstType final : public ReferenceToType {
     337public:
     338        readonly<StructDecl> base;
     339
     340        StructInstType( const std::string& n, CV::Qualifiers q = {},
     341                std::vector<ptr<Attribute>> && as = {} )
    365342        : ReferenceToType( n, q, std::move(as) ), base() {}
    366 
    367         SueInstType(
    368                 const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
     343        StructInstType( const StructDecl * b, CV::Qualifiers q = {},
     344                std::vector<ptr<Attribute>> && as = {} );
    369345
    370346        bool isComplete() const override;
    371347
    372         const decl_t * aggr() const override { return base; }
    373 
    374         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    375 private:
    376         SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; }
    377         MUTATE_FRIEND
    378 };
    379 
    380 /// An instance of a struct type.
    381 using StructInstType = SueInstType<StructDecl>;
    382 
    383 /// An instance of a union type.
    384 using UnionInstType = SueInstType<UnionDecl>;
    385 
    386 /// An instance of an enum type.
    387 using EnumInstType = SueInstType<EnumDecl>;
    388 
    389 /// An instance of a trait type.
     348        const StructDecl * aggr() const override { return base; }
     349
     350        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     351private:
     352        StructInstType * clone() const override { return new StructInstType{ *this }; }
     353        MUTATE_FRIEND
     354};
     355
     356/// instance of union type
     357class UnionInstType final : public ReferenceToType {
     358public:
     359        readonly<UnionDecl> base;
     360
     361        UnionInstType( const std::string& n, CV::Qualifiers q = {},
     362                std::vector<ptr<Attribute>> && as = {} )
     363        : ReferenceToType( n, q, std::move(as) ), base() {}
     364        UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
     365                std::vector<ptr<Attribute>> && as = {} );
     366
     367        bool isComplete() const override;
     368
     369        const UnionDecl * aggr() const override { return base; }
     370
     371        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     372private:
     373        UnionInstType * clone() const override { return new UnionInstType{ *this }; }
     374        MUTATE_FRIEND
     375};
     376
     377/// instance of enum type
     378class EnumInstType final : public ReferenceToType {
     379public:
     380        readonly<EnumDecl> base;
     381
     382        EnumInstType( const std::string& n, CV::Qualifiers q = {},
     383                std::vector<ptr<Attribute>> && as = {} )
     384        : ReferenceToType( n, q, std::move(as) ), base() {}
     385        EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
     386                std::vector<ptr<Attribute>> && as = {} );
     387
     388        bool isComplete() const override;
     389
     390        const EnumDecl * aggr() const override { return base; }
     391
     392        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     393private:
     394        EnumInstType * clone() const override { return new EnumInstType{ *this }; }
     395        MUTATE_FRIEND
     396};
     397
     398/// instance of trait type
    390399class TraitInstType final : public ReferenceToType {
    391400public:
    392401        readonly<TraitDecl> base;
    393402
    394         TraitInstType(
    395                 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     403        TraitInstType( const std::string& n, CV::Qualifiers q = {},
     404                std::vector<ptr<Attribute>> && as = {} )
    396405        : ReferenceToType( n, q, std::move(as) ), base() {}
    397 
    398         TraitInstType(
    399                 const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
     406        TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
     407                std::vector<ptr<Attribute>> && as = {} );
    400408
    401409        // not meaningful for TraitInstType
     
    416424        TypeDecl::Kind kind;
    417425
    418         TypeInstType(
    419                 const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
     426        TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
    420427                std::vector<ptr<Attribute>> && as = {} )
    421428        : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
     
    423430                std::vector<ptr<Attribute>> && as = {} )
    424431        : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
    425 
    426         TypeInstType( const TypeInstType & o );
    427432
    428433        /// sets `base`, updating `kind` correctly
  • src/AST/TypeEnvironment.cpp

    re67a82d r67ca73e  
    5959        std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) );
    6060        out << ")";
    61 
     61       
    6262        if ( clz.bound ) {
    6363                out << " -> ";
     
    9292                                }
    9393                        }
    94 
     94                       
    9595                        i = next;  // go to next node even if this removed
    9696                }
     
    161161                Pass<Occurs> occur{ var, env };
    162162                maybe_accept( ty, occur );
    163                 return occur.core.result;
    164         }
    165 }
    166 
    167 bool TypeEnvironment::combine(
     163                return occur.pass.result;
     164        }
     165}
     166
     167bool TypeEnvironment::combine( 
    168168                const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
    169169        // short-circuit easy cases
     
    199199                                auto st = internal_lookup( *vt );
    200200                                if ( st == env.end() ) {
    201                                         // unbound, safe to add if occurs
     201                                        // unbound, safe to add if occurs 
    202202                                        if ( r.bound && occurs( r.bound, *vt, *this ) ) return false;
    203203                                        r.vars.emplace( *vt );
     
    266266}
    267267
    268 bool TypeEnvironment::bindVar(
    269                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
    270                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
    271                 const SymbolTable & symtab
     268bool TypeEnvironment::bindVar( 
     269                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
     270                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 
     271                const SymbolTable & symtab 
    272272) {
    273273        // remove references from bound type, so that type variables can only bind to value types
     
    286286                        ptr<Type> newType = it->bound;
    287287                        reset_qualifiers( newType, typeInst->qualifiers );
    288                         if ( unifyInexact(
    289                                         newType, target, *this, need, have, open,
     288                        if ( unifyInexact( 
     289                                        newType, target, *this, need, have, open, 
    290290                                        widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
    291291                                if ( common ) {
     
    300300                }
    301301        } else {
    302                 env.emplace_back(
     302                env.emplace_back( 
    303303                        typeInst->name, target, widen.first && widen.second, data );
    304304        }
     
    306306}
    307307
    308 bool TypeEnvironment::bindVarToVar(
    309                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
    310                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
    311                 WidenMode widen, const SymbolTable & symtab
     308bool TypeEnvironment::bindVarToVar( 
     309                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
     310                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 
     311                WidenMode widen, const SymbolTable & symtab 
    312312) {
    313313        auto c1 = internal_lookup( var1->name );
    314314        auto c2 = internal_lookup( var2->name );
    315 
     315       
    316316        // exit early if variables already bound together
    317317        if ( c1 != env.end() && c1 == c2 ) {
     
    396396}
    397397
    398 bool TypeEnvironment::mergeBound(
     398bool TypeEnvironment::mergeBound( 
    399399                EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
    400400        if ( from.bound ) {
     
    406406                        AssertionSet need, have;
    407407
    408                         if ( unifyInexact(
     408                        if ( unifyInexact( 
    409409                                        toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
    410410                                // unifies, set common type if necessary
     
    424424}
    425425
    426 bool TypeEnvironment::mergeClasses(
     426bool TypeEnvironment::mergeClasses( 
    427427        ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
    428428) {
  • src/AST/TypeEnvironment.hpp

    re67a82d r67ca73e  
    3737/// Adding this comparison operator significantly improves assertion satisfaction run time for
    3838/// some cases. The current satisfaction algorithm's speed partially depends on the order of
    39 /// assertions. Assertions which have fewer possible matches should appear before assertions
    40 /// which have more possible matches. This seems to imply that this could be further improved
    41 /// by providing an indexer as an additional argument and ordering based on the number of
     39/// assertions. Assertions which have fewer possible matches should appear before assertions 
     40/// which have more possible matches. This seems to imply that this could be further improved 
     41/// by providing an indexer as an additional argument and ordering based on the number of 
    4242/// matches of the same kind (object, function) for the names of the declarations.
    4343///
    44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
     44/// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 
    4545/// comparator.
    4646///
    47 /// Note: since this compares pointers for position, minor changes in the source file that
    48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the
    49 /// placement of a line directive can reorder type pointers with respect to each other so that
    50 /// assertions are seen in different orders, causing a potentially different number of
    51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27
    52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so
    53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle
    54 /// name instead of type as the second comparator, but this causes some assertions to never be
     47/// Note: since this compares pointers for position, minor changes in the source file that 
     48/// affect memory layout can alter compilation time in unpredictable ways. For example, the 
     49/// placement of a line directive can reorder type pointers with respect to each other so that 
     50/// assertions are seen in different orders, causing a potentially different number of 
     51/// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 
     52/// seconds by reordering line directives alone, so it would be nice to fix this comparison so 
     53/// that assertions compare more consistently. I've tried to modify this to compare on mangle 
     54/// name instead of type as the second comparator, but this causes some assertions to never be 
    5555/// recorded. More investigation is needed.
    5656struct AssertCompare {
     
    8686void print( std::ostream &, const OpenVarSet &, Indenter indent = {} );
    8787
    88 /// Represents an equivalence class of bound type variables, optionally with the concrete type
     88/// Represents an equivalence class of bound type variables, optionally with the concrete type 
    8989/// they bind to.
    9090struct EqvClass {
     
    9595
    9696        EqvClass() : vars(), bound(), allowWidening( true ), data() {}
    97 
     97       
    9898        /// Copy-with-bound constructor
    99         EqvClass( const EqvClass & o, const Type * b )
     99        EqvClass( const EqvClass & o, const Type * b ) 
    100100        : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {}
    101101
     
    142142        void writeToSubstitution( TypeSubstitution & sub ) const;
    143143
    144         template< typename node_t >
    145         auto apply( node_t && type ) const {
     144        template< typename node_t, enum Node::ref_type ref_t >
     145        int apply( ptr_base< node_t, ref_t > & type ) const {
    146146                TypeSubstitution sub;
    147147                writeToSubstitution( sub );
    148                 return sub.apply( std::forward<node_t>(type) );
    149         }
    150 
    151         template< typename node_t >
    152         auto applyFree( node_t && type ) const {
     148                return sub.apply( type );
     149        }
     150
     151        template< typename node_t, enum Node::ref_type ref_t >
     152        int applyFree( ptr_base< node_t, ref_t > & type ) const {
    153153                TypeSubstitution sub;
    154154                writeToSubstitution( sub );
    155                 return sub.applyFree( std::forward<node_t>(type) );
     155                return sub.applyFree( type );
    156156        }
    157157
     
    172172        void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars );
    173173
    174         /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if
     174        /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 
    175175        /// needed. Returns false on failure.
    176         bool bindVar(
    177                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
    178                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
     176        bool bindVar( 
     177                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
     178                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
    179179                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    180 
    181         /// Binds the type classes represented by `var1` and `var2` together; will add one or both
     180       
     181        /// Binds the type classes represented by `var1` and `var2` together; will add one or both 
    182182        /// classes if needed. Returns false on failure.
    183         bool bindVarToVar(
    184                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
    185                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
     183        bool bindVarToVar( 
     184                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
     185                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
    186186                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    187187
     
    198198
    199199        /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
    200         bool mergeBound(
     200        bool mergeBound( 
    201201                EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
    202202
    203203        /// Merges two type classes from local environment, returning false if fails
    204         bool mergeClasses(
    205                 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
     204        bool mergeClasses( 
     205                ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 
    206206                const SymbolTable & symtab );
    207207
  • src/AST/TypeSubstitution.cpp

    re67a82d r67ca73e  
    1818
    1919namespace ast {
    20 
    21 
    22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
    2320
    2421TypeSubstitution::TypeSubstitution() {
     
    9592namespace {
    9693        struct EnvTrimmer {
    97                 const TypeSubstitution * env;
     94                ptr<TypeSubstitution> env;
    9895                TypeSubstitution * newEnv;
    9996                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
     
    111108        if ( env ) {
    112109                TypeSubstitution * newEnv = new TypeSubstitution();
     110#if TIME_TO_CONVERT_PASSES
    113111                Pass<EnvTrimmer> trimmer( env, newEnv );
    114112                expr->accept( trimmer );
     113#else
     114                (void)expr;
     115                (void)env;
     116#endif
    115117                return newEnv;
    116118        }
     
    119121
    120122void TypeSubstitution::normalize() {
    121         Pass<Substituter> sub( *this, true );
     123#if TIME_TO_CONVERT_PASSES
     124        PassVisitor<Substituter> sub( *this, true );
    122125        do {
    123                 sub.core.subCount = 0;
    124                 sub.core.freeOnly = true;
     126                sub.pass.subCount = 0;
     127                sub.pass.freeOnly = true;
    125128                for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
    126                         i->second = i->second->accept( sub );
     129                        i->second = i->second->acceptMutator( sub );
    127130                }
    128         } while ( sub.core.subCount );
    129 }
    130 
    131 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
     131        } while ( sub.pass.subCount );
     132#endif
     133}
     134
     135#if TIME_TO_CONVERT_PASSES
     136
     137Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
    132138        BoundVarsType::const_iterator bound = boundVars.find( inst->name );
    133139        if ( bound != boundVars.end() ) return inst;
     
    140146                // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
    141147                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    142                 if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
     148                if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    143149                        if ( inst->name == replacement->name ) {
    144150                                return inst;
     
    147153                // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
    148154                subCount++;
    149                 ptr<Type> newType = i->second; // force clone if needed
    150                 add_qualifiers( newType, inst->qualifiers );
    151                 // Note: need to recursively apply substitution to the new type because normalize does not
    152                 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
    153                 newType = newType->accept( *visitor );
    154                 return newType.release();
    155         } // if
    156 }
    157 
    158 const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
     155                Type * newtype = i->second->clone();
     156                newtype->get_qualifiers() |= inst->get_qualifiers();
     157                delete inst;
     158                // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
     159                return newtype->acceptMutator( *visitor );
     160        } // if
     161}
     162
     163Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
    159164        VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
    160165        if ( i == sub.varEnv.end() ) {
     
    162167        } else {
    163168                subCount++;
    164                 return i->second;
    165         } // if
    166 }
    167 
    168 void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
     169                delete nameExpr;
     170                return i->second->clone();
     171        } // if
     172}
     173
     174void TypeSubstitution::Substituter::premutate( Type * type ) {
    169175        GuardValue( boundVars );
    170176        // bind type variables from forall-qualifiers
    171177        if ( freeOnly ) {
    172                 for ( const TypeDecl * tyvar : ptype->forall ) {
    173                                 boundVars.insert( tyvar->name );
     178                for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
     179                        boundVars.insert( (*tyvar)->name );
    174180                } // for
    175181        } // if
    176182}
    177183
    178 void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) {
     184template< typename TypeClass >
     185void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
    179186        GuardValue( boundVars );
    180187        // bind type variables from forall-qualifiers
    181188        if ( freeOnly ) {
    182                 for ( const TypeDecl * tyvar : type->forall ) {
    183                         boundVars.insert( tyvar->name );
     189                for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
     190                        boundVars.insert( (*tyvar)->name );
    184191                } // for
    185192                // bind type variables from generic type instantiations
    186                 if ( auto decl = type->aggr() ) {
    187                         if ( ! type->params.empty() ) {
    188                                 for ( const TypeDecl * tyvar : decl->params ) {
    189                                         boundVars.insert( tyvar->name );
    190                                 } // for
    191                         } // if
    192                 }
    193         } // if
    194 }
    195 
    196 void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
     193                std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
     194                if ( baseParameters && ! type->parameters.empty() ) {
     195                        for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
     196                                boundVars.insert( (*tyvar)->name );
     197                        } // for
     198                } // if
     199        } // if
     200}
     201
     202void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
    197203        handleAggregateType( aggregateUseType );
    198204}
    199205
    200 void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
     206void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
    201207        handleAggregateType( aggregateUseType );
    202208}
     209
     210#endif
    203211
    204212} // namespace ast
  • src/AST/TypeSubstitution.hpp

    re67a82d r67ca73e  
    4444        TypeSubstitution &operator=( const TypeSubstitution &other );
    4545
    46         template< typename SynTreeClass >
    47         struct ApplyResult {
    48                 // const SynTreeClass * node;
    49                 ast::ptr<SynTreeClass> node;
    50                 int count;
    51         };
    52 
    53         template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const;
    54         template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const;
     46        template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
     47        template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
    5548
    5649        template< typename node_t, enum Node::ref_type ref_t >
    5750        int apply( ptr_base< node_t, ref_t > & input ) const {
    5851                const node_t * p = input.get();
    59                 auto ret = apply(p);
    60                 input = ret.node;
    61                 return ret.count;
     52                int ret = apply(p);
     53                input = p;
     54                return ret;
    6255        }
    6356
     
    6558        int applyFree( ptr_base< node_t, ref_t > & input ) const {
    6659                const node_t * p = input.get();
    67                 auto ret = applyFree(p);
    68                 input = ret.node;
    69                 return ret.count;
     60                int ret = applyFree(p);
     61                input = p;
     62                return ret;
    7063        }
    7164
     
    9992        void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
    10093
    101         template<typename core_t>
     94        template<typename pass_type>
    10295        friend class Pass;
    10396
     
    154147// PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
    155148#include "Pass.hpp"
    156 #include "Copy.hpp"
    157149
    158150namespace ast {
     
    160152// definitition must happen after PassVisitor is included so that WithGuards can be used
    161153struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
    162                 static size_t traceId;
    163154
    164155                Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    165156
    166                 const Type * postvisit( const TypeInstType * aggregateUseType );
    167                 const Expr * postvisit( const NameExpr * nameExpr );
     157#if TIME_TO_CONVERT_PASSES
     158
     159                Type * postmutate( TypeInstType * aggregateUseType );
     160                Expression * postmutate( NameExpr * nameExpr );
    168161
    169162                /// Records type variable bindings from forall-statements
    170                 void previsit( const ParameterizedType * type );
     163                void premutate( Type * type );
    171164                /// Records type variable bindings from forall-statements and instantiations of generic types
    172                 void handleAggregateType( const ReferenceToType * type );
    173 
    174                 void previsit( const StructInstType * aggregateUseType );
    175                 void previsit( const UnionInstType * aggregateUseType );
     165                template< typename TypeClass > void handleAggregateType( TypeClass * type );
     166
     167                void premutate( StructInstType * aggregateUseType );
     168                void premutate( UnionInstType * aggregateUseType );
     169
     170#endif
    176171
    177172                const TypeSubstitution & sub;
     
    184179
    185180template< typename SynTreeClass >
    186 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
     181int TypeSubstitution::apply( const SynTreeClass *& input ) const {
    187182        assert( input );
    188183        Pass<Substituter> sub( *this, false );
    189         input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
    190         return { input, sub.core.subCount };
     184        input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
     185///     std::cerr << "substitution result is: ";
     186///     newType->print( std::cerr );
     187///     std::cerr << std::endl;
     188        return sub.pass.subCount;
    191189}
    192190
    193191template< typename SynTreeClass >
    194 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
     192int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
    195193        assert( input );
    196194        Pass<Substituter> sub( *this, true );
    197         input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
    198         return { input, sub.core.subCount };
     195        input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
     196///     std::cerr << "substitution result is: ";
     197///     newType->print( std::cerr );
     198///     std::cerr << std::endl;
     199        return sub.pass.subCount;
    199200}
    200201
  • src/AST/module.mk

    re67a82d r67ca73e  
    2222        AST/DeclReplacer.cpp \
    2323        AST/Expr.cpp \
    24         AST/ForallSubstitutionTable.cpp \
    2524        AST/GenericSubstitution.cpp \
    2625        AST/Init.cpp \
  • src/AST/porting.md

    re67a82d r67ca73e  
    4747      template<typename node_t>
    4848      friend node_t * mutate(const node_t * node);
    49       template<typename node_t>
    50       friend node_t * shallowCopy(const node_t * node);
    51     or equilant.
    52 * You should use the `mutate` function where possible as it avoids extra copies.
    53   * If you must copy use `shallowCopy` or `deepCopy` as required.
    5449
    5550All leaves of the `Node` inheritance tree are now declared `final`
  • src/Common/Eval.cc

    re67a82d r67ca73e  
    168168        if (expr) {
    169169                expr->accept(ev);
    170                 return std::make_pair(ev.core.value, ev.core.valid);
     170                return std::make_pair(ev.pass.value, ev.pass.valid);
    171171        } else {
    172172                return std::make_pair(0, false);
  • src/Common/ScopedMap.h

    re67a82d r67ca73e  
    249249
    250250        /// Gets the note at the given scope
    251         Note& getNote() { return scopes.back().note; }
    252         const Note& getNote() const { return scopes.back().note; }
    253251        Note& getNote( size_type i ) { return scopes[i].note; }
    254252        const Note& getNote( size_type i ) const { return scopes[i].note; }
  • src/Common/Stats/Heap.cc

    re67a82d r67ca73e  
    5353                const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
    5454                size_t       passes_cnt = 1;
    55 
    56                 StatBlock    stacktrace_stats[100];
    57                 size_t       stacktrace_stats_count = 0;
    58                 bool         stacktrace_stats_enabled = true;
    59 
    60                 size_t       trace[1000];
    61                 const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t);
    62                 size_t       stacktrace_depth;
    63 
    64                 size_t new_stacktrace_id(const char * const name) {
    65                         stacktrace_stats[stacktrace_stats_count].name = name;
    66                         return stacktrace_stats_count++;
    67                 }
    68 
    69                 void stacktrace_push(size_t id) {
    70                         ++stacktrace_depth;
    71                         assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc");
    72                         trace[stacktrace_depth] = id;
    73                 }
    74 
    75                 void stacktrace_pop() {
    76                         assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty");
    77                         --stacktrace_depth;
    78                 }
    7955
    8056                void newPass( const char * const name ) {
     
    140116                        for(size_t i = 0; i < passes_cnt; i++) {
    141117                                print(passes[i], nc, total_mallocs, total_frees, overall_peak);
    142                         }
    143 
    144                         print('-', nct);
    145                         std::cerr << std::setw(nc) << "Trace";
    146                         std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
    147 
    148                         print('-', nct);
    149                         for (size_t i = 0; i < stacktrace_stats_count; i++) {
    150                                 print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak);
    151118                        }
    152119                        print('-', nct);
     
    221188                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    222189                                }
    223 
    224                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    225                                         stacktrace_stats[trace[stacktrace_depth]].mallocs++;
    226                                 }
    227190                                return __malloc( size );
    228191                        }
     
    233196                                        passes[passes_cnt - 1].frees++;
    234197                                        passes[passes_cnt - 1].n_allocs--;
    235                                 }
    236                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    237                                         stacktrace_stats[trace[stacktrace_depth]].frees++;
    238198                                }
    239199                                return __free( ptr );
     
    248208                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    249209                                }
    250                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    251                                         stacktrace_stats[trace[stacktrace_depth]].mallocs++;
    252                                 }
    253210                                return __calloc( nelem, size );
    254211                        }
     
    261218                                        passes[passes_cnt - 1].frees++;
    262219                                } // if
    263                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    264                                         stacktrace_stats[trace[stacktrace_depth]].mallocs++;
    265                                         stacktrace_stats[trace[stacktrace_depth]].frees++;
    266                                 }
    267220                                return s;
    268221                        }
  • src/Common/Stats/Heap.h

    re67a82d r67ca73e  
    2020                void newPass( const char * const name );
    2121                void print();
    22 
    23                 size_t new_stacktrace_id(const char * const name);
    24                 void stacktrace_push(size_t id);
    25                 void stacktrace_pop();
    2622        }
    2723}
  • src/CompilationState.cc

    re67a82d r67ca73e  
    1414//
    1515
    16 #include "config.h"
    17 
    1816int
    1917        astp = false,
     
    3028        genproto = false,
    3129        deterministic_output = false,
    32         useNewAST = CFA_USE_NEW_AST,
    3330        nomainp = false,
    3431        parsep = false,
  • src/CompilationState.h

    re67a82d r67ca73e  
    2929        genproto,
    3030        deterministic_output,
    31         useNewAST,
    3231        nomainp,
    3332        parsep,
  • src/InitTweak/InitTweak.cc

    re67a82d r67ca73e  
    127127        ast::Pass< InitFlattener_new > flattener;
    128128        maybe_accept( init, flattener );
    129         return std::move( flattener.core.argList );
     129        return std::move( flattener.pass.argList );
    130130}
    131131
     
    561561                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    562562                maybe_accept( stmt, finder );
    563                 return std::move( finder.core.matches );
     563                return std::move( finder.pass.matches );
    564564        }
    565565
  • src/Parser/ExpressionNode.cc

    re67a82d r67ca73e  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 20 14:01:46 2020
    13 // Update Count     : 1076
     12// Last Modified On : Wed Jul 15 08:24:08 2020
     13// Update Count     : 1046
    1414//
    1515
     
    6565
    6666void lnthSuffix( string & str, int & type, int & ltype ) {
    67         // 'u' can appear before or after length suffix
    6867        string::size_type posn = str.find_last_of( "lL" );
    6968
    7069        if ( posn == string::npos ) return;                                     // no suffix
    71         size_t end = str.length() - 1;
    72         if ( posn == end ) { type = 3; return; }                        // no length after 'l' => long
    73        
     70        if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long
     71
    7472        string::size_type next = posn + 1;                                      // advance to length
    7573        if ( str[next] == '3' ) {                                                       // 32
     
    8684                } // if
    8785        } // if
    88 
    89         char fix = '\0';
    90         if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ?
    91         str.erase( posn );                                                                      // remove length suffix and possibly uU
    92         if ( type == 5 ) {                                                                      // L128 does not need uU
    93                 end = str.length() - 1;
    94                 if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove
    95         } else if ( fix != '\0' ) str += fix;                           // put 'uU' back if removed
     86        // remove "lL" for these cases because it may not imply long
     87        str.erase( posn );                                                                      // remove length suffix and "uU"
    9688} // lnthSuffix
    9789
     
    164156        if ( isdigit( str[str.length() - 1] ) ) {                       // no suffix ?
    165157                lnthSuffix( str, type, ltype );                                 // could have length suffix
     158                if ( type == 5 && Unsigned ) str.erase( str.length() - 1 ); // L128 and terminating "uU" ?
    166159        } else {
    167160                // At least one digit in integer constant, so safe to backup while looking for suffix.
     
    202195                        if ( type < 5 ) {                                                       // not L128 ?
    203196                                sscanf( (char *)str.c_str(), "%llx", &v );
    204 #if defined(__SIZEOF_INT128__)
    205197                        } else {                                                                        // hex int128 constant
    206198                                unsigned int len = str.length();
     
    212204                          FHEX1: ;
    213205                                sscanf( (char *)str.c_str(), "%llx", &v );
    214 #endif // __SIZEOF_INT128__
    215206                        } // if
    216207                        //printf( "%llx %llu\n", v, v );
    217208                } else if ( checkB( str[1] ) ) {                                // binary constant ?
    218 #if defined(__SIZEOF_INT128__)
    219209                        unsigned int len = str.length();
    220210                        if ( type == 5 && len > 2 + 64 ) {
     
    224214                                scanbin( str2, v2 );
    225215                        } // if
    226 #endif // __SIZEOF_INT128__
    227216                        scanbin( str, v );
    228217                        //printf( "%#llx %llu\n", v, v );
     
    234223                                unsigned int len = str.length();
    235224                                if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large " + str );
    236                                 char buf[32];
    237225                                if ( len <= 1 + 21 ) {                                  // value < 21 octal digitis
    238                                         sscanf( (char *)str.c_str(), "%llo", &v );
     226                                        sscanf( (char *)str.c_str(), "%llo", &v ); // leave value in octal
    239227                                } else {
    240228                                        sscanf( &str[len - 21], "%llo", &v );
     
    249237                                        } // if
    250238                                        v = val >> 64; v2 = (uint64_t)val;      // replace octal constant with 2 hex constants
     239                                        char buf[32];
    251240                                        sprintf( buf, "%#llx", v2 );
    252241                                        str2 = buf;
     242                                        sprintf( buf, "%#llx", v );
     243                                        str = buf;
    253244                                } // if
    254                                 sprintf( buf, "%#llx", v );
    255                                 str = buf;
    256245#endif // __SIZEOF_INT128__
    257246                        } // if
     
    267256                        if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") )
    268257                                SemanticError( yylloc, "128-bit decimal constant to large " + str );
    269                         char buf[32];
    270258                        if ( len <= 19 ) {                                                      // value < 19 decimal digitis
    271                                 sscanf( (char *)str.c_str(), "%llu", &v );
     259                                sscanf( (char *)str.c_str(), "%llu", &v ); // leave value in decimal
    272260                        } else {
    273261                                sscanf( &str[len - 19], "%llu", &v );
     
    282270                                } // if
    283271                                v = val >> 64; v2 = (uint64_t)val;              // replace decimal constant with 2 hex constants
     272                                char buf[32];
    284273                                sprintf( buf, "%#llx", v2 );
    285274                                str2 = buf;
     275                                sprintf( buf, "%#llx", v );
     276                                str = buf;
    286277                        } // if
    287                         sprintf( buf, "%#llx", v );
    288                         str = buf;
    289278#endif // __SIZEOF_INT128__
    290279                } // if
  • src/ResolvExpr/AdjustExprType.cc

    re67a82d r67ca73e  
    100100
    101101namespace {
    102         class AdjustExprType_new final : public ast::WithShortCircuiting {
     102        struct AdjustExprType_new final : public ast::WithShortCircuiting {
     103                const ast::TypeEnvironment & tenv;
    103104                const ast::SymbolTable & symtab;
    104         public:
    105                 const ast::TypeEnvironment & tenv;
    106105
    107106                AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    108                 : symtab( syms ), tenv( e ) {}
     107                : tenv( e ), symtab( syms ) {}
    109108
    110                 void previsit( const ast::VoidType * ) { visit_children = false; }
    111                 void previsit( const ast::BasicType * ) { visit_children = false; }
    112                 void previsit( const ast::PointerType * ) { visit_children = false; }
    113                 void previsit( const ast::ArrayType * ) { visit_children = false; }
    114                 void previsit( const ast::FunctionType * ) { visit_children = false; }
    115                 void previsit( const ast::StructInstType * ) { visit_children = false; }
    116                 void previsit( const ast::UnionInstType * ) { visit_children = false; }
    117                 void previsit( const ast::EnumInstType * ) { visit_children = false; }
    118                 void previsit( const ast::TraitInstType * ) { visit_children = false; }
    119                 void previsit( const ast::TypeInstType * ) { visit_children = false; }
    120                 void previsit( const ast::TupleType * ) { visit_children = false; }
    121                 void previsit( const ast::VarArgsType * ) { visit_children = false; }
    122                 void previsit( const ast::ZeroType * ) { visit_children = false; }
    123                 void previsit( const ast::OneType * ) { visit_children = false; }
     109                void premutate( const ast::VoidType * ) { visit_children = false; }
     110                void premutate( const ast::BasicType * ) { visit_children = false; }
     111                void premutate( const ast::PointerType * ) { visit_children = false; }
     112                void premutate( const ast::ArrayType * ) { visit_children = false; }
     113                void premutate( const ast::FunctionType * ) { visit_children = false; }
     114                void premutate( const ast::StructInstType * ) { visit_children = false; }
     115                void premutate( const ast::UnionInstType * ) { visit_children = false; }
     116                void premutate( const ast::EnumInstType * ) { visit_children = false; }
     117                void premutate( const ast::TraitInstType * ) { visit_children = false; }
     118                void premutate( const ast::TypeInstType * ) { visit_children = false; }
     119                void premutate( const ast::TupleType * ) { visit_children = false; }
     120                void premutate( const ast::VarArgsType * ) { visit_children = false; }
     121                void premutate( const ast::ZeroType * ) { visit_children = false; }
     122                void premutate( const ast::OneType * ) { visit_children = false; }
    124123
    125                 const ast::Type * postvisit( const ast::ArrayType * at ) {
     124                const ast::Type * postmutate( const ast::ArrayType * at ) {
    126125                        return new ast::PointerType{ at->base, at->qualifiers };
    127126                }
    128127
    129                 const ast::Type * postvisit( const ast::FunctionType * ft ) {
     128                const ast::Type * postmutate( const ast::FunctionType * ft ) {
    130129                        return new ast::PointerType{ ft };
    131130                }
    132131
    133                 const ast::Type * postvisit( const ast::TypeInstType * inst ) {
     132                const ast::Type * postmutate( const ast::TypeInstType * inst ) {
    134133                        // replace known function-type-variables with pointer-to-function
    135134                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
  • src/ResolvExpr/Candidate.hpp

    re67a82d r67ca73e  
    5151
    5252        Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
    53         : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {
    54                 assert(x->result);
    55         }
     53        : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
    5654
    5755        Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero )
    5856        : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
    59           need( o.need ) {
    60                 assert(x->result);
    61         }
     57          need( o.need ) {}
    6258
    6359        Candidate(
    64                 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
     60                const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
    6561                const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero )
    66         : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {
    67                 assert(x->result);
    68         }
     62        : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {}
    6963
    7064        Candidate(
     
    7266                ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero )
    7367        : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ),
    74           need( n.begin(), n.end() ) {
    75                 assert(x->result);
    76         }
     68          need( n.begin(), n.end() ) {}
    7769};
    7870
  • src/ResolvExpr/CandidateFinder.cpp

    re67a82d r67ca73e  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1 14:55:00 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed Jun 5 14:30:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    5454                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    5555        }
    56 
     56       
    5757        return expr;
    5858}
     
    6161UniqueId globalResnSlot = 0;
    6262
    63 Cost computeConversionCost(
    64         const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
    65         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     63Cost computeConversionCost( 
     64        const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
     65        const ast::TypeEnvironment & env
    6666) {
    6767        PRINT(
     
    7474                std::cerr << std::endl;
    7575        )
    76         Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env );
     76        Cost convCost = conversionCost( argType, paramType, symtab, env );
    7777        PRINT(
    7878                std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    107107
    108108        /// Computes conversion cost for a given expression to a given type
    109         const ast::Expr * computeExpressionConversionCost(
    110                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
     109        const ast::Expr * computeExpressionConversionCost( 
     110                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 
    111111        ) {
    112                 Cost convCost = computeConversionCost(
    113                                 arg->result, paramType, arg->get_lvalue(), symtab, env );
     112                Cost convCost = computeConversionCost( arg->result, paramType, symtab, env );
    114113                outCost += convCost;
    115114
    116                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
    117                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to
     115                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 
     116                // conversion. Ignore poly cost for now, since this requires resolution of the cast to 
    118117                // infer parameters and this does not currently work for the reason stated below
    119118                Cost tmpCost = convCost;
     
    124123                        return new ast::CastExpr{ arg, newType };
    125124
    126                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not
    127                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
     125                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not 
     126                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 
    128127                        // once this is fixed it should be possible to resolve the cast.
    129                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
    130                         // but it shouldn't be because this makes the conversion from DT* to DT* since
     128                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 
     129                        // but it shouldn't be because this makes the conversion from DT* to DT* since 
    131130                        // commontype(zero_t, DT*) is DT*, rather than nothing
    132131
    133132                        // CandidateFinder finder{ symtab, env };
    134133                        // finder.find( arg, ResolvMode::withAdjustment() );
    135                         // assertf( finder.candidates.size() > 0,
     134                        // assertf( finder.candidates.size() > 0, 
    136135                        //      "Somehow castable expression failed to find alternatives." );
    137                         // assertf( finder.candidates.size() == 1,
     136                        // assertf( finder.candidates.size() == 1, 
    138137                        //      "Somehow got multiple alternatives for known cast expression." );
    139138                        // return finder.candidates.front()->expr;
     
    144143
    145144        /// Computes conversion cost for a given candidate
    146         Cost computeApplicationConversionCost(
    147                 CandidateRef cand, const ast::SymbolTable & symtab
     145        Cost computeApplicationConversionCost( 
     146                CandidateRef cand, const ast::SymbolTable & symtab 
    148147        ) {
    149148                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     
    168167                                if ( function->isVarArgs ) {
    169168                                        convCost.incUnsafe();
    170                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
     169                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 
    171170                                                << convCost << std::endl; ; )
    172171                                        // convert reference-typed expressions into value-typed expressions
    173                                         cand->expr = ast::mutate_field_index(
    174                                                 appExpr, &ast::ApplicationExpr::args, i,
     172                                        cand->expr = ast::mutate_field_index( 
     173                                                appExpr, &ast::ApplicationExpr::args, i, 
    175174                                                referenceToRvalueConversion( args[i], convCost ) );
    176175                                        continue;
     
    181180                                // Default arguments should be free - don't include conversion cost.
    182181                                // Unwrap them here because they are not relevant to the rest of the system
    183                                 cand->expr = ast::mutate_field_index(
     182                                cand->expr = ast::mutate_field_index( 
    184183                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
    185184                                ++param;
     
    189188                        // mark conversion cost and also specialization cost of param type
    190189                        const ast::Type * paramType = (*param)->get_type();
    191                         cand->expr = ast::mutate_field_index(
    192                                 appExpr, &ast::ApplicationExpr::args, i,
    193                                 computeExpressionConversionCost(
     190                        cand->expr = ast::mutate_field_index( 
     191                                appExpr, &ast::ApplicationExpr::args, i, 
     192                                computeExpressionConversionCost( 
    194193                                        args[i], paramType, symtab, cand->env, convCost ) );
    195194                        convCost.decSpec( specCost( paramType ) );
     
    199198                if ( param != params.end() ) return Cost::infinity;
    200199
    201                 // specialization cost of return types can't be accounted for directly, it disables
     200                // specialization cost of return types can't be accounted for directly, it disables 
    202201                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    203202                //
     
    216215        }
    217216
    218         void makeUnifiableVars(
    219                 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
    220                 ast::AssertionSet & need
     217        void makeUnifiableVars( 
     218                const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 
     219                ast::AssertionSet & need 
    221220        ) {
    222221                for ( const ast::TypeDecl * tyvar : type->forall ) {
     
    255254
    256255                ArgPack()
    257                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
     256                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 
    258257                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    259 
     258               
     259                ArgPack(
     260                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
     261                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
     262                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
     263                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     264               
    260265                ArgPack(
    261                         const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    262                         const ast::AssertionSet & have, const ast::OpenVarSet & open )
    263                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    264                   open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    265 
    266                 ArgPack(
    267                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
    268                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
    269                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
     266                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     267                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     268                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    270269                        unsigned nextExpl = 0, unsigned explAlt = 0 )
    271270                : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
    272271                  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    273272                  nextExpl( nextExpl ), explAlt( explAlt ) {}
    274 
     273               
    275274                ArgPack(
    276                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
     275                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 
    277276                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    278                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
    279                   need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
     277                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 
     278                  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 
    280279                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    281 
     280               
    282281                /// true if this pack is in the middle of an exploded argument
    283282                bool hasExpl() const { return nextExpl > 0; }
     
    287286                        return args[ nextArg-1 ][ explAlt ];
    288287                }
    289 
     288               
    290289                /// Ends a tuple expression, consolidating the appropriate args
    291290                void endTuple( const std::vector< ArgPack > & packs ) {
     
    308307
    309308        /// Instantiates an argument to match a parameter, returns false if no matching results left
    310         bool instantiateArgument(
    311                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
    312                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    313                 unsigned nTuples = 0
     309        bool instantiateArgument( 
     310                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 
     311                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 
     312                unsigned nTuples = 0 
    314313        ) {
    315314                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     
    319318                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    320319                                // ^^^ need to handle the case where a tuple has a default argument
    321                                 if ( ! instantiateArgument(
     320                                if ( ! instantiateArgument( 
    322321                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    323322                                nTuples = 0;
     
    330329                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    331330                        // paramType is a ttype, consumes all remaining arguments
    332 
     331                       
    333332                        // completed tuples; will be spliced to end of results to finish
    334333                        std::vector< ArgPack > finalResults{};
     
    343342                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
    344343                                        unsigned nextArg = results[i].nextArg;
    345 
     344                                       
    346345                                        // use next element of exploded tuple if present
    347346                                        if ( results[i].hasExpl() ) {
     
    353352                                                results.emplace_back(
    354353                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    355                                                         copy( results[i].need ), copy( results[i].have ),
     354                                                        copy( results[i].need ), copy( results[i].have ), 
    356355                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    357356                                                        results[i].explAlt );
     
    371370                                                        // push empty tuple expression
    372371                                                        newResult.parent = i;
    373                                                         newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
     372                                                        std::vector< ast::ptr< ast::Expr > > emptyList;
     373                                                        newResult.expr =
     374                                                                new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
    374375                                                        argType = newResult.expr->result;
    375376                                                } else {
     
    399400
    400401                                                // check unification for ttype before adding to final
    401                                                 if (
    402                                                         unify(
     402                                                if ( 
     403                                                        unify( 
    403404                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
    404                                                                 newResult.open, symtab )
     405                                                                newResult.open, symtab ) 
    405406                                                ) {
    406407                                                        finalResults.emplace_back( move( newResult ) );
     
    423424                                                if ( expl.exprs.empty() ) {
    424425                                                        results.emplace_back(
    425                                                                 results[i], move( env ), copy( results[i].need ),
     426                                                                results[i], move( env ), copy( results[i].need ), 
    426427                                                                copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
    427 
     428                                                       
    428429                                                        continue;
    429430                                                }
     
    431432                                                // add new result
    432433                                                results.emplace_back(
    433                                                         i, expl.exprs.front(), move( env ), copy( results[i].need ),
    434                                                         copy( results[i].have ), move( open ), nextArg + 1, nTuples,
     434                                                        i, expl.exprs.front(), move( env ), copy( results[i].need ), 
     435                                                        copy( results[i].have ), move( open ), nextArg + 1, nTuples, 
    435436                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    436437                                        }
     
    478479
    479480                                        results.emplace_back(
    480                                                 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
     481                                                i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 
    481482                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
    482483                                }
     
    494495                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    495496                                                results.emplace_back(
    496                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
     497                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 
    497498                                                        move( need ), move( have ), move( open ), nextArg, nTuples );
    498499                                        }
     
    516517                                if ( expl.exprs.empty() ) {
    517518                                        results.emplace_back(
    518                                                 results[i], move( env ), move( need ), move( have ), move( open ),
     519                                                results[i], move( env ), move( need ), move( have ), move( open ), 
    519520                                                nextArg + 1, expl.cost );
    520 
     521                                       
    521522                                        continue;
    522523                                }
     
    538539                                        // add new result
    539540                                        results.emplace_back(
    540                                                 i, expr, move( env ), move( need ), move( have ), move( open ),
     541                                                i, expr, move( env ), move( need ), move( have ), move( open ), 
    541542                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    542543                                }
     
    547548                genStart = genEnd;
    548549
    549                 return genEnd != results.size();  // were any new results added?
     550                return genEnd != results.size();
    550551        }
    551552
    552553        /// Generate a cast expression from `arg` to `toType`
    553         const ast::Expr * restructureCast(
     554        const ast::Expr * restructureCast( 
    554555                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    555556        ) {
    556                 if (
    557                         arg->result->size() > 1
    558                         && ! toType->isVoid()
    559                         && ! dynamic_cast< const ast::ReferenceType * >( toType )
     557                if ( 
     558                        arg->result->size() > 1 
     559                        && ! toType->isVoid() 
     560                        && ! dynamic_cast< const ast::ReferenceType * >( toType ) 
    560561                ) {
    561                         // Argument is a tuple and the target type is neither void nor a reference. Cast each
    562                         // member of the tuple to its corresponding target type, producing the tuple of those
    563                         // cast expressions. If there are more components of the tuple than components in the
    564                         // target type, then excess components do not come out in the result expression (but
     562                        // Argument is a tuple and the target type is neither void nor a reference. Cast each 
     563                        // member of the tuple to its corresponding target type, producing the tuple of those 
     564                        // cast expressions. If there are more components of the tuple than components in the 
     565                        // target type, then excess components do not come out in the result expression (but 
    565566                        // UniqueExpr ensures that the side effects will still be produced)
    566567                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    567                                 // expressions which may contain side effects require a single unique instance of
     568                                // expressions which may contain side effects require a single unique instance of 
    568569                                // the expression
    569570                                arg = new ast::UniqueExpr{ arg->location, arg };
     
    573574                                // cast each component
    574575                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    575                                 components.emplace_back(
     576                                components.emplace_back( 
    576577                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    577578                        }
     
    593594
    594595        /// Actually visits expressions to find their candidate interpretations
    595         class Finder final : public ast::WithShortCircuiting {
     596        struct Finder final : public ast::WithShortCircuiting {
     597                CandidateFinder & selfFinder;
    596598                const ast::SymbolTable & symtab;
    597         public:
    598                 static size_t traceId;
    599                 CandidateFinder & selfFinder;
    600599                CandidateList & candidates;
    601600                const ast::TypeEnvironment & tenv;
    602601                ast::ptr< ast::Type > & targetType;
    603602
    604                 enum Errors {
    605                         NotFound,
    606                         NoMatch,
    607                         ArgsToFew,
    608                         ArgsToMany,
    609                         RetsToFew,
    610                         RetsToMany,
    611                         NoReason
    612                 };
    613 
    614                 struct {
    615                         Errors code = NotFound;
    616                 } reason;
    617 
    618603                Finder( CandidateFinder & f )
    619                 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
     604                : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),
    620605                  targetType( f.targetType ) {}
    621 
     606               
    622607                void previsit( const ast::Node * ) { visit_children = false; }
    623608
     
    626611                void addCandidate( Args &&... args ) {
    627612                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
    628                         reason.code = NoReason;
    629613                }
    630614
     
    655639
    656640                /// Completes a function candidate with arguments located
    657                 void validateFunctionCandidate(
    658                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    659                         CandidateList & out
     641                void validateFunctionCandidate( 
     642                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 
     643                        CandidateList & out 
    660644                ) {
    661                         ast::ApplicationExpr * appExpr =
     645                        ast::ApplicationExpr * appExpr = 
    662646                                new ast::ApplicationExpr{ func->expr->location, func->expr };
    663647                        // sum cost and accumulate arguments
     
    673657                        appExpr->args = move( vargs );
    674658                        // build and validate new candidate
    675                         auto newCand =
     659                        auto newCand = 
    676660                                std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    677661                        PRINT(
     
    685669                /// Builds a list of candidates for a function, storing them in out
    686670                void makeFunctionCandidates(
    687                         const CandidateRef & func, const ast::FunctionType * funcType,
     671                        const CandidateRef & func, const ast::FunctionType * funcType, 
    688672                        const ExplodedArgs_new & args, CandidateList & out
    689673                ) {
     
    692676                        ast::TypeEnvironment funcEnv{ func->env };
    693677                        makeUnifiableVars( funcType, funcOpen, funcNeed );
    694                         // add all type variables as open variables now so that those not used in the
    695                         // parameter list are still considered open
     678                        // add all type variables as open variables now so that those not used in the parameter
     679                        // list are still considered open
    696680                        funcEnv.add( funcType->forall );
    697681
     
    699683                                // attempt to narrow based on expected target type
    700684                                const ast::Type * returnType = funcType->returns.front()->get_type();
    701                                 if ( ! unify(
    702                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     685                                if ( ! unify( 
     686                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 
    703687                                ) {
    704688                                        // unification failed, do not pursue this candidate
     
    714698                        for ( const ast::DeclWithType * param : funcType->params ) {
    715699                                auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param );
    716                                 // Try adding the arguments corresponding to the current parameter to the existing
     700                                // Try adding the arguments corresponding to the current parameter to the existing 
    717701                                // matches
    718                                 if ( ! instantiateArgument(
     702                                if ( ! instantiateArgument( 
    719703                                        obj->type, obj->init, args, results, genStart, symtab ) ) return;
    720704                        }
     
    766750                                                        if ( expl.exprs.empty() ) {
    767751                                                                results.emplace_back(
    768                                                                         results[i], move( env ), copy( results[i].need ),
    769                                                                         copy( results[i].have ), move( open ), nextArg + 1,
     752                                                                        results[i], move( env ), copy( results[i].need ), 
     753                                                                        copy( results[i].have ), move( open ), nextArg + 1, 
    770754                                                                        expl.cost );
    771755
     
    776760                                                        results.emplace_back(
    777761                                                                i, expl.exprs.front(), move( env ), copy( results[i].need ),
    778                                                                 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,
     762                                                                copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 
    779763                                                                expl.exprs.size() == 1 ? 0 : 1, j );
    780764                                                }
     
    796780                /// Adds implicit struct-conversions to the alternative list
    797781                void addAnonConversions( const CandidateRef & cand ) {
    798                         // adds anonymous member interpretations whenever an aggregate value type is seen.
    799                         // it's okay for the aggregate expression to have reference type -- cast it to the
     782                        // adds anonymous member interpretations whenever an aggregate value type is seen. 
     783                        // it's okay for the aggregate expression to have reference type -- cast it to the 
    800784                        // base type to treat the aggregate as the referenced value
    801785                        ast::ptr< ast::Expr > aggrExpr( cand->expr );
    802786                        ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    803787                        cand->env.apply( aggrType );
    804 
     788                       
    805789                        if ( aggrType.as< ast::ReferenceType >() ) {
    806790                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     
    815799
    816800                /// Adds aggregate member interpretations
    817                 void addAggMembers(
    818                         const ast::ReferenceToType * aggrInst, const ast::Expr * expr,
    819                         const Candidate & cand, const Cost & addedCost, const std::string & name
     801                void addAggMembers( 
     802                        const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 
     803                        const Candidate & cand, const Cost & addedCost, const std::string & name 
    820804                ) {
    821805                        for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    822806                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    823                                 CandidateRef newCand = std::make_shared<Candidate>(
     807                                CandidateRef newCand = std::make_shared<Candidate>( 
    824808                                        cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    825                                 // add anonymous member interpretations whenever an aggregate value type is seen
     809                                // add anonymous member interpretations whenever an aggregate value type is seen 
    826810                                // as a member expression
    827811                                addAnonConversions( newCand );
     
    831815
    832816                /// Adds tuple member interpretations
    833                 void addTupleMembers(
    834                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    835                         const Cost & addedCost, const ast::Expr * member
     817                void addTupleMembers( 
     818                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 
     819                        const Cost & addedCost, const ast::Expr * member 
    836820                ) {
    837821                        if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    838                                 // get the value of the constant expression as an int, must be between 0 and the
     822                                // get the value of the constant expression as an int, must be between 0 and the 
    839823                                // length of the tuple to have meaning
    840824                                long long val = constantExpr->intValue();
    841825                                if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    842826                                        addCandidate(
    843                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     827                                                cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 
    844828                                                addedCost );
    845829                                }
     
    853837                        if ( funcFinder.candidates.empty() ) return;
    854838
    855                         reason.code = NoMatch;
    856 
    857                         std::vector< CandidateFinder > argCandidates =
     839                        std::vector< CandidateFinder > argCandidates =
    858840                                selfFinder.findSubExprs( untypedExpr->args );
    859 
     841                       
    860842                        // take care of possible tuple assignments
    861843                        // if not tuple assignment, handled as normal function call
     
    895877                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    896878                                                        CandidateRef newFunc{ new Candidate{ *func } };
    897                                                         newFunc->expr =
     879                                                        newFunc->expr = 
    898880                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    899881                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
    900882                                                }
    901                                         } else if (
    902                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     883                                        } else if ( 
     884                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 
    903885                                        ) {
    904886                                                if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
    905887                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    906888                                                                CandidateRef newFunc{ new Candidate{ *func } };
    907                                                                 newFunc->expr =
     889                                                                newFunc->expr = 
    908890                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    909891                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     
    919901                                std::vector< ExplodedArg > funcE;
    920902                                funcE.reserve( funcFinder.candidates.size() );
    921                                 for ( const CandidateRef & func : funcFinder ) {
     903                                for ( const CandidateRef & func : funcFinder ) { 
    922904                                        funcE.emplace_back( *func, symtab );
    923905                                }
     
    931913                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    932914                                                                CandidateRef newOp{ new Candidate{ *op} };
    933                                                                 newOp->expr =
     915                                                                newOp->expr = 
    934916                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
    935917                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     
    940922                        }
    941923
    942                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     924                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error 
    943925                        // candidates
    944926                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     
    952934                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    953935                                        auto function = pointer->base.strict_as< ast::FunctionType >();
    954 
     936                                       
    955937                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    956938                                        std::cerr << "parameters are:" << std::endl;
     
    975957                        promoteCvtCost( winners );
    976958
    977                         // function may return a struct/union value, in which case we need to add candidates
    978                         // for implicit conversions to each of the anonymous members, which must happen after
     959                        // function may return a struct/union value, in which case we need to add candidates 
     960                        // for implicit conversions to each of the anonymous members, which must happen after 
    979961                        // `findMinCost`, since anon conversions are never the cheapest
    980962                        for ( const CandidateRef & c : winners ) {
     
    984966
    985967                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    986                                 // If resolution is unsuccessful with a target type, try again without, since it
     968                                // If resolution is unsuccessful with a target type, try again without, since it 
    987969                                // will sometimes succeed when it wouldn't with a target type binding.
    988970                                // For example:
     
    1001983                /// true if expression is an lvalue
    1002984                static bool isLvalue( const ast::Expr * x ) {
    1003                         return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
     985                        return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
    1004986                }
    1005987
     
    1007989                        CandidateFinder finder{ symtab, tenv };
    1008990                        finder.find( addressExpr->arg );
    1009 
    1010                         if( finder.candidates.empty() ) return;
    1011 
    1012                         reason.code = NoMatch;
    1013 
    1014991                        for ( CandidateRef & r : finder.candidates ) {
    1015992                                if ( ! isLvalue( r->expr ) ) continue;
     
    10321009                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    10331010
    1034                         if( !finder.candidates.empty() ) reason.code = NoMatch;
    1035 
    10361011                        CandidateList matches;
    10371012                        for ( CandidateRef & cand : finder.candidates ) {
     
    10411016                                cand->env.extractOpenVars( open );
    10421017
    1043                                 // It is possible that a cast can throw away some values in a multiply-valued
    1044                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
    1045                                 // subexpression results that are cast directly. The candidate is invalid if it
     1018                                // It is possible that a cast can throw away some values in a multiply-valued 
     1019                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 
     1020                                // subexpression results that are cast directly. The candidate is invalid if it 
    10461021                                // has fewer results than there are types to cast to.
    10471022                                int discardedValues = cand->expr->result->size() - toType->size();
     
    10501025                                // unification run for side-effects
    10511026                                unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1052                                 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1053                                                 symtab, cand->env );
     1027                                Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env );
    10541028                                PRINT(
    10551029                                        std::cerr << "working on cast with result: " << toType << std::endl;
     
    10631037                                        // count one safe conversion for each value that is thrown away
    10641038                                        thisCost.incSafe( discardedValues );
    1065                                         CandidateRef newCand = std::make_shared<Candidate>(
    1066                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1067                                                 copy( cand->env ), move( open ), move( need ), cand->cost,
     1039                                        CandidateRef newCand = std::make_shared<Candidate>( 
     1040                                                restructureCast( cand->expr, toType, castExpr->isGenerated ), 
     1041                                                copy( cand->env ), move( open ), move( need ), cand->cost, 
    10681042                                                cand->cost + thisCost );
    10691043                                        inferParameters( newCand, matches );
     
    10831057                        finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    10841058                        for ( CandidateRef & r : finder.candidates ) {
    1085                                 addCandidate(
    1086                                         *r,
     1059                                addCandidate( 
     1060                                        *r, 
    10871061                                        new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    10881062                        }
     
    10931067                        aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    10941068                        for ( CandidateRef & agg : aggFinder.candidates ) {
    1095                                 // it's okay for the aggregate expression to have reference type -- cast it to the
     1069                                // it's okay for the aggregate expression to have reference type -- cast it to the 
    10961070                                // base type to treat the aggregate as the referenced value
    10971071                                Cost addedCost = Cost::zero;
     
    11001074                                // find member of the given type
    11011075                                if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1102                                         addAggMembers(
     1076                                        addAggMembers( 
    11031077                                                structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    11041078                                } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1105                                         addAggMembers(
     1079                                        addAggMembers( 
    11061080                                                unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    11071081                                } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     
    11181092                        std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name );
    11191093                        PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
    1120                         if( declList.empty() ) return;
    1121 
    1122                         reason.code = NoMatch;
    1123 
    11241094                        for ( auto & data : declList ) {
    11251095                                Cost cost = Cost::zero;
     
    11271097
    11281098                                CandidateRef newCand = std::make_shared<Candidate>(
    1129                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1099                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 
    11301100                                        cost );
    11311101                                PRINT(
     
    11371107                                        std::cerr << std::endl;
    11381108                                )
    1139                                 newCand->expr = ast::mutate_field(
    1140                                         newCand->expr.get(), &ast::Expr::result,
     1109                                newCand->expr = ast::mutate_field( 
     1110                                        newCand->expr.get(), &ast::Expr::result, 
    11411111                                        renameTyVars( newCand->expr->result ) );
    1142                                 // add anonymous member interpretations whenever an aggregate value type is seen
     1112                                // add anonymous member interpretations whenever an aggregate value type is seen 
    11431113                                // as a name expression
    11441114                                addAnonConversions( newCand );
     
    11501120                        // not sufficient to just pass `variableExpr` here, type might have changed since
    11511121                        // creation
    1152                         addCandidate(
     1122                        addCandidate( 
    11531123                                new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    11541124                }
     
    11601130                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    11611131                        if ( sizeofExpr->type ) {
    1162                                 addCandidate(
    1163                                         new ast::SizeofExpr{
    1164                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
     1132                                addCandidate( 
     1133                                        new ast::SizeofExpr{ 
     1134                                                sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 
    11651135                                        tenv );
    11661136                        } else {
     
    11711141                                CandidateList winners = findMinCost( finder.candidates );
    11721142                                if ( winners.size() != 1 ) {
    1173                                         SemanticError(
     1143                                        SemanticError( 
    11741144                                                sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    11751145                                }
     
    11841154                void postvisit( const ast::AlignofExpr * alignofExpr ) {
    11851155                        if ( alignofExpr->type ) {
    1186                                 addCandidate(
    1187                                         new ast::AlignofExpr{
    1188                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
     1156                                addCandidate( 
     1157                                        new ast::AlignofExpr{ 
     1158                                                alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 
    11891159                                        tenv );
    11901160                        } else {
     
    11951165                                CandidateList winners = findMinCost( finder.candidates );
    11961166                                if ( winners.size() != 1 ) {
    1197                                         SemanticError(
     1167                                        SemanticError( 
    11981168                                                alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    11991169                                }
     
    12021172                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    12031173                                choice->cost = Cost::zero;
    1204                                 addCandidate(
     1174                                addCandidate( 
    12051175                                        *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    12061176                        }
     
    12151185                        for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    12161186                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1217                                 addCandidate(
     1187                                addCandidate( 
    12181188                                        new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    12191189                        }
     
    12361206                        finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    12371207                        if ( finder2.candidates.empty() ) return;
    1238 
    1239                         reason.code = NoMatch;
    12401208
    12411209                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    12501218
    12511219                                        addCandidate(
    1252                                                 new ast::LogicalExpr{
     1220                                                new ast::LogicalExpr{ 
    12531221                                                        logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    12541222                                                move( env ), move( open ), move( need ), r1->cost + r2->cost );
     
    12721240                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    12731241                        if ( finder3.candidates.empty() ) return;
    1274 
    1275                         reason.code = NoMatch;
    12761242
    12771243                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    12901256                                                ast::AssertionSet have;
    12911257
    1292                                                 // unify true and false results, then infer parameters to produce new
     1258                                                // unify true and false results, then infer parameters to produce new 
    12931259                                                // candidates
    12941260                                                ast::ptr< ast::Type > common;
    1295                                                 if (
    1296                                                         unify(
    1297                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab,
    1298                                                                 common )
     1261                                                if ( 
     1262                                                        unify( 
     1263                                                                r2->expr->result, r3->expr->result, env, need, have, open, symtab, 
     1264                                                                common ) 
    12991265                                                ) {
    13001266                                                        // generate typed expression
    1301                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1267                                                        ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 
    13021268                                                                conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    13031269                                                        newExpr->result = common ? common : r2->expr->result;
    13041270                                                        // convert both options to result type
    13051271                                                        Cost cost = r1->cost + r2->cost + r3->cost;
    1306                                                         newExpr->arg2 = computeExpressionConversionCost(
     1272                                                        newExpr->arg2 = computeExpressionConversionCost( 
    13071273                                                                newExpr->arg2, newExpr->result, symtab, env, cost );
    13081274                                                        newExpr->arg3 = computeExpressionConversionCost(
     
    13211287                        ast::TypeEnvironment env{ tenv };
    13221288                        ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
    1323 
     1289                       
    13241290                        CandidateFinder finder2{ symtab, env };
    13251291                        finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     
    13511317                        finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    13521318                        if ( finder2.candidates.empty() ) return;
    1353 
    1354                         reason.code = NoMatch;
    13551319
    13561320                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    13661330
    13671331                                        ast::ptr< ast::Type > common;
    1368                                         if (
    1369                                                 unify(
    1370                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab,
    1371                                                         common )
     1332                                        if ( 
     1333                                                unify( 
     1334                                                        r1->expr->result, r2->expr->result, env, need, have, open, symtab, 
     1335                                                        common ) 
    13721336                                        ) {
    13731337                                                // generate new expression
    1374                                                 ast::RangeExpr * newExpr =
     1338                                                ast::RangeExpr * newExpr = 
    13751339                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    13761340                                                newExpr->result = common ? common : r1->expr->result;
    13771341                                                // add candidate
    13781342                                                CandidateRef newCand = std::make_shared<Candidate>(
    1379                                                         newExpr, move( env ), move( open ), move( need ),
     1343                                                        newExpr, move( env ), move( open ), move( need ), 
    13801344                                                        r1->cost + r2->cost );
    13811345                                                inferParameters( newCand, candidates );
     
    13861350
    13871351                void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1388                         std::vector< CandidateFinder > subCandidates =
     1352                        std::vector< CandidateFinder > subCandidates = 
    13891353                                selfFinder.findSubExprs( tupleExpr->exprs );
    13901354                        std::vector< CandidateList > possibilities;
     
    14061370
    14071371                                addCandidate(
    1408                                         new ast::TupleExpr{ tupleExpr->location, move( exprs ) },
     1372                                        new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 
    14091373                                        move( env ), move( open ), move( need ), sumCost( subs ) );
    14101374                        }
     
    14481412                                toType = SymTab::validateType( initExpr->location, toType, symtab );
    14491413                                toType = adjustExprType( toType, tenv, symtab );
    1450                                 // The call to find must occur inside this loop, otherwise polymorphic return
    1451                                 // types are not bound to the initialization type, since return type variables are
    1452                                 // only open for the duration of resolving the UntypedExpr.
     1414                                // The call to find must occur inside this loop, otherwise polymorphic return 
     1415                                // types are not bound to the initialization type, since return type variables are 
     1416                                // only open for the duration of resolving the UntypedExpr. 
    14531417                                CandidateFinder finder{ symtab, tenv, toType };
    14541418                                finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    14551419                                for ( CandidateRef & cand : finder.candidates ) {
    1456                                         if(reason.code == NotFound) reason.code = NoMatch;
    1457 
    14581420                                        ast::TypeEnvironment env{ cand->env };
    14591421                                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    14641426                                        )
    14651427
    1466                                         // It is possible that a cast can throw away some values in a multiply-valued
    1467                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
    1468                                         // the subexpression results that are cast directly. The candidate is invalid
     1428                                        // It is possible that a cast can throw away some values in a multiply-valued 
     1429                                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 
     1430                                        // the subexpression results that are cast directly. The candidate is invalid 
    14691431                                        // if it has fewer results than there are types to cast to.
    14701432                                        int discardedValues = cand->expr->result->size() - toType->size();
     
    14731435                                        // unification run for side-effects
    14741436                                        unify( toType, cand->expr->result, env, need, have, open, symtab );
    1475                                         Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1476                                                         symtab, env );
    1477 
     1437                                        Cost thisCost = castCost( cand->expr->result, toType, symtab, env );
     1438                                       
    14781439                                        if ( thisCost != Cost::infinity ) {
    14791440                                                // count one safe conversion for each value that is thrown away
    14801441                                                thisCost.incSafe( discardedValues );
    1481                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1482                                                         new ast::InitExpr{
    1483                                                                 initExpr->location, restructureCast( cand->expr, toType ),
    1484                                                                 initAlt.designation },
    1485                                                         move(env), move( open ), move( need ), cand->cost, thisCost );
     1442                                                CandidateRef newCand = std::make_shared<Candidate>( 
     1443                                                        new ast::InitExpr{ 
     1444                                                                initExpr->location, restructureCast( cand->expr, toType ), 
     1445                                                                initAlt.designation }, 
     1446                                                        copy( cand->env ), move( open ), move( need ), cand->cost, thisCost );
    14861447                                                inferParameters( newCand, matches );
    14871448                                        }
     
    15081469        };
    15091470
    1510         // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
    1511         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1471        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    15121472        /// return type. Skips ambiguous candidates.
    15131473        CandidateList pruneCandidates( CandidateList & candidates ) {
     
    15261486                        {
    15271487                                ast::ptr< ast::Type > newType = candidate->expr->result;
    1528                                 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    15291488                                candidate->env.apply( newType );
    15301489                                mangleName = Mangle::mangle( newType );
     
    15351494                                if ( candidate->cost < found->second.candidate->cost ) {
    15361495                                        PRINT(
    1537                                                 std::cerr << "cost " << candidate->cost << " beats "
     1496                                                std::cerr << "cost " << candidate->cost << " beats " 
    15381497                                                        << found->second.candidate->cost << std::endl;
    15391498                                        )
     
    15411500                                        found->second = PruneStruct{ candidate };
    15421501                                } else if ( candidate->cost == found->second.candidate->cost ) {
    1543                                         // if one of the candidates contains a deleted identifier, can pick the other,
    1544                                         // since deleted expressions should not be ambiguous if there is another option
     1502                                        // if one of the candidates contains a deleted identifier, can pick the other, 
     1503                                        // since deleted expressions should not be ambiguous if there is another option 
    15451504                                        // that is at least as good
    15461505                                        if ( findDeletedExpr( candidate->expr ) ) {
     
    15561515                                } else {
    15571516                                        PRINT(
    1558                                                 std::cerr << "cost " << candidate->cost << " loses to "
     1517                                                std::cerr << "cost " << candidate->cost << " loses to " 
    15591518                                                        << found->second.candidate->cost << std::endl;
    15601519                                        )
     
    15711530
    15721531                        CandidateRef cand = target.second.candidate;
    1573 
     1532                       
    15741533                        ast::ptr< ast::Type > newResult = cand->expr->result;
    15751534                        cand->env.applyFree( newResult );
    15761535                        cand->expr = ast::mutate_field(
    15771536                                cand->expr.get(), &ast::Expr::result, move( newResult ) );
    1578 
     1537                       
    15791538                        out.emplace_back( cand );
    15801539                }
     
    15901549
    15911550        if ( mode.failFast && candidates.empty() ) {
    1592                 switch(finder.core.reason.code) {
    1593                 case Finder::NotFound:
    1594                         { SemanticError( expr, "No alternatives for expression " ); break; }
    1595                 case Finder::NoMatch:
    1596                         { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
    1597                 case Finder::ArgsToFew:
    1598                 case Finder::ArgsToMany:
    1599                 case Finder::RetsToFew:
    1600                 case Finder::RetsToMany:
    1601                 case Finder::NoReason:
    1602                 default:
    1603                         { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
    1604                 }
     1551                SemanticError( expr, "No reasonable alternatives for expression " );
    16051552        }
    16061553
     
    16111558                std::vector< std::string > errors;
    16121559                for ( CandidateRef & candidate : candidates ) {
    1613                         satisfyAssertions( candidate, localSyms, satisfied, errors );
     1560                        satisfyAssertions( candidate, symtab, satisfied, errors );
    16141561                }
    16151562
     
    16361583
    16371584                CandidateList pruned = pruneCandidates( candidates );
    1638 
     1585               
    16391586                if ( mode.failFast && pruned.empty() ) {
    16401587                        std::ostringstream stream;
     
    16551602                )
    16561603                PRINT(
    1657                         std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     1604                        std::cerr << "there are " << candidates.size() << " alternatives after elimination" 
    16581605                                << std::endl;
    16591606                )
    16601607        }
    16611608
    1662         // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     1609        // adjust types after pruning so that types substituted by pruneAlternatives are correctly 
    16631610        // adjusted
    16641611        if ( mode.adjust ) {
    16651612                for ( CandidateRef & r : candidates ) {
    1666                         r->expr = ast::mutate_field(
    1667                                 r->expr.get(), &ast::Expr::result,
    1668                                 adjustExprType( r->expr->result, r->env, localSyms ) );
     1613                        r->expr = ast::mutate_field( 
     1614                                r->expr.get(), &ast::Expr::result, 
     1615                                adjustExprType( r->expr->result, r->env, symtab ) );
    16691616                }
    16701617        }
     
    16781625}
    16791626
    1680 std::vector< CandidateFinder > CandidateFinder::findSubExprs(
    1681         const std::vector< ast::ptr< ast::Expr > > & xs
     1627std::vector< CandidateFinder > CandidateFinder::findSubExprs( 
     1628        const std::vector< ast::ptr< ast::Expr > > & xs 
    16821629) {
    16831630        std::vector< CandidateFinder > out;
    16841631
    16851632        for ( const auto & x : xs ) {
    1686                 out.emplace_back( localSyms, env );
     1633                out.emplace_back( symtab, env );
    16871634                out.back().find( x, ResolvMode::withAdjustment() );
    1688 
     1635               
    16891636                PRINT(
    16901637                        std::cerr << "findSubExprs" << std::endl;
  • src/ResolvExpr/CandidateFinder.hpp

    re67a82d r67ca73e  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1  9:51:00 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed Jun 5 14:30:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    2828struct CandidateFinder {
    2929        CandidateList candidates;          ///< List of candidate resolutions
    30         const ast::SymbolTable & localSyms;   ///< Symbol table to lookup candidates
     30        const ast::SymbolTable & symtab;   ///< Symbol table to lookup candidates
    3131        const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
    3232        ast::ptr< ast::Type > targetType;  ///< Target type for resolution
    3333
    34         CandidateFinder(
    35                 const ast::SymbolTable & syms, const ast::TypeEnvironment & env,
     34        CandidateFinder( 
     35                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    3636                const ast::Type * tt = nullptr )
    37         : candidates(), localSyms( syms ), env( env ), targetType( tt ) {}
     37        : candidates(), symtab( symtab ), env( env ), targetType( tt ) {}
    3838
    3939        /// Fill candidates with feasible resolutions for `expr`
     
    4949        iterator begin() { return candidates.begin(); }
    5050        const_iterator begin() const { return candidates.begin(); }
    51 
     51       
    5252        iterator end() { return candidates.end(); }
    5353        const_iterator end() const { return candidates.end(); }
     
    5555
    5656/// Computes conversion cost between two types
    57 Cost computeConversionCost(
    58         const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
    59         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     57Cost computeConversionCost( 
     58        const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
     59        const ast::TypeEnvironment & env );
    6060
    6161} // namespace ResolvExpr
  • src/ResolvExpr/CastCost.cc

    re67a82d r67ca73e  
    1010// Created On       : Sun May 17 06:57:43 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  4 15:00:00 2019
    13 // Update Count     : 9
     12// Last Modified On : Thu Aug  8 16:12:00 2019
     13// Update Count     : 8
    1414//
    1515
     
    142142
    143143                CastCost_new(
    144                         const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
     144                        const ast::Type * dst, const ast::SymbolTable & symtab,
    145145                        const ast::TypeEnvironment & env, CostCalculation costFunc )
    146                 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {}
     146                : ConversionCost_new( dst, symtab, env, costFunc ) {}
    147147
    148148                void postvisit( const ast::BasicType * basicType ) {
     
    152152                                cost = Cost::unsafe;
    153153                        } else {
    154                                 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
     154                                cost = conversionCost( basicType, dst, symtab, env );
    155155                        }
    156156                }
     
    183183                }
    184184        };
    185 
    186         #warning For overload resolution between the two versions.
    187         int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,
    188                         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {
    189                 return ptrsCastable( t1, t2, symtab, env );
    190         }
    191         Cost localCastCost(
    192                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    193                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    194         ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }
    195185} // anonymous namespace
    196186
    197 
    198 
    199187Cost castCost(
    200         const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    201         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     188        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     189        const ast::TypeEnvironment & env
    202190) {
    203191        if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     
    205193                        // check cast cost against bound type, if present
    206194                        if ( eqvClass->bound ) {
    207                                 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
     195                                return castCost( src, eqvClass->bound, symtab, env );
    208196                        } else {
    209197                                return Cost::infinity;
     
    213201                        auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
    214202                        if ( type->base ) {
    215                                 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
     203                                return castCost( src, type->base, symtab, env ) + Cost::safe;
    216204                        }
    217205                }
     
    236224                #warning cast on ptrsCastable artifact of having two functions, remove when port done
    237225                return convertToReferenceCost(
    238                         src, refType, srcIsLvalue, symtab, env, localPtrsCastable );
     226                        src, refType, symtab, env,
     227                        ( int (*)(
     228                                const ast::Type *, const ast::Type *, const ast::SymbolTable &,
     229                                const ast::TypeEnvironment & )
     230                        ) ptrsCastable );
    239231        } else {
    240232                #warning cast on castCost artifact of having two functions, remove when port done
    241                 ast::Pass< CastCost_new > converter(
    242                         dst, srcIsLvalue, symtab, env, localCastCost );
     233                ast::Pass< CastCost_new > converter{
     234                        dst, symtab, env,
     235                        ( Cost (*)(
     236                                const ast::Type *, const ast::Type *, const ast::SymbolTable &,
     237                                const ast::TypeEnvironment & )
     238                        ) castCost };
    243239                src->accept( converter );
    244                 return converter.core.cost;
     240                return converter.pass.cost;
    245241        }
    246242}
  • src/ResolvExpr/CommonType.cc

    re67a82d r67ca73e  
    666666                const ast::OpenVarSet & open;
    667667        public:
    668                 static size_t traceId;
    669668                ast::ptr< ast::Type > result;
    670669
     
    894893        };
    895894
    896         // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");
    897895        namespace {
    898896                ast::ptr< ast::Type > handleReference(
     
    941939                        ast::ptr< ast::Type > result;
    942940                        const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
    943                         const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
     941                        const ast::ReferenceType * ref2 = type1.as< ast::ReferenceType >();
    944942
    945943                        if ( depth1 > depth2 ) {
     
    968966                ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };
    969967                type1->accept( visitor );
    970                 ast::ptr< ast::Type > result = visitor.core.result;
     968                ast::ptr< ast::Type > result = visitor.pass.result;
    971969
    972970                // handling for opaque type declarations (?)
  • src/ResolvExpr/ConversionCost.cc

    re67a82d r67ca73e  
    481481        }
    482482
    483 namespace {
    484         # warning For overload resolution between the two versions.
    485         int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
    486                         const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
    487                 return ptrsAssignable( t1, t2, env );
    488         }
    489         Cost localConversionCost(
    490                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    491                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    492         ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }
    493 }
     483static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
     484                const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
     485        return ptrsAssignable( t1, t2, env );
     486}
     487
     488// TODO: This is used for overload resolution. It might be able to be dropped once the old system
     489// is removed.
     490static Cost localConversionCost(
     491        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     492        const ast::TypeEnvironment & env
     493) { return conversionCost( src, dst, symtab, env ); }
    494494
    495495Cost conversionCost(
    496         const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    497         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     496        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     497        const ast::TypeEnvironment & env
    498498) {
    499499        if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    500500                if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
    501501                        if ( eqv->bound ) {
    502                                 return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
     502                                return conversionCost(src, eqv->bound, symtab, env );
    503503                        } else {
    504504                                return Cost::infinity;
     
    508508                        assertf( type, "Unexpected typedef." );
    509509                        if ( type->base ) {
    510                                 return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
     510                                return conversionCost( src, type->base, symtab, env ) + Cost::safe;
    511511                        }
    512512                }
     
    518518        } else if ( const ast::ReferenceType * refType =
    519519                         dynamic_cast< const ast::ReferenceType * >( dst ) ) {
    520                 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
     520                return convertToReferenceCost( src, refType, symtab, env, localPtrsAssignable );
    521521        } else {
    522                 ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost );
     522                ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
    523523                src->accept( converter );
    524                 return converter.core.cost;
    525         }
    526 }
    527 
    528 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     524                return converter.pass.cost;
     525        }
     526}
     527
     528static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst,
    529529                int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    530                 PtrsCalculation func ) {
     530                NumCostCalculation func ) {
    531531        if ( 0 < diff ) {
    532532                Cost cost = convertToReferenceCost(
    533                         strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst,
    534                         srcIsLvalue, (diff - 1), symtab, env, func );
     533                        strict_dynamic_cast< const ast::ReferenceType * >( src )->base,
     534                        dst, (diff - 1), symtab, env, func );
    535535                cost.incReference();
    536536                return cost;
     
    538538                Cost cost = convertToReferenceCost(
    539539                        src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
    540                         srcIsLvalue, (diff + 1), symtab, env, func );
     540                        (diff + 1), symtab, env, func );
    541541                cost.incReference();
    542542                return cost;
     
    563563                        }
    564564                } else {
    565                         ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost );
     565                        ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
    566566                        src->accept( converter );
    567                         return converter.core.cost;
     567                        return converter.pass.cost;
    568568                }
    569569        } else {
     
    572572                assert( dstAsRef );
    573573                if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
    574                         if ( srcIsLvalue ) {
     574                        if ( src->is_lvalue() ) {
    575575                                if ( src->qualifiers == dstAsRef->base->qualifiers ) {
    576576                                        return Cost::reference;
     
    591591
    592592Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
    593                 bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    594                 PtrsCalculation func ) {
     593            const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     594                NumCostCalculation func ) {
    595595        int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
    596         return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func );
     596        return convertToReferenceCost( src, dst, sdepth - ddepth, symtab, env, func );
    597597}
    598598
     
    651651        assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
    652652
    653         cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
     653        cost = costCalc( refType->base, dst, symtab, env );
    654654        if ( refType->base->qualifiers == dst->qualifiers ) {
    655655                cost.incReference();
     
    667667void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
    668668        (void)enumInstType;
    669         static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
    670         cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
     669        static const ast::BasicType integer( ast::BasicType::SignedInt );
     670        cost = costCalc( &integer, dst, symtab, env );
    671671        if ( cost < Cost::unsafe ) {
    672672                cost.incSafe();
     
    680680void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
    681681        if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
    682                 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
     682                cost = costCalc( eqv->bound, dst, symtab, env );
    683683        } else if ( const ast::TypeInstType * dstAsInst =
    684684                        dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     
    690690                assertf( type, "Unexpected typedef.");
    691691                if ( type->base ) {
    692                         cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe;
     692                        cost = costCalc( type->base, dst, symtab, env ) + Cost::safe;
    693693                }
    694694        }
     
    703703                auto dstEnd = dstAsTuple->types.end();
    704704                while ( srcIt != srcEnd && dstIt != dstEnd ) {
    705                         Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env );
     705                        Cost newCost = costCalc( * srcIt++, * dstIt++, symtab, env );
    706706                        if ( newCost == Cost::infinity ) {
    707707                                return;
     
    738738                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    739739                }
    740         } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
    741                 cost = Cost::zero;
    742                 // +1 for zero_t ->, +1 for disambiguation
    743                 cost.incSafe( maxIntCost + 2 );
    744740        }
    745741}
     
    759755                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    760756                }
    761         }
    762 }
    763 // size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
     757        } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
     758                cost = Cost::zero;
     759                cost.incSafe( maxIntCost + 2 );
     760        }
     761}
     762
    764763
    765764} // namespace ResolvExpr
  • src/ResolvExpr/ConversionCost.h

    re67a82d r67ca73e  
    7272
    7373// Some function pointer types, differ in return type.
    74 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool,
     74using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *,
    7575        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    76 using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *,
     76using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,
    7777        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    7878
     
    8181protected:
    8282        const ast::Type * dst;
    83         bool srcIsLvalue;
    8483        const ast::SymbolTable & symtab;
    8584        const ast::TypeEnvironment & env;
    8685        CostCalculation costCalc;
    8786public:
    88         static size_t traceId;
    8987        Cost cost;
    9088
    91         ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
     89        ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,
    9290                        const ast::TypeEnvironment & env, CostCalculation costCalc ) :
    93                 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
    94                 costCalc( costCalc ), cost( Cost::infinity )
     91                dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity )
    9592        {}
    9693
     
    113110
    114111Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
    115         bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
    116         PtrsCalculation func );
     112        const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func );
    117113
    118114} // namespace ResolvExpr
  • src/ResolvExpr/CurrentObject.cc

    re67a82d r67ca73e  
    2121#include <string>                      // for string, operator<<, allocator
    2222
    23 #include "AST/Copy.hpp"                // for shallowCopy
    2423#include "AST/Expr.hpp"                // for InitAlternative
    2524#include "AST/GenericSubstitution.hpp" // for genericSubstitution
    2625#include "AST/Init.hpp"                // for Designation
    2726#include "AST/Node.hpp"                // for readonly
    28 #include "AST/Print.hpp"                // for readonly
    2927#include "AST/Type.hpp"
    3028#include "Common/Indenter.h"           // for Indenter, operator<<
     
    598596                SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
    599597
    600                 void setPosition(
    601                         std::deque< ptr< Expr > >::const_iterator begin,
     598                void setPosition( 
     599                        std::deque< ptr< Expr > >::const_iterator begin, 
    602600                        std::deque< ptr< Expr > >::const_iterator end
    603601                ) override {
     
    639637                        auto res = eval(expr);
    640638                        if ( ! res.second ) {
    641                                 SemanticError( location,
     639                                SemanticError( location, 
    642640                                        toString("Array designator must be a constant expression: ", expr ) );
    643641                        }
     
    646644
    647645        public:
    648                 ArrayIterator( const CodeLocation & loc, const ArrayType * at )
     646                ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 
    649647                : location( loc ), array( at ), base( at->base ) {
    650648                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     
    657655
    658656                void setPosition( const Expr * expr ) {
    659                         // need to permit integer-constant-expressions, including: integer constants,
    660                         // enumeration constants, character constants, sizeof expressions, alignof expressions,
     657                        // need to permit integer-constant-expressions, including: integer constants, 
     658                        // enumeration constants, character constants, sizeof expressions, alignof expressions, 
    661659                        // cast expressions
    662660                        if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    664662                                        index = constExpr->intValue();
    665663                                } catch ( SemanticErrorException & ) {
    666                                         SemanticError( expr,
     664                                        SemanticError( expr, 
    667665                                                "Constant expression of non-integral type in array designator: " );
    668666                                }
    669667                        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
    670668                                setPosition( castExpr->arg );
    671                         } else if (
    672                                 dynamic_cast< const SizeofExpr * >( expr )
    673                                 || dynamic_cast< const AlignofExpr * >( expr )
     669                        } else if ( 
     670                                dynamic_cast< const SizeofExpr * >( expr ) 
     671                                || dynamic_cast< const AlignofExpr * >( expr ) 
    674672                        ) {
    675673                                index = 0;
    676674                        } else {
    677                                 assertf( false,
     675                                assertf( false, 
    678676                                        "bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    679677                        }
    680678                }
    681679
    682                 void setPosition(
    683                         std::deque< ptr< Expr > >::const_iterator begin,
     680                void setPosition( 
     681                        std::deque< ptr< Expr > >::const_iterator begin, 
    684682                        std::deque< ptr< Expr > >::const_iterator end
    685683                ) override {
     
    760758                }
    761759
    762                 AggregateIterator(
    763                         const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
     760                AggregateIterator( 
     761                        const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 
    764762                        const MemberList & ms )
    765                 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
     763                : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 
    766764                  sub( genericSubstitution( i ) ) {
    767765                        PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
     
    770768
    771769        public:
    772                 void setPosition(
    773                         std::deque< ptr< Expr > >::const_iterator begin,
     770                void setPosition( 
     771                        std::deque< ptr< Expr > >::const_iterator begin, 
    774772                        std::deque< ptr< Expr > >::const_iterator end
    775773                ) final {
     
    788786                                        return;
    789787                                }
    790                                 assertf( false,
     788                                assertf( false, 
    791789                                        "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    792790                        } else {
    793                                 assertf( false,
     791                                assertf( false, 
    794792                                        "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
    795793                        }
     
    805803                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    806804                                        // need to substitute for generic types so that casts are to concrete types
    807                                         alt.type = shallowCopy(alt.type.get());
    808805                                        PRINT( std::cerr << "  type is: " << alt.type; )
    809806                                        sub.apply( alt.type ); // also apply to designation??
     
    845842                                for ( InitAlternative & alt : ret ) {
    846843                                        PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    847                                         alt.designation.get_and_mutate()->designators.emplace_front(
     844                                        alt.designation.get_and_mutate()->designators.emplace_front( 
    848845                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    849846                                }
     
    900897        class TupleIterator final : public AggregateIterator {
    901898        public:
    902                 TupleIterator( const CodeLocation & loc, const TupleType * inst )
    903                 : AggregateIterator(
    904                         loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
     899                TupleIterator( const CodeLocation & loc, const TupleType * inst ) 
     900                : AggregateIterator( 
     901                        loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 
    905902                ) {}
    906903
     
    929926                                return new UnionIterator{ loc, uit };
    930927                        } else {
    931                                 assertf(
    932                                         dynamic_cast< const EnumInstType * >( type )
    933                                                 || dynamic_cast< const TypeInstType * >( type ),
     928                                assertf( 
     929                                        dynamic_cast< const EnumInstType * >( aggr )
     930                                                || dynamic_cast< const TypeInstType * >( aggr ),
    934931                                        "Encountered unhandled ReferenceToType in createMemberIterator: %s",
    935932                                                toString( type ).c_str() );
     
    952949                using DesignatorChain = std::deque< ptr< Expr > >;
    953950                PRINT( std::cerr << "___findNext" << std::endl; )
    954 
     951               
    955952                // find all the d's
    956953                std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
     
    10161013                // set new designators
    10171014                assertf( ! objStack.empty(), "empty object stack when setting designation" );
    1018                 Designation * actualDesignation =
     1015                Designation * actualDesignation = 
    10191016                        new Designation{ designation->location, DesignatorChain{d} };
    10201017                objStack.back()->setPosition( d ); // destroys d
  • src/ResolvExpr/PolyCost.cc

    re67a82d r67ca73e  
    5858
    5959// TODO: When the old PolyCost is torn out get rid of the _new suffix.
    60 class PolyCost_new {
     60struct PolyCost_new {
     61        int result;
    6162        const ast::SymbolTable &symtab;
    62 public:
    63         int result;
    6463        const ast::TypeEnvironment &env_;
    6564
    66         PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
    67         : symtab( symtab ), result( 0 ), env_( env ) {}
     65        PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
     66                result( 0 ), symtab( symtab ), env_( env ) {}
    6867
    6968        void previsit( const ast::TypeInstType * type ) {
     
    8786        ast::Pass<PolyCost_new> costing( symtab, env );
    8887        type->accept( costing );
    89         return costing.core.result;
     88        return costing.pass.result;
    9089}
    9190
  • src/ResolvExpr/PtrsAssignable.cc

    re67a82d r67ca73e  
    155155                ast::Pass<PtrsAssignable_new> visitor( dst, env );
    156156                src->accept( visitor );
    157                 return visitor.core.result;
     157                return visitor.pass.result;
    158158        }
    159159
  • src/ResolvExpr/PtrsCastable.cc

    re67a82d r67ca73e  
    293293                ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab };
    294294                src->accept( ptrs );
    295                 return ptrs.core.result;
     295                return ptrs.pass.result;
    296296        }
    297297}
  • src/ResolvExpr/RenameVars.cc

    re67a82d r67ca73e  
    1919#include <utility>                 // for pair
    2020
    21 #include "AST/ForallSubstitutionTable.hpp"
    2221#include "AST/Pass.hpp"
    2322#include "AST/Type.hpp"
     
    3130#include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    3231
    33 #include "AST/Copy.hpp"
    34 
    3532namespace ResolvExpr {
    3633
     
    4037                int resetCount = 0;
    4138                ScopedMap< std::string, std::string > nameMap;
     39
    4240        public:
    43                 ast::ForallSubstitutionTable subs;
    44 
    4541                void reset() {
    4642                        level = 0;
     
    4844                }
    4945
     46                using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
     47
    5048                void rename( TypeInstType * type ) {
    51                         auto it = nameMap.find( type->name );
     49                        mapConstIterator it = nameMap.find( type->name );
    5250                        if ( it != nameMap.end() ) {
    5351                                type->name = it->second;
     
    6765                                        // ditto for assertion names, the next level in
    6866                                        level++;
    69                                 }
    70                         }
     67                                        // acceptAll( td->assertions, *this );
     68                                } // for
     69                        } // if
    7170                }
    7271
     
    7877
    7978                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    80                         // re-linking of base type handled by WithForallSubstitutor
    81 
    82                         // rename
    83                         auto it = nameMap.find( type->name );
     79                        mapConstIterator it = nameMap.find( type->name );
    8480                        if ( it != nameMap.end() ) {
    85                                 // unconditionally mutate because map will *always* have different name,
    86                                 // if this mutates, will *always* have been mutated by ForallSubstitutor above
    87                                 ast::TypeInstType * mut = ast::mutate( type );
    88                                 mut->name = it->second;
    89                     type = mut;
     81                                ast::TypeInstType * mutType = ast::mutate( type );
     82                                mutType->name = it->second;
     83                    type = mutType;
    9084                        }
    91 
    9285                        return type;
    9386                }
     
    9588                template<typename NodeT>
    9689                const NodeT * openLevel( const NodeT * type ) {
    97                         if ( type->forall.empty() ) return type;
     90                        if ( !type->forall.empty() ) {
     91                                nameMap.beginScope();
     92                                // Load new names from this forall clause and perform renaming.
     93                                NodeT * mutType = ast::mutate( type );
     94                                for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
     95                                        std::ostringstream output;
     96                                        output << "_" << resetCount << "_" << level << "_" << td->name;
     97                                        std::string newname( output.str() );
     98                                        nameMap[ td->name ] = newname;
     99                                        ++level;
    98100
    99                         nameMap.beginScope();
    100 
    101                         // Load new names from this forall clause and perform renaming.
    102                         NodeT * mutType = ast::mutate( type );
    103                         assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
    104                         for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
    105                                 std::ostringstream output;
    106                                 output << "_" << resetCount << "_" << level << "_" << td->name;
    107                                 std::string newname =  output.str();
    108                                 nameMap[ td->name ] = newname;
    109                                 ++level;
    110 
    111                                 ast::TypeDecl * mutDecl = ast::mutate( td.get() );
    112                                 assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
    113                                 mutDecl->name = newname;
    114                                 // assertion above means `td = mutDecl;` is unnecessary
     101                                        ast::TypeDecl * decl = ast::mutate( td.get() );
     102                                        decl->name = newname;
     103                                        td = decl;
     104                                }
    115105                        }
    116                         // assertion above means `type = mutType;` is unnecessary
    117 
    118106                        return type;
    119107                }
    120108
    121                 void closeLevel( const ast::ParameterizedType * type ) {
    122                         if ( type->forall.empty() ) return;
    123 
    124                         nameMap.endScope();
     109                template<typename NodeT>
     110                const NodeT * closeLevel( const NodeT * type ) {
     111                        if ( !type->forall.empty() ) {
     112                                nameMap.endScope();
     113                        }
     114                        return type;
    125115                }
    126116        };
     
    129119        RenamingData renaming;
    130120
    131         struct RenameVars_old {
     121        struct RenameVars {
    132122                void previsit( TypeInstType * instType ) {
    133123                        renaming.openLevel( (Type*)instType );
     
    140130                        renaming.closeLevel( type );
    141131                }
    142         };
    143 
    144         struct RenameVars_new /*: public ast::WithForallSubstitutor*/ {
    145                 #warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor
    146                 ast::ForallSubstitutionTable & subs = renaming.subs;
    147132
    148133                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
     
    161146                        return renaming.rename( renaming.openLevel( type ) );
    162147                }
    163                 void postvisit( const ast::ParameterizedType * type ) {
    164                         renaming.closeLevel( type );
     148                const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
     149                        return renaming.closeLevel( type );
    165150                }
    166151        };
     
    169154
    170155void renameTyVars( Type * t ) {
    171         PassVisitor<RenameVars_old> renamer;
     156        PassVisitor<RenameVars> renamer;
    172157        t->accept( renamer );
    173158}
    174159
    175160const ast::Type * renameTyVars( const ast::Type * t ) {
    176         ast::Type *tc = ast::deepCopy(t);
    177         ast::Pass<RenameVars_new> renamer;
    178 //      return t->accept( renamer );
    179         return tc->accept( renamer );
     161        ast::Pass<RenameVars> renamer;
     162        return t->accept( renamer );
    180163}
    181164
  • src/ResolvExpr/ResolveTypeof.cc

    re67a82d r67ca73e  
    9999                        // replace basetypeof(<enum>) by int
    100100                        if ( dynamic_cast<EnumInstType*>(newType) ) {
    101                                 Type* newerType =
    102                                         new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
     101                                Type* newerType = 
     102                                        new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 
    103103                                        newType->attributes };
    104104                                delete newType;
    105105                                newType = newerType;
    106106                        }
    107                         newType->get_qualifiers().val
     107                        newType->get_qualifiers().val 
    108108                                = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
    109109                } else {
    110110                        newType->get_qualifiers().val |= oldQuals;
    111111                }
    112 
     112               
    113113                return newType;
    114114        }
     
    120120                ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {}
    121121
    122                 void previsit( const ast::TypeofType * ) { visit_children = false; }
     122                void premutate( const ast::TypeofType * ) { visit_children = false; }
    123123
    124                 const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
     124                const ast::Type * postmutate( const ast::TypeofType * typeofType ) {
    125125                        // pass on null expression
    126126                        if ( ! typeofType->expr ) return typeofType;
     
    133133                                // typeof wrapping expression
    134134                                ast::TypeEnvironment dummy;
    135                                 ast::ptr< ast::Expr > newExpr =
     135                                ast::ptr< ast::Expr > newExpr = 
    136136                                        resolveInVoidContext( typeofType->expr, localSymtab, dummy );
    137137                                assert( newExpr->result && ! newExpr->result->isVoid() );
     
    143143                                // replace basetypeof(<enum>) by int
    144144                                if ( newType.as< ast::EnumInstType >() ) {
    145                                         newType = new ast::BasicType{
     145                                        newType = new ast::BasicType{ 
    146146                                                ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) };
    147147                                }
    148                                 reset_qualifiers(
    149                                         newType,
     148                                reset_qualifiers( 
     149                                        newType, 
    150150                                        ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
    151151                        } else {
     
    153153                        }
    154154
    155                         return newType.release();
     155                        return newType;
    156156                }
    157157        };
  • src/ResolvExpr/Resolver.cc

    re67a82d r67ca73e  
    982982                ast::Pass<DeleteFinder_new> finder;
    983983                expr->accept( finder );
    984                 return finder.core.delExpr;
     984                return finder.pass.delExpr;
    985985        }
    986986
     
    10721072                /// Strips extraneous casts out of an expression
    10731073                struct StripCasts_new final {
    1074                         const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
     1074                        const ast::Expr * postmutate( const ast::CastExpr * castExpr ) {
    10751075                                if (
    1076                                         castExpr->isGenerated == ast::GeneratedCast
     1076                                        castExpr->isGenerated
    10771077                                        && typesCompatible( castExpr->arg->result, castExpr->result )
    10781078                                ) {
     
    11281128
    11291129                // set up and resolve expression cast to void
    1130                 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
     1130                ast::CastExpr * untyped = new ast::CastExpr{ expr };
    11311131                CandidateRef choice = findUnfinishedKindExpression(
    11321132                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     
    12361236
    12371237        public:
    1238                 static size_t traceId;
    12391238                Resolver_new() = default;
    12401239                Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
     
    12671266                const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
    12681267        };
    1269         // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
    1270 
    1271         void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) {
    1272                 ast::Pass< Resolver_new >::run( translationUnit );
     1268
     1269        void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) {
     1270                ast::Pass< Resolver_new > resolver;
     1271                accept_all( translationUnit, resolver );
    12731272        }
    12741273
     
    13001299                // default value expressions have an environment which shouldn't be there and trips up
    13011300                // later passes.
    1302                 assert( functionDecl->unique() );
    1303                 ast::FunctionType * mutType = mutate( functionDecl->type.get() );
    1304 
    1305                 for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
    1306                         if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
     1301                ast::ptr< ast::FunctionDecl > ret = functionDecl;
     1302                for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
     1303                        const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
     1304
     1305                        if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
    13071306                                if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
    13081307                                        if ( init->value->env == nullptr ) continue;
    13091308                                        // clone initializer minus the initializer environment
    1310                                         auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
    1311                                         auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
    1312                                         auto mutValue = mutate( mutInit->value.get() );
    1313 
    1314                                         mutValue->env = nullptr;
    1315                                         mutInit->value = mutValue;
    1316                                         mutParam->init = mutInit;
    1317                                         mutType->params[i] = mutParam;
    1318 
    1319                                         assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
     1309                                        ast::chain_mutate( ret )
     1310                                                ( &ast::FunctionDecl::type )
     1311                                                        ( &ast::FunctionType::params )[i]
     1312                                                                ( &ast::ObjectDecl::init )
     1313                                                                        ( &ast::SingleInit::value )->env = nullptr;
     1314
     1315                                        assert( functionDecl != ret.get() || functionDecl->unique() );
     1316                                        assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env );
    13201317                                }
    13211318                        }
    13221319                }
    1323                 mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
    1324                 return functionDecl;
     1320                return ret.get();
    13251321        }
    13261322
     
    13451341                // in case we decide to allow nested enums
    13461342                GuardValue( inEnumDecl );
    1347                 inEnumDecl = true;
     1343                inEnumDecl = false;
    13481344        }
    13491345
  • src/ResolvExpr/SatisfyAssertions.cpp

    re67a82d r67ca73e  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon Jun 10 17:45:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1 13:56:00 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 10 17:45:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    188188
    189189                                matches.emplace_back(
    190                                         cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
     190                                        cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have ),
    191191                                        std::move( newOpen ), crntResnSlot );
    192192                        }
     
    229229                InferMatcher( InferCache & inferred ) : inferred( inferred ) {}
    230230
    231                 const ast::Expr * postvisit( const ast::Expr * expr ) {
     231                const ast::Expr * postmutate( const ast::Expr * expr ) {
    232232                        // Skip if no slots to find
    233                         if ( !expr->inferred.hasSlots() ) return expr;
    234                         // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
    235                         std::vector<UniqueId> missingSlots;
     233                        if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
     234
    236235                        // find inferred parameters for resolution slots
    237                         ast::InferredParams * newInferred = new ast::InferredParams();
     236                        ast::InferredParams newInferred;
    238237                        for ( UniqueId slot : expr->inferred.resnSlots() ) {
    239238                                // fail if no matching assertions found
    240239                                auto it = inferred.find( slot );
    241240                                if ( it == inferred.end() ) {
    242                                         std::cerr << "missing assertion " << slot << std::endl;
    243                                         missingSlots.push_back(slot);
    244                                         continue;
     241                                        assert(!"missing assertion");
    245242                                }
    246243
     
    248245                                for ( auto & entry : it->second ) {
    249246                                        // recurse on inferParams of resolved expressions
    250                                         entry.second.expr = postvisit( entry.second.expr );
    251                                         auto res = newInferred->emplace( entry );
     247                                        entry.second.expr = postmutate( entry.second.expr );
     248                                        auto res = newInferred.emplace( entry );
    252249                                        assert( res.second && "all assertions newly placed" );
    253250                                }
     
    255252
    256253                        ast::Expr * ret = mutate( expr );
    257                         ret->inferred.set_inferParams( newInferred );
    258                         if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots;
     254                        ret->inferred.set_inferParams( std::move( newInferred ) );
    259255                        return ret;
    260256                }
     
    303299                        Cost cost;
    304300
    305                         OutType(
    306                                 const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
     301                        OutType( 
     302                                const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
    307303                                const std::vector< DeferRef > & as, const ast::SymbolTable & symtab )
    308304                        : env( e ), open( o ), assns( as ), cost( Cost::zero ) {
     
    310306                                for ( const DeferRef & assn : assns ) {
    311307                                        // compute conversion cost from satisfying decl to assertion
    312                                         cost += computeConversionCost(
    313                                                 assn.match.adjType, assn.decl->get_type(), false, symtab, env );
    314 
     308                                        cost += computeConversionCost( 
     309                                                assn.match.adjType, assn.decl->get_type(), symtab, env );
     310                                       
    315311                                        // mark vars+specialization on function-type assertions
    316                                         const ast::FunctionType * func =
     312                                        const ast::FunctionType * func = 
    317313                                                GenPoly::getFunctionType( assn.match.cdata.id->get_type() );
    318314                                        if ( ! func ) continue;
     
    321317                                                cost.decSpec( specCost( param->get_type() ) );
    322318                                        }
    323 
     319                                       
    324320                                        cost.incVar( func->forall.size() );
    325 
     321                                       
    326322                                        for ( const ast::TypeDecl * td : func->forall ) {
    327323                                                cost.decSpec( td->assertions.size() );
     
    333329                };
    334330
    335                 CandidateEnvMerger(
    336                         const ast::TypeEnvironment & env, const ast::OpenVarSet & open,
     331                CandidateEnvMerger( 
     332                        const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 
    337333                        const ast::SymbolTable & syms )
    338334                : crnt(), envs{ env }, opens{ open }, symtab( syms ) {}
  • src/ResolvExpr/SatisfyAssertions.hpp

    re67a82d r67ca73e  
    2828
    2929/// Recursively satisfies all assertions provided in a candidate; returns true if succeeds
    30 void satisfyAssertions(
    31         CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
     30void satisfyAssertions( 
     31        CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 
    3232        std::vector<std::string> & errors );
    3333
  • src/ResolvExpr/SpecCost.cc

    re67a82d r67ca73e  
    1010// Created On       : Tue Oct 02 15:50:00 2018
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul  3 11:07:00 2019
    13 // Update Count     : 3
    14 //
    15 
    16 #include <cassert>
     12// Last Modified On : Wed Jun 19 10:43:00 2019
     13// Update Count     : 2
     14//
     15
    1716#include <limits>
    1817#include <list>
     
    130129                        typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
    131130
    132                 #warning Should use a standard maybe_accept
    133                 void maybe_accept( ast::Type const * type ) {
    134                         if ( type ) {
    135                                 auto node = type->accept( *visitor );
    136                                 assert( node == nullptr || node == type );
    137                         }
    138                 }
    139 
    140131                // Update the minimum to the new lowest non-none value.
    141132                template<typename T>
     
    143134                        for ( const auto & node : list ) {
    144135                                count = -1;
    145                                 maybe_accept( mapper( node ) );
     136                                mapper( node )->accept( *visitor );
    146137                                if ( count != -1 && count < minimum ) minimum = count;
    147138                        }
     
    217208        }
    218209        ast::Pass<SpecCounter> counter;
    219         type->accept( counter );
    220         return counter.core.get_count();
     210        type->accept( *counter.pass.visitor );
     211        return counter.pass.get_count();
    221212}
    222213
  • src/ResolvExpr/Unify.cc

    re67a82d r67ca73e  
    2525#include <vector>
    2626
    27 #include "AST/Copy.hpp"
    2827#include "AST/Decl.hpp"
    2928#include "AST/Node.hpp"
    3029#include "AST/Pass.hpp"
    31 #include "AST/Print.hpp"
    3230#include "AST/Type.hpp"
    3331#include "AST/TypeEnvironment.hpp"
     
    137135                findOpenVars( newSecond, open, closed, need, have, FirstOpen );
    138136
    139                 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     137                return unifyExact(
     138                        newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
    140139        }
    141140
     
    149148                newFirst->get_qualifiers() = Type::Qualifiers();
    150149                newSecond->get_qualifiers() = Type::Qualifiers();
    151 
     150///   std::cerr << "first is ";
     151///   first->print( std::cerr );
     152///   std::cerr << std::endl << "second is ";
     153///   second->print( std::cerr );
     154///   std::cerr << std::endl << "newFirst is ";
     155///   newFirst->print( std::cerr );
     156///   std::cerr << std::endl << "newSecond is ";
     157///   newSecond->print( std::cerr );
     158///   std::cerr << std::endl;
    152159                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    153160                delete newFirst;
     
    163170                ast::AssertionSet need, have;
    164171
    165                 ast::Type * newFirst  = shallowCopy( first  );
    166                 ast::Type * newSecond = shallowCopy( second );
    167                 newFirst ->qualifiers = {};
    168                 newSecond->qualifiers = {};
    169                 ast::ptr< ast::Type > t1_(newFirst );
    170                 ast::ptr< ast::Type > t2_(newSecond);
    171 
    172                 ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
    173                 ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
     172                ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
     173                env.apply( newFirst );
     174                env.apply( newSecond );
     175                reset_qualifiers( newFirst );
     176                reset_qualifiers( newSecond );
    174177
    175178                return unifyExact(
    176                         subFirst,
    177                         subSecond,
    178                         newEnv, need, have, open, noWiden(), symtab );
     179                        newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
    179180        }
    180181
     
    325326
    326327        void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
     328///   std::cerr << "assertion set is" << std::endl;
     329///   printAssertionSet( assertions, std::cerr, 8 );
     330///   std::cerr << "looking for ";
     331///   assert->print( std::cerr );
     332///   std::cerr << std::endl;
    327333                AssertionSet::iterator i = assertions.find( assert );
    328334                if ( i != assertions.end() ) {
     335///     std::cerr << "found it!" << std::endl;
    329336                        i->second.isUsed = true;
    330337                } // if
     
    702709                const ast::SymbolTable & symtab;
    703710        public:
    704                 static size_t traceId;
    705711                bool result;
    706712
     
    791797                        for ( const ast::DeclWithType * d : src ) {
    792798                                ast::Pass<TtypeExpander_new> expander{ env };
    793                                 // TtypeExpander pass is impure (may mutate nodes in place)
    794                                 // need to make nodes shared to prevent accidental mutation
    795                                 ast::ptr<ast::DeclWithType> dc = d;
    796                                 dc = dc->accept( expander );
    797                                 auto types = flatten( dc->get_type() );
     799                                d = d->accept( expander );
     800                                auto types = flatten( d->get_type() );
    798801                                for ( ast::ptr< ast::Type > & t : types ) {
    799802                                        // outermost const, volatile, _Atomic qualifiers in parameters should not play
     
    804807                                        // requirements than a non-mutex function
    805808                                        remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
    806                                         dst.emplace_back( new ast::ObjectDecl{ dc->location, "", t } );
     809                                        dst.emplace_back( new ast::ObjectDecl{ d->location, "", t } );
    807810                                }
    808811                        }
     
    940943
    941944        private:
    942                 // Returns: other, cast as XInstType
    943                 // Assigns this->result: whether types are compatible (up to generic parameters)
    944                 template< typename XInstType >
    945                 const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
     945                template< typename RefType >
     946                const RefType * handleRefType( const RefType * inst, const ast::Type * other ) {
    946947                        // check that the other type is compatible and named the same
    947                         auto otherInst = dynamic_cast< const XInstType * >( other );
    948                         this->result = otherInst && inst->name == otherInst->name;
     948                        auto otherInst = dynamic_cast< const RefType * >( other );
     949                        result = otherInst && inst->name == otherInst->name;
    949950                        return otherInst;
    950951                }
     
    967968                }
    968969
    969                 template< typename XInstType >
    970                 void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
     970                template< typename RefType >
     971                void handleGenericRefType( const RefType * inst, const ast::Type * other ) {
    971972                        // check that other type is compatible and named the same
    972                         const XInstType * otherInst = handleRefType( inst, other );
    973                         if ( ! this->result ) return;
     973                        const RefType * inst2 = handleRefType( inst, other );
     974                        if ( ! inst2 ) return;
    974975
    975976                        // check that parameters of types unify, if any
    976977                        const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
    977                         const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
     978                        const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;
    978979
    979980                        auto it = params.begin();
     
    11131114
    11141115                        ast::Pass<TtypeExpander_new> expander{ tenv };
    1115 
    1116                         ast::ptr<ast::TupleType> tuplec = tuple;
    1117                         ast::ptr<ast::TupleType> tuple2c = tuple2;
    1118                         const ast::Type * flat = tuplec->accept( expander );
    1119                         const ast::Type * flat2 = tuple2c->accept( expander );
     1116                        const ast::Type * flat = tuple->accept( expander );
     1117                        const ast::Type * flat2 = tuple2->accept( expander );
    11201118
    11211119                        auto types = flatten( flat );
     
    11421140        };
    11431141
    1144         // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new");
    11451142        bool unify(
    11461143                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     
    11911188                        ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab };
    11921189                        type1->accept( comparator );
    1193                         return comparator.core.result;
     1190                        return comparator.pass.result;
    11941191                }
    11951192        }
     
    12051202                // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
    12061203                // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
    1207                 ast::Type * t1 = shallowCopy(type1.get());
    1208                 ast::Type * t2 = shallowCopy(type2.get());
    1209                 t1->qualifiers = {};
    1210                 t2->qualifiers = {};
    1211                 ast::ptr< ast::Type > t1_(t1);
    1212                 ast::ptr< ast::Type > t2_(t2);
     1204                ast::ptr<ast::Type> t1{ type1 }, t2{ type2 };
     1205                reset_qualifiers( t1 );
     1206                reset_qualifiers( t2 );
    12131207
    12141208                if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) {
     1209                        t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
     1210
    12151211                        // if exact unification on unqualified types, try to merge qualifiers
    12161212                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
    1217                                 t1->qualifiers = q1 | q2;
    1218                                 common = t1;
     1213                                common = type1;
     1214                                reset_qualifiers( common, q1 | q2 );
    12191215                                return true;
    12201216                        } else {
     
    12231219
    12241220                } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) {
     1221                        t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
     1222
    12251223                        // no exact unification, but common type
    1226                         auto c = shallowCopy(common.get());
    1227                         c->qualifiers = q1 | q2;
    1228                         common = c;
     1224                        reset_qualifiers( common, q1 | q2 );
    12291225                        return true;
    12301226                } else {
  • src/ResolvExpr/typeops.h

    re67a82d r67ca73e  
    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 : Thu Aug  8 16:36:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    8383                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    8484        Cost castCost(
    85                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    86                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     85                const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     86                const ast::TypeEnvironment & env );
    8787
    8888        // in ConversionCost.cc
     
    9090                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    9191        Cost conversionCost(
    92                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    93                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     92                const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     93                const ast::TypeEnvironment & env );
    9494
    9595        // in AlternativeFinder.cc
  • src/SymTab/Autogen.h

    re67a82d r67ca73e  
    2121
    2222#include "AST/Decl.hpp"
    23 #include "AST/Eval.hpp"
    2423#include "AST/Expr.hpp"
    2524#include "AST/Init.hpp"
     
    266265                }
    267266
    268                 ast::ptr< ast::Expr > begin, end;
    269                 std::string cmp, update;
     267                ast::ptr< ast::Expr > begin, end, cmp, update;
    270268
    271269                if ( forward ) {
     
    273271                        begin = ast::ConstantExpr::from_int( loc, 0 );
    274272                        end = array->dimension;
    275                         cmp = "?<?";
    276                         update = "++?";
     273                        cmp = new ast::NameExpr{ loc, "?<?" };
     274                        update = new ast::NameExpr{ loc, "++?" };
    277275                } else {
    278276                        // generate: for ( int i = N-1; i >= 0; --i )
    279                         begin = ast::call(
    280                                 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
     277                        begin = new ast::UntypedExpr{
     278                                loc, new ast::NameExpr{ loc, "?-?" },
     279                                { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } };
    281280                        end = ast::ConstantExpr::from_int( loc, 0 );
    282                         cmp = "?>=?";
    283                         update = "--?";
     281                        cmp = new ast::NameExpr{ loc, "?>=?" };
     282                        update = new ast::NameExpr{ loc, "--?" };
    284283                }
    285284
     
    287286                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
    288287                        new ast::SingleInit{ loc, begin } };
    289                 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
    290                
    291                 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
    292                
    293                 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
    294                
    295                 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
     288               
     289                ast::ptr< ast::Expr > cond = new ast::UntypedExpr{
     290                        loc, cmp, { new ast::VariableExpr{ loc, index }, end } };
     291               
     292                ast::ptr< ast::Expr > inc = new ast::UntypedExpr{
     293                        loc, update, { new ast::VariableExpr{ loc, index } } };
     294               
     295                ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{
     296                        loc, new ast::NameExpr{ loc, "?[?]" },
     297                        { dstParam, new ast::VariableExpr{ loc, index } } };
    296298               
    297299                // srcParam must keep track of the array indices to build the source parameter and/or
    298300                // array list initializer
    299                 srcParam.addArrayIndex( indexVar, array->dimension );
     301                srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );
    300302
    301303                // for stmt's body, eventually containing call
     
    383385                if ( isUnnamedBitfield( obj ) ) return {};
    384386
    385                 ast::ptr< ast::Type > addCast;
     387                ast::ptr< ast::Type > addCast = nullptr;
    386388                if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
    387389                        assert( dstParam->result );
  • src/SymTab/FixFunction.cc

    re67a82d r67ca73e  
    106106                bool isVoid = false;
    107107
    108                 void previsit( const ast::FunctionDecl * ) { visit_children = false; }
     108                void premutate( const ast::FunctionDecl * ) { visit_children = false; }
    109109
    110                 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
     110                const ast::DeclWithType * postmutate( const ast::FunctionDecl * func ) {
    111111                        return new ast::ObjectDecl{
    112112                                func->location, func->name, new ast::PointerType{ func->type }, nullptr,
     
    114114                }
    115115
    116                 void previsit( const ast::ArrayType * ) { visit_children = false; }
     116                void premutate( const ast::ArrayType * ) { visit_children = false; }
    117117
    118                 const ast::Type * postvisit( const ast::ArrayType * array ) {
     118                const ast::Type * postmutate( const ast::ArrayType * array ) {
    119119                        return new ast::PointerType{
    120120                                array->base, array->dimension, array->isVarLen, array->isStatic,
     
    122122                }
    123123
    124                 void previsit( const ast::VoidType * ) { isVoid = true; }
     124                void premutate( const ast::VoidType * ) { isVoid = true; }
    125125
    126                 void previsit( const ast::BasicType * ) { visit_children = false; }
    127                 void previsit( const ast::PointerType * ) { visit_children = false; }
    128                 void previsit( const ast::StructInstType * ) { visit_children = false; }
    129                 void previsit( const ast::UnionInstType * ) { visit_children = false; }
    130                 void previsit( const ast::EnumInstType * ) { visit_children = false; }
    131                 void previsit( const ast::TraitInstType * ) { visit_children = false; }
    132                 void previsit( const ast::TypeInstType * ) { visit_children = false; }
    133                 void previsit( const ast::TupleType * ) { visit_children = false; }
    134                 void previsit( const ast::VarArgsType * ) { visit_children = false; }
    135                 void previsit( const ast::ZeroType * ) { visit_children = false; }
    136                 void previsit( const ast::OneType * ) { visit_children = false; }
     126                void premutate( const ast::BasicType * ) { visit_children = false; }
     127                void premutate( const ast::PointerType * ) { visit_children = false; }
     128                void premutate( const ast::StructInstType * ) { visit_children = false; }
     129                void premutate( const ast::UnionInstType * ) { visit_children = false; }
     130                void premutate( const ast::EnumInstType * ) { visit_children = false; }
     131                void premutate( const ast::TraitInstType * ) { visit_children = false; }
     132                void premutate( const ast::TypeInstType * ) { visit_children = false; }
     133                void premutate( const ast::TupleType * ) { visit_children = false; }
     134                void premutate( const ast::VarArgsType * ) { visit_children = false; }
     135                void premutate( const ast::ZeroType * ) { visit_children = false; }
     136                void premutate( const ast::OneType * ) { visit_children = false; }
    137137        };
    138138} // anonymous namespace
     
    141141        ast::Pass< FixFunction_new > fixer;
    142142        dwt = dwt->accept( fixer );
    143         isVoid |= fixer.core.isVoid;
     143        isVoid |= fixer.pass.isVoid;
    144144        return dwt;
    145145}
  • src/SymTab/Mangler.cc

    re67a82d r67ca73e  
    447447                ast::Pass<Mangler_new> mangler( mode );
    448448                maybeAccept( decl, mangler );
    449                 return mangler.core.get_mangleName();
     449                return mangler.pass.get_mangleName();
    450450        }
    451451
     
    691691                                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    692692                                                        assert->accept( sub_mangler );
    693                                                         assertionNames.push_back( sub_mangler.core.get_mangleName() );
     693                                                        assertionNames.push_back( sub_mangler.pass.get_mangleName() );
    694694                                                        acount++;
    695695                                                } // for
  • src/SynTree/ApplicationExpr.cc

    re67a82d r67ca73e  
    3434
    3535ParamEntry::ParamEntry( const ParamEntry &other ) :
    36                 decl( other.decl ), declptr( other.declptr ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
     36                decl( other.decl ), declptr( maybeClone( other.declptr ) ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
    3737}
    3838
    3939ParamEntry::~ParamEntry() {
    40         // delete declptr;
     40        delete declptr;
    4141        delete actualType;
    4242        delete formalType;
  • src/SynTree/Expression.cc

    re67a82d r67ca73e  
    6969void Expression::print( std::ostream & os, Indenter indent ) const {
    7070        printInferParams( inferParams, os, indent+1, 0 );
    71 
    72         if ( result ) {
    73                 os << std::endl << indent << "with resolved type:" << std::endl;
    74                 os << (indent+1);
    75                 result->print( os, indent+1 );
    76         }
    7771
    7872        if ( env ) {
  • src/SynTree/Statement.h

    re67a82d r67ca73e  
    518518class ImplicitCtorDtorStmt : public Statement {
    519519  public:
    520         // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere
     520        // Non-owned pointer to the constructor/destructor statement
    521521        Statement * callStmt;
    522522
  • src/Tuples/Explode.cc

    re67a82d r67ca73e  
    129129                        for ( const ast::Expr * expr : tupleExpr->exprs ) {
    130130                                exprs.emplace_back( applyCast( expr, false ) );
     131                                //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
    131132                        }
    132133                        if ( first ) {
     
    147148        }
    148149
    149         const ast::Expr * postvisit( const ast::UniqueExpr * node ) {
     150        const ast::Expr * postmutate( const ast::UniqueExpr * node ) {
    150151                // move cast into unique expr so that the unique expr has type T& rather than
    151152                // type T. In particular, this transformation helps with generating the
     
    161162                        castAdded = false;
    162163                        const ast::Type * newType = getReferenceBase( newNode->result );
    163                         return new ast::CastExpr{ newNode->location, newNode, newType };
     164                        return new ast::CastExpr{ newNode->location, node, newType };
    164165                }
    165166                return newNode;
    166167        }
    167168
    168         const ast::Expr * postvisit( const ast::TupleIndexExpr * tupleExpr ) {
     169        const ast::Expr * postmutate( const ast::TupleIndexExpr * tupleExpr ) {
    169170                // tuple index expr needs to be rebuilt to ensure that the type of the
    170171                // field is consistent with the type of the tuple expr, since the field
     
    179180        ast::Pass<CastExploderCore> exploder;
    180181        expr = expr->accept( exploder );
    181         if ( ! exploder.core.foundUniqueExpr ) {
     182        if ( ! exploder.pass.foundUniqueExpr ) {
    182183                expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
    183184        }
  • src/Tuples/Explode.h

    re67a82d r67ca73e  
    210210                        }
    211211                        // Cast a reference away to a value-type to allow further explosion.
    212                         if ( local->result.as< ast::ReferenceType >() ) {
     212                        if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
    213213                                local = new ast::CastExpr{ local, tupleType };
    214214                        }
     
    220220                                // delete idx;
    221221                        }
     222                        // delete local;
    222223                }
    223224        } else {
  • src/Tuples/TupleAssignment.cc

    re67a82d r67ca73e  
    465465                                        // resolve ctor/dtor for the new object
    466466                                        ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
    467                                                         InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms );
     467                                                        InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
    468468                                        // remove environments from subexpressions of stmtExpr
    469469                                        ast::Pass< EnvRemover > rm{ env };
     
    504504
    505505                        std::vector< ast::ptr< ast::Expr > > match() override {
    506                                 // temporary workaround for new and old ast to coexist and avoid name collision
    507                                 static UniqueName lhsNamer( "__massassign_Ln" );
    508                                 static UniqueName rhsNamer( "__massassign_Rn" );
     506                                static UniqueName lhsNamer( "__massassign_L" );
     507                                static UniqueName rhsNamer( "__massassign_R" );
    509508                                // empty tuple case falls into this matcher
    510509                                assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     
    535534
    536535                        std::vector< ast::ptr< ast::Expr > > match() override {
    537                                 // temporary workaround for new and old ast to coexist and avoid name collision
    538                                 static UniqueName lhsNamer( "__multassign_Ln" );
    539                                 static UniqueName rhsNamer( "__multassign_Rn" );
     536                                static UniqueName lhsNamer( "__multassign_L" );
     537                                static UniqueName rhsNamer( "__multassign_R" );
    540538
    541539                                if ( lhs.size() != rhs.size() ) return {};
     
    562560                                        // resolve the cast expression so that rhsCand return type is bound by the cast
    563561                                        // type as needed, and transfer the resulting environment
    564                                         ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env };
     562                                        ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
    565563                                        finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
    566564                                        assert( finder.candidates.size() == 1 );
     
    611609                                        // explode the LHS so that each field of a tuple-valued expr is assigned
    612610                                        ResolvExpr::CandidateList lhs;
    613                                         explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true );
     611                                        explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
    614612                                        for ( ResolvExpr::CandidateRef & cand : lhs ) {
    615613                                                // each LHS value must be a reference - some come in with a cast, if not
     
    631629                                                        if ( isTuple( rhsCand->expr ) ) {
    632630                                                                // multiple assignment
    633                                                                 explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
     631                                                                explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
    634632                                                                matcher.reset(
    635633                                                                        new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    650648                                                        // multiple assignment
    651649                                                        ResolvExpr::CandidateList rhs;
    652                                                         explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
     650                                                        explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
    653651                                                        matcher.reset(
    654652                                                                new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    680678                                )
    681679
    682                                 ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env };
     680                                ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
    683681
    684682                                try {
  • src/Tuples/TupleExpansion.cc

    re67a82d r67ca73e  
    323323                std::vector<ast::ptr<ast::Type>> types;
    324324                ast::CV::Qualifiers quals{
    325                         ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict |
     325                        ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
    326326                        ast::CV::Atomic | ast::CV::Mutex };
    327327
  • src/Tuples/Tuples.cc

    re67a82d r67ca73e  
    4343        };
    4444        struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
    45                 using ImpurityDetector::previsit;
    4645                void previsit( ast::UniqueExpr const * ) {
    4746                        visit_children = false;
     
    5352                ast::Pass<Detector> detector;
    5453                expr->accept( detector );
    55                 return detector.core.maybeImpure;
     54                return detector.pass.maybeImpure;
    5655        }
    5756} // namespace
  • src/config.h.in

    re67a82d r67ca73e  
    2727/* Location of cfa install. */
    2828#undef CFA_PREFIX
    29 
    30 /* Sets whether or not to use the new-ast, this is adefault value and can be
    31    overrided by --old-ast and --new-ast */
    32 #undef CFA_USE_NEW_AST
    3329
    3430/* Major.Minor */
  • src/main.cc

    re67a82d r67ca73e  
    3131using namespace std;
    3232
    33 #include "AST/Convert.hpp"
     33
    3434#include "CompilationState.h"
    3535#include "../config.h"                      // for CFA_LIBDIR
     
    340340                } // if
    341341
    342                 if( useNewAST) {
    343                         auto transUnit = convert( move( translationUnit ) );
    344                         PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    345                         translationUnit = convert( move( transUnit ) );
    346                 } else {
    347                         PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
    348                 }
    349 
     342                PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
    350343                if ( exprp ) {
    351344                        dump( translationUnit );
     
    465458        { "prototypes", no_argument, nullptr, 'p' },
    466459        { "deterministic-out", no_argument, nullptr, 'd' },
    467         { "old-ast", no_argument, nullptr, 'O'},
    468         { "new-ast", no_argument, nullptr, 'A'},
    469460        { "print", required_argument, nullptr, 'P' },
    470461        { "prelude-dir", required_argument, nullptr, PreludeDir },
     
    488479        "generate prototypes for prelude functions",            // -p
    489480        "don't print output that isn't deterministic",        // -d
    490         "Use the old-ast",                                    // -O
    491         "Use the new-ast",                                    // -A
    492481        "print",                                              // -P
    493482        "<directory> prelude directory for debug/nodebug",      // no flag
     
    595584                        break;
    596585                  case 'd':                                     // don't print non-deterministic output
    597                         deterministic_output = true;
    598                         break;
    599                   case 'O':                                     // don't print non-deterministic output
    600                         useNewAST = false;
    601                         break;
    602                   case 'A':                                     // don't print non-deterministic output
    603                         useNewAST = true;
     586                    deterministic_output = true;
    604587                        break;
    605588                  case 'P':                                                                             // print options
  • tests/.expect/alloc-ERROR.txt

    re67a82d r67ca73e  
    1616          Name: stp
    1717
    18       with resolved type:
    19         unsigned long int
    2018
    2119
     
    3028    Name: stp
    3129    constant expression (10 10: signed int)
    32     with resolved type:
    33       signed int
    3430
    3531
  • tests/.expect/castError.txt

    re67a82d r67ca73e  
    33  Name: f
    44... to:
    5   char
    6 with resolved type:
    75  char Alternatives are:
    86Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
     
    119      ... returning nothing
    1210
    13       with resolved type:
    14         pointer to function
    15           accepting unspecified arguments
    16         ... returning nothing
    17 
    1811    ... to:
    19       char
    20     with resolved type:
    2112      char
    2213  (types:
     
    2718Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    2819      Variable Expression: f: double
    29       with resolved type:
    30         double
    3120    ... to:
    32       char
    33     with resolved type:
    3421      char
    3522  (types:
     
    4027Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    4128      Variable Expression: f: signed int
    42       with resolved type:
    43         signed int
    4429    ... to:
    45       char
    46     with resolved type:
    4730      char
    4831  (types:
     
    5639  Comma Expression:
    5740    constant expression (3 3: signed int)
    58     with resolved type:
    59       signed int
    6041    Name: v
    61 ... to: nothing
    62 with resolved type:
    63   void  Alternatives are:
     42... to: nothing Alternatives are:
    6443Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of:
    6544      Comma Expression:
    6645        constant expression (3 3: signed int)
    67         with resolved type:
    68           signed int
    6946        Variable Expression: v: unsigned char
    70         with resolved type:
    71           unsigned char
    72       with resolved type:
    73         unsigned char
    7447    ... to: nothing
    75     with resolved type:
    76       void
    7748  (types:
    7849    void
     
    8354      Comma Expression:
    8455        constant expression (3 3: signed int)
    85         with resolved type:
    86           signed int
    8756        Variable Expression: v: signed short int
    88         with resolved type:
    89           signed short int
    90       with resolved type:
    91         signed short int
    9257    ... to: nothing
    93     with resolved type:
    94       void
    9558  (types:
    9659    void
     
    10669    char
    10770
    108 with resolved type:
    109   instance of struct S with body 1
    110   ... with parameters
    111     char
    112 
  • tests/.expect/declarationSpecifier.x64.txt

    re67a82d r67ca73e  
    11291129static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    11301130static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    1131 signed int _X13cfa_args_argci_1;
    1132 char **_X13cfa_args_argvPPc_1;
    1133 char **_X13cfa_args_envpPPc_1;
    11341131signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    11351132    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11361133    {
    1137         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    1138     }
    1139 
    1140     {
    1141         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    1142     }
    1143 
    1144     {
    1145         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    1146     }
    1147 
    1148     {
    11491134        signed int _tmp_cp_ret4;
    11501135        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/declarationSpecifier.x86.txt

    re67a82d r67ca73e  
    11291129static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    11301130static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    1131 signed int _X13cfa_args_argci_1;
    1132 char **_X13cfa_args_argvPPc_1;
    1133 char **_X13cfa_args_envpPPc_1;
    11341131signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    11351132    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11361133    {
    1137         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    1138     }
    1139 
    1140     {
    1141         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    1142     }
    1143 
    1144     {
    1145         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    1146     }
    1147 
    1148     {
    11491134        signed int _tmp_cp_ret4;
    11501135        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/gccExtensions.x64.txt

    re67a82d r67ca73e  
    321321static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    322322static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    323 signed int _X13cfa_args_argci_1;
    324 char **_X13cfa_args_argvPPc_1;
    325 char **_X13cfa_args_envpPPc_1;
    326323signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    327324    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    328325    {
    329         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    330     }
    331 
    332     {
    333         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    334     }
    335 
    336     {
    337         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    338     }
    339 
    340     {
    341326        signed int _tmp_cp_ret4;
    342327        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/gccExtensions.x86.txt

    re67a82d r67ca73e  
    299299static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    300300static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    301 signed int _X13cfa_args_argci_1;
    302 char **_X13cfa_args_argvPPc_1;
    303 char **_X13cfa_args_envpPPc_1;
    304301signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    305302    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    306303    {
    307         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    308     }
    309 
    310     {
    311         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    312     }
    313 
    314     {
    315         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    316     }
    317 
    318     {
    319304        signed int _tmp_cp_ret4;
    320305        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/init1.txt

    re67a82d r67ca73e  
    1111... to:
    1212  reference to signed int
    13 with resolved type:
    14   reference to signed int
    1513init1.cfa:97:1 error: No reasonable alternatives for expression Applying untyped:
    1614  Name: ?{}
     
    1816  Generated Cast of:
    1917    Variable Expression: _retval_f_py: pointer to signed int
    20     with resolved type:
    21       pointer to signed int
    2218  ... to:
    23     reference to pointer to signed int
    24   with resolved type:
    2519    reference to pointer to signed int
    2620  Name: px
     
    3024... to:
    3125  reference to float
    32 with resolved type:
    33   reference to float
    3426init1.cfa:107:1 error: No reasonable alternatives for expression Applying untyped:
    3527  Name: ?{}
     
    3729  Generated Cast of:
    3830    Variable Expression: _retval_f_py2: pointer to float
    39     with resolved type:
    40       pointer to float
    4131  ... to:
    42     reference to pointer to float
    43   with resolved type:
    4432    reference to pointer to float
    4533  Name: cpx
     
    4937... to:
    5038  reference to instance of type T (not function type)
    51 with resolved type:
    52   reference to instance of type T (not function type)
    5339init1.cfa:118:1 error: No reasonable alternatives for expression Applying untyped:
    5440  Name: ?{}
     
    5642  Generated Cast of:
    5743    Variable Expression: _retval_anycvt: pointer to instance of type T (not function type)
    58     with resolved type:
    59       pointer to instance of type T (not function type)
    6044  ... to:
    61     reference to pointer to instance of type T (not function type)
    62   with resolved type:
    6345    reference to pointer to instance of type T (not function type)
    6446  Name: s
  • tests/.expect/minmax.txt

    re67a82d r67ca73e  
    11char                    z a     min a
    2 signed int              4 -3    min -3
     2signed int              4 3     min 3
    33unsigned int            4 3     min 3
    4 signed long int         4 -3    min -3
     4signed long int         4 3     min 3
    55unsigned long int       4 3     min 3
    6 signed long long int    4 -3    min -3
     6signed long long int    4 3     min 3
    77unsigned long long int  4 3     min 3
    88float                   4. 3.1  min 3.1
     
    1111
    1212char                    z a     max z
    13 signed int              4 -3    max 4
     13signed int              4 3     max 4
    1414unsigned int            4 3     max 4
    15 signed long int         4 -3    max 4
     15signed long int         4 3     max 4
    1616unsigned long int       4 3     max 4
    17 signed long long int    4 -3    max 4
     17signed long long int    4 3     max 4
    1818unsigned long long int  4 3     max 4
    1919float                   4. 3.1  max 4.
  • tests/Makefile.am

    re67a82d r67ca73e  
    163163        $(CFACOMPILETEST) -DERR2 -c -fsyntax-only -o $(abspath ${@})
    164164
    165 # Exception Tests
    166 # Test with libcfathread; it changes how storage works.
    167 
    168 exceptions/%-threads : exceptions/%.cfa $(CFACCBIN)
    169         $(CFACOMPILETEST) -include exceptions/with-threads.hfa -c -o $(abspath ${@}).o
    170         $(CFACCLOCAL) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) $(abspath ${@}).o -o $(abspath ${@})
    171 
    172165#------------------------------------------------------------------------------
    173166# Other targets
  • tests/alloc.cfa

    re67a82d r67ca73e  
    1010// Created On       : Wed Feb  3 07:56:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 14 16:59:59 2020
    13 // Update Count     : 430
     12// Last Modified On : Mon Apr  6 21:08:23 2020
     13// Update Count     : 428
    1414//
    1515
     
    9090        // do not free
    9191
    92         ip1 = alloc_set( 2 * dim, ip, 2 * dim );                                // CFA array alloc, fill
     92        ip1 = alloc_set( 2 * dim, ip );                                         // CFA array alloc, fill
    9393        printf( "CFA array alloc, fill from array\n" );
    9494        for ( i; 2 * dim ) { printf( "%#x %#x, ", ip[i], ip1[i] ); }
     
    288288        // do not free
    289289
    290         stp1 = alloc_align_set( Alignment, dim, stp, dim );     // CFA array memalign, fill
     290        stp1 = alloc_align_set( Alignment, dim, stp );          // CFA array memalign, fill
    291291        assert( (uintptr_t)stp % Alignment == 0 );
    292292        printf( "CFA array alloc_align, fill array\n" );
  • tests/errors/.expect/completeType.x64.txt

    re67a82d r67ca73e  
    66    Name: x
    77
    8 ... to: nothing
    9 with resolved type:
    10   void  Alternatives are:
     8... to: nothing Alternatives are:
    119Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    1210      Application of
     
    2220
    2321
    24         with resolved type:
    25           pointer to forall
    26             _90_4_DT: data type
    27             function
    28           ... with parameters
    29             intrinsic pointer to instance of type _90_4_DT (not function type)
    30           ... returning
    31             _retval__operator_deref: reference to instance of type _90_4_DT (not function type)
    32             ... with attributes:
    33               Attribute with name: unused
    34 
    35 
    3622      ... to arguments
    3723        Variable Expression: x: pointer to instance of struct A with body 0
    38         with resolved type:
    39           pointer to instance of struct A with body 0
    4024
    41       with resolved type:
    42         reference to instance of struct A with body 0
    4325    ... to: nothing
    44     with resolved type:
    45       void
    4626  (types:
    4727    void
     
    6343
    6444
    65         with resolved type:
    66           pointer to forall
    67             _90_4_DT: data type
    68             function
    69           ... with parameters
    70             intrinsic pointer to instance of type _90_4_DT (not function type)
    71           ... returning
    72             _retval__operator_deref: reference to instance of type _90_4_DT (not function type)
    73             ... with attributes:
    74               Attribute with name: unused
    75 
    76 
    7745      ... to arguments
    7846        Variable Expression: x: pointer to instance of struct B with body 1
    79         with resolved type:
    80           pointer to instance of struct B with body 1
    8147
    82       with resolved type:
    83         reference to instance of struct B with body 1
    8448    ... to: nothing
    85     with resolved type:
    86       void
    8749  (types:
    8850    void
     
    159121            ... returning nothing
    160122
    161             with resolved type:
    162               pointer to forall
    163                 _109_0_T: sized data type
    164                 ... with assertions
    165                   ?=?: pointer to function
    166                   ... with parameters
    167                     reference to instance of type _109_0_T (not function type)
    168                     instance of type _109_0_T (not function type)
    169                   ... returning
    170                     _retval__operator_assign: instance of type _109_0_T (not function type)
    171                     ... with attributes:
    172                       Attribute with name: unused
    173 
    174 
    175                   ?{}: pointer to function
    176                   ... with parameters
    177                     reference to instance of type _109_0_T (not function type)
    178                   ... returning nothing
    179 
    180                   ?{}: pointer to function
    181                   ... with parameters
    182                     reference to instance of type _109_0_T (not function type)
    183                     instance of type _109_0_T (not function type)
    184                   ... returning nothing
    185 
    186                   ^?{}: pointer to function
    187                   ... with parameters
    188                     reference to instance of type _109_0_T (not function type)
    189                   ... returning nothing
    190 
    191 
    192                 function
    193               ... with parameters
    194                 pointer to instance of type _109_0_T (not function type)
    195               ... returning nothing
    196 
    197123          ... to arguments
    198124            Variable Expression: z: pointer to instance of type T (not function type)
    199             with resolved type:
    200               pointer to instance of type T (not function type)
    201125
    202           with resolved type:
    203             void
    204126        (types:
    205127          void
  • tests/errors/.expect/completeType.x86.txt

    re67a82d r67ca73e  
    66    Name: x
    77
    8 ... to: nothing
    9 with resolved type:
    10   void  Alternatives are:
     8... to: nothing Alternatives are:
    119Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    1210      Application of
     
    2220
    2321
    24         with resolved type:
    25           pointer to forall
    26             _89_4_DT: data type
    27             function
    28           ... with parameters
    29             intrinsic pointer to instance of type _89_4_DT (not function type)
    30           ... returning
    31             _retval__operator_deref: reference to instance of type _89_4_DT (not function type)
    32             ... with attributes:
    33               Attribute with name: unused
    34 
    35 
    3622      ... to arguments
    3723        Variable Expression: x: pointer to instance of struct A with body 0
    38         with resolved type:
    39           pointer to instance of struct A with body 0
    4024
    41       with resolved type:
    42         reference to instance of struct A with body 0
    4325    ... to: nothing
    44     with resolved type:
    45       void
    4626  (types:
    4727    void
     
    6343
    6444
    65         with resolved type:
    66           pointer to forall
    67             _89_4_DT: data type
    68             function
    69           ... with parameters
    70             intrinsic pointer to instance of type _89_4_DT (not function type)
    71           ... returning
    72             _retval__operator_deref: reference to instance of type _89_4_DT (not function type)
    73             ... with attributes:
    74               Attribute with name: unused
    75 
    76 
    7745      ... to arguments
    7846        Variable Expression: x: pointer to instance of struct B with body 1
    79         with resolved type:
    80           pointer to instance of struct B with body 1
    8147
    82       with resolved type:
    83         reference to instance of struct B with body 1
    8448    ... to: nothing
    85     with resolved type:
    86       void
    8749  (types:
    8850    void
     
    159121            ... returning nothing
    160122
    161             with resolved type:
    162               pointer to forall
    163                 _108_0_T: sized data type
    164                 ... with assertions
    165                   ?=?: pointer to function
    166                   ... with parameters
    167                     reference to instance of type _108_0_T (not function type)
    168                     instance of type _108_0_T (not function type)
    169                   ... returning
    170                     _retval__operator_assign: instance of type _108_0_T (not function type)
    171                     ... with attributes:
    172                       Attribute with name: unused
    173 
    174 
    175                   ?{}: pointer to function
    176                   ... with parameters
    177                     reference to instance of type _108_0_T (not function type)
    178                   ... returning nothing
    179 
    180                   ?{}: pointer to function
    181                   ... with parameters
    182                     reference to instance of type _108_0_T (not function type)
    183                     instance of type _108_0_T (not function type)
    184                   ... returning nothing
    185 
    186                   ^?{}: pointer to function
    187                   ... with parameters
    188                     reference to instance of type _108_0_T (not function type)
    189                   ... returning nothing
    190 
    191 
    192                 function
    193               ... with parameters
    194                 pointer to instance of type _108_0_T (not function type)
    195               ... returning nothing
    196 
    197123          ... to arguments
    198124            Variable Expression: z: pointer to instance of type T (not function type)
    199             with resolved type:
    200               pointer to instance of type T (not function type)
    201125
    202           with resolved type:
    203             void
    204126        (types:
    205127          void
  • tests/exceptions/terminate.cfa

    re67a82d r67ca73e  
    142142        }
    143143}
     144
  • tests/heap.cfa

    re67a82d r67ca73e  
    1010// Created On       : Tue Nov  6 17:54:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug  9 08:05:16 2020
    13 // Update Count     : 57
     12// Last Modified On : Tue Aug  4 06:36:17 2020
     13// Update Count     : 56
    1414//
    1515
     
    232232                size_t s = i + default_mmap_start();                    // cross over point
    233233                char * area = (char *)calloc( 1, s );
     234//              if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    234235                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    235236                         area[malloc_size( area ) - 1] != '\0' ||
    236                          ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage3" );
     237                         ! malloc_zero_fill( area ) ) //abort( "calloc/realloc/free corrupt storage3" );
     238                        printf( "C %zd %d %d %d %d\n", s, area[0] != '\0', area[s - 1] != '\0', area[malloc_size( area ) - 1] != '\0', ! malloc_zero_fill( area ) );
    237239
    238240                // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
    239241                for ( r; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    240242                        area = (char *)realloc( area, r );                      // attempt to reuse storage
     243//                      if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    241244                        if ( area[0] != '\0' || area[r - 1] != '\0' ||
    242245                                 area[malloc_size( area ) - 1] != '\0' ||
     
    252255                // initial N byte allocation
    253256                char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
     257//              if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    254258                //sout | alignments[a] | area;
    255259                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
  • tests/linking/withthreads.cfa

    re67a82d r67ca73e  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // withthreads.cfa --
     7// nothreads.cfa --
    88//
    99// Author           : Thierry Delisle
  • tests/literals.cfa

    re67a82d r67ca73e  
    1010// Created On       : Sat Sep  9 16:34:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 20 13:51:12 2020
    13 // Update Count     : 225
     12// Last Modified On : Tue Feb 12 08:07:39 2019
     13// Update Count     : 224
    1414//
    1515
     
    214214        -01234567_l8;  -01234567_l16;  -01234567_l32;  -01234567_l64;  -01234567_l8u;  -01234567_ul16;  -01234567_l32u;  -01234567_ul64;
    215215
    216 #if defined( __SIZEOF_INT128__ )
     216#ifdef __LP64__ // 64-bit processor
    217217        01234567_l128;   01234567_ul128;
    218218        +01234567_l128;  +01234567_ul128;
    219219        -01234567_l128;  -01234567_ul128;
    220 #endif // __SIZEOF_INT128__
     220#endif // __LP64__
    221221
    222222        // decimal
     
    225225        -1234567890L8;  -1234567890L16;  -1234567890l32;  -1234567890l64;  -1234567890UL8;  -1234567890L16U;  -1234567890Ul32;  -1234567890l64u;
    226226
    227 #if defined( __SIZEOF_INT128__ )
     227#ifdef __LP64__ // 64-bit processor
    228228        1234567890l128;   1234567890l128u;
    229229        +1234567890l128;  +1234567890l128u;
    230230        -1234567890l128;  -1234567890l128u;
    231     1234567890123456789_L128u; 1234567890123456789_L128u;
    232         18446708753438544741_l64u; 18446708753438544741_Ul64;
    233 #endif // __SIZEOF_INT128__
     231#endif // __LP64__
    234232
    235233        // hexadecimal
  • tests/minmax.cfa

    re67a82d r67ca73e  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 15 08:28:01 2020
    13 // Update Count     : 54
     12// Last Modified On : Tue Dec  4 21:45:31 2018
     13// Update Count     : 52
    1414//
    1515
     
    2323
    2424        sout | "char\t\t\t"                                     | 'z' | ' ' | 'a' | "\tmin " | min( 'z', 'a' );
    25         sout | "signed int\t\t"                         | 4 | -3 | "\tmin" | min( 4, -3 );
     25        sout | "signed int\t\t"                         | 4 | 3 | "\tmin" | min( 4, 3 );
    2626        sout | "unsigned int\t\t"                       | 4u | 3u | "\tmin" | min( 4u, 3u );
    27         sout | "signed long int\t\t"            | 4l | -3l | "\tmin" | min( 4l, -3l );
     27        sout | "signed long int\t\t"            | 4l | 3l | "\tmin" | min( 4l, 3l );
    2828        sout | "unsigned long int\t"            | 4ul | 3ul | "\tmin" | min( 4ul, 3ul );
    29         sout | "signed long long int\t"         | 4ll | -3ll | "\tmin" | min( 4ll, -3ll );
     29        sout | "signed long long int\t"         | 4ll | 3ll | "\tmin" | min( 4ll, 3ll );
    3030        sout | "unsigned long long int\t"       | 4ull | 3ull | "\tmin" | min( 4ull, 3ull );
    3131        sout | "float\t\t\t"                            | 4.0f | 3.1f | "\tmin" | min( 4.0f, 3.1f );
     
    3636
    3737        sout | "char\t\t\t"                                     | 'z' | ' ' | 'a' | "\tmax " | max( 'z', 'a' );
    38         sout | "signed int\t\t"                         | 4 | -3 | "\tmax" | max( 4, -3 );
     38        sout | "signed int\t\t"                         | 4 | 3 | "\tmax" | max( 4, 3 );
    3939        sout | "unsigned int\t\t"                       | 4u | 3u | "\tmax" | max( 4u, 3u );
    40         sout | "signed long int\t\t"            | 4l | -3l | "\tmax" | max( 4l, -3l );
     40        sout | "signed long int\t\t"            | 4l | 3l | "\tmax" | max( 4l, 3l );
    4141        sout | "unsigned long int\t"            | 4ul | 3ul | "\tmax" | max( 4ul, 3ul );
    42         sout | "signed long long int\t"         | 4ll | -3ll | "\tmax" | max( 4ll, -3ll );
     42        sout | "signed long long int\t"         | 4ll | 3ll | "\tmax" | max( 4ll, 3ll );
    4343        sout | "unsigned long long int\t"       | 4ull | 3ull | "\tmax" | max( 4ull, 3ull );
    4444        sout | "float\t\t\t"                            | 4.0f | 3.1f | "\tmax" | max( 4.0f, 3.1f );
  • tests/pybin/tools.py

    re67a82d r67ca73e  
    246246# transform path to canonical form
    247247def canonical_path(path):
    248         abspath = os.path.abspath(os.path.realpath(__main__.__file__))
     248        abspath = os.path.abspath(__main__.__file__)
    249249        dname = os.path.dirname(abspath)
    250250        return os.path.join(dname, os.path.normpath(path) )
  • tests/raii/.expect/ctor-autogen-ERR1.txt

    re67a82d r67ca73e  
    77        x: signed int
    88      ... returning nothing
    9 
    10       with resolved type:
    11         function
    12         ... with parameters
    13           _dst: reference to instance of struct Managed with body 1
    14           x: signed int
    15         ... returning nothing
    169
    1710      ... deleted by: ?{}: function
     
    3326
    3427
    35               with resolved type:
    36                 pointer to function
    37                 ... with parameters
    38                   intrinsic reference to signed int
    39                   intrinsic signed int
    40                 ... returning
    41                   _retval__operator_assign: signed int
    42                   ... with attributes:
    43                     Attribute with name: unused
    44 
    45 
    4628            ... to arguments
    4729              Generated Cast of:
     
    5133                  Generated Cast of:
    5234                    Variable Expression: m: reference to instance of struct Managed with body 1
    53                     with resolved type:
    54                       reference to instance of struct Managed with body 1
    5535                  ... to:
    5636                    instance of struct Managed with body 1
    57                   with resolved type:
    58                     instance of struct Managed with body 1
    59                 with resolved type:
    60                   signed int
    6137              ... to:
    62                 reference to signed int
    63               with resolved type:
    6438                reference to signed int
    6539              Generated Cast of:
    6640                constant expression (0 0: zero_t)
    67                 with resolved type:
    68                   zero_t
    6941              ... to:
    7042                signed int
    71               with resolved type:
    72                 signed int
    7343
    74             with resolved type:
    75               signed int
    7644            ... with environment:
    7745              Types:
     
    8250    Generated Cast of:
    8351      Variable Expression: x: instance of struct Managed with body 1
    84       with resolved type:
    85         instance of struct Managed with body 1
    8652    ... to:
    8753      reference to instance of struct Managed with body 1
    88     with resolved type:
    89       reference to instance of struct Managed with body 1
    9054    constant expression (123 123: signed int)
    91     with resolved type:
    92       signed int
    9355
    94   with resolved type:
    95     void
    9656... to: nothing
    97 with resolved type:
    98   void
  • tests/warnings/.expect/self-assignment.txt

    re67a82d r67ca73e  
    11warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Generated Cast of:
    22  Variable Expression: j: signed int
    3   with resolved type:
    4     signed int
    53... to:
    6   reference to signed int
    7 with resolved type:
    84  reference to signed int
    95warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Generated Cast of:
    106  Variable Expression: s: instance of struct S with body 1
    11   with resolved type:
    12     instance of struct S with body 1
    137... to:
    14   reference to instance of struct S with body 1
    15 with resolved type:
    168  reference to instance of struct S with body 1
    179warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Generated Cast of:
     
    2012  ... from aggregate:
    2113    Variable Expression: s: instance of struct S with body 1
    22     with resolved type:
    23       instance of struct S with body 1
    24   with resolved type:
    25     signed int
    2614... to:
    27   reference to signed int
    28 with resolved type:
    2915  reference to signed int
    3016warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Generated Cast of:
     
    3622    ... from aggregate:
    3723      Variable Expression: t: instance of struct T with body 1
    38       with resolved type:
    39         instance of struct T with body 1
    40     with resolved type:
    41       instance of struct S with body 1
    42   with resolved type:
    43     signed int
    4424... to:
    4525  reference to signed int
    46 with resolved type:
    47   reference to signed int
Note: See TracChangeset for help on using the changeset viewer.