Changeset 4c925cd


Ignore:
Timestamp:
Aug 14, 2020, 11:40:04 AM (3 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
5715d43, fa5e0112
Parents:
309d814 (diff), badd22f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Files:
8 added
76 edited

Legend:

Unmodified
Added
Removed
  • configure.ac

    r309d814 r4c925cd  
    2424#Trasforming cc1 will break compilation
    2525M4CFA_PROGRAM_NAME
     26
     27#==============================================================================
     28# New AST toggling support
     29AH_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])
     30AC_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])
     37AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
    2638
    2739#==============================================================================
  • driver/cc1.cc

    r309d814 r4c925cd  
    1010// Created On       : Fri Aug 26 14:23:51 2005
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 30 18:09:05 2020
    13 // Update Count     : 404
     12// Last Modified On : Thu Aug 13 21:03:15 2020
     13// Update Count     : 407
    1414//
    1515
     
    170170                        if ( arg == "-quiet" ) {
    171171                        } else if ( arg == "-imultilib" || arg == "-imultiarch" ) {
    172                                 i += 1;                                                                 // and the argument
     172                                i += 1;                                                                 // and argument
    173173                        } else if ( prefix( arg, "-A" ) ) {
    174174                        } else if ( prefix( arg, "-D__GNU" ) ) {
     
    177177                                //********
    178178                        } else if ( arg == "-D" && prefix( argv[i + 1], "__GNU" ) ) {
    179                                 i += 1;                                                                 // and the argument
     179                                i += 1;                                                                 // and argument
    180180
    181181                                // strip flags controlling cpp step
     
    184184                                cpp_flag = true;
    185185                        } else if ( arg == "-D" && string( argv[i + 1] ) == "__CPP__" ) {
    186                                 i += 1;                                                                 // and the argument
     186                                i += 1;                                                                 // and argument
    187187                                cpp_flag = true;
    188188
     
    194194                                cpp_out = argv[i];
    195195                        } else {
    196                                 args[nargs++] = argv[i];                                // pass the flag along
     196                                args[nargs++] = argv[i];                                // pass flag along
    197197                                // CPP flags with an argument
    198198                                if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
     
    200200                                         arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
    201201                                        i += 1;
    202                                         args[nargs++] = argv[i];                        // pass the argument along
     202                                        args[nargs++] = argv[i];                        // pass argument along
    203203                                        #ifdef __DEBUG_H__
    204204                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
    205205                                        #endif // __DEBUG_H__
    206206                                } else if ( arg == "-MD" || arg == "-MMD" ) {
     207                                        // gcc frontend generates the dependency file-name after the -MD/-MMD flag, but it is necessary to
     208                                        // prefix that file name with -MF.
    207209                                        args[nargs++] = "-MF";                          // insert before file
    208210                                        i += 1;
    209                                         args[nargs++] = argv[i];                        // pass the argument along
     211                                        args[nargs++] = argv[i];                        // pass argument along
    210212                                        #ifdef __DEBUG_H__
    211213                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
     
    279281        // Run the C preprocessor and save the output in the given file.
    280282
    281         if ( fork() == 0 ) {                                                             // child process ?
     283        if ( fork() == 0 ) {                                                            // child process ?
    282284                // -o xxx.ii cannot be used to write the output file from cpp because no output file is created if cpp detects
    283285                // an error (e.g., cannot find include file). Whereas, output is always generated, even when there is an error,
     
    388390
    389391                        } else {
    390                                 args[nargs++] = argv[i];                                // pass the flag along
     392                                args[nargs++] = argv[i];                                // pass flag along
    391393                                if ( arg == "-o" ) {
    392394                                        i += 1;
    393395                                        cpp_out = argv[i];
    394                                         args[nargs++] = argv[i];                        // pass the argument along
     396                                        args[nargs++] = argv[i];                        // pass argument along
    395397                                        #ifdef __DEBUG_H__
    396398                                        cerr << "arg:\"" << argv[i] << "\"" << endl;
  • driver/cfa.cc

    r309d814 r4c925cd  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 30 18:28:23 2020
    13 // Update Count     : 433
     12// Last Modified On : Thu Aug 13 17:22:02 2020
     13// Update Count     : 435
    1414//
    1515
     
    180180
    181181                        if ( arg == "-Xlinker" || arg == "-o" ) {
    182                                 args[nargs++] = argv[i];                                // pass argument along
     182                                args[nargs++] = argv[i];                                // pass flag along
    183183                                i += 1;
    184184                                if ( i == argc ) continue;                              // next argument available ?
    185185                                args[nargs++] = argv[i];                                // pass argument along
    186186                                if ( arg == "-o" ) o_file = i;                  // remember file
    187                         } else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) {                           // CFA pass through
    188                                 if(arg.size() == 5) {
     187                        } else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) { // CFA pass through
     188                                if ( arg.size() == 5 ) {
    189189                                        i += 1;
    190                                         if ( i == argc ) continue;                              // next argument available ?
     190                                        if ( i == argc ) continue;                      // next argument available ?
    191191                                        Putenv( argv, argv[i] );
    192 
    193                                         // CFA specific arguments
    194                                 }
    195                                 else if(arg[5] == ',') {
     192                                } else if ( arg[5] == ',' ) {                   // CFA specific arguments
    196193                                        Putenv( argv, argv[i] + 6 );
    197 
    198                                         // CFA specific arguments
    199                                 }
    200                                 else {
     194                                } else {                                                                // CFA specific arguments
    201195                                        args[nargs++] = argv[i];
    202                                 }
    203 
     196                                } // if
    204197                        } else if ( arg == "-CFA" ) {
    205198                                CFA_flag = true;                                                // strip the -CFA flag
     
    235228                        } else if ( arg == "-v" ) {
    236229                                verbose = true;                                                 // verbosity required
    237                                 args[nargs++] = argv[i];                                // pass argument along
     230                                args[nargs++] = argv[i];                                // pass flag along
    238231                        } else if ( arg == "-g" ) {
    239232                                debugging = true;                                               // symbolic debugging required
    240                                 args[nargs++] = argv[i];                                // pass argument along
     233                                args[nargs++] = argv[i];                                // pass flag along
    241234                        } else if ( arg == "-save-temps" ) {
    242                                 args[nargs++] = argv[i];                                // pass argument along
     235                                args[nargs++] = argv[i];                                // pass flag along
    243236                                Putenv( argv, arg );                                    // save cfa-cpp output
    244237                        } else if ( prefix( arg, "-x" ) ) {                     // file suffix ?
    245238                                string lang;
    246                                 args[nargs++] = argv[i];                                // pass argument along
     239                                args[nargs++] = argv[i];                                // pass flag along
    247240                                if ( arg.length() == 2 ) {                              // separate argument ?
    248241                                        i += 1;
     
    261254                        } else if ( prefix( arg, "-std=" ) || prefix( arg, "--std=" ) ) {
    262255                                std_flag = true;                                                // -std=XX provided
    263                                 args[nargs++] = argv[i];                                // pass argument along
     256                                args[nargs++] = argv[i];                                // pass flag along
    264257                        } else if ( arg == "-w" ) {
    265                                 args[nargs++] = argv[i];                                // pass argument along
     258                                args[nargs++] = argv[i];                                // pass flag along
    266259                                Putenv( argv, arg );
    267260                        } else if ( prefix( arg, "-W" ) ) {                     // check before next tests
    268261                                if ( arg == "-Werror" || arg == "-Wall" ) {
    269                                         args[nargs++] = argv[i];                        // pass argument along
     262                                        args[nargs++] = argv[i];                        // pass flag along
    270263                                        Putenv( argv, argv[i] );
    271264                                } else {
     
    281274                                bprefix = arg.substr(2);                                // strip the -B flag
    282275                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    283                                 args[nargs++] = argv[i];                                // pass argument along
     276                                args[nargs++] = argv[i];                                // pass flag along
    284277                                if ( arg == "-E" || arg == "-M" || arg == "-MM" ) {
    285278                                        cpp_flag = true;                                        // cpp only
    286279                                } // if
    287280                                link = false;                           // no linkage required
     281                        } else if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
     282                                                arg == "-include" || arg == "-imacros" || arg == "-idirafter" || arg == "-iprefix" ||
     283                                                arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
     284                                args[nargs++] = argv[i];                                // pass flag along
     285                                i += 1;
     286                                args[nargs++] = argv[i];                                // pass argument along
    288287                        } else if ( arg[1] == 'l' ) {
    289288                                // if the user specifies a library, load it after user code
  • libcfa/src/Makefile.am

    r309d814 r4c925cd  
    4444
    4545headers = common.hfa fstream.hfa heap.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa \
    46                 time.hfa stdlib.hfa memory.hfa parseargs.hfa \
     46                time.hfa stdlib.hfa parseargs.hfa \
    4747                containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
    4848
  • libcfa/src/concurrency/invoke.h

    r309d814 r4c925cd  
    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        };
    2835
    2936        struct __stack_context_t {
     
    5158                // base of stack
    5259                void * base;
     60
     61                // Information for exception handling.
     62                struct exception_context_t exception_context;
    5363        };
    5464
     
    8494        };
    8595
    86         static inline struct __stack_t * __get_stack( struct $coroutine * cor ) { return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2)); }
     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        }
    8799
    88100        // struct which calls the monitor is accepting
  • libcfa/src/concurrency/kernel/startup.cfa

    r309d814 r4c925cd  
    516516        ( this.terminated ){ 0 };
    517517        ( this.runner ){};
    518         init( this, name, _cltr );
     518
     519        disable_interrupts();
     520                init( this, name, _cltr );
     521        enable_interrupts( __cfaabi_dbg_ctx );
    519522
    520523        __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this);
     
    540543        free( this.stack );
    541544
    542         deinit( this );
     545        disable_interrupts();
     546                deinit( this );
     547        enable_interrupts( __cfaabi_dbg_ctx );
    543548}
    544549
  • libcfa/src/concurrency/ready_queue.cfa

    r309d814 r4c925cd  
    150150//  queues or removing them.
    151151uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
     152        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     153
    152154        // Step 1 : lock global lock
    153155        // It is needed to avoid processors that register mid Critical-Section
     
    164166        }
    165167
     168        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    166169        return s;
    167170}
    168171
    169172void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
     173        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     174
    170175        // Step 1 : release local locks
    171176        // This must be done while the global lock is held to avoid
     
    182187        /*paranoid*/ assert(true == lock);
    183188        __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
     189
     190        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    184191}
    185192
     
    419426        // Actually pop the list
    420427        struct $thread * thrd;
    421         bool emptied;
    422         [thrd, emptied] = pop(lane);
     428        thrd = pop(lane);
    423429
    424430        /* paranoid */ verify(thrd);
     
    457463                        if(head(lane)->link.next == thrd) {
    458464                                $thread * pthrd;
    459                                 bool emptied;
    460                                 [pthrd, emptied] = pop(lane);
     465                                pthrd = pop(lane);
    461466
    462467                                /* paranoid */ verify( pthrd == thrd );
     
    608613                        while(!is_empty(lanes.data[idx])) {
    609614                                struct $thread * thrd;
    610                                 __attribute__((unused)) bool _;
    611                                 [thrd, _] = pop(lanes.data[idx]);
     615                                thrd = pop(lanes.data[idx]);
    612616
    613617                                push(cltr, thrd);
  • libcfa/src/concurrency/ready_subqueue.hfa

    r309d814 r4c925cd  
    144144// returns popped
    145145// returns true of lane was empty before push, false otherwise
    146 [$thread *, bool] pop(__intrusive_lane_t & this) {
     146$thread * 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, prev] = 0p;
     164        node->link.next = 0p;
     165        node->link.prev = 0p;
    165166
    166167        // Update head time stamp
     
    180181                /* paranoid */ verify(tail(this)->link.prev == head(this));
    181182                /* paranoid */ verify(head(this)->link.next == tail(this));
    182                 return [node, true];
     183                return node;
    183184        }
    184185        else {
     
    187188                /* paranoid */ verify(head(this)->link.next != tail(this));
    188189                /* paranoid */ verify(this.before.link.ts != 0);
    189                 return [node, false];
     190                return node;
    190191        }
    191192}
  • libcfa/src/exception.c

    r309d814 r4c925cd  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr May 21 12:18:00 2020
    13 // Update Count     : 20
     12// Last Modified On : Wed Aug 12 13:55:00 2020
     13// Update Count     : 21
    1414//
    1515
     
    2828#include <unwind.h>
    2929#include <bits/debug.hfa>
     30#include "concurrency/invoke.h"
    3031#include "stdhdr/assert.h"
    3132
     
    5960
    6061// Temperary global exception context. Does not work with concurency.
    61 struct exception_context_t {
    62         struct __cfaehm_try_resume_node * top_resume;
    63 
    64         exception_t * current_exception;
    65         int current_handler_index;
    66 } static shared_stack = {NULL, NULL, 0};
     62static struct exception_context_t shared_stack = {NULL, NULL};
    6763
    6864// Get the current exception context.
     
    122118
    123119// MEMORY MANAGEMENT =========================================================
     120
     121struct __cfaehm_node {
     122        struct _Unwind_Exception unwind_exception;
     123        struct __cfaehm_node * next;
     124        int handler_index;
     125};
     126
     127#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
     128#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
     129#define UNWIND_TO_NODE(unwind) ((struct __cfaehm_node *)(unwind))
     130#define NULL_MAP(map, ptr) ((ptr) ? (map(ptr)) : NULL)
    124131
    125132// How to clean up an exception in various situations.
     
    137144}
    138145
    139 // We need a piece of storage to raise the exception, for now its a single
    140 // piece.
    141 static struct _Unwind_Exception this_exception_storage;
    142 
    143 struct __cfaehm_node {
    144         struct __cfaehm_node * next;
    145 };
    146 
    147 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    148 #define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
    149 
    150146// Creates a copy of the indicated exception and sets current_exception to it.
    151147static void __cfaehm_allocate_exception( exception_t * except ) {
     
    161157        }
    162158
     159        // Initialize the node:
     160        exception_t * except_store = NODE_TO_EXCEPT(store);
     161        store->unwind_exception.exception_class = __cfaehm_exception_class;
     162        store->unwind_exception.exception_cleanup = __cfaehm_exception_cleanup;
     163        store->handler_index = 0;
     164        except->virtual_table->copy( except_store, except );
     165
    163166        // Add the node to the list:
    164         store->next = EXCEPT_TO_NODE(context->current_exception);
    165         context->current_exception = NODE_TO_EXCEPT(store);
    166 
    167         // Copy the exception to storage.
    168         except->virtual_table->copy( context->current_exception, except );
    169 
    170         // Set up the exception storage.
    171         this_exception_storage.exception_class = __cfaehm_exception_class;
    172         this_exception_storage.exception_cleanup = __cfaehm_exception_cleanup;
     167        store->next = NULL_MAP(EXCEPT_TO_NODE, context->current_exception);
     168        context->current_exception = except_store;
    173169}
    174170
     
    185181        if ( context->current_exception == except ) {
    186182                node = to_free->next;
    187                 context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;
     183                context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node);
    188184        } else {
    189185                node = EXCEPT_TO_NODE(context->current_exception);
     
    213209        // Verify actions follow the rules we expect.
    214210        verify((actions & _UA_CLEANUP_PHASE) && (actions & _UA_FORCE_UNWIND));
    215         verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDER_FRAME)));
     211        verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME)));
    216212
    217213        if ( actions & _UA_END_OF_STACK ) {
     
    222218}
    223219
     220static struct _Unwind_Exception cancel_exception_storage;
     221
    224222// Cancel the current stack, prefroming approprate clean-up and messaging.
    225223void __cfaehm_cancel_stack( exception_t * exception ) {
    226224        // TODO: Detect current stack and pick a particular stop-function.
    227225        _Unwind_Reason_Code ret;
    228         ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
     226        ret = _Unwind_ForcedUnwind( &cancel_exception_storage, _Stop_Fn, (void*)0x22 );
    229227        printf("UNWIND ERROR %d after force unwind\n", ret);
    230228        abort();
     
    247245static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) {
    248246        struct exception_context_t * context = this_exception_context();
    249         struct _Unwind_Exception * storage = &this_exception_storage;
    250247        if ( NULL == context->current_exception ) {
    251248                printf("UNWIND ERROR missing exception in begin unwind\n");
    252249                abort();
    253250        }
     251        struct _Unwind_Exception * storage =
     252                &EXCEPT_TO_NODE(context->current_exception)->unwind_exception;
    254253
    255254        // Call stdlibc to raise the exception
     
    419418                                _Unwind_Reason_Code ret = (0 == index)
    420419                                        ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    421                                 context->current_handler_index = index;
     420                                UNWIND_TO_NODE(unwind_exception)->handler_index = index;
    422421
    423422                                // Based on the return value, check if we matched the exception
     
    425424                                        __cfadbg_print_safe(exception, " handler found\n");
    426425                                } else {
     426                                        // TODO: Continue the search if there is more in the table.
    427427                                        __cfadbg_print_safe(exception, " no handler\n");
    428428                                }
     
    516516        // Exception handler
    517517        // Note: Saving the exception context on the stack breaks termination exceptions.
    518         catch_block( this_exception_context()->current_handler_index,
     518        catch_block( EXCEPT_TO_NODE( this_exception_context()->current_exception )->handler_index,
    519519                     this_exception_context()->current_exception );
    520520}
  • libcfa/src/iostream.cfa

    r309d814 r4c925cd  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 10 09:32:14 2020
    13 // Update Count     : 1126
     12// Last Modified On : Tue Aug 11 22:16:33 2020
     13// Update Count     : 1128
    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 
    5739        ostype & ?|?( ostype & os, bool b ) {
    5840                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
  • libcfa/src/iostream.hfa

    r309d814 r4c925cd  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 16 07:43:32 2020
    13 // Update Count     : 348
     12// Last Modified On : Tue Aug 11 22:16:14 2020
     13// Update Count     : 350
    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 
    7469        ostype & ?|?( ostype &, bool );
    7570        void ?|?( ostype &, bool );
  • libcfa/src/stdlib.hfa

    r309d814 r4c925cd  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 30 16:14:58 2020
    13 // Update Count     : 490
     12// Last Modified On : Tue Aug 11 21:11:46 2020
     13// Update Count     : 495
    1414//
    1515
     
    136136        T * alloc_set( char fill ) {
    137137                return (T *)memset( (T *)alloc(), (int)fill, sizeof(T) ); // initialize with fill value
    138         } // alloc
    139 
    140         T * alloc_set( T fill ) {
     138        } // alloc_set
     139
     140        T * alloc_set( const T & fill ) {
    141141                return (T *)memcpy( (T *)alloc(), &fill, sizeof(T) ); // initialize with fill value
    142         } // alloc
     142        } // alloc_set
    143143
    144144        T * alloc_set( size_t dim, char fill ) {
    145145                return (T *)memset( (T *)alloc( dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
    146         } // alloc
    147 
    148         T * alloc_set( size_t dim, T fill ) {
     146        } // alloc_set
     147
     148        T * alloc_set( size_t dim, const T & fill ) {
    149149                T * r = (T *)alloc( dim );
    150150                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
    151151                return r;
    152         } // alloc
     152        } // alloc_set
    153153
    154154        T * alloc_set( size_t dim, const T fill[] ) {
    155155                return (T *)memcpy( (T *)alloc( dim ), fill, dim * sizeof(T) ); // initialize with fill value
    156         } // alloc
     156        } // alloc_set
    157157
    158158        T * alloc_set( T ptr[], size_t dim, char fill ) {       // realloc array with fill
     
    166166        } // alloc_set
    167167
    168         T * alloc_set( T ptr[], size_t dim, T & fill ) {        // realloc array with fill
     168        T * alloc_set( T ptr[], size_t dim, const T & fill ) {  // realloc array with fill
    169169                size_t odim = malloc_size( ptr ) / sizeof(T);   // current dimension
    170170                size_t nsize = dim * sizeof(T);                                 // new allocation
     
    177177                } // if
    178178                return nptr;
    179         } // alloc_align_set
     179        } // alloc_set
    180180} // distribution
    181181
     
    204204        T * alloc_align_set( size_t align, char fill ) {
    205205                return (T *)memset( (T *)alloc_align( align ), (int)fill, sizeof(T) ); // initialize with fill value
    206         } // alloc_align
    207 
    208         T * alloc_align_set( size_t align, T fill ) {
     206        } // alloc_align_set
     207
     208        T * alloc_align_set( size_t align, const T & fill ) {
    209209                return (T *)memcpy( (T *)alloc_align( align ), &fill, sizeof(T) ); // initialize with fill value
    210         } // alloc_align
     210        } // alloc_align_set
    211211
    212212        T * alloc_align_set( size_t align, size_t dim, char fill ) {
    213213                return (T *)memset( (T *)alloc_align( align, dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
    214         } // alloc_align
    215 
    216         T * alloc_align_set( size_t align, size_t dim, T fill ) {
     214        } // alloc_align_set
     215
     216        T * alloc_align_set( size_t align, size_t dim, const T & fill ) {
    217217                T * r = (T *)alloc_align( align, dim );
    218218                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
    219219                return r;
    220         } // alloc_align
     220        } // alloc_align_set
    221221
    222222        T * alloc_align_set( size_t align, size_t dim, const T fill[] ) {
    223223                return (T *)memcpy( (T *)alloc_align( align, dim ), fill, dim * sizeof(T) );
    224         } // alloc_align
     224        } // alloc_align_set
    225225
    226226        T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ) {
     
    234234        } // alloc_align_set
    235235
    236         T * alloc_align_set( T ptr[], size_t align, size_t dim, T & fill ) {
     236        T * alloc_align_set( T ptr[], size_t align, size_t dim, const T & fill ) {
    237237                size_t odim = malloc_size( ptr ) / sizeof(T);   // current dimension
    238238                size_t nsize = dim * sizeof(T);                                 // new allocation
  • src/AST/Attribute.hpp

    r309d814 r4c925cd  
    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);
    5355};
    5456
  • src/AST/CVQualifiers.hpp

    r309d814 r4c925cd  
    2727                Restrict = 1 << 1,
    2828                Volatile = 1 << 2,
    29                 Lvalue   = 1 << 3,
    30                 Mutex    = 1 << 4,
    31                 Atomic   = 1 << 5,
    32                 NumQualifiers = 6
     29                Mutex    = 1 << 3,
     30                Atomic   = 1 << 4,
     31                NumQualifiers = 5
    3332        };
    3433
    3534        /// Mask for equivalence-preserving qualfiers
    36         enum { EquivQualifiers = ~(Restrict | Lvalue) };
     35        enum { EquivQualifiers = ~Restrict };
    3736
    3837        /// Underlying data for qualifiers
     
    4443                                bool is_restrict : 1;
    4544                                bool is_volatile : 1;
    46                                 bool is_lvalue   : 1;
    4745                                bool is_mutex    : 1;
    4846                                bool is_atomic   : 1;
  • src/AST/Convert.cpp

    r309d814 r4c925cd  
    2020
    2121#include "AST/Attribute.hpp"
     22#include "AST/Copy.hpp"
    2223#include "AST/Decl.hpp"
    2324#include "AST/Expr.hpp"
     
    587588                assert( tgtResnSlots.empty() );
    588589
    589                 if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
     590                if ( srcInferred.data.inferParams ) {
    590591                        const ast::InferredParams &srcParams = srcInferred.inferParams();
    591592                        for (auto & srcParam : srcParams) {
     
    593594                                        srcParam.second.decl,
    594595                                        get<Declaration>().accept1(srcParam.second.declptr),
    595                                         get<Type>().accept1(srcParam.second.actualType),
    596                                         get<Type>().accept1(srcParam.second.formalType),
    597                                         get<Expression>().accept1(srcParam.second.expr)
     596                                        get<Type>().accept1(srcParam.second.actualType)->clone(),
     597                                        get<Type>().accept1(srcParam.second.formalType)->clone(),
     598                                        get<Expression>().accept1(srcParam.second.expr)->clone()
    598599                                ));
    599600                                assert(res.second);
    600601                        }
    601                 } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
     602                }
     603                if ( srcInferred.data.resnSlots ) {
    602604                        const ast::ResnSlots &srcSlots = srcInferred.resnSlots();
    603605                        for (auto srcSlot : srcSlots) {
     
    620622
    621623                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                }
    622635                return visitBaseExpr_skipResultType(src, tgt);
    623636        }
     
    979992
    980993        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                }
    981999                auto rslt = new StmtExpr(
    982                         get<CompoundStmt>().accept1(node->stmts)
     1000                        get<CompoundStmt>().accept1(stmts)
    9831001                );
    9841002
     
    19862004
    19872005                assert( oldInferParams.empty() || oldResnSlots.empty() );
    1988                 assert( newInferred.mode == ast::Expr::InferUnion::Empty );
     2006                // assert( newInferred.mode == ast::Expr::InferUnion::Empty );
    19892007
    19902008                if ( !oldInferParams.empty() ) {
     
    21172135                                old->location,
    21182136                                GET_ACCEPT_1(member, DeclWithType),
    2119                                 GET_ACCEPT_1(aggregate, Expr)
     2137                                GET_ACCEPT_1(aggregate, Expr),
     2138                                ast::MemberExpr::NoOpConstructionChosen
    21202139                        )
    21212140                );
  • src/AST/Decl.cpp

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

    r309d814 r4c925cd  
    3333
    3434// Must be included in *all* AST classes; should be #undef'd at the end of the file
    35 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     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);
    3638
    3739namespace ast {
     
    8890        virtual const Type * get_type() const = 0;
    8991        /// Set type of this declaration. May be verified by subclass
    90         virtual void set_type(Type *) = 0;
     92        virtual void set_type( const Type * ) = 0;
    9193
    9294        const DeclWithType * accept( Visitor & v ) const override = 0;
     
    111113
    112114        const Type* get_type() const override { return type; }
    113         void set_type( Type * ty ) override { type = ty; }
     115        void set_type( const Type * ty ) override { type = ty; }
    114116
    115117        const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
     
    133135
    134136        const Type * get_type() const override;
    135         void set_type(Type * t) override;
     137        void set_type( const Type * t ) override;
    136138
    137139        bool has_body() const { return stmts; }
     
    150152        std::vector<ptr<DeclWithType>> assertions;
    151153
    152         NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
    153                 Type* b, Linkage::Spec spec = Linkage::Cforall )
     154        NamedTypeDecl(
     155                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     156                const Type * b, Linkage::Spec spec = Linkage::Cforall )
    154157        : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
    155158
     
    186189        };
    187190
    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 ) {}
     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 ) {}
    192196
    193197        const char * typeString() const override;
  • src/AST/Expr.cpp

    r309d814 r4c925cd  
    2020#include <vector>
    2121
     22#include "Copy.hpp"                // for shallowCopy
     23#include "Eval.hpp"                // for call
    2224#include "GenericSubstitution.hpp"
     25#include "LinkageSpec.hpp"
    2326#include "Stmt.hpp"
    2427#include "Type.hpp"
     
    2730#include "Common/SemanticError.h"
    2831#include "GenPoly/Lvalue.h"        // for referencesPermissable
    29 #include "InitTweak/InitTweak.h"   // for getPointerBase
     32#include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
    3033#include "ResolvExpr/typeops.h"    // for extractResultType
    3134#include "Tuples/Tuples.h"         // for makeTupleType
    3235
    3336namespace ast {
     37
     38namespace {
     39        std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
     40}
     41
     42// --- Expr
     43bool Expr::get_lvalue() const {
     44        return false;
     45}
    3446
    3547// --- ApplicationExpr
     
    4658}
    4759
     60bool 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
    4867// --- UntypedExpr
    4968
     
    5170        assert( arg );
    5271
    53         UntypedExpr * ret = new UntypedExpr{
    54                 loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
    55         };
     72        UntypedExpr * ret = call( loc, "*?", arg );
    5673        if ( const Type * ty = arg->result ) {
    5774                const Type * base = InitTweak::getPointerBase( ty );
     
    6582                        // base type
    6683                        ret->result = base;
    67                         add_qualifiers( ret->result, CV::Lvalue );
    6884                }
    6985        }
    7086        return ret;
     87}
     88
     89bool UntypedExpr::get_lvalue() const {
     90        std::string fname = InitTweak::getFunctionName( this );
     91        return lvalueFunctionNames.count( fname );
    7192}
    7293
     
    7495        assert( lhs && rhs );
    7596
    76         UntypedExpr * ret = new UntypedExpr{
    77                 loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
    78         };
     97        UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
    7998        if ( lhs->result && rhs->result ) {
    8099                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    108127AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
    109128        if ( arg->result ) {
    110                 if ( arg->result->is_lvalue() ) {
     129                if ( arg->get_lvalue() ) {
    111130                        // lvalue, retains all levels of reference, and gains a pointer inside the references
    112131                        Type * res = addrType( arg->result );
    113                         res->set_lvalue( false ); // result of & is never an lvalue
    114132                        result = res;
    115133                } else {
     
    118136                                        dynamic_cast< const ReferenceType * >( arg->result.get() ) ) {
    119137                                Type * res = addrType( refType->base );
    120                                 res->set_lvalue( false ); // result of & is never an lvalue
    121138                                result = res;
    122139                        } else {
     
    139156: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
    140157
     158bool 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
    141163// --- KeywordCastExpr
    142164
    143165const char * KeywordCastExpr::targetString() const {
    144166        return AggregateDecl::aggrString( target );
     167}
     168
     169// --- UntypedMemberExpr
     170
     171bool UntypedMemberExpr::get_lvalue() const {
     172        return aggregate->get_lvalue();
    145173}
    146174
     
    153181        assert( aggregate->result );
    154182
    155         // take ownership of member type
    156         result = mem->get_type();
     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
    157220        // substitute aggregate generic parameters into member type
    158221        genericSubstitution( aggregate->result ).apply( result );
    159         // ensure lvalue and appropriate restrictions from aggregate type
    160         add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue );
     222        // ensure appropriate restrictions from aggregate type
     223        add_qualifiers( result, aggregate->result->qualifiers );
     224}
     225
     226MemberExpr::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
     235bool MemberExpr::get_lvalue() const {
     236        // This is actually wrong by C, but it works with our current set-up.
     237        return true;
    161238}
    162239
     
    170247        assert( var );
    171248        assert( var->get_type() );
    172         result = var->get_type();
    173         add_qualifiers( result, CV::Lvalue );
     249        result = shallowCopy( var->get_type() );
     250}
     251
     252bool VariableExpr::get_lvalue() const {
     253        // It isn't always an lvalue, but it is never an rvalue.
     254        return true;
    174255}
    175256
     
    258339: Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
    259340
     341// --- CommaExpr
     342bool 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}
     347
    260348// --- ConstructorExpr
    261349
     
    276364        assert( t && i );
    277365        result = t;
    278         add_qualifiers( result, CV::Lvalue );
     366}
     367
     368bool CompoundLiteralExpr::get_lvalue() const {
     369        return true;
    279370}
    280371
     
    293384        // like MemberExpr, TupleIndexExpr is always an lvalue
    294385        result = type->types[ index ];
    295         add_qualifiers( result, CV::Lvalue );
     386}
     387
     388bool TupleIndexExpr::get_lvalue() const {
     389        return tuple->get_lvalue();
    296390}
    297391
  • src/AST/Expr.hpp

    r309d814 r4c925cd  
    3131
    3232// Must be included in *all* AST classes; should be #undef'd at the end of the file
    33 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     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
    3437
    3538class ConverterOldToNew;
     
    4245struct ParamEntry {
    4346        UniqueId decl;
    44         ptr<Decl> declptr;
     47        readonly<Decl> declptr;
    4548        ptr<Type> actualType;
    4649        ptr<Type> formalType;
     
    6265class Expr : public ParseNode {
    6366public:
    64         /// Saves space (~16 bytes) by combining ResnSlots and InferredParams
     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         */
    6573        struct InferUnion {
     74                // mode is now unused
    6675                enum { Empty, Slots, Params } mode;
    67                 union data_t {
    68                         char def;
    69                         ResnSlots resnSlots;
    70                         InferredParams inferParams;
    71 
    72                         data_t() : def('\0') {}
    73                         ~data_t() {}
     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                        }
    7487                } data;
    7588
    7689                /// initializes from other InferUnion
    7790                void init_from( const InferUnion& o ) {
    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;
     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);
    8296                        }
    8397                }
     
    8599                /// initializes from other InferUnion (move semantics)
    86100                void init_from( InferUnion&& o ) {
    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                         }
     101                        data.resnSlots = o.data.resnSlots;
     102                        data.inferParams = o.data.inferParams;
     103                        o.data.resnSlots = nullptr;
     104                        o.data.inferParams = nullptr;
    102105                }
    103106
     
    107110                InferUnion& operator= ( const InferUnion& ) = delete;
    108111                InferUnion& operator= ( InferUnion&& ) = delete;
    109                 ~InferUnion() { reset(); }
     112
     113                bool hasSlots() const { return data.resnSlots; }
    110114
    111115                ResnSlots& 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();
     116                        if (!data.resnSlots) {
     117                                data.resnSlots = new ResnSlots();
    116118                        }
    117                         assertf(false, "unreachable");
     119                        return *data.resnSlots;
    118120                }
    119121
    120122                const ResnSlots& resnSlots() const {
    121                         if (mode == Slots) {
    122                                 return data.resnSlots;
     123                        if (data.resnSlots) {
     124                                return *data.resnSlots;
    123125                        }
    124126                        assertf(false, "Mode was not already resnSlots");
     
    127129
    128130                InferredParams& inferParams() {
    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;
     131                        if (!data.inferParams) {
     132                                data.inferParams = new InferredParams();
    133133                        }
    134                         assertf(false, "unreachable");
     134                        return *data.inferParams;
    135135                }
    136136
    137137                const InferredParams& inferParams() const {
    138                         if (mode == Params) {
    139                                 return data.inferParams;
     138                        if (data.inferParams) {
     139                                return *data.inferParams;
    140140                        }
    141141                        assertf(false, "Mode was not already Params");
     
    143143                }
    144144
    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                         }
     145                void set_inferParams( InferredParams * ps ) {
     146                        delete data.resnSlots;
     147                        data.resnSlots = nullptr;
     148                        delete data.inferParams;
     149                        data.inferParams = ps;
    158150                }
    159151
     
    161153                /// and the other is in `Params`.
    162154                void splice( InferUnion && o ) {
    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);
     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;
    173160                                }
    174                         } else assertf(false, "invalid mode");
     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                        }
    175179                }
    176180        };
     
    185189
    186190        Expr * set_extension( bool ex ) { extension = ex; return this; }
     191        virtual bool get_lvalue() const;
    187192
    188193        virtual const Expr * accept( Visitor & v ) const override = 0;
     
    201206        ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} );
    202207
     208        bool get_lvalue() const final;
     209
    203210        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    204211private:
     
    215222        UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} )
    216223        : Expr( loc ), func( f ), args( std::move(as) ) {}
     224
     225        bool get_lvalue() const final;
    217226
    218227        /// Creates a new dereference expression
     
    291300        CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
    292301
     302        bool get_lvalue() const final;
     303
    293304        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    294305private:
     
    338349        : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); }
    339350
     351        bool get_lvalue() const final;
     352
    340353        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    341354private:
     
    352365        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg );
    353366
     367        bool get_lvalue() const final;
     368
    354369        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    355370private:
    356371        MemberExpr * clone() const override { return new MemberExpr{ *this }; }
    357372        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;
    358380};
    359381
     
    365387        VariableExpr( const CodeLocation & loc );
    366388        VariableExpr( const CodeLocation & loc, const DeclWithType * v );
     389
     390        bool get_lvalue() const final;
    367391
    368392        /// generates a function pointer for a given function
     
    532556
    533557        CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 )
    534         : Expr( loc ), arg1( a1 ), arg2( a2 ) {}
     558        : Expr( loc ), arg1( a1 ), arg2( a2 ) {
     559                this->result = a2->result;
     560        }
     561
     562        bool get_lvalue() const final;
    535563
    536564        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    605633        CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
    606634
     635        bool get_lvalue() const final;
     636
    607637        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    608638private:
     
    660690
    661691        TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
     692
     693        bool get_lvalue() const final;
    662694
    663695        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

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

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

    r309d814 r4c925cd  
    2525
    2626// Must be included in *all* AST classes; should be #undef'd at the end of the file
    27 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     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);
    2830
    2931namespace ast {
  • src/AST/Node.cpp

    r309d814 r4c925cd  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jun  5 10:21:00 2020
     13// Update Count     : 1
    1414//
    1515
     
    1717#include "Fwd.hpp"
    1818
     19#include <csignal>  // MEMORY DEBUG -- for raise
    1920#include <iostream>
    2021
     
    2930#include "Print.hpp"
    3031
    31 template< typename node_t, enum ast::Node::ref_type ref_t >
    32 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
    33 
    34 template< typename node_t, enum ast::Node::ref_type ref_t >
    35 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
    36 
    37 template< typename node_t, enum ast::Node::ref_type ref_t >
    38 void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
     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
     39void * MEM_TRAP_OBJ = nullptr;
     40
     41void _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
     58template< typename node_t, enum ast::Node::ref_type ref_t >
     59void ast::ptr_base<node_t, ref_t>::_strict_fail() const {
     60        strict_fail(node);
     61}
     62
     63template< typename node_t, enum ast::Node::ref_type ref_t >
     64void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
     65        node->increment(ref_t);
     66        _trap( node );
     67}
     68
     69template< typename node_t, enum ast::Node::ref_type ref_t >
     70void 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
     75template< typename node_t, enum ast::Node::ref_type ref_t >
     76void ast::ptr_base<node_t, ref_t>::_check() const {
     77        // if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
     78}
    3979
    4080template< typename node_t, enum ast::Node::ref_type ref_t >
  • src/AST/Node.hpp

    r309d814 r4c925cd  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun  3 13:26:00 2019
    13 // Update Count     : 5
     12// Last Modified On : Fri Jun 5 9:47:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    3838        Node& operator= (const Node&) = delete;
    3939        Node& operator= (Node&&) = delete;
    40         virtual ~Node() = default;
     40        virtual ~Node() {}
    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);
    5961
    6062        mutable size_t strong_count = 0;
     
    6971        }
    7072
    71         void decrement(ast::Node::ref_type ref) const {
     73        void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
    7274                switch (ref) {
    7375                        case ref_type::strong: strong_count--; break;
     
    7577                }
    7678
    77                 if(!strong_count && !weak_count) {
     79                if( do_delete && !strong_count && !weak_count) {
    7880                        delete this;
    7981                }
     
    9496        assertf(
    9597                node->weak_count == 0,
    96                 "Error: mutating node with weak references to it will invalided some references"
     98                "Error: mutating node with weak references to it will invalidate some references"
    9799        );
    98100        return node->clone();
     
    104106        // skip mutate if equivalent
    105107        if ( node->*field == val ) return node;
    106        
     108
    107109        // mutate and return
    108110        node_t * ret = mutate( node );
     
    123125        (ret->*field)[i] = std::forward< field_t >( val );
    124126        return ret;
     127}
     128
     129/// Mutate an entire indexed collection by cloning to accepted value
     130template<typename node_t, typename parent_t, typename coll_t>
     131const 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;
    125136}
    126137
     
    219230        operator const node_t * () const { _check(); return node; }
    220231
     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
    221241        /// wrapper for convenient access to dynamic_cast
    222242        template<typename o_node_t>
    223243        const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); }
    224244
    225         /// wrapper for convenient access to strict_dynamic_cast
     245        /// Wrapper that makes sure dynamic_cast returns non-null.
    226246        template<typename o_node_t>
    227         const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); }
     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; }
    228255
    229256        /// Returns a mutable version of the pointer in this node.
     
    244271
    245272        void _inc( const node_t * other );
    246         void _dec( const node_t * other );
     273        void _dec( const node_t * other, bool do_delete = true );
    247274        void _check() const;
     275        void _strict_fail() const __attribute__((noreturn));
    248276
    249277        const node_t * node;
  • src/AST/Pass.hpp

    r309d814 r4c925cd  
    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
    3739// Private prelude header, needed for some of the magic tricks this class pulls off
    3840#include "AST/Pass.proto.hpp"
     
    4648//
    4749// Several additional features are available through inheritance
    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
     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
    6467//-------------------------------------------------------------------------------------------------
    65 template< typename pass_t >
     68template< typename core_t >
    6669class Pass final : public ast::Visitor {
    6770public:
     71        using core_type = core_t;
     72        using type = Pass<core_t>;
     73
    6874        /// Forward any arguments to the pass constructor
    6975        /// Propagate 'this' if necessary
    7076        template< typename... Args >
    7177        Pass( Args &&... args)
    72                 : pass( std::forward<Args>( args )... )
     78                : core( std::forward<Args>( args )... )
    7379        {
    7480                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    75                 typedef Pass<pass_t> this_t;
    76                 this_t * const * visitor = __pass::visitor(pass, 0);
     81                type * const * visitor = __pass::visitor(core, 0);
    7782                if(visitor) {
    78                         *const_cast<this_t **>( visitor ) = this;
     83                        *const_cast<type **>( visitor ) = this;
    7984                }
    8085        }
     
    8287        virtual ~Pass() = default;
    8388
     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
    84102        /// Storage for the actual pass
    85         pass_t pass;
     103        core_t core;
    86104
    87105        /// Visit function declarations
     
    179197        const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
    180198
    181         template<typename pass_type>
    182         friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
     199        template<typename core_type>
     200        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
    183201private:
    184202
    185         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
     203        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; }
    186204
    187205private:
     
    202220        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    203221
     222        /// Mutate forall-list, accounting for presence of type substitution map
     223        template<typename node_t>
     224        void mutate_forall( const node_t *& );
     225
    204226public:
    205227        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
     
    210232        /// Internal RAII guard for symbol table features
    211233        struct guard_symtab {
    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;
     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;
    215237        };
    216238
    217239        /// Internal RAII guard for scope features
    218240        struct guard_scope {
    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;
     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;
    222253        };
    223254
     
    227258
    228259/// Apply a pass to an entire translation unit
    229 template<typename pass_t>
    230 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
     260template<typename core_t>
     261void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
    231262
    232263//-------------------------------------------------------------------------------------------------
     
    268299        };
    269300
    270         template< typename pass_t>
    271         friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );
     301        template< typename core_t>
     302        friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup );
    272303public:
    273304
     
    305336
    306337/// Used to get a pointer to the pass with its wrapped type
    307 template<typename pass_t>
     338template<typename core_t>
    308339struct WithVisitorRef {
    309         Pass<pass_t> * const visitor = nullptr;
     340        Pass<core_t> * const visitor = nullptr;
    310341};
    311342
     
    314345        SymbolTable symtab;
    315346};
     347
     348/// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
     349struct WithForallSubstitutor {
     350        ForallSubstitutionTable subs;
     351};
     352
    316353}
    317354
     
    321358extern struct PassVisitorStats {
    322359        size_t depth = 0;
    323         Stats::Counters::MaxCounter<double> * max = nullptr;
    324         Stats::Counters::AverageCounter<double> * avg = nullptr;
     360        Stats::Counters::MaxCounter<double> * max;
     361        Stats::Counters::AverageCounter<double> * avg;
    325362} pass_visitor_stats;
    326363}
  • src/AST/Pass.impl.hpp

    r309d814 r4c925cd  
    2525        using namespace ast; \
    2626        /* back-up the visit children */ \
    27         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
     27        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 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    (pass, 0) ); \
     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 ); \
    3032        /* call the implementation of the previsit of this pass */ \
    31         __pass::previsit( pass, node, 0 );
     33        __pass::previsit( core, node, 0 );
    3234
    3335#define VISIT( code... ) \
     
    4042#define VISIT_END( type, node ) \
    4143        /* call the implementation of the postvisit of this pass */ \
    42         auto __return = __pass::postvisit( pass, node, 0 ); \
     44        auto __return = __pass::postvisit( core, node, 0 ); \
    4345        assertf(__return, "post visit should never return null"); \
     46        /* end tracing memory allocation if requested by this pass */ \
     47        __pass::endTrace( core, 0 ); \
    4448        return __return;
    4549
     
    119123        }
    120124
    121         template< typename pass_t >
     125        template< typename core_t >
    122126        template< typename node_t >
    123         auto ast::Pass< pass_t >::call_accept( const node_t * node )
     127        auto ast::Pass< core_t >::call_accept( const node_t * node )
    124128                -> typename std::enable_if<
    125129                                !std::is_base_of<ast::Expr, node_t>::value &&
     
    127131                        , decltype( node->accept(*this) )
    128132                >::type
    129 
    130133        {
    131134                __pedantic_pass_assert( __visit_children() );
    132                 __pedantic_pass_assert( expr );
     135                __pedantic_pass_assert( node );
    133136
    134137                static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
     
    138141        }
    139142
    140         template< typename pass_t >
    141         const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
     143        template< typename core_t >
     144        const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    142145                __pedantic_pass_assert( __visit_children() );
    143146                __pedantic_pass_assert( expr );
    144147
    145                 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
     148                const ast::TypeSubstitution ** env_ptr = __pass::env( core, 0);
    146149                if ( env_ptr && expr->env ) {
    147150                        *env_ptr = expr->env;
     
    151154        }
    152155
    153         template< typename pass_t >
    154         const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
     156        template< typename core_t >
     157        const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    155158                __pedantic_pass_assert( __visit_children() );
    156159                __pedantic_pass_assert( stmt );
     
    160163
    161164                // get the stmts/decls that will need to be spliced in
    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);
     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);
    166169
    167170                // These may be modified by subnode but most be restored once we exit this statemnet.
    168                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
     171                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( core, 0) );
    169172                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    170173                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    202205        }
    203206
    204         template< typename pass_t >
     207        template< typename core_t >
    205208        template< template <class...> class container_t >
    206         container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     209        container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    207210                __pedantic_pass_assert( __visit_children() );
    208211                if( statements.empty() ) return {};
     
    215218
    216219                // get the stmts/decls that will need to be spliced in
    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);
     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);
    221224
    222225                // These may be modified by subnode but most be restored once we exit this statemnet.
     
    268271        }
    269272
    270         template< typename pass_t >
     273        template< typename core_t >
    271274        template< template <class...> class container_t, typename node_t >
    272         container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     275        container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    273276                __pedantic_pass_assert( __visit_children() );
    274277                if( container.empty() ) return {};
     
    299302        }
    300303
    301         template< typename pass_t >
     304        template< typename core_t >
    302305        template<typename node_t, typename parent_t, typename child_t>
    303         void ast::Pass< pass_t >::maybe_accept(
     306        void ast::Pass< core_t >::maybe_accept(
    304307                const node_t * & parent,
    305308                child_t parent_t::*child
     
    323326        }
    324327
     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        }
    325344}
    326345
     
    333352//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    334353
    335 template< typename pass_t >
    336 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
     354template< typename core_t >
     355inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) {
    337356        // We are going to aggregate errors for all these statements
    338357        SemanticErrorException errors;
     
    342361
    343362        // get the stmts/decls that will need to be spliced in
    344         auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
    345         auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
     363        auto decls_before = __pass::declsToAddBefore( visitor.core, 0);
     364        auto decls_after  = __pass::declsToAddAfter ( visitor.core, 0);
    346365
    347366        // update pass statitistics
     
    392411//--------------------------------------------------------------------------
    393412// ObjectDecl
    394 template< typename pass_t >
    395 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
     413template< typename core_t >
     414const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) {
    396415        VISIT_START( node );
    397416
     
    406425        )
    407426
    408         __pass::symtab::addId( pass, 0, node );
     427        __pass::symtab::addId( core, 0, node );
    409428
    410429        VISIT_END( DeclWithType, node );
     
    413432//--------------------------------------------------------------------------
    414433// FunctionDecl
    415 template< typename pass_t >
    416 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
    417         VISIT_START( node );
    418 
    419         __pass::symtab::addId( pass, 0, node );
     434template< typename core_t >
     435const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) {
     436        VISIT_START( node );
     437
     438        __pass::symtab::addId( core, 0, node );
    420439
    421440        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
     
    425444                // shadow with exprs and not the other way around.
    426445                guard_symtab guard { *this };
    427                 __pass::symtab::addWith( pass, 0, node->withExprs, node );
     446                __pass::symtab::addWith( core, 0, node->withExprs, node );
    428447                {
    429448                        guard_symtab guard { *this };
    430449                        // implicit add __func__ identifier as specified in the C manual 6.4.2.2
    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 ) ),
     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 },
    435454                                        nullptr, VariableLen, DynamicDim
    436                                 )
    437                         );
    438                         __pass::symtab::addId( pass, 0, &func );
     455                                }
     456                        } };
     457                        __pass::symtab::addId( core, 0, func );
    439458                        VISIT(
    440459                                maybe_accept( node, &FunctionDecl::type );
     
    454473//--------------------------------------------------------------------------
    455474// StructDecl
    456 template< typename pass_t >
    457 const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
     475template< typename core_t >
     476const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) {
    458477        VISIT_START( node );
    459478
    460479        // make up a forward declaration and add it before processing the members
    461480        // needs to be on the heap because addStruct saves the pointer
    462         __pass::symtab::addStructFwd( pass, 0, node );
     481        __pass::symtab::addStructFwd( core, 0, node );
    463482
    464483        VISIT({
     
    469488
    470489        // this addition replaces the forward declaration
    471         __pass::symtab::addStruct( pass, 0, node );
     490        __pass::symtab::addStruct( core, 0, node );
    472491
    473492        VISIT_END( Decl, node );
     
    476495//--------------------------------------------------------------------------
    477496// UnionDecl
    478 template< typename pass_t >
    479 const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
     497template< typename core_t >
     498const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) {
    480499        VISIT_START( node );
    481500
    482501        // make up a forward declaration and add it before processing the members
    483         __pass::symtab::addUnionFwd( pass, 0, node );
     502        __pass::symtab::addUnionFwd( core, 0, node );
    484503
    485504        VISIT({
     
    489508        })
    490509
    491         __pass::symtab::addUnion( pass, 0, node );
     510        __pass::symtab::addUnion( core, 0, node );
    492511
    493512        VISIT_END( Decl, node );
     
    496515//--------------------------------------------------------------------------
    497516// EnumDecl
    498 template< typename pass_t >
    499 const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
    500         VISIT_START( node );
    501 
    502         __pass::symtab::addEnum( pass, 0, node );
     517template< typename core_t >
     518const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) {
     519        VISIT_START( node );
     520
     521        __pass::symtab::addEnum( core, 0, node );
    503522
    504523        VISIT(
     
    513532//--------------------------------------------------------------------------
    514533// TraitDecl
    515 template< typename pass_t >
    516 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
     534template< typename core_t >
     535const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) {
    517536        VISIT_START( node );
    518537
     
    523542        })
    524543
    525         __pass::symtab::addTrait( pass, 0, node );
     544        __pass::symtab::addTrait( core, 0, node );
    526545
    527546        VISIT_END( Decl, node );
     
    530549//--------------------------------------------------------------------------
    531550// TypeDecl
    532 template< typename pass_t >
    533 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
     551template< typename core_t >
     552const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) {
    534553        VISIT_START( node );
    535554
     
    543562        // note that assertions come after the type is added to the symtab, since they are not part of the type proper
    544563        // and may depend on the type itself
    545         __pass::symtab::addType( pass, 0, node );
     564        __pass::symtab::addType( core, 0, node );
    546565
    547566        VISIT(
     
    559578//--------------------------------------------------------------------------
    560579// TypedefDecl
    561 template< typename pass_t >
    562 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
     580template< typename core_t >
     581const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) {
    563582        VISIT_START( node );
    564583
     
    569588        })
    570589
    571         __pass::symtab::addType( pass, 0, node );
     590        __pass::symtab::addType( core, 0, node );
    572591
    573592        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
     
    578597//--------------------------------------------------------------------------
    579598// AsmDecl
    580 template< typename pass_t >
    581 const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
     599template< typename core_t >
     600const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) {
    582601        VISIT_START( node );
    583602
     
    591610//--------------------------------------------------------------------------
    592611// StaticAssertDecl
    593 template< typename pass_t >
    594 const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
     612template< typename core_t >
     613const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) {
    595614        VISIT_START( node );
    596615
     
    605624//--------------------------------------------------------------------------
    606625// CompoundStmt
    607 template< typename pass_t >
    608 const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
     626template< typename core_t >
     627const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    609628        VISIT_START( node );
    610629        VISIT({
    611630                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    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);
     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);
    616635                });
    617636                ValueGuard< bool > guard2( inFunction );
     
    625644//--------------------------------------------------------------------------
    626645// ExprStmt
    627 template< typename pass_t >
    628 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
     646template< typename core_t >
     647const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) {
    629648        VISIT_START( node );
    630649
     
    638657//--------------------------------------------------------------------------
    639658// AsmStmt
    640 template< typename pass_t >
    641 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
     659template< typename core_t >
     660const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) {
    642661        VISIT_START( node )
    643662
     
    654673//--------------------------------------------------------------------------
    655674// DirectiveStmt
    656 template< typename pass_t >
    657 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
     675template< typename core_t >
     676const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) {
    658677        VISIT_START( node )
    659678
     
    663682//--------------------------------------------------------------------------
    664683// IfStmt
    665 template< typename pass_t >
    666 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
     684template< typename core_t >
     685const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) {
    667686        VISIT_START( node );
    668687
     
    681700//--------------------------------------------------------------------------
    682701// WhileStmt
    683 template< typename pass_t >
    684 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
     702template< typename core_t >
     703const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
    685704        VISIT_START( node );
    686705
     
    698717//--------------------------------------------------------------------------
    699718// ForStmt
    700 template< typename pass_t >
    701 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {
     719template< typename core_t >
     720const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) {
    702721        VISIT_START( node );
    703722
     
    716735//--------------------------------------------------------------------------
    717736// SwitchStmt
    718 template< typename pass_t >
    719 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {
     737template< typename core_t >
     738const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) {
    720739        VISIT_START( node );
    721740
     
    730749//--------------------------------------------------------------------------
    731750// CaseStmt
    732 template< typename pass_t >
    733 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {
     751template< typename core_t >
     752const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) {
    734753        VISIT_START( node );
    735754
     
    744763//--------------------------------------------------------------------------
    745764// BranchStmt
    746 template< typename pass_t >
    747 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {
     765template< typename core_t >
     766const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) {
    748767        VISIT_START( node );
    749768        VISIT_END( Stmt, node );
     
    752771//--------------------------------------------------------------------------
    753772// ReturnStmt
    754 template< typename pass_t >
    755 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {
     773template< typename core_t >
     774const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) {
    756775        VISIT_START( node );
    757776
     
    765784//--------------------------------------------------------------------------
    766785// ThrowStmt
    767 template< typename pass_t >
    768 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {
     786template< typename core_t >
     787const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) {
    769788        VISIT_START( node );
    770789
     
    779798//--------------------------------------------------------------------------
    780799// TryStmt
    781 template< typename pass_t >
    782 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {
     800template< typename core_t >
     801const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) {
    783802        VISIT_START( node );
    784803
     
    794813//--------------------------------------------------------------------------
    795814// CatchStmt
    796 template< typename pass_t >
    797 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
     815template< typename core_t >
     816const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) {
    798817        VISIT_START( node );
    799818
     
    811830//--------------------------------------------------------------------------
    812831// FinallyStmt
    813 template< typename pass_t >
    814 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
     832template< typename core_t >
     833const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) {
    815834        VISIT_START( node );
    816835
     
    824843//--------------------------------------------------------------------------
    825844// FinallyStmt
    826 template< typename pass_t >
    827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {
     845template< typename core_t >
     846const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) {
    828847        VISIT_START( node );
    829848
     
    837856//--------------------------------------------------------------------------
    838857// WaitForStmt
    839 template< typename pass_t >
    840 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
     858template< typename core_t >
     859const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) {
    841860        VISIT_START( node );
    842861                // for( auto & clause : node->clauses ) {
     
    906925//--------------------------------------------------------------------------
    907926// WithStmt
    908 template< typename pass_t >
    909 const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
     927template< typename core_t >
     928const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) {
    910929        VISIT_START( node );
    911930
     
    915934                        // catch statements introduce a level of scope (for the caught exception)
    916935                        guard_symtab guard { *this };
    917                         __pass::symtab::addWith( pass, 0, node->exprs, node );
     936                        __pass::symtab::addWith( core, 0, node->exprs, node );
    918937                        maybe_accept( node, &WithStmt::stmt );
    919938                }
     
    924943//--------------------------------------------------------------------------
    925944// NullStmt
    926 template< typename pass_t >
    927 const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
     945template< typename core_t >
     946const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) {
    928947        VISIT_START( node );
    929948        VISIT_END( NullStmt, node );
     
    932951//--------------------------------------------------------------------------
    933952// DeclStmt
    934 template< typename pass_t >
    935 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
     953template< typename core_t >
     954const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) {
    936955        VISIT_START( node );
    937956
     
    945964//--------------------------------------------------------------------------
    946965// ImplicitCtorDtorStmt
    947 template< typename pass_t >
    948 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
     966template< typename core_t >
     967const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
    949968        VISIT_START( node );
    950969
    951970        // For now this isn't visited, it is unclear if this causes problem
    952971        // if all tests are known to pass, remove this code
    953         // VISIT(
    954         //      maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    955         // )
     972        VISIT(
     973                maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
     974        )
    956975
    957976        VISIT_END( Stmt, node );
     
    960979//--------------------------------------------------------------------------
    961980// ApplicationExpr
    962 template< typename pass_t >
    963 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
     981template< typename core_t >
     982const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) {
    964983        VISIT_START( node );
    965984
     
    978997//--------------------------------------------------------------------------
    979998// UntypedExpr
    980 template< typename pass_t >
    981 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
     999template< typename core_t >
     1000const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) {
    9821001        VISIT_START( node );
    9831002
     
    9961015//--------------------------------------------------------------------------
    9971016// NameExpr
    998 template< typename pass_t >
    999 const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
     1017template< typename core_t >
     1018const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) {
    10001019        VISIT_START( node );
    10011020
     
    10101029//--------------------------------------------------------------------------
    10111030// CastExpr
    1012 template< typename pass_t >
    1013 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
     1031template< typename core_t >
     1032const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) {
    10141033        VISIT_START( node );
    10151034
     
    10261045//--------------------------------------------------------------------------
    10271046// KeywordCastExpr
    1028 template< typename pass_t >
    1029 const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
     1047template< typename core_t >
     1048const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) {
    10301049        VISIT_START( node );
    10311050
     
    10421061//--------------------------------------------------------------------------
    10431062// VirtualCastExpr
    1044 template< typename pass_t >
    1045 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
     1063template< typename core_t >
     1064const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) {
    10461065        VISIT_START( node );
    10471066
     
    10581077//--------------------------------------------------------------------------
    10591078// AddressExpr
    1060 template< typename pass_t >
    1061 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
     1079template< typename core_t >
     1080const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) {
    10621081        VISIT_START( node );
    10631082
     
    10741093//--------------------------------------------------------------------------
    10751094// LabelAddressExpr
    1076 template< typename pass_t >
    1077 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
     1095template< typename core_t >
     1096const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) {
    10781097        VISIT_START( node );
    10791098
     
    10881107//--------------------------------------------------------------------------
    10891108// UntypedMemberExpr
    1090 template< typename pass_t >
    1091 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
     1109template< typename core_t >
     1110const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) {
    10921111        VISIT_START( node );
    10931112
     
    11051124//--------------------------------------------------------------------------
    11061125// MemberExpr
    1107 template< typename pass_t >
    1108 const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
     1126template< typename core_t >
     1127const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) {
    11091128        VISIT_START( node );
    11101129
     
    11211140//--------------------------------------------------------------------------
    11221141// VariableExpr
    1123 template< typename pass_t >
    1124 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
     1142template< typename core_t >
     1143const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) {
    11251144        VISIT_START( node );
    11261145
     
    11351154//--------------------------------------------------------------------------
    11361155// ConstantExpr
    1137 template< typename pass_t >
    1138 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
     1156template< typename core_t >
     1157const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) {
    11391158        VISIT_START( node );
    11401159
     
    11491168//--------------------------------------------------------------------------
    11501169// SizeofExpr
    1151 template< typename pass_t >
    1152 const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
     1170template< typename core_t >
     1171const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) {
    11531172        VISIT_START( node );
    11541173
     
    11691188//--------------------------------------------------------------------------
    11701189// AlignofExpr
    1171 template< typename pass_t >
    1172 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
     1190template< typename core_t >
     1191const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) {
    11731192        VISIT_START( node );
    11741193
     
    11891208//--------------------------------------------------------------------------
    11901209// UntypedOffsetofExpr
    1191 template< typename pass_t >
    1192 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
     1210template< typename core_t >
     1211const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) {
    11931212        VISIT_START( node );
    11941213
     
    12051224//--------------------------------------------------------------------------
    12061225// OffsetofExpr
    1207 template< typename pass_t >
    1208 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
     1226template< typename core_t >
     1227const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) {
    12091228        VISIT_START( node );
    12101229
     
    12211240//--------------------------------------------------------------------------
    12221241// OffsetPackExpr
    1223 template< typename pass_t >
    1224 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
     1242template< typename core_t >
     1243const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) {
    12251244        VISIT_START( node );
    12261245
     
    12371256//--------------------------------------------------------------------------
    12381257// LogicalExpr
    1239 template< typename pass_t >
    1240 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
     1258template< typename core_t >
     1259const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) {
    12411260        VISIT_START( node );
    12421261
     
    12541273//--------------------------------------------------------------------------
    12551274// ConditionalExpr
    1256 template< typename pass_t >
    1257 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
     1275template< typename core_t >
     1276const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) {
    12581277        VISIT_START( node );
    12591278
     
    12721291//--------------------------------------------------------------------------
    12731292// CommaExpr
    1274 template< typename pass_t >
    1275 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
     1293template< typename core_t >
     1294const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) {
    12761295        VISIT_START( node );
    12771296
     
    12891308//--------------------------------------------------------------------------
    12901309// TypeExpr
    1291 template< typename pass_t >
    1292 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
     1310template< typename core_t >
     1311const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) {
    12931312        VISIT_START( node );
    12941313
     
    13051324//--------------------------------------------------------------------------
    13061325// AsmExpr
    1307 template< typename pass_t >
    1308 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
     1326template< typename core_t >
     1327const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) {
    13091328        VISIT_START( node );
    13101329
     
    13221341//--------------------------------------------------------------------------
    13231342// ImplicitCopyCtorExpr
    1324 template< typename pass_t >
    1325 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
     1343template< typename core_t >
     1344const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
    13261345        VISIT_START( node );
    13271346
     
    13381357//--------------------------------------------------------------------------
    13391358// ConstructorExpr
    1340 template< typename pass_t >
    1341 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
     1359template< typename core_t >
     1360const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) {
    13421361        VISIT_START( node );
    13431362
     
    13541373//--------------------------------------------------------------------------
    13551374// CompoundLiteralExpr
    1356 template< typename pass_t >
    1357 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
     1375template< typename core_t >
     1376const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) {
    13581377        VISIT_START( node );
    13591378
     
    13701389//--------------------------------------------------------------------------
    13711390// RangeExpr
    1372 template< typename pass_t >
    1373 const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
     1391template< typename core_t >
     1392const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) {
    13741393        VISIT_START( node );
    13751394
     
    13871406//--------------------------------------------------------------------------
    13881407// UntypedTupleExpr
    1389 template< typename pass_t >
    1390 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
     1408template< typename core_t >
     1409const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) {
    13911410        VISIT_START( node );
    13921411
     
    14031422//--------------------------------------------------------------------------
    14041423// TupleExpr
    1405 template< typename pass_t >
    1406 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
     1424template< typename core_t >
     1425const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) {
    14071426        VISIT_START( node );
    14081427
     
    14191438//--------------------------------------------------------------------------
    14201439// TupleIndexExpr
    1421 template< typename pass_t >
    1422 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
     1440template< typename core_t >
     1441const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) {
    14231442        VISIT_START( node );
    14241443
     
    14351454//--------------------------------------------------------------------------
    14361455// TupleAssignExpr
    1437 template< typename pass_t >
    1438 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
     1456template< typename core_t >
     1457const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) {
    14391458        VISIT_START( node );
    14401459
     
    14511470//--------------------------------------------------------------------------
    14521471// StmtExpr
    1453 template< typename pass_t >
    1454 const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
     1472template< typename core_t >
     1473const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) {
    14551474        VISIT_START( node );
    14561475
    14571476        VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
    14581477                // get the stmts that will need to be spliced in
    1459                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    1460                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     1478                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     1479                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    14611480
    14621481                // These may be modified by subnode but most be restored once we exit this statemnet.
    1463                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );
     1482                ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( core, 0) );
    14641483                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    14651484                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    14791498//--------------------------------------------------------------------------
    14801499// UniqueExpr
    1481 template< typename pass_t >
    1482 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
     1500template< typename core_t >
     1501const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) {
    14831502        VISIT_START( node );
    14841503
     
    14951514//--------------------------------------------------------------------------
    14961515// UntypedInitExpr
    1497 template< typename pass_t >
    1498 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
     1516template< typename core_t >
     1517const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) {
    14991518        VISIT_START( node );
    15001519
     
    15121531//--------------------------------------------------------------------------
    15131532// InitExpr
    1514 template< typename pass_t >
    1515 const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
     1533template< typename core_t >
     1534const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) {
    15161535        VISIT_START( node );
    15171536
     
    15291548//--------------------------------------------------------------------------
    15301549// DeletedExpr
    1531 template< typename pass_t >
    1532 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
     1550template< typename core_t >
     1551const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) {
    15331552        VISIT_START( node );
    15341553
     
    15461565//--------------------------------------------------------------------------
    15471566// DefaultArgExpr
    1548 template< typename pass_t >
    1549 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
     1567template< typename core_t >
     1568const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) {
    15501569        VISIT_START( node );
    15511570
     
    15621581//--------------------------------------------------------------------------
    15631582// GenericExpr
    1564 template< typename pass_t >
    1565 const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
     1583template< typename core_t >
     1584const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) {
    15661585        VISIT_START( node );
    15671586
     
    16021621//--------------------------------------------------------------------------
    16031622// VoidType
    1604 template< typename pass_t >
    1605 const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
     1623template< typename core_t >
     1624const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) {
    16061625        VISIT_START( node );
    16071626
     
    16111630//--------------------------------------------------------------------------
    16121631// BasicType
    1613 template< typename pass_t >
    1614 const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
     1632template< typename core_t >
     1633const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) {
    16151634        VISIT_START( node );
    16161635
     
    16201639//--------------------------------------------------------------------------
    16211640// PointerType
    1622 template< typename pass_t >
    1623 const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
     1641template< typename core_t >
     1642const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) {
    16241643        VISIT_START( node );
    16251644
     
    16341653//--------------------------------------------------------------------------
    16351654// ArrayType
    1636 template< typename pass_t >
    1637 const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
     1655template< typename core_t >
     1656const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) {
    16381657        VISIT_START( node );
    16391658
     
    16481667//--------------------------------------------------------------------------
    16491668// ReferenceType
    1650 template< typename pass_t >
    1651 const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
     1669template< typename core_t >
     1670const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) {
    16521671        VISIT_START( node );
    16531672
     
    16611680//--------------------------------------------------------------------------
    16621681// QualifiedType
    1663 template< typename pass_t >
    1664 const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
     1682template< typename core_t >
     1683const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) {
    16651684        VISIT_START( node );
    16661685
     
    16751694//--------------------------------------------------------------------------
    16761695// FunctionType
    1677 template< typename pass_t >
    1678 const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
    1679         VISIT_START( node );
    1680 
    1681         VISIT(
    1682                 maybe_accept( node, &FunctionType::forall  );
     1696template< typename core_t >
     1697const 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 );
    16831703                maybe_accept( node, &FunctionType::returns );
    16841704                maybe_accept( node, &FunctionType::params  );
    1685         )
     1705        })
    16861706
    16871707        VISIT_END( Type, node );
     
    16901710//--------------------------------------------------------------------------
    16911711// StructInstType
    1692 template< typename pass_t >
    1693 const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
    1694         VISIT_START( node );
    1695 
    1696         __pass::symtab::addStruct( pass, 0, node->name );
     1712template< typename core_t >
     1713const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) {
     1714        VISIT_START( node );
     1715
     1716        __pass::symtab::addStruct( core, 0, node->name );
    16971717
    16981718        VISIT({
    16991719                guard_symtab guard { *this };
    1700                 maybe_accept( node, &StructInstType::forall );
     1720                guard_forall_subs forall_guard { *this, node };
     1721                mutate_forall( node );
    17011722                maybe_accept( node, &StructInstType::params );
    17021723        })
     
    17071728//--------------------------------------------------------------------------
    17081729// UnionInstType
    1709 template< typename pass_t >
    1710 const 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         {
     1730template< typename core_t >
     1731const 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({
    17161737                guard_symtab guard { *this };
    1717                 maybe_accept( node, &UnionInstType::forall );
     1738                guard_forall_subs forall_guard { *this, node };
     1739                mutate_forall( node );
    17181740                maybe_accept( node, &UnionInstType::params );
    1719         }
     1741        })
    17201742
    17211743        VISIT_END( Type, node );
     
    17241746//--------------------------------------------------------------------------
    17251747// EnumInstType
    1726 template< typename pass_t >
    1727 const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
    1728         VISIT_START( node );
    1729 
    1730         VISIT(
    1731                 maybe_accept( node, &EnumInstType::forall );
     1748template< typename core_t >
     1749const 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 );
    17321755                maybe_accept( node, &EnumInstType::params );
    1733         )
     1756        })
    17341757
    17351758        VISIT_END( Type, node );
     
    17381761//--------------------------------------------------------------------------
    17391762// TraitInstType
    1740 template< typename pass_t >
    1741 const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
    1742         VISIT_START( node );
    1743 
    1744         VISIT(
    1745                 maybe_accept( node, &TraitInstType::forall );
     1763template< typename core_t >
     1764const 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 );
    17461770                maybe_accept( node, &TraitInstType::params );
    1747         )
     1771        })
    17481772
    17491773        VISIT_END( Type, node );
     
    17521776//--------------------------------------------------------------------------
    17531777// TypeInstType
    1754 template< typename pass_t >
    1755 const 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 );
     1778template< typename core_t >
     1779const 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 );
    17611790        )
    17621791
     
    17661795//--------------------------------------------------------------------------
    17671796// TupleType
    1768 template< typename pass_t >
    1769 const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
     1797template< typename core_t >
     1798const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) {
    17701799        VISIT_START( node );
    17711800
     
    17801809//--------------------------------------------------------------------------
    17811810// TypeofType
    1782 template< typename pass_t >
    1783 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
     1811template< typename core_t >
     1812const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) {
    17841813        VISIT_START( node );
    17851814
     
    17931822//--------------------------------------------------------------------------
    17941823// VarArgsType
    1795 template< typename pass_t >
    1796 const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
     1824template< typename core_t >
     1825const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) {
    17971826        VISIT_START( node );
    17981827
     
    18021831//--------------------------------------------------------------------------
    18031832// ZeroType
    1804 template< typename pass_t >
    1805 const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
     1833template< typename core_t >
     1834const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) {
    18061835        VISIT_START( node );
    18071836
     
    18111840//--------------------------------------------------------------------------
    18121841// OneType
    1813 template< typename pass_t >
    1814 const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
     1842template< typename core_t >
     1843const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) {
    18151844        VISIT_START( node );
    18161845
     
    18201849//--------------------------------------------------------------------------
    18211850// GlobalScopeType
    1822 template< typename pass_t >
    1823 const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
     1851template< typename core_t >
     1852const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) {
    18241853        VISIT_START( node );
    18251854
     
    18301859//--------------------------------------------------------------------------
    18311860// Designation
    1832 template< typename pass_t >
    1833 const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
     1861template< typename core_t >
     1862const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) {
    18341863        VISIT_START( node );
    18351864
     
    18411870//--------------------------------------------------------------------------
    18421871// SingleInit
    1843 template< typename pass_t >
    1844 const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
     1872template< typename core_t >
     1873const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) {
    18451874        VISIT_START( node );
    18461875
     
    18541883//--------------------------------------------------------------------------
    18551884// ListInit
    1856 template< typename pass_t >
    1857 const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
     1885template< typename core_t >
     1886const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) {
    18581887        VISIT_START( node );
    18591888
     
    18681897//--------------------------------------------------------------------------
    18691898// ConstructorInit
    1870 template< typename pass_t >
    1871 const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
     1899template< typename core_t >
     1900const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) {
    18721901        VISIT_START( node );
    18731902
     
    18831912//--------------------------------------------------------------------------
    18841913// Attribute
    1885 template< typename pass_t >
    1886 const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
     1914template< typename core_t >
     1915const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node  )  {
    18871916        VISIT_START( node );
    18881917
     
    18961925//--------------------------------------------------------------------------
    18971926// TypeSubstitution
    1898 template< typename pass_t >
    1899 const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
     1927template< typename core_t >
     1928const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) {
    19001929        VISIT_START( node );
    19011930
     
    19071936                                guard_symtab guard { *this };
    19081937                                auto new_node = p.second->accept( *this );
    1909                                 if (new_node != p.second) mutated = false;
     1938                                if (new_node != p.second) mutated = true;
    19101939                                new_map.insert({ p.first, new_node });
    19111940                        }
     
    19231952                                guard_symtab guard { *this };
    19241953                                auto new_node = p.second->accept( *this );
    1925                                 if (new_node != p.second) mutated = false;
     1954                                if (new_node != p.second) mutated = true;
    19261955                                new_map.insert({ p.first, new_node });
    19271956                        }
  • src/AST/Pass.proto.hpp

    r309d814 r4c925cd  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
     19#include "Common/Stats/Heap.h"
     20
    1921namespace ast {
    20 template<typename pass_type>
     22template<typename core_t>
    2123class Pass;
    2224
     
    8284                };
    8385
    84                 std::stack< cleanup_t > cleanups;
     86                std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
    8587        };
    8688
     
    111113        /// "Short hand" to check if this is a valid previsit function
    112114        /// Mostly used to make the static_assert look (and print) prettier
    113         template<typename pass_t, typename node_t>
     115        template<typename core_t, typename node_t>
    114116        struct is_valid_previsit {
    115                 using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
     117                using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) );
    116118
    117119                static constexpr bool value = std::is_void< ret_t >::value ||
     
    127129        template<>
    128130        struct __assign<true> {
    129                 template<typename pass_t, typename node_t>
    130                 static inline void result( pass_t & pass, const node_t * & node ) {
    131                         pass.previsit( node );
     131                template<typename core_t, typename node_t>
     132                static inline void result( core_t & core, const node_t * & node ) {
     133                        core.previsit( node );
    132134                }
    133135        };
     
    135137        template<>
    136138        struct __assign<false> {
    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 );
     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 );
    140142                        assertf(node, "Previsit must not return NULL");
    141143                }
     
    150152        template<>
    151153        struct __return<true> {
    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 );
     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 );
    155157                        return node;
    156158                }
     
    159161        template<>
    160162        struct __return<false> {
    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 );
     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 );
    164166                }
    165167        };
     
    180182        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    181183        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    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() ) {
     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() ) {
    184186                static_assert(
    185                         is_valid_previsit<pass_t, node_t>::value,
     187                        is_valid_previsit<core_t, node_t>::value,
    186188                        "Previsit may not change the type of the node. It must return its paremeter or void."
    187189                );
     
    189191                __assign<
    190192                        std::is_void<
    191                                 decltype( pass.previsit( node ) )
     193                                decltype( core.previsit( node ) )
    192194                        >::value
    193                 >::result( pass, node );
     195                >::result( core, node );
    194196        }
    195197
    196         template<typename pass_t, typename node_t>
    197         static inline auto previsit( pass_t &, const node_t *, long ) {}
     198        template<typename core_t, typename node_t>
     199        static inline auto previsit( core_t &, const node_t *, long ) {}
    198200
    199201        // PostVisit : never mutates the passed pointer but may return a different node
    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 ) )
     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 ) )
    203205        {
    204206                return __return<
    205207                        std::is_void<
    206                                 decltype( pass.postvisit( node ) )
     208                                decltype( core.postvisit( node ) )
    207209                        >::value
    208                 >::result( pass, node );
     210                >::result( core, node );
    209211        }
    210212
    211         template<typename pass_t, typename node_t>
    212         static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
     213        template<typename core_t, typename node_t>
     214        static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
    213215
    214216        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    225227        // The type is not strictly enforced but does match the accessory
    226228        #define FIELD_PTR( name, default_type ) \
    227         template< typename pass_t > \
    228         static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
     229        template< typename core_t > \
     230        static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
    229231        \
    230         template< typename pass_t > \
    231         static inline default_type * name( pass_t &, long ) { return nullptr; }
     232        template< typename core_t > \
     233        static inline default_type * name( core_t &, long ) { return nullptr; }
    232234
    233235        // List of fields and their expected types
     
    239241        FIELD_PTR( visit_children, __pass::bool_ref )
    240242        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    241         FIELD_PTR( visitor, ast::Pass<pass_t> * const )
     243        FIELD_PTR( visitor, ast::Pass<core_t> * const )
    242244
    243245        // Remove the macro to make sure we don't clash
    244246        #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) {}
    245263
    246264        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     
    248266        // detect it using the same strategy
    249267        namespace scope {
    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
     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
    268286        // detect the presence of a member name `symtab` and call all the members appropriately
    269287        namespace symtab {
    270288                // Some simple scoping rules
    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 ) {}
     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 ) {}
    286304
    287305                // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    288306                // Create macro to condense these common patterns
    289307                #define SYMTAB_FUNC1( func, type ) \
    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 ); \
     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 ); \
    293311                } \
    294312                \
    295                 template<typename pass_t> \
    296                 static inline void func( pass_t &, long, type ) {}
     313                template<typename core_t> \
     314                static inline void func( core_t &, long, type ) {}
    297315
    298316                #define SYMTAB_FUNC2( func, type1, type2 ) \
    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 ); \
     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 ); \
    302320                } \
    303321                        \
    304                 template<typename pass_t> \
    305                 static inline void func( pass_t &, long, type1, type2 ) {}
     322                template<typename core_t> \
     323                static inline void func( core_t &, long, type1, type2 ) {}
    306324
    307325                SYMTAB_FUNC1( addId     , const DeclWithType *  );
     
    311329                SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    312330                SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    313                 SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
     331                SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
    314332
    315333                // A few extra functions have more complicated behaviour, they are hand written
    316                 template<typename pass_t>
    317                 static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {
     334                template<typename core_t>
     335                static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
    318336                        ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    319337                        fwd->params = decl->params;
    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() ) {
     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() ) {
    328346                        UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
    329347                        fwd->params = decl->params;
    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 );
     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 );
    340358                        }
    341359                }
    342360
    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 );
     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 );
    350368                        }
    351369                }
    352370
    353                 template<typename pass_t>
    354                 static inline void addUnion( pass_t &, long, const std::string & ) {}
     371                template<typename core_t>
     372                static inline void addUnion( core_t &, long, const std::string & ) {}
    355373
    356374                #undef SYMTAB_FUNC1
    357375                #undef SYMTAB_FUNC2
    358         };
    359 };
    360 };
     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
  • src/AST/Print.cpp

    r309d814 r4c925cd  
    2929
    3030template <typename C, typename... T>
    31 constexpr auto make_array(T&&... values) ->
    32         array<C,sizeof...(T)>
     31constexpr array<C,sizeof...(T)> make_array(T&&... values)
    3332{
    3433        return array<C,sizeof...(T)>{
     
    129128
    130129        void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
    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()
     130                if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) {
     131                        os << indent << "with " << inferred.data.resnSlots->size()
    135132                           << " pending inference slots" << endl;
    136                         return;
    137                 }
    138                 case ast::Expr::InferUnion::Params: {
     133                }
     134                if (inferred.data.inferParams && !inferred.data.inferParams->empty()) {
    139135                        os << indent << "with inferred parameters " << level << ":" << endl;
    140136                        ++indent;
    141                         for ( const auto & i : inferred.data.inferParams ) {
     137                        for ( const auto & i : *inferred.data.inferParams ) {
    142138                                os << indent;
    143                                 short_print( Decl::fromId( i.second.decl ) );
     139                                short_print( i.second.declptr );
    144140                                os << endl;
    145141                                print( i.second.expr->inferred, level+1 );
    146142                        }
    147143                        --indent;
    148                         return;
    149                 }
    150144                }
    151145        }
     
    233227                }
    234228
    235                 if ( ! short_mode && ! node->assertions.empty() ) {
     229                if ( ! node->assertions.empty() ) {
    236230                        os << endl << indent << "... with assertions" << endl;
    237231                        ++indent;
     
    842836        virtual const ast::Expr * visit( const ast::CastExpr * node ) override final {
    843837                ++indent;
    844                 os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
     838                os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent;
    845839                safe_print( node->arg );
    846840                os << endl << indent-1 << "... to:";
  • src/AST/Stmt.hpp

    r309d814 r4c925cd  
    2727
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    29 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     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);
    3032
    3133namespace ast {
     
    412414class ImplicitCtorDtorStmt final : public Stmt {
    413415public:
    414         readonly<Stmt> callStmt;
     416        ptr<Stmt> callStmt;
    415417
    416418        ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
  • src/AST/Type.cpp

    r309d814 r4c925cd  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 15 16:56:28 2019
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:16:00 2020
     13// Update Count     : 5
    1414//
    1515
     
    2121
    2222#include "Decl.hpp"
     23#include "ForallSubstitutor.hpp" // for substituteForall
    2324#include "Init.hpp"
     25#include "Common/utility.h"      // for copy, move
    2426#include "InitTweak/InitTweak.h" // for getPointerBase
    2527#include "Tuples/Tuples.h"       // for isTtype
     
    9092// GENERATED END
    9193
     94// --- ParameterizedType
     95
     96void ParameterizedType::initWithSub(
     97        const ParameterizedType & o, Pass< ForallSubstitutor > & sub
     98) {
     99        forall = sub.core( o.forall );
     100}
     101
    92102// --- FunctionType
     103
     104FunctionType::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}
    93112
    94113namespace {
     
    106125
    107126// --- ReferenceToType
     127
     128void 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
     133ReferenceToType::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
    108140std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
    109141        assertf( aggr(), "Must have aggregate to perform lookup" );
     
    116148}
    117149
    118 // --- StructInstType
    119 
    120 StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
    121         std::vector<ptr<Attribute>>&& as )
    122 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    123 
    124 bool StructInstType::isComplete() const { return base ? base->body : false; }
    125 
    126 // --- UnionInstType
    127 
    128 UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
    129         std::vector<ptr<Attribute>>&& as )
    130 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    131 
    132 bool UnionInstType::isComplete() const { return base ? base->body : false; }
    133 
    134 // --- EnumInstType
    135 
    136 EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
    137         std::vector<ptr<Attribute>>&& as )
    138 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    139 
    140 bool EnumInstType::isComplete() const { return base ? base->body : false; }
     150// --- SueInstType (StructInstType, UnionInstType, EnumInstType)
     151
     152template<typename decl_t>
     153SueInstType<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 ) {}
     156
     157template<typename decl_t>
     158bool SueInstType<decl_t>::isComplete() const {
     159        return base ? base->body : false;
     160}
     161
     162template class SueInstType<StructDecl>;
     163template class SueInstType<UnionDecl>;
     164template class SueInstType<EnumDecl>;
    141165
    142166// --- TraitInstType
    143167
    144 TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
    145         std::vector<ptr<Attribute>>&& as )
    146 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     168TraitInstType::TraitInstType(
     169        const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     170: ReferenceToType( b->name, q, move(as) ), base( b ) {}
    147171
    148172// --- TypeInstType
     173
     174TypeInstType::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}
    149180
    150181void TypeInstType::set_base( const TypeDecl * b ) {
     
    158189
    159190TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    160 : Type( q ), types( std::move(ts) ), members() {
     191: Type( q ), types( move(ts) ), members() {
    161192        // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    162193        // named, but members without initializer nodes end up getting constructors, which breaks
  • src/AST/Type.hpp

    r309d814 r4c925cd  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:56:46 2019
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:15:00 2020
     13// Update Count     : 6
    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 template<typename node_t> friend node_t * mutate(const node_t * node);
     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);
    3234
    3335namespace ast {
     36
     37template< typename T > class Pass;
     38
     39struct ForallSubstitutor;
    3440
    3541class Type : public Node {
     
    4450        bool is_volatile() const { return qualifiers.is_volatile; }
    4551        bool is_restrict() const { return qualifiers.is_restrict; }
    46         bool is_lvalue() const { return qualifiers.is_lvalue; }
    4752        bool is_mutex() const { return qualifiers.is_mutex; }
    4853        bool is_atomic() const { return qualifiers.is_atomic; }
     
    5156        Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
    5257        Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
    53         Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
    5458        Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
    5559        Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
     
    163167        static const char *typeNames[];
    164168
    165         BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
     169        BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    166170        : Type(q, std::move(as)), kind(k) {}
    167171
     
    265269/// Base type for potentially forall-qualified types
    266270class ParameterizedType : public Type {
     271protected:
     272        /// initializes forall with substitutor
     273        void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
    267274public:
    268275        using ForallList = std::vector<ptr<TypeDecl>>;
     
    276283        ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
    277284        : 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
    278292
    279293private:
     
    301315        : ParameterizedType(q), returns(), params(), isVarArgs(va) {}
    302316
     317        FunctionType( const FunctionType & o );
     318
    303319        /// true if either the parameters or return values contain a tttype
    304320        bool isTtype() const;
     
    314330/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
    315331class ReferenceToType : public ParameterizedType {
     332protected:
     333        /// Initializes forall and parameters based on substitutor
     334        void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub );
    316335public:
    317336        std::vector<ptr<Expr>> params;
     
    319338        bool hoistType = false;
    320339
    321         ReferenceToType( const std::string& n, CV::Qualifiers q = {},
    322                 std::vector<ptr<Attribute>> && as = {} )
     340        ReferenceToType(
     341                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    323342        : ParameterizedType(q, std::move(as)), params(), name(n) {}
     343
     344        ReferenceToType( const ReferenceToType & o );
    324345
    325346        /// Gets aggregate declaration this type refers to
     
    333354};
    334355
    335 /// instance of struct type
    336 class StructInstType final : public ReferenceToType {
    337 public:
    338         readonly<StructDecl> base;
    339 
    340         StructInstType( const std::string& n, CV::Qualifiers q = {},
    341                 std::vector<ptr<Attribute>> && as = {} )
     356// Common implementation for the SUE instance types. Not to be used directly.
     357template<typename decl_t>
     358class SueInstType final : public ReferenceToType {
     359public:
     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 = {} )
    342365        : ReferenceToType( n, q, std::move(as) ), base() {}
    343         StructInstType( const StructDecl * b, CV::Qualifiers q = {},
    344                 std::vector<ptr<Attribute>> && as = {} );
     366
     367        SueInstType(
     368                const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    345369
    346370        bool isComplete() const override;
    347371
    348         const StructDecl * aggr() const override { return base; }
    349 
    350         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    351 private:
    352         StructInstType * clone() const override { return new StructInstType{ *this }; }
    353         MUTATE_FRIEND
    354 };
    355 
    356 /// instance of union type
    357 class UnionInstType final : public ReferenceToType {
    358 public:
    359         readonly<UnionDecl> base;
    360 
    361         UnionInstType( const std::string& n, CV::Qualifiers q = {},
    362                 std::vector<ptr<Attribute>> && as = {} )
     372        const decl_t * aggr() const override { return base; }
     373
     374        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     375private:
     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.
     381using StructInstType = SueInstType<StructDecl>;
     382
     383/// An instance of a union type.
     384using UnionInstType = SueInstType<UnionDecl>;
     385
     386/// An instance of an enum type.
     387using EnumInstType = SueInstType<EnumDecl>;
     388
     389/// An instance of a trait type.
     390class TraitInstType final : public ReferenceToType {
     391public:
     392        readonly<TraitDecl> base;
     393
     394        TraitInstType(
     395                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    363396        : 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 ); }
    372 private:
    373         UnionInstType * clone() const override { return new UnionInstType{ *this }; }
    374         MUTATE_FRIEND
    375 };
    376 
    377 /// instance of enum type
    378 class EnumInstType final : public ReferenceToType {
    379 public:
    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 ); }
    393 private:
    394         EnumInstType * clone() const override { return new EnumInstType{ *this }; }
    395         MUTATE_FRIEND
    396 };
    397 
    398 /// instance of trait type
    399 class TraitInstType final : public ReferenceToType {
    400 public:
    401         readonly<TraitDecl> base;
    402 
    403         TraitInstType( const std::string& n, CV::Qualifiers q = {},
    404                 std::vector<ptr<Attribute>> && as = {} )
    405         : ReferenceToType( n, q, std::move(as) ), base() {}
    406         TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
    407                 std::vector<ptr<Attribute>> && as = {} );
     397
     398        TraitInstType(
     399                const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    408400
    409401        // not meaningful for TraitInstType
     
    424416        TypeDecl::Kind kind;
    425417
    426         TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
     418        TypeInstType(
     419                const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
    427420                std::vector<ptr<Attribute>> && as = {} )
    428421        : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
     
    431424        : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
    432425
     426        TypeInstType( const TypeInstType & o );
     427
    433428        /// sets `base`, updating `kind` correctly
    434429        void set_base( const TypeDecl * );
  • src/AST/TypeEnvironment.cpp

    r309d814 r4c925cd  
    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.pass.result;
    164         }
    165 }
    166 
    167 bool TypeEnvironment::combine( 
     163                return occur.core.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

    r309d814 r4c925cd  
    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, enum Node::ref_type ref_t >
    145         int apply( ptr_base< node_t, ref_t > & type ) const {
     144        template< typename node_t >
     145        auto apply( node_t && type ) const {
    146146                TypeSubstitution sub;
    147147                writeToSubstitution( sub );
    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 {
     148                return sub.apply( std::forward<node_t>(type) );
     149        }
     150
     151        template< typename node_t >
     152        auto applyFree( node_t && type ) const {
    153153                TypeSubstitution sub;
    154154                writeToSubstitution( sub );
    155                 return sub.applyFree( type );
     155                return sub.applyFree( std::forward<node_t>(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

    r309d814 r4c925cd  
    1818
    1919namespace ast {
     20
     21
     22// size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
    2023
    2124TypeSubstitution::TypeSubstitution() {
     
    9295namespace {
    9396        struct EnvTrimmer {
    94                 ptr<TypeSubstitution> env;
     97                const TypeSubstitution * env;
    9598                TypeSubstitution * newEnv;
    9699                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
     
    108111        if ( env ) {
    109112                TypeSubstitution * newEnv = new TypeSubstitution();
    110 #if TIME_TO_CONVERT_PASSES
    111113                Pass<EnvTrimmer> trimmer( env, newEnv );
    112114                expr->accept( trimmer );
    113 #else
    114                 (void)expr;
    115                 (void)env;
    116 #endif
    117115                return newEnv;
    118116        }
     
    121119
    122120void TypeSubstitution::normalize() {
    123 #if TIME_TO_CONVERT_PASSES
    124         PassVisitor<Substituter> sub( *this, true );
     121        Pass<Substituter> sub( *this, true );
    125122        do {
    126                 sub.pass.subCount = 0;
    127                 sub.pass.freeOnly = true;
     123                sub.core.subCount = 0;
     124                sub.core.freeOnly = true;
    128125                for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
    129                         i->second = i->second->acceptMutator( sub );
    130                 }
    131         } while ( sub.pass.subCount );
    132 #endif
    133 }
    134 
    135 #if TIME_TO_CONVERT_PASSES
    136 
    137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
     126                        i->second = i->second->accept( sub );
     127                }
     128        } while ( sub.core.subCount );
     129}
     130
     131const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
    138132        BoundVarsType::const_iterator bound = boundVars.find( inst->name );
    139133        if ( bound != boundVars.end() ) return inst;
     
    146140                // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
    147141                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    148                 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
     142                if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    149143                        if ( inst->name == replacement->name ) {
    150144                                return inst;
     
    153147                // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
    154148                subCount++;
    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 
    163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
     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
     158const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
    164159        VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
    165160        if ( i == sub.varEnv.end() ) {
     
    167162        } else {
    168163                subCount++;
    169                 delete nameExpr;
    170                 return i->second->clone();
    171         } // if
    172 }
    173 
    174 void TypeSubstitution::Substituter::premutate( Type * type ) {
     164                return i->second;
     165        } // if
     166}
     167
     168void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
    175169        GuardValue( boundVars );
    176170        // bind type variables from forall-qualifiers
    177171        if ( freeOnly ) {
    178                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    179                         boundVars.insert( (*tyvar)->name );
     172                for ( const TypeDecl * tyvar : ptype->forall ) {
     173                                boundVars.insert( tyvar->name );
    180174                } // for
    181175        } // if
    182176}
    183177
    184 template< typename TypeClass >
    185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
     178void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) {
    186179        GuardValue( boundVars );
    187180        // bind type variables from forall-qualifiers
    188181        if ( freeOnly ) {
    189                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    190                         boundVars.insert( (*tyvar)->name );
     182                for ( const TypeDecl * tyvar : type->forall ) {
     183                        boundVars.insert( tyvar->name );
    191184                } // for
    192185                // bind type variables from generic type instantiations
    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 
    202 void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
     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
     196void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
    203197        handleAggregateType( aggregateUseType );
    204198}
    205199
    206 void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
     200void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
    207201        handleAggregateType( aggregateUseType );
    208202}
    209 
    210 #endif
    211203
    212204} // namespace ast
  • src/AST/TypeSubstitution.hpp

    r309d814 r4c925cd  
    4444        TypeSubstitution &operator=( const TypeSubstitution &other );
    4545
    46         template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
    47         template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
     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;
    4855
    4956        template< typename node_t, enum Node::ref_type ref_t >
    5057        int apply( ptr_base< node_t, ref_t > & input ) const {
    5158                const node_t * p = input.get();
    52                 int ret = apply(p);
    53                 input = p;
    54                 return ret;
     59                auto ret = apply(p);
     60                input = ret.node;
     61                return ret.count;
    5562        }
    5663
     
    5865        int applyFree( ptr_base< node_t, ref_t > & input ) const {
    5966                const node_t * p = input.get();
    60                 int ret = applyFree(p);
    61                 input = p;
    62                 return ret;
     67                auto ret = applyFree(p);
     68                input = ret.node;
     69                return ret.count;
    6370        }
    6471
     
    9299        void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
    93100
    94         template<typename pass_type>
     101        template<typename core_t>
    95102        friend class Pass;
    96103
     
    147154// PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
    148155#include "Pass.hpp"
     156#include "Copy.hpp"
    149157
    150158namespace ast {
     
    152160// definitition must happen after PassVisitor is included so that WithGuards can be used
    153161struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
     162                static size_t traceId;
    154163
    155164                Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    156165
    157 #if TIME_TO_CONVERT_PASSES
    158 
    159                 Type * postmutate( TypeInstType * aggregateUseType );
    160                 Expression * postmutate( NameExpr * nameExpr );
     166                const Type * postvisit( const TypeInstType * aggregateUseType );
     167                const Expr * postvisit( const NameExpr * nameExpr );
    161168
    162169                /// Records type variable bindings from forall-statements
    163                 void premutate( Type * type );
     170                void previsit( const ParameterizedType * type );
    164171                /// Records type variable bindings from forall-statements and instantiations of generic types
    165                 template< typename TypeClass > void handleAggregateType( TypeClass * type );
    166 
    167                 void premutate( StructInstType * aggregateUseType );
    168                 void premutate( UnionInstType * aggregateUseType );
    169 
    170 #endif
     172                void handleAggregateType( const ReferenceToType * type );
     173
     174                void previsit( const StructInstType * aggregateUseType );
     175                void previsit( const UnionInstType * aggregateUseType );
    171176
    172177                const TypeSubstitution & sub;
     
    179184
    180185template< typename SynTreeClass >
    181 int TypeSubstitution::apply( const SynTreeClass *& input ) const {
     186TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
    182187        assert( input );
    183188        Pass<Substituter> sub( *this, false );
    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;
     189        input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
     190        return { input, sub.core.subCount };
    189191}
    190192
    191193template< typename SynTreeClass >
    192 int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
     194TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
    193195        assert( input );
    194196        Pass<Substituter> sub( *this, true );
    195197        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;
     198        return { input, sub.core.subCount };
    200199}
    201200
  • src/AST/module.mk

    r309d814 r4c925cd  
    2222        AST/DeclReplacer.cpp \
    2323        AST/Expr.cpp \
     24        AST/ForallSubstitutionTable.cpp \
    2425        AST/GenericSubstitution.cpp \
    2526        AST/Init.cpp \
  • src/AST/porting.md

    r309d814 r4c925cd  
    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.
    4954
    5055All leaves of the `Node` inheritance tree are now declared `final`
  • src/Common/Eval.cc

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

    r309d814 r4c925cd  
    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; }
    251253        Note& getNote( size_type i ) { return scopes[i].note; }
    252254        const Note& getNote( size_type i ) const { return scopes[i].note; }
  • src/Common/Stats/Heap.cc

    r309d814 r4c925cd  
    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                }
    5579
    5680                void newPass( const char * const name ) {
     
    116140                        for(size_t i = 0; i < passes_cnt; i++) {
    117141                                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);
    118151                        }
    119152                        print('-', nct);
     
    188221                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    189222                                }
     223
     224                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     225                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     226                                }
    190227                                return __malloc( size );
    191228                        }
     
    196233                                        passes[passes_cnt - 1].frees++;
    197234                                        passes[passes_cnt - 1].n_allocs--;
     235                                }
     236                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     237                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
    198238                                }
    199239                                return __free( ptr );
     
    208248                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    209249                                }
     250                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     251                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     252                                }
    210253                                return __calloc( nelem, size );
    211254                        }
     
    218261                                        passes[passes_cnt - 1].frees++;
    219262                                } // if
     263                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     264                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     265                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
     266                                }
    220267                                return s;
    221268                        }
  • src/Common/Stats/Heap.h

    r309d814 r4c925cd  
    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();
    2226        }
    2327}
  • src/CompilationState.cc

    r309d814 r4c925cd  
    1414//
    1515
     16#include "config.h"
     17
    1618int
    1719        astp = false,
     
    2830        genproto = false,
    2931        deterministic_output = false,
     32        useNewAST = CFA_USE_NEW_AST,
    3033        nomainp = false,
    3134        parsep = false,
  • src/CompilationState.h

    r309d814 r4c925cd  
    2929        genproto,
    3030        deterministic_output,
     31        useNewAST,
    3132        nomainp,
    3233        parsep,
  • src/InitTweak/InitTweak.cc