Changeset 63be3387


Ignore:
Timestamp:
Nov 14, 2022, 11:52:44 AM (19 months ago)
Author:
caparson <caparson@…>
Branches:
ADT, ast-experimental, master
Children:
7d9598d
Parents:
b77f0e1 (diff), 19a8c40 (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:
27 added
2 deleted
72 edited

Legend:

Unmodified
Added
Removed
  • benchmark/io/http/worker.hfa

    rb77f0e1 r63be3387  
    22
    33#include <iofwd.hfa>
    4 #include <queueLockFree.hfa>
     4#include <containers/lockfree.hfa>
    55#include <thread.hfa>
    66
  • doc/theses/mike_brooks_MMath/programs/hello-md.cfa

    rb77f0e1 r63be3387  
    11#include "array.hfa"
    2 
    3 
    4 trait ix( C &, E &, ztype(N) ) {
    5     E & ?[?]( C &, ptrdiff_t );
    6     void __taglen( tag(C), tag(N) );
    7 };
    8 
    9 forall( ztype(Zn), ztype(S), Timmed &, Tbase & )
    10 void __taglen( tag(arpk(Zn, S, Timmed, Tbase)), tag(Zn) ) {}
    112
    123
     
    3829
    3930
    40 forall( ztype( N ) )
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40forall( [N] )
    4141void print1d_cstyle( array(float, N) & c );
    4242
    43 forall( C &, ztype( N ) | ix( C, float, N ) )
     43forall( [N], C & | ar( C, float, N ) )
    4444void print1d( C & c );
    4545
     
    5858
    5959
    60 forall( ztype( N ) )
     60forall( [N] )
    6161void print1d_cstyle( array(float, N) & c ) {
    62     for( i; z(N) ) {
     62    for( i; N ) {
    6363        printf("%.1f  ", c[i]);
    6464    }
     
    7878
    7979
    80 forall( C &, ztype( N ) | ix( C, float, N ) )
     80forall( [N], C & | ar( C, float, N ) )
    8181void print1d( C & c ) {
    82     for( i; z(N) ) {
     82    for( i; N ) {
    8383        printf("%.1f  ", c[i]);
    8484    }
     
    9999
    100100
    101 void fill( array(float, Z(5), Z(7)) & a ) {
     101void fill( array(float, 5, 7) & a ) {
    102102    for ( i; (ptrdiff_t) 5 ) {
    103103        for ( j; 7 ) {
    104             a[[i,j]] = 1.0 * i + 0.1 * j;
    105             printf("%.1f  ", a[[i,j]]);
     104            a[i,j] = 1.0 * i + 0.1 * j;
     105            printf("%.1f  ", a[i,j]);
    106106        }
    107107        printf("\n");
     
    118118
    119119
    120 array( float, Z(5), Z(7) ) a;
     120array( float, 5, 7 ) a;
    121121fill(a);
    122122/*
     
    148148
    149149
    150 print1d( a[[ 2, all ]] );  // 2.0  2.1  2.2  2.3  2.4  2.5  2.6
    151 print1d( a[[ all, 3 ]] );  // 0.3  1.3  2.3  3.3  4.3
     150print1d( a[ 2, all ] );  // 2.0  2.1  2.2  2.3  2.4  2.5  2.6
     151print1d( a[ all, 3 ] );  // 0.3  1.3  2.3  3.3  4.3
    152152
    153153
    154154
    155 print1d_cstyle( a[[ 2, all ]] );
     155print1d_cstyle( a[ 2, all ] );
    156156
    157157
     
    161161
    162162
    163 #ifdef SHOWERR1
     163#ifdef SHOW_ERROR_1
    164164
    165 print1d_cstyle( a[[ all, 2 ]] );  // bad
     165print1d_cstyle( a[ all, 2 ] );  // bad
    166166
    167167#endif
  • doc/theses/thierry_delisle_PhD/thesis/text/front.tex

    rb77f0e1 r63be3387  
    161161Thanks to Andrew Beach, Michael Brooks, Colby Parsons, Mubeen Zulfiqar, Fangren Yu and Jiada Liang for their work on the \CFA project as well as all the discussions which have helped me concretize the ideas in this thesis.
    162162
    163 Finally, I acknowledge that this has been possible thanks to the financial help offered by the David R. Cheriton School of Computer Science and the corporate partnership with Huawei Ltd.
     163Finally, I acknowledge that this has been possible thanks to the financial help offered by the David R. Cheriton School of Computer Science, the corporate partnership with Huawei Ltd. and the Natural Sciences and Engineering Research Council.
    164164\cleardoublepage
    165165
  • libcfa/src/Makefile.am

    rb77f0e1 r63be3387  
    6262        containers/array.hfa \
    6363        containers/list.hfa \
    64         containers/queueLockFree.hfa \
    65         containers/stackLockFree.hfa \
     64        containers/lockfree.hfa \
    6665        containers/string_sharectx.hfa \
    6766        containers/vector2.hfa \
     
    112111        concurrency/invoke.h \
    113112        concurrency/future.hfa \
     113        concurrency/once.hfa \
    114114        concurrency/kernel/fwd.hfa \
    115115        concurrency/mutex_stmt.hfa
     
    127127
    128128thread_libsrc = ${inst_thread_headers_src} ${inst_thread_headers_src:.hfa=.cfa} \
     129        interpose_thread.cfa \
    129130        bits/signal.hfa \
    130131        concurrency/clib/cfathread.cfa \
     
    145146        concurrency/stats.cfa \
    146147        concurrency/stats.hfa \
    147         concurrency/stats.hfa
     148        concurrency/stats.hfa \
     149        concurrency/pthread.cfa
    148150
    149151else
  • libcfa/src/bits/containers.hfa

    rb77f0e1 r63be3387  
    152152
    153153                void append( __queue(T) & this, T * val ) with(this) {
     154                        verify(get_next( *val ) == 0p);
    154155                        verify(this.tail != 0p);
    155156                        verify(*this.tail == 1p);
  • libcfa/src/bits/defs.hfa

    rb77f0e1 r63be3387  
    3030#ifdef __cforall
    3131#define __cfa_anonymous_object(x) inline struct x
    32 #define __cfa_dlink(x) inline dlink(x)
    3332#else
    3433#define __cfa_anonymous_object(x) struct x __cfa_anonymous_object
    35 #define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute
    3634#endif
    3735
  • libcfa/src/concurrency/clib/cfathread.cfa

    rb77f0e1 r63be3387  
    172172
    173173                pthread_attr_t attr;
    174                 if (int ret = pthread_attr_init(&attr); 0 != ret) {
     174                if (int ret = __cfaabi_pthread_attr_init(&attr); 0 != ret) {
    175175                        abort | "failed to create master epoll thread attr: " | ret | strerror(ret);
    176176                }
    177177
    178                 if (int ret = pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) {
     178                if (int ret = __cfaabi_pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) {
    179179                        abort | "failed to create master epoll thread: " | ret | strerror(ret);
    180180                }
  • libcfa/src/concurrency/invoke.h

    rb77f0e1 r63be3387  
    146146
    147147        // Link lists fields
    148         // instrusive link field for threads
     148        // instrusive link field for threads in the ready-queue
    149149        struct __thread_desc_link {
    150150                struct thread$ * next;
    151151                volatile unsigned long long ts;
    152152        };
     153
     154        // Link lists fields
     155        // instrusive link field for threads in the user_link/cltr_link
     156        struct __thread_user_link {
     157                #ifdef __cforall
     158                        inline dlink(thread$);
     159                #else
     160                        struct thread$ * next; struct thread$ * back;
     161                #endif
     162        };
     163        _Static_assert(sizeof(struct __thread_user_link) == 2 * sizeof(struct thread$ *), "__thread_user_link should be consistent in C and Cforall");
    153164
    154165        struct thread$ {
     
    159170                // Link lists fields
    160171                // instrusive link field for threads
    161                 struct __thread_desc_link link;
     172                struct __thread_desc_link rdy_link;
    162173
    163174                // current execution status for coroutine
     
    195206                struct __monitor_group_t monitors;
    196207
    197                 // used to put threads on dlist data structure
    198                 __cfa_dlink(thread$);
    199 
    200                 struct {
    201                         struct thread$ * next;
    202                         struct thread$ * prev;
    203                 } node;
     208                // intrusive link fields, used for locks, monitors and any user defined data structure
     209                // default link fields for dlist
     210                struct __thread_user_link user_link;
     211
     212                // secondary intrusive link fields, used for global cluster list
     213                // default link fields for dlist
     214                struct __thread_user_link cltr_link;
    204215
    205216                // used to store state between clh lock/unlock
     
    214225
    215226                #if defined( __CFA_WITH_VERIFY__ )
     227                        struct processor * volatile executing;
    216228                        void * canary;
    217229                #endif
    218230        };
    219         #ifdef __cforall
    220                 P9_EMBEDDED( thread$, dlink(thread$) )
    221         #endif
     231
    222232        // Wrapper for gdb
    223233        struct cfathread_thread_t { struct thread$ debug; };
     
    231241        #ifdef __cforall
    232242        extern "Cforall" {
     243                static inline thread$ * volatile & ?`next ( thread$ * this ) {
     244                        return this->user_link.next;
     245                }
    233246
    234247                static inline thread$ *& get_next( thread$ & this ) __attribute__((const)) {
    235                         return this.link.next;
    236                 }
    237 
    238                 static inline [thread$ *&, thread$ *& ] __get( thread$ & this ) __attribute__((const)) {
    239                         return this.node.[next, prev];
    240                 }
     248                        return this.user_link.next;
     249                }
     250
     251                static inline tytagref( dlink(thread$), dlink(thread$) ) ?`inner( thread$ & this ) {
     252                        dlink(thread$) & b = this.user_link;
     253                        tytagref( dlink(thread$), dlink(thread$) ) result = { b };
     254                        return result;
     255                }
     256
     257                static inline tytagref(struct __thread_user_link, dlink(thread$)) ?`inner( struct thread$ & this ) {
     258                        struct __thread_user_link & ib = this.cltr_link;
     259                        dlink(thread$) & b = ib`inner;
     260                        tytagref(struct __thread_user_link, dlink(thread$)) result = { b };
     261                        return result;
     262                }
     263
     264                P9_EMBEDDED(struct __thread_user_link, dlink(thread$))
    241265
    242266                static inline void ?{}(__monitor_group_t & this) {
  • libcfa/src/concurrency/io.cfa

    rb77f0e1 r63be3387  
    610610                if( we ) {
    611611                        sigval_t value = { PREEMPT_IO };
    612                         pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);
     612                        __cfaabi_pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);
    613613                }
    614614
     
    639639                }
    640640        }
    641 
    642         #if defined(CFA_WITH_IO_URING_IDLE)
    643                 bool __kernel_read(struct processor * proc, io_future_t & future, iovec & iov, int fd) {
    644                         io_context$ * ctx = proc->io.ctx;
    645                         /* paranoid */ verify( ! __preemption_enabled() );
    646                         /* paranoid */ verify( proc == __cfaabi_tls.this_processor );
    647                         /* paranoid */ verify( ctx );
    648 
    649                         __u32 idx;
    650                         struct io_uring_sqe * sqe;
    651 
    652                         // We can proceed to the fast path
    653                         if( !__alloc(ctx, &idx, 1) ) {
    654                                 /* paranoid */ verify( false ); // for now check if this happens, next time just abort the sleep.
    655                                 return false;
    656                         }
    657 
    658                         // Allocation was successful
    659                         __fill( &sqe, 1, &idx, ctx );
    660 
    661                         sqe->user_data = (uintptr_t)&future;
    662                         sqe->flags = 0;
    663                         sqe->fd = fd;
    664                         sqe->off = 0;
    665                         sqe->ioprio = 0;
    666                         sqe->fsync_flags = 0;
    667                         sqe->__pad2[0] = 0;
    668                         sqe->__pad2[1] = 0;
    669                         sqe->__pad2[2] = 0;
    670 
    671                         #if defined(CFA_HAVE_IORING_OP_READ)
    672                                 sqe->opcode = IORING_OP_READ;
    673                                 sqe->addr = (uint64_t)iov.iov_base;
    674                                 sqe->len = iov.iov_len;
    675                         #elif defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV)
    676                                 sqe->opcode = IORING_OP_READV;
    677                                 sqe->addr = (uintptr_t)&iov;
    678                                 sqe->len = 1;
    679                         #else
    680                                 #error CFA_WITH_IO_URING_IDLE but none of CFA_HAVE_READV, CFA_HAVE_IORING_OP_READV or CFA_HAVE_IORING_OP_READ defined
    681                         #endif
    682 
    683                         asm volatile("": : :"memory");
    684 
    685                         /* paranoid */ verify( sqe->user_data == (uintptr_t)&future );
    686                         __submit_only( ctx, &idx, 1 );
    687 
    688                         /* paranoid */ verify( proc == __cfaabi_tls.this_processor );
    689                         /* paranoid */ verify( ! __preemption_enabled() );
    690 
    691                         return true;
    692                 }
    693 
    694                 void __cfa_io_idle( struct processor * proc ) {
    695                         iovec iov;
    696                         __atomic_acquire( &proc->io.ctx->cq.lock );
    697 
    698                         __attribute__((used)) volatile bool was_reset = false;
    699 
    700                         with( proc->idle_wctx) {
    701 
    702                                 // Do we already have a pending read
    703                                 if(available(*ftr)) {
    704                                         // There is no pending read, we need to add one
    705                                         reset(*ftr);
    706 
    707                                         iov.iov_base = rdbuf;
    708                                         iov.iov_len  = sizeof(eventfd_t);
    709                                         __kernel_read(proc, *ftr, iov, evfd );
    710                                         ftr->result = 0xDEADDEAD;
    711                                         *((eventfd_t *)rdbuf) = 0xDEADDEADDEADDEAD;
    712                                         was_reset = true;
    713                                 }
    714                         }
    715 
    716                         if( !__atomic_load_n( &proc->do_terminate, __ATOMIC_SEQ_CST ) ) {
    717                                 __ioarbiter_flush( *proc->io.ctx );
    718                                 proc->idle_wctx.sleep_time = rdtscl();
    719                                 ioring_syscsll( *proc->io.ctx, 1, IORING_ENTER_GETEVENTS);
    720                         }
    721 
    722                         ready_schedule_lock();
    723                         __cfa_do_drain( proc->io.ctx, proc->cltr );
    724                         ready_schedule_unlock();
    725 
    726                         asm volatile ("" :: "m" (was_reset));
    727                 }
    728         #endif
    729641#endif
  • libcfa/src/concurrency/io/setup.cfa

    rb77f0e1 r63be3387  
    3434        bool __cfa_io_flush( processor * proc ) { return false; }
    3535        bool __cfa_io_drain( processor * proc ) __attribute__((nonnull (1))) { return false; }
    36         void __cfa_io_idle ( processor * ) __attribute__((nonnull (1))) {}
    3736        void __cfa_io_stop ( processor * proc ) {}
    3837
     
    317316        }
    318317
    319 //=============================================================================================
    320 // I/O Context Sleep
    321 //=============================================================================================
    322         // static inline void __epoll_ctl(io_context$ & ctx, int op, const char * error) {
    323         //      struct epoll_event ev;
    324         //      ev.events = EPOLLIN | EPOLLONESHOT;
    325         //      ev.data.u64 = (__u64)&ctx;
    326         //      int ret = epoll_ctl(iopoll.epollfd, op, ctx.efd, &ev);
    327         //      if (ret < 0) {
    328         //              abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) );
    329         //      }
    330         // }
    331 
    332         // static void __epoll_register(io_context$ & ctx) {
    333         //      __epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD");
    334         // }
    335 
    336         // static void __epoll_unregister(io_context$ & ctx) {
    337         //      // Read the current epoch so we know when to stop
    338         //      size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);
    339 
    340         //      // Remove the fd from the iopoller
    341         //      __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");
    342 
    343         //      // Notify the io poller thread of the shutdown
    344         //      iopoll.run = false;
    345         //      sigval val = { 1 };
    346         //      pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
    347 
    348         //      // Make sure all this is done
    349         //      __atomic_thread_fence(__ATOMIC_SEQ_CST);
    350 
    351         //      // Wait for the next epoch
    352         //      while(curr == iopoll.epoch && !iopoll.stopped) Pause();
    353         // }
    354 
    355         // void __ioctx_prepare_block(io_context$ & ctx) {
    356         //      __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.fd, &ctx);
    357         //      __epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM");
    358         // }
    359 
    360318
    361319//=============================================================================================
  • libcfa/src/concurrency/kernel.cfa

    rb77f0e1 r63be3387  
    138138extern bool __cfa_io_drain( processor * proc ) __attribute__((nonnull (1)));
    139139extern bool __cfa_io_flush( processor * ) __attribute__((nonnull (1)));
    140 extern void __cfa_io_idle( processor * ) __attribute__((nonnull (1)));
    141 
    142 #if defined(CFA_WITH_IO_URING_IDLE)
    143         extern bool __kernel_read(processor * proc, io_future_t & future, iovec &, int fd);
    144 #endif
     140
    145141
    146142extern void __disable_interrupts_hard();
     
    162158        verify(this);
    163159
    164         /* paranoid */ verify( this->idle_wctx.ftr   != 0p );
    165         /* paranoid */ verify( this->idle_wctx.rdbuf != 0p );
    166 
    167         // used for idle sleep when io_uring is present
    168         // mark it as already fulfilled so we know if there is a pending request or not
    169         this->idle_wctx.ftr->self.ptr = 1p;
    170 
    171160        __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
    172161        #if !defined(__CFA_NO_STATISTICS__)
     
    291280        /* paranoid */ verify( ! __preemption_enabled() );
    292281        /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
    293         /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
     282        /* paranoid */ verifyf( thrd_dst->rdy_link.next == 0p, "Expected null got %p", thrd_dst->rdy_link.next );
    294283        __builtin_prefetch( thrd_dst->context.SP );
    295284
     
    321310                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor
    322311                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor
     312                /* paranoid */ verify( __atomic_exchange_n( &thrd_dst->executing, this, __ATOMIC_SEQ_CST) == 0p );
    323313                /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
    324314
     
    332322
    333323                /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
     324                /* paranoid */ verify( __atomic_exchange_n( &thrd_dst->executing, 0p, __ATOMIC_SEQ_CST) == this );
    334325                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst );
    335326                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst );
     327                /* paranoid */ verify( thrd_dst->state != Halted );
    336328                /* paranoid */ verify( thrd_dst->context.SP );
    337                 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr );
    338329                /* paranoid */ verify( kernelTLS().this_thread == thrd_dst );
    339330                /* paranoid */ verify( ! __preemption_enabled() );
     
    452443                                        "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted );
    453444        /* paranoid */ #endif
    454         /* paranoid */ verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next );
     445        /* paranoid */ verifyf( thrd->rdy_link.next == 0p, "Expected null got %p", thrd->rdy_link.next );
    455446        /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
    456447
     
    600591                /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : thread$ %p has been corrupted.\n StackPointer too small.\n", thrd );
    601592
    602                 thrd->state = Halting;
    603593                if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); }
    604594                if( thrd != this->owner ) { abort( "Thread internal monitor has incorrect owner" ); }
    605595                if( this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); }
     596
     597                thrd->state = Halting;
     598                thrd->ticket = TICKET_DEAD;
    606599
    607600                // Leave the thread
     
    624617                // If that is the case, abandon the preemption.
    625618                bool preempted = false;
    626                 if(thrd->link.next == 0p) {
     619                if(thrd->rdy_link.next == 0p) {
    627620                        preempted = true;
    628621                        thrd->preempted = reason;
     
    726719
    727720
    728         #if !defined(CFA_WITH_IO_URING_IDLE)
    729                 #if !defined(__CFA_NO_STATISTICS__)
    730                         if(this->print_halts) {
    731                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl());
     721        #if !defined(__CFA_NO_STATISTICS__)
     722                if(this->print_halts) {
     723                        __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl());
     724                }
     725        #endif
     726
     727        __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
     728
     729        {
     730                eventfd_t val;
     731                ssize_t ret = read( this->idle_wctx.evfd, &val, sizeof(val) );
     732                if(ret < 0) {
     733                        switch((int)errno) {
     734                        case EAGAIN:
     735                        #if EAGAIN != EWOULDBLOCK
     736                                case EWOULDBLOCK:
     737                        #endif
     738                        case EINTR:
     739                                // No need to do anything special here, just assume it's a legitimate wake-up
     740                                break;
     741                        default:
     742                                abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
    732743                        }
    733                 #endif
    734 
    735                 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
    736 
    737                 {
    738                         eventfd_t val;
    739                         ssize_t ret = read( this->idle_wctx.evfd, &val, sizeof(val) );
    740                         if(ret < 0) {
    741                                 switch((int)errno) {
    742                                 case EAGAIN:
    743                                 #if EAGAIN != EWOULDBLOCK
    744                                         case EWOULDBLOCK:
    745                                 #endif
    746                                 case EINTR:
    747                                         // No need to do anything special here, just assume it's a legitimate wake-up
    748                                         break;
    749                                 default:
    750                                         abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
    751                                 }
    752                         }
    753                 }
    754 
    755                 #if !defined(__CFA_NO_STATISTICS__)
    756                         if(this->print_halts) {
    757                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl());
    758                         }
    759                 #endif
    760         #else
    761                 __cfa_io_idle( this );
     744                }
     745        }
     746
     747        #if !defined(__CFA_NO_STATISTICS__)
     748                if(this->print_halts) {
     749                        __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl());
     750                }
    762751        #endif
    763752}
     
    775764                insert_first(this.idles, proc);
    776765
     766                // update the pointer to the head wait context, which should now point to this proc.
    777767                __atomic_store_n(&this.fdw, &proc.idle_wctx, __ATOMIC_SEQ_CST);
    778768        unlock( this );
     
    791781
    792782                {
     783                        // update the pointer to the head wait context
    793784                        struct __fd_waitctx * wctx = 0;
    794785                        if(!this.idles`isEmpty) wctx = &this.idles`first.idle_wctx;
  • libcfa/src/concurrency/kernel.hfa

    rb77f0e1 r63be3387  
    6464        // 1 - means the proc should wake-up immediately
    6565        // FD - means the proc is going asleep and should be woken by writing to the FD.
     66        //      The FD value should always be the evfd field just below.
    6667        volatile int sem;
    6768
     
    6970        int evfd;
    7071
    71         // buffer into which the proc will read from evfd
    72         // unused if not using io_uring for idle sleep
    73         void * rdbuf;
    74 
    75         // future use to track the read of the eventfd
    76         // unused if not using io_uring for idle sleep
    77         io_future_t * ftr;
    78 
     72        // Used for debugging, should be removed eventually.
    7973        volatile unsigned long long wake__time;
    8074        volatile unsigned long long sleep_time;
     
    160154// P9_EMBEDDED( processor, dlink(processor) )
    161155static inline tytagref( dlink(processor), dlink(processor) ) ?`inner( processor & this ) {
    162     dlink(processor) & b = this.link;
    163     tytagref( dlink(processor), dlink(processor) ) result = { b };
    164     return result;
     156        dlink(processor) & b = this.link;
     157        tytagref( dlink(processor), dlink(processor) ) result = { b };
     158        return result;
    165159}
    166160
     
    256250        // List of threads
    257251        __spinlock_t thread_list_lock;
    258         __dllist_t(struct thread$) threads;
     252        dlist(struct thread$, struct __thread_user_link) threads;
    259253        unsigned int nthreads;
    260254
     
    269263                io_context_params params;
    270264        } io;
     265
     266        struct {
     267                struct processor ** procs;
     268                unsigned cnt;
     269        } managed;
    271270
    272271        #if !defined(__CFA_NO_STATISTICS__)
     
    298297static inline struct cluster   * active_cluster  () { return publicTLS_get( this_processor )->cltr; }
    299298
     299// set the number of internal processors
     300// these processors are in addition to any explicitly declared processors
     301unsigned set_concurrency( cluster & this, unsigned new_count );
     302
    300303#if !defined(__CFA_NO_STATISTICS__)
    301304        void print_stats_now( cluster & this, int flags );
  • libcfa/src/concurrency/kernel/cluster.cfa

    rb77f0e1 r63be3387  
    483483
    484484        // We add a boat-load of assertions here because the anchor code is very fragile
    485         /* paranoid */ _Static_assert( offsetof( thread$, link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
    486         /* paranoid */ verify( offsetof( thread$, link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
    487         /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, link )) == (uintptr_t)(&this.l.anchor) );
    488         /* paranoid */ verify( &mock_head(this)->link.next == &this.l.anchor.next );
    489         /* paranoid */ verify( &mock_head(this)->link.ts   == &this.l.anchor.ts   );
    490         /* paranoid */ verify( mock_head(this)->link.next == 0p );
    491         /* paranoid */ verify( mock_head(this)->link.ts   == MAX );
     485        /* paranoid */ _Static_assert( offsetof( thread$, rdy_link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
     486        /* paranoid */ verify( offsetof( thread$, rdy_link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
     487        /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, rdy_link )) == (uintptr_t)(&this.l.anchor) );
     488        /* paranoid */ verify( &mock_head(this)->rdy_link.next == &this.l.anchor.next );
     489        /* paranoid */ verify( &mock_head(this)->rdy_link.ts   == &this.l.anchor.ts   );
     490        /* paranoid */ verify( mock_head(this)->rdy_link.next == 0p );
     491        /* paranoid */ verify( mock_head(this)->rdy_link.ts   == MAX );
    492492        /* paranoid */ verify( mock_head(this) == this.l.prev );
    493493        /* paranoid */ verify( __alignof__(__intrusive_lane_t) == 64 );
  • libcfa/src/concurrency/kernel/private.hfa

    rb77f0e1 r63be3387  
    2020#endif
    2121
     22#include <signal.h>
     23
    2224#include "kernel.hfa"
    2325#include "thread.hfa"
     
    3941}
    4042
    41 // Defines whether or not we *want* to use io_uring_enter as the idle_sleep blocking call
    42 // #define CFA_WANT_IO_URING_IDLE
    43 
    44 // Defines whether or not we *can* use io_uring_enter as the idle_sleep blocking call
    45 #if defined(CFA_WANT_IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H)
    46         #if defined(CFA_HAVE_IORING_OP_READ) || (defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV))
    47                 #define CFA_WITH_IO_URING_IDLE
    48         #endif
    49 #endif
    50 
    5143// #define READYQ_USE_LINEAR_AVG
    5244#define READYQ_USE_LOGDBL_AVG
     
    6355#endif
    6456
     57extern "C" {
     58        __attribute__((visibility("protected"))) int __cfaabi_pthread_create(pthread_t *_thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
     59        __attribute__((visibility("protected"))) int __cfaabi_pthread_join(pthread_t _thread, void **retval);
     60        __attribute__((visibility("protected"))) pthread_t __cfaabi_pthread_self(void);
     61        __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_init(pthread_attr_t *attr);
     62        __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_destroy(pthread_attr_t *attr);
     63        __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_setstack( pthread_attr_t *attr, void *stackaddr, size_t stacksize );
     64        __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_getstacksize( const pthread_attr_t *attr, size_t *stacksize );
     65        __attribute__((visibility("protected"))) int __cfaabi_pthread_sigqueue(pthread_t _thread, int sig, const union sigval value);
     66        __attribute__((visibility("protected"))) int __cfaabi_pthread_sigmask( int how, const sigset_t *set, sigset_t *oset);
     67}
     68
    6569//-----------------------------------------------------------------------------
    6670// Scheduler
     
    153157#define TICKET_RUNNING ( 0) // thread is running
    154158#define TICKET_UNBLOCK ( 1) // thread should ignore next block
     159#define TICKET_DEAD    (0xDEAD) // thread should never be unparked
    155160
    156161//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/kernel/startup.cfa

    rb77f0e1 r63be3387  
    1616#define __cforall_thread__
    1717#define _GNU_SOURCE
     18
     19// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    1820
    1921// C Includes
     
    113115KERNEL_STORAGE(thread$,              mainThread);
    114116KERNEL_STORAGE(__stack_t,            mainThreadCtx);
    115 // KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock);
    116 KERNEL_STORAGE(eventfd_t,            mainIdleEventFd);
    117 KERNEL_STORAGE(io_future_t,          mainIdleFuture);
    118117#if !defined(__CFA_NO_STATISTICS__)
    119118KERNEL_STORAGE(__stats_t, mainProcStats);
     
    222221                ( this.runner ){};
    223222                init( this, "Main Processor", *mainCluster, 0p );
    224                 kernel_thread = pthread_self();
     223                kernel_thread = __cfaabi_pthread_self();
    225224
    226225                runner{ &this };
     
    232231        mainProcessor = (processor *)&storage_mainProcessor;
    233232        (*mainProcessor){};
    234 
    235         mainProcessor->idle_wctx.rdbuf = &storage_mainIdleEventFd;
    236         mainProcessor->idle_wctx.ftr   = (io_future_t*)&storage_mainIdleFuture;
    237         /* paranoid */ verify( sizeof(storage_mainIdleEventFd) == sizeof(eventfd_t) );
    238233
    239234        __cfa_io_start( mainProcessor );
     
    283278}
    284279
     280extern "C"{
     281        void pthread_delete_kernel_threads_();
     282}
     283
     284
    285285static void __kernel_shutdown(void) {
    286286        if(!cfa_main_returned) return;
     287
     288        //delete kernel threads for pthread_concurrency
     289        pthread_delete_kernel_threads_();
     290
    287291        /* paranoid */ verify( __preemption_enabled() );
    288292        disable_interrupts();
     
    327331
    328332                /* paranoid */ verify( this.do_terminate == true );
    329                 __cfaabi_dbg_print_safe("Kernel : destroyed main processor context %p\n", &runner);
     333                __cfadbg_print_safe(runtime_core, "Kernel : destroyed main processor context %p\n", &runner);
    330334        }
    331335
     
    373377        register_tls( proc );
    374378
    375         // used for idle sleep when io_uring is present
    376         io_future_t future;
    377         eventfd_t idle_buf;
    378         proc->idle_wctx.ftr = &future;
    379         proc->idle_wctx.rdbuf = &idle_buf;
    380 
    381 
    382379        // SKULLDUGGERY: We want to create a context for the processor coroutine
    383380        // which is needed for the 2-step context switch. However, there is no reason
     
    388385        (proc->runner){ proc, &info };
    389386
    390         __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
     387        __cfadbg_print_safe(runtime_core, "Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
    391388
    392389        //Set global state
     
    514511        self_mon.recursion = 1;
    515512        self_mon_p = &self_mon;
    516         link.next = 0p;
    517         link.ts   = MAX;
     513        rdy_link.next = 0p;
     514        rdy_link.ts   = MAX;
    518515        preferred = ready_queue_new_preferred();
    519516        last_proc = 0p;
    520517        random_state = __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl();
    521518        #if defined( __CFA_WITH_VERIFY__ )
     519                executing = 0p;
    522520                canary = 0x0D15EA5E0D15EA5Ep;
    523521        #endif
    524522
    525         node.next = 0p;
    526         node.prev = 0p;
    527523        doregister(curr_cluster, this);
    528524
     
    647643        #endif
    648644
    649         threads{ __get };
     645        threads{};
    650646
    651647        io.arbiter = create();
    652648        io.params = io_params;
     649
     650        managed.procs = 0p;
     651        managed.cnt = 0;
    653652
    654653        doregister(this);
     
    667666
    668667void ^?{}(cluster & this) libcfa_public {
     668        set_concurrency( this, 0 );
     669
    669670        destroy(this.io.arbiter);
    670671
     
    722723        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    723724        cltr->nthreads += 1;
    724         push_front(cltr->threads, thrd);
     725        insert_first(cltr->threads, thrd);
    725726        unlock    (cltr->thread_list_lock);
    726727}
     
    728729void unregister( cluster * cltr, thread$ & thrd ) {
    729730        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    730         remove(cltr->threads, thrd );
    731         cltr->nthreads -= 1;
     731        {
     732                tytagref( dlink(thread$), dlink(thread$) ) ?`inner( thread$ & this ) = void;
     733                with( DLINK_VIA( thread$, struct __thread_user_link ) )
     734                        remove( thrd );
     735                cltr->nthreads -= 1;
     736        }
    732737        unlock(cltr->thread_list_lock);
    733738}
     
    777782        pthread_attr_t attr;
    778783
    779         check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
     784        check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
    780785
    781786        size_t stacksize = max( PTHREAD_STACK_MIN, DEFAULT_STACK_SIZE );
     
    804809        #endif
    805810
    806         check( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
    807         check( pthread_create( pthread, &attr, start, arg ), "pthread_create" );
     811        check( __cfaabi_pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
     812        check( __cfaabi_pthread_create( pthread, &attr, start, arg ), "pthread_create" );
    808813        return stack;
    809814}
    810815
    811816void __destroy_pthread( pthread_t pthread, void * stack, void ** retval ) {
    812         int err = pthread_join( pthread, retval );
     817        int err = __cfaabi_pthread_join( pthread, retval );
    813818        if( err != 0 ) abort("KERNEL ERROR: joining pthread %p caused error %s\n", (void*)pthread, strerror(err));
    814819
     
    816821                pthread_attr_t attr;
    817822
    818                 check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
     823                check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
    819824
    820825                size_t stacksize;
    821826                // default stack size, normally defined by shell limit
    822                 check( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );
     827                check( __cfaabi_pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );
    823828                assert( stacksize >= PTHREAD_STACK_MIN );
    824829                stacksize += __page_size;
     
    838843}
    839844
     845unsigned set_concurrency( cluster & this, unsigned new ) libcfa_public {
     846        unsigned old = this.managed.cnt;
     847
     848        __cfadbg_print_safe(runtime_core, "Kernel : resizing cluster from %u to %u\n", old, (unsigned)new);
     849
     850        // Delete all the old unneeded procs
     851        if(old > new) for(i; (unsigned)new ~ old) {
     852                __cfadbg_print_safe(runtime_core, "Kernel : destroying %u\n", i);
     853                delete( this.managed.procs[i] );
     854        }
     855
     856        // Allocate new array (uses realloc and memcpies the data)
     857        this.managed.procs = alloc( new, this.managed.procs`realloc );
     858        this.managed.cnt = new;
     859
     860        // Create the desired new procs
     861        if(old < new) for(i; old ~ new) {
     862                __cfadbg_print_safe(runtime_core, "Kernel : constructing %u\n", i);
     863                (*(this.managed.procs[i] = alloc())){ this };
     864        }
     865
     866        // return the old count
     867        return old;
     868}
     869
    840870#if defined(__CFA_WITH_VERIFY__)
    841871static bool verify_fwd_bck_rng(void) {
  • libcfa/src/concurrency/locks.hfa

    rb77f0e1 r63be3387  
    2121
    2222#include "bits/weakso_locks.hfa"
    23 #include "containers/queueLockFree.hfa"
     23#include "containers/lockfree.hfa"
    2424#include "containers/list.hfa"
    2525
     
    498498}
    499499
    500 static inline size_t on_wait(simple_owner_lock & this) with(this) { 
     500static inline size_t on_wait(simple_owner_lock & this) with(this) {
    501501        lock( lock __cfaabi_dbg_ctx2 );
    502502        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
  • libcfa/src/concurrency/monitor.cfa

    rb77f0e1 r63be3387  
    122122
    123123                // Some one else has the monitor, wait in line for it
    124                 /* paranoid */ verify( thrd->link.next == 0p );
     124                /* paranoid */ verify( thrd->user_link.next == 0p );
    125125                append( this->entry_queue, thrd );
    126                 /* paranoid */ verify( thrd->link.next == 1p );
     126                /* paranoid */ verify( thrd->user_link.next == 1p );
    127127
    128128                unlock( this->lock );
     
    233233
    234234                // Some one else has the monitor, wait in line for it
    235                 /* paranoid */ verify( thrd->link.next == 0p );
     235                /* paranoid */ verify( thrd->user_link.next == 0p );
    236236                append( this->entry_queue, thrd );
    237                 /* paranoid */ verify( thrd->link.next == 1p );
     237                /* paranoid */ verify( thrd->user_link.next == 1p );
    238238                unlock( this->lock );
    239239
     
    791791        thread$ * new_owner = pop_head( this->entry_queue );
    792792        /* paranoid */ verifyf( !this->owner || active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    793         /* paranoid */ verify( !new_owner || new_owner->link.next == 0p );
     793        /* paranoid */ verify( !new_owner || new_owner->user_link.next == 0p );
    794794        __set_owner( this, new_owner );
    795795
     
    935935        __queue_t(thread$) & entry_queue = monitors[0]->entry_queue;
    936936
     937        #if defined( __CFA_WITH_VERIFY__ )
     938                thread$ * last = 0p;
     939        #endif
    937940        // For each thread in the entry-queue
    938941        for(    thread$ ** thrd_it = &entry_queue.head;
    939942                (*thrd_it) != 1p;
    940                 thrd_it = &(*thrd_it)->link.next
     943                thrd_it = &get_next(**thrd_it)
    941944        ) {
     945                thread$ * curr = *thrd_it;
     946
     947                /* paranoid */ verifyf( !last || last->user_link.next == curr, "search not making progress, from %p (%p) to %p", last, last->user_link.next, curr );
     948                /* paranoid */ verifyf( curr != last, "search not making progress, from %p to %p", last, curr );
     949
    942950                // For each acceptable check if it matches
    943951                int i = 0;
     
    946954                for( __acceptable_t * it = begin; it != end; it++, i++ ) {
    947955                        // Check if we have a match
    948                         if( *it == (*thrd_it)->monitors ) {
     956                        if( *it == curr->monitors ) {
    949957
    950958                                // If we have a match return it
     
    953961                        }
    954962                }
     963
     964                #if defined( __CFA_WITH_VERIFY__ )
     965                        last = curr;
     966                #endif
    955967        }
    956968
     
    10251037
    10261038                // Some one else has the monitor, wait in line for it
    1027                 /* paranoid */ verify( thrd->link.next == 0p );
     1039                /* paranoid */ verify( thrd->user_link.next == 0p );
    10281040                append( this->entry_queue, thrd );
    1029                 /* paranoid */ verify( thrd->link.next == 1p );
     1041                /* paranoid */ verify( thrd->user_link.next == 1p );
    10301042
    10311043                unlock( this->lock );
  • libcfa/src/concurrency/preemption.cfa

    rb77f0e1 r63be3387  
    352352        sigset_t oldset;
    353353        int ret;
    354         ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     354        ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    355355        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    356356
     
    385385        sigaddset( &mask, sig );
    386386
    387         if ( pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {
     387        if ( __cfaabi_pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {
    388388            abort( "internal error, pthread_sigmask" );
    389389        }
     
    396396        sigaddset( &mask, sig );
    397397
    398         if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
     398        if ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    399399                abort( "internal error, pthread_sigmask" );
    400400        }
     
    404404static void preempt( processor * this ) {
    405405        sigval_t value = { PREEMPT_NORMAL };
    406         pthread_sigqueue( this->kernel_thread, SIGUSR1, value );
     406        __cfaabi_pthread_sigqueue( this->kernel_thread, SIGUSR1, value );
    407407}
    408408
     
    415415        sigset_t oldset;
    416416        int ret;
    417         ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     417        ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    418418        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    419419
     
    434434        sigset_t oldset;
    435435        int ret;
    436         ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     436        ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    437437        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    438438
     
    505505        sigval val;
    506506        val.sival_int = 0;
    507         pthread_sigqueue( alarm_thread, SIGALRM, val );
     507        __cfaabi_pthread_sigqueue( alarm_thread, SIGALRM, val );
    508508
    509509        // Wait for the preemption thread to finish
     
    579579        static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" );
    580580        #endif
    581         if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {
     581        if ( __cfaabi_pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {
    582582                abort( "internal error, sigprocmask" );
    583583        }
     
    607607        sigset_t mask;
    608608        sigfillset(&mask);
    609         if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
     609        if ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    610610            abort( "internal error, pthread_sigmask" );
    611611        }
  • libcfa/src/concurrency/ready_subqueue.hfa

    rb77f0e1 r63be3387  
    2525static inline thread$ * mock_head(const __intrusive_lane_t & this) {
    2626        thread$ * rhead = (thread$ *)(
    27                 (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, link )
     27                (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, rdy_link )
    2828        );
    2929        return rhead;
     
    3434static inline void push( __intrusive_lane_t & this, thread$ * node ) {
    3535        /* paranoid */ verify( this.l.lock );
    36         /* paranoid */ verify( node->link.next == 0p );
    37         /* paranoid */ verify( __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED) == MAX  );
    38         /* paranoid */ verify( this.l.prev->link.next == 0p );
    39         /* paranoid */ verify( __atomic_load_n(&this.l.prev->link.ts, __ATOMIC_RELAXED)   == MAX  );
     36        /* paranoid */ verify( node->rdy_link.next == 0p );
     37        /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED) == MAX  );
     38        /* paranoid */ verify( this.l.prev->rdy_link.next == 0p );
     39        /* paranoid */ verify( __atomic_load_n(&this.l.prev->rdy_link.ts, __ATOMIC_RELAXED)   == MAX  );
    4040        if( this.l.anchor.next == 0p ) {
    4141                /* paranoid */ verify( this.l.anchor.next == 0p );
     
    5151
    5252        // Get the relevant nodes locally
    53         this.l.prev->link.next = node;
    54         __atomic_store_n(&this.l.prev->link.ts, rdtscl(), __ATOMIC_RELAXED);
     53        this.l.prev->rdy_link.next = node;
     54        __atomic_store_n(&this.l.prev->rdy_link.ts, rdtscl(), __ATOMIC_RELAXED);
    5555        this.l.prev = node;
    5656        #if !defined(__CFA_NO_STATISTICS__)
     
    7070        // Get the relevant nodes locally
    7171        thread$ * node = this.l.anchor.next;
    72         this.l.anchor.next = node->link.next;
    73         __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);
     72        this.l.anchor.next = node->rdy_link.next;
     73        __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);
    7474        bool is_empty = this.l.anchor.next == 0p;
    75         node->link.next = 0p;
    76         __atomic_store_n(&node->link.ts, ULLONG_MAX, __ATOMIC_RELAXED);
     75        node->rdy_link.next = 0p;
     76        __atomic_store_n(&node->rdy_link.ts, ULLONG_MAX, __ATOMIC_RELAXED);
    7777        #if !defined(__CFA_NO_STATISTICS__)
    7878                this.l.cnt--;
     
    8383
    8484        unsigned long long ats = __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED);
    85         /* paranoid */ verify( node->link.next == 0p );
    86         /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) == MAX );
    87         /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) != 0   );
     85        /* paranoid */ verify( node->rdy_link.next == 0p );
     86        /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) == MAX );
     87        /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) != 0   );
    8888        /* paranoid */ verify( ats != 0 );
    8989        /* paranoid */ verify( (ats == MAX) == is_empty );
  • libcfa/src/concurrency/thread.cfa

    rb77f0e1 r63be3387  
    4444        self_mon_p = &self_mon;
    4545        curr_cluster = &cl;
    46         link.next = 0p;
    47         link.ts   = MAX;
     46        rdy_link.next = 0p;
     47        rdy_link.ts   = MAX;
    4848        preferred = ready_queue_new_preferred();
    4949        last_proc = 0p;
    5050        random_state = __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl();
    5151        #if defined( __CFA_WITH_VERIFY__ )
     52                executing = 0p;
    5253                canary = 0x0D15EA5E0D15EA5Ep;
    5354        #endif
    54 
    55         node.next = 0p;
    56         node.prev = 0p;
    5755
    5856        clh_node = malloc( );
     
    177175
    178176//-----------------------------------------------------------------------------
     177bool migrate( thread$ * thrd, struct cluster & cl ) {
     178
     179        monitor$ * tmon = get_monitor(thrd);
     180        monitor$ * __monitors[] = { tmon };
     181        monitor_guard_t __guard = { __monitors, 1 };
     182
     183
     184        {
     185                // if nothing needs to be done, return false
     186                if( thrd->curr_cluster == &cl ) return false;
     187
     188                // are we migrating ourself?
     189                const bool local = thrd == active_thread();
     190
     191                /* paranoid */ verify( !local || &cl != active_cluster() );
     192                /* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() );
     193                /* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr );
     194                /* paranoid */ verify( local || tmon->signal_stack.top->owner->waiting_thread == thrd );
     195                /* paranoid */ verify( local || tmon->signal_stack.top );
     196
     197                // make sure we aren't interrupted while doing this
     198                // not as important if we aren't local
     199                disable_interrupts();
     200
     201                // actually move the thread
     202                unregister( thrd->curr_cluster, *thrd );
     203                thrd->curr_cluster = &cl;
     204                doregister( thrd->curr_cluster, *thrd );
     205
     206                // restore interrupts
     207                enable_interrupts();
     208
     209                // if this is the local thread, we are still running on the old cluster
     210                if(local) yield();
     211
     212                /* paranoid */ verify( !local || &cl == active_cluster() );
     213                /* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() );
     214                /* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr );
     215                /* paranoid */ verify(  local || tmon->signal_stack.top );
     216                /* paranoid */ verify(  local || tmon->signal_stack.top->owner->waiting_thread == thrd );
     217
     218                return true;
     219        }
     220}
     221
     222//-----------------------------------------------------------------------------
    179223#define GENERATOR LCG
    180224
  • libcfa/src/concurrency/thread.hfa

    rb77f0e1 r63be3387  
    132132
    133133//----------
     134// misc
     135bool migrate( thread$ * thrd, struct cluster & cl );
     136
     137forall( T & | is_thread(T) )
     138static inline bool migrate( T & mutex thrd, struct cluster & cl ) { return migrate( &(thread&)thrd, cl ); }
     139
     140
     141//----------
    134142// prng
    135143static inline {
  • libcfa/src/containers/array.hfa

    rb77f0e1 r63be3387  
     1#pragma once
     2
    13#include <assert.h>
    24
     
    1820    // About the choice of integral types offered as subscript overloads:
    1921    // Intent is to cover these use cases:
     22    //    a[0]                                                // i : zero_t
     23    //    a[1]                                                // i : one_t
     24    //    a[2]                                                // i : int
    2025    //    float foo( ptrdiff_t i ) { return a[i]; }           // i : ptrdiff_t
     26    //    float foo( size_t i ) { return a[i]; }              // i : size_t
    2127    //    forall( [N] ) ... for( i; N ) { total += a[i]; }    // i : typeof( sizeof(42) )
    2228    //    for( i; 5 ) { total += a[i]; }                      // i : int
     29    //
    2330    // It gets complicated by:
    2431    // -  CFA does overloading on concrete types, like int and unsigned int, not on typedefed
     
    2835    //    should give them type size_t.
    2936    //
    30     //                          gcc -m32         cfa -m32 given bug         gcc -m64
     37    //                          gcc -m32         cfa -m32 given bug         gcc -m64 (and cfa)
    3138    // ptrdiff_t                int              int                        long int
    3239    // size_t                   unsigned int     unsigned int               unsigned long int
    3340    // typeof( sizeof(42) )     unsigned int     unsigned long int          unsigned long int
    3441    // int                      int              int                        int
     42    //
     43    // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int}
     44    //
     45    // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t)
     46    // because assertion satisfaction requires types to match exacly.  Both higher-dimensional
     47    // subscripting and operations on slices use asserted subscript operators.  The test case
     48    // array-container/array-sbscr-cases covers the combinations.  Mike beleives that commenting out
     49    // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit.
     50    // Mike is open to being shown a smaller set of overloads that still passes the test.
     51
     52    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, zero_t ) {
     53        assert( 0 < N );
     54        return (Timmed &) a.strides[0];
     55    }
     56
     57    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, one_t ) {
     58        assert( 1 < N );
     59        return (Timmed &) a.strides[1];
     60    }
    3561
    3662    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) {
     
    77103        return N;
    78104    }
     105
     106    static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {}
    79107
    80108    // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa)
     
    156184#endif
    157185
     186// Available for users to work around Trac #265
     187// If `a[...0...]` isn't working, try `a[...ix0...]` instead.
     188
     189#define ix0 ((ptrdiff_t)0)
     190
     191
     192
    158193//
    159194// Rotation
     
    185220//
    186221
    187 trait ar(A &, Tv &) {
    188     Tv& ?[?]( A&, ptrdiff_t );
    189     size_t ?`len( A& );
    190 };
     222// desired:
     223// trait ar(A &, Tv &, [N]) {
     224//     Tv& ?[?]( A&, zero_t );
     225//     Tv& ?[?]( A&, one_t  );
     226//     Tv& ?[?]( A&, int    );
     227//                   ...
     228//     size_t ?`len( A& );
     229//     void __taglen( tag(C), tag(N) );
     230// };
     231
     232// working around N's not being accepted as arguments to traits
     233
     234#define ar(A, Tv, N) {                 \
     235    Tv& ?[?]( A&, zero_t );            \
     236    Tv& ?[?]( A&, one_t );             \
     237    Tv& ?[?]( A&, int );               \
     238    Tv& ?[?]( A&, unsigned int );      \
     239    Tv& ?[?]( A&, long int );          \
     240    Tv& ?[?]( A&, unsigned long int ); \
     241    size_t ?`len( A& );                \
     242    void __taglen( tag(A), tag(N) );   \
     243}
  • libcfa/src/heap.cfa

    rb77f0e1 r63be3387  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Oct 13 22:21:52 2022
    13 // Update Count     : 1557
     12// Last Modified On : Sun Oct 30 20:56:20 2022
     13// Update Count     : 1584
    1414//
    1515
     
    4343
    4444#define FASTLOOKUP                                                                              // use O(1) table lookup from allocation size to bucket size
    45 #define RETURNSPIN                                                                              // toggle spinlock / lockfree stack
    4645#define OWNERSHIP                                                                               // return freed memory to owner thread
     46#define RETURNSPIN                                                                              // toggle spinlock / lockfree queue
     47#if ! defined( OWNERSHIP ) && defined( RETURNSPIN )
     48#warning "RETURNSPIN is ignored without OWNERSHIP; suggest commenting out RETURNSPIN"
     49#endif // ! OWNERSHIP && RETURNSPIN
    4750
    4851#define CACHE_ALIGN 64
     
    109112
    110113
    111 //######################### Spin Lock #########################
     114//######################### Helpers #########################
     115
     116
     117// generic Bsearchl does not inline, so substitute with hand-coded binary-search.
     118inline __attribute__((always_inline))
     119static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
     120        size_t l = 0, m, h = dim;
     121        while ( l < h ) {
     122                m = (l + h) / 2;
     123                if ( (unsigned int &)(vals[m]) < key ) {                // cast away const
     124                        l = m + 1;
     125                } else {
     126                        h = m;
     127                } // if
     128        } // while
     129        return l;
     130} // Bsearchl
    112131
    113132
     
    206225
    207226
    208 #define SPINLOCK 0
    209 #define LOCKFREE 1
    210 #define BUCKETLOCK SPINLOCK
    211 #if BUCKETLOCK == SPINLOCK
    212 #elif BUCKETLOCK == LOCKFREE
    213 #include <stackLockFree.hfa>
    214 #else
    215         #error undefined lock type for bucket lock
    216 #endif // LOCKFREE
    217 
    218227// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    219228// Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
     
    232241                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    233242                                                                size_t blockSize;               // size for munmap (must overlay alignment)
    234                                                                 #if BUCKETLOCK == SPINLOCK
    235243                                                                Storage * next;                 // freed block points to next freed block of same size
    236                                                                 #endif // SPINLOCK
    237244                                                        };
    238245                                                        size_t size;                            // allocation size in bytes
    239246                                                };
    240                                                 #if BUCKETLOCK == LOCKFREE
    241                                                 Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
    242                                                 #endif // LOCKFREE
    243247                                        };
    244248                                } real; // RealHeader
     
    259263        struct __attribute__(( aligned (8) )) FreeHeader {
    260264                size_t blockSize __attribute__(( aligned(8) )); // size of allocations on this list
    261                 #if BUCKETLOCK == SPINLOCK
    262265                #ifdef OWNERSHIP
    263266                #ifdef RETURNSPIN
     
    266269                Storage * returnList;                                                   // other thread return list
    267270                #endif // OWNERSHIP
     271
    268272                Storage * freeList;                                                             // thread free list
    269                 #else
    270                 StackLF(Storage) freeList;
    271                 #endif // BUCKETLOCK
    272273                Heap * homeManager;                                                             // heap owner (free storage to bucket, from bucket to heap)
    273274        }; // FreeHeader
     
    290291        #endif // __STATISTICS__
    291292}; // Heap
    292 
    293 #if BUCKETLOCK == LOCKFREE
    294 inline __attribute__((always_inline))
    295 static {
    296         Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; }
    297         void ?{}( Heap.FreeHeader & ) {}
    298         void ^?{}( Heap.FreeHeader & ) {}
    299 } // distribution
    300 #endif // LOCKFREE
    301293
    302294
     
    385377
    386378
    387 // generic Bsearchl does not inline, so substitute with hand-coded binary-search.
    388 inline __attribute__((always_inline))
    389 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
    390         size_t l = 0, m, h = dim;
    391         while ( l < h ) {
    392                 m = (l + h) / 2;
    393                 if ( (unsigned int &)(vals[m]) < key ) {                // cast away const
    394                         l = m + 1;
    395                 } else {
    396                         h = m;
    397                 } // if
    398         } // while
    399         return l;
    400 } // Bsearchl
    401 
    402 
    403379void heapMasterCtor() with( heapMaster ) {
    404380        // Singleton pattern to initialize heap master
     
    409385        __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
    410386
    411         ?{}( extLock );
    412         ?{}( mgrLock );
     387        extLock = 0;
     388        mgrLock = 0;
    413389
    414390        char * end = (char *)sbrk( 0 );
     
    497473                                #ifdef OWNERSHIP
    498474                                #ifdef RETURNSPIN
    499                                 ?{}( freeLists[j].returnLock );
     475                                freeLists[j].returnLock = 0;
     476                                freeLists[j].returnList = 0p;
    500477                                #endif // RETURNSPIN
    501                                 freeLists[j].returnList = 0p;
    502478                                #endif // OWNERSHIP
     479
    503480                                freeLists[j].freeList = 0p;
    504481                                freeLists[j].homeManager = heap;
    505482                                freeLists[j].blockSize = bucketSizes[j];
    506483                        } // for
    507        
     484
    508485                        heapBuffer = 0p;
    509486                        heapReserve = 0;
     
    522499        if ( unlikely( ! heapMasterBootFlag ) ) heapMasterCtor();
    523500
    524         lock( heapMaster.mgrLock );             // protect heapMaster counters
     501        lock( heapMaster.mgrLock );                                                     // protect heapMaster counters
    525502
    526503        // get storage for heap manager
     
    710687        // find the closest bucket size less than or equal to the mmapStart size
    711688        maxBucketsUsed = Bsearchl( mmapStart, bucketSizes, NoBucketSizes ); // binary search
     689
    712690        verify( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    713691        verify( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
     
    832810
    833811                size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() );
    834                 // Do not call abort or strerror( errno ) as they may call malloc.
    835812                if ( unlikely( sbrk( increase ) == (void *)-1 ) ) {     // failed, no memory ?
    836813                        unlock( extLock );
    837                         abort( NO_MEMORY_MSG, size );                           // no memory
     814                        abort( NO_MEMORY_MSG, size );                           // give up
    838815                } // if
    839816
     
    971948                #endif // __STATISTICS__
    972949
    973                 // Spin until the lock is acquired for this particular size of block.
    974 
    975                 #if BUCKETLOCK == SPINLOCK
    976950                block = freeHead->freeList;                                             // remove node from stack
    977                 #else
    978                 block = pop( freeHead->freeList );
    979                 #endif // BUCKETLOCK
    980951                if ( unlikely( block == 0p ) ) {                                // no free block ?
     952                        // Freelist for this size is empty, so check return list (OWNERSHIP), carve it out of the heap, if there
     953                        // is enough left, or get some more heap storage and carve it off.
    981954                        #ifdef OWNERSHIP
    982                         // Freelist for that size is empty, so carve it out of the heap, if there is enough left, or get some more
    983                         // and then carve it off.
    984                         #ifdef RETURNSPIN
    985                         #if BUCKETLOCK == SPINLOCK
    986                         lock( freeHead->returnLock );
    987                         block = freeHead->returnList;
    988                         freeHead->returnList = 0p;
    989                         unlock( freeHead->returnLock );
    990                         #else
    991                         block = __atomic_exchange_n( &freeHead->returnList, nullptr, __ATOMIC_SEQ_CST );
    992                         #endif // RETURNSPIN
    993 
    994                         if ( likely( block == 0p ) ) {                  // return list also empty?
     955                        if ( unlikely( freeHead->returnList ) ) {       // race, get next time if lose race
     956                                #ifdef RETURNSPIN
     957                                lock( freeHead->returnLock );
     958                                block = freeHead->returnList;
     959                                freeHead->returnList = 0p;
     960                                unlock( freeHead->returnLock );
     961                                #else
     962                                block = __atomic_exchange_n( &freeHead->returnList, 0p, __ATOMIC_SEQ_CST );
     963                                #endif // RETURNSPIN
     964
     965                                verify( block );
     966                                #ifdef __STATISTICS__
     967                                stats.return_pulls += 1;
     968                                #endif // __STATISTICS__
     969
     970                                // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
     971
     972                                freeHead->freeList = block->header.kind.real.next; // merge returnList into freeHead
     973                        } else {
    995974                        #endif // OWNERSHIP
    996975                                // Do not leave kernel thread as manager_extend accesses heapManager.
     
    1002981
    1003982                                #ifdef __CFA_DEBUG__
    1004                                 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes.
     983                                // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes.
    1005984                                memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) );
    1006985                                #endif // __CFA_DEBUG__
    1007                         #endif // BUCKETLOCK
    1008986                        #ifdef OWNERSHIP
    1009                         } else {                                                                        // merge returnList into freeHead
    1010                                 #ifdef __STATISTICS__
    1011                                 stats.return_pulls += 1;
    1012                                 #endif // __STATISTICS__
    1013 
    1014                                 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
    1015 
    1016                                 freeHead->freeList = block->header.kind.real.next;
    1017987                        } // if
    1018988                        #endif // OWNERSHIP
     
    1026996  if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p;
    1027997                tsize = ceiling2( tsize, __page_size );                 // must be multiple of page size
     998
    1028999                #ifdef __STATISTICS__
    10291000                stats.counters[STAT_NAME].alloc += tsize;
     
    10421013                        if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
    10431014                        // Do not call strerror( errno ) as it may call malloc.
    1044                         abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", size, heapMaster.mmapStart, errno );
     1015                        abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.",
     1016                                   size, heapMaster.mmapStart, errno );
    10451017                } // if
    10461018                block->header.kind.real.blockSize = MarkMmappedBit( tsize ); // storage size for munmap
    10471019
    10481020                #ifdef __CFA_DEBUG__
    1049                 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes.  The rest of
    1050                 // the storage set to 0 by mmap.
     1021                // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes. The
     1022                // rest of the storage set to 0 by mmap.
    10511023                memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) );
    10521024                #endif // __CFA_DEBUG__
     
    11261098                #endif // __CFA_DEBUG__
    11271099
     1100                #ifdef OWNERSHIP
    11281101                if ( likely( heapManager == freeHead->homeManager ) ) { // belongs to this thread
    11291102                        header->kind.real.next = freeHead->freeList; // push on stack
     
    11321105                        verify( heapManager );
    11331106
    1134                         #ifdef OWNERSHIP
    11351107                        #ifdef RETURNSPIN
    11361108                        lock( freeHead->returnLock );
     
    11411113                        header->kind.real.next = freeHead->returnList; // link new node to top node
    11421114                        // CAS resets header->kind.real.next = freeHead->returnList on failure
    1143                         while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, header,
     1115                        while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, (Heap.Storage *)header,
    11441116                                                                                                   false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) );
    11451117                        #endif // RETURNSPIN
    1146 
    1147                         #else                                                                           // no OWNERSHIP
    1148 
    1149                         freeHead = &heap->freeLists[ClearStickyBits( header->kind.real.home ) - &freeHead->homeManager->freeLists[0]];
    1150                         header->kind.real.next = freeHead->freeList; // push on stack
    1151                         freeHead->freeList = (Heap.Storage *)header;
    1152                         #endif // ! OWNERSHIP
    1153 
    1154                         #ifdef __U_STATISTICS__
    1155                         stats.return_pushes += 1;
    1156                         stats.return_storage_request += rsize;
    1157                         stats.return_storage_alloc += size;
    1158                         #endif // __U_STATISTICS__
    1159 
    1160                         // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
    1161                 } // if
     1118                } // if
     1119
     1120                #else                                                                                   // no OWNERSHIP
     1121
     1122                // kind.real.home is address in owner thread's freeLists, so compute the equivalent position in this thread's freeList.
     1123                freeHead = &freeLists[ClearStickyBits( (Heap.FreeHeader *)(header->kind.real.home) ) - &freeHead->homeManager->freeLists[0]];
     1124                header->kind.real.next = freeHead->freeList;    // push on stack
     1125                freeHead->freeList = (Heap.Storage *)header;
     1126                #endif // ! OWNERSHIP
     1127
     1128                #ifdef __U_STATISTICS__
     1129                stats.return_pushes += 1;
     1130                stats.return_storage_request += rsize;
     1131                stats.return_storage_alloc += size;
     1132                #endif // __U_STATISTICS__
     1133
     1134                // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
    11621135        } // if
    11631136
     
    11861159                #endif // __STATISTICS__
    11871160
    1188                 #if BUCKETLOCK == SPINLOCK
    11891161                for ( Heap.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    1190                 #else
    1191                         for(;;) {
    1192 //              for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
    1193 //              for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
    1194 //                      Heap.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
    1195 //                      typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works`
    1196 //                      p = temp;
    1197                 #endif // BUCKETLOCK
    11981162                        total += size;
    11991163                        #ifdef __STATISTICS__
  • libcfa/src/interpose.cfa

    rb77f0e1 r63be3387  
    4242
    4343typedef void (* generic_fptr_t)(void);
     44static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) {
     45        const char * error;
     46
     47        union { generic_fptr_t fptr; void * ptr; } originalFunc;
     48
     49        #if defined( _GNU_SOURCE )
     50                if ( version ) {
     51                        originalFunc.ptr = dlvsym( library, symbol, version );
     52                } else {
     53                        originalFunc.ptr = dlsym( library, symbol );
     54                }
     55        #else
     56                originalFunc.ptr = dlsym( library, symbol );
     57        #endif // _GNU_SOURCE
     58
     59        error = dlerror();
     60        if ( error ) abort( "interpose_symbol : internal error, %s\n", error );
     61
     62        return originalFunc.fptr;
     63}
     64
    4465static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
    4566        const char * error;
    4667
    4768        static void * library;
     69        static void * pthread_library;
    4870        if ( ! library ) {
    4971                #if defined( RTLD_NEXT )
     
    5880                #endif
    5981        } // if
    60 
    61         union { generic_fptr_t fptr; void * ptr; } originalFunc;
    62 
    63         #if defined( _GNU_SOURCE )
    64                 if ( version ) {
    65                         originalFunc.ptr = dlvsym( library, symbol, version );
    66                 } else {
    67                         originalFunc.ptr = dlsym( library, symbol );
    68                 }
    69         #else
    70                 originalFunc.ptr = dlsym( library, symbol );
    71         #endif // _GNU_SOURCE
    72 
    73         error = dlerror();
    74         if ( error ) abort( "interpose_symbol : internal error, %s\n", error );
    75 
    76         return originalFunc.fptr;
     82        if ( ! pthread_library ) {
     83                #if defined( RTLD_NEXT )
     84                        pthread_library = RTLD_NEXT;
     85                #else
     86                        // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
     87                        pthread_library = dlopen( "libpthread.so", RTLD_LAZY );
     88                        error = dlerror();
     89                        if ( error ) {
     90                                abort( "interpose_symbol : failed to open libpthread, %s\n", error );
     91                        }
     92                #endif
     93        } // if
     94
     95        return do_interpose_symbol(library, symbol, version);
    7796}
    7897
     
    97116
    98117extern "C" {
     118        void __cfathreadabi_interpose_startup( generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ) ) __attribute__((weak));
    99119        void __cfaabi_interpose_startup( void ) {
    100120                const char *version = 0p;
     
    108128                INTERPOSE_LIBC( exit , version );
    109129#pragma GCC diagnostic pop
     130
     131                if(__cfathreadabi_interpose_startup) __cfathreadabi_interpose_startup( do_interpose_symbol );
    110132
    111133                // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
  • src/AST/Convert.cpp

    rb77f0e1 r63be3387  
    234234                }
    235235                return declWithTypePostamble( decl, node );
     236        }
     237
     238        // InlineMemberDecl vanish after EnumAndPointerDecay pass so no necessary to implement NewToOld
     239        const ast::DeclWithType * visit( const ast::InlineMemberDecl * node ) override final { 
     240                assert( false );
     241                (void) node;
     242                return nullptr;
    236243        }
    237244
     
    16141621                        { old->get_funcSpec().val }
    16151622                );
    1616                 decl->enumInLine = old->enumInLine;
    16171623                cache.emplace(old, decl);
    16181624                assert(cache.find( old ) != cache.end());
     
    18591865                decl->uniqueId   = old->uniqueId;
    18601866                decl->storage    = { old->storageClasses.val };
     1867
     1868                this->node = decl;
     1869        }
     1870
     1871        virtual void visit( const InlineMemberDecl * old ) override final {
     1872                if ( inCache( old ) ) {
     1873                        return;
     1874                }
     1875                auto&& type = GET_ACCEPT_1(type, Type);
     1876                auto&& attr = GET_ACCEPT_V(attributes, Attribute);
     1877
     1878                auto decl = new ast::InlineMemberDecl(
     1879                        old->location,
     1880                        old->name,
     1881                        type,
     1882                        { old->get_storageClasses().val },
     1883                        { old->linkage.val },
     1884                        std::move(attr),
     1885                        { old->get_funcSpec().val }
     1886                );
     1887                cache.emplace(old, decl);
     1888                assert(cache.find( old ) != cache.end());
     1889                decl->scopeLevel = old->scopeLevel;
     1890                decl->mangleName = old->mangleName;
     1891                decl->isDeleted  = old->isDeleted;
     1892                decl->asmName    = GET_ACCEPT_1(asmName, Expr);
     1893                decl->uniqueId   = old->uniqueId;
     1894                decl->extension  = old->extension;
    18611895
    18621896                this->node = decl;
  • src/AST/Decl.hpp

    rb77f0e1 r63be3387  
    105105        ptr<Init> init;
    106106        ptr<Expr> bitfieldWidth;
    107         bool enumInLine = false; // enum inline is not a real object declaration.
    108         // It is a place holder for a set of enum value (ObjectDecl)
    109         bool importValue = false; // if the value copied from somewhere else
    110107
    111108        ObjectDecl( const CodeLocation & loc, const std::string & name, const Type * type,
     
    400397};
    401398
     399/// Static Assertion `_Static_assert( ... , ... );`
    402400class StaticAssertDecl : public Decl {
    403401public:
     
    411409private:
    412410        StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); }
     411        MUTATE_FRIEND
     412};
     413
     414/// Inline Member Declaration `inline TypeName;`
     415class InlineMemberDecl final : public DeclWithType {
     416public:
     417        ptr<Type> type;
     418
     419        InlineMemberDecl( const CodeLocation & loc, const std::string & name, const Type * type,
     420                Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
     421                std::vector< ptr<Attribute> > && attrs = {}, Function::Specs fs = {} )
     422        : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ) {}
     423
     424        const Type * get_type() const override { return type; }
     425        void set_type( const Type * ty ) override { type = ty; }
     426
     427        const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
     428private:
     429        InlineMemberDecl * clone() const override { return new InlineMemberDecl{ *this }; }
    413430        MUTATE_FRIEND
    414431};
  • src/AST/Fwd.hpp

    rb77f0e1 r63be3387  
    3737class DirectiveDecl;
    3838class StaticAssertDecl;
     39class InlineMemberDecl;
    3940
    4041class Stmt;
  • src/AST/Pass.hpp

    rb77f0e1 r63be3387  
    141141        const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) override final;
    142142        const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) override final;
     143        const ast::DeclWithType *     visit( const ast::InlineMemberDecl     * ) override final;
    143144        const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) override final;
    144145        const ast::Stmt *             visit( const ast::ExprStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    rb77f0e1 r63be3387  
    617617                                maybe_accept( node, &FunctionDecl::returns );
    618618                                maybe_accept( node, &FunctionDecl::type );
     619                                maybe_accept( node, &FunctionDecl::attributes );
    619620                                // First remember that we are now within a function.
    620621                                ValueGuard< bool > oldInFunction( inFunction );
     
    625626                                atFunctionTop = true;
    626627                                maybe_accept( node, &FunctionDecl::stmts );
    627                                 maybe_accept( node, &FunctionDecl::attributes );
    628628                        }
    629629                }
     
    800800
    801801        VISIT_END( StaticAssertDecl, node );
     802}
     803
     804//--------------------------------------------------------------------------
     805// InlineMemberDecl
     806template< typename core_t >
     807const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::InlineMemberDecl * node ) {
     808        VISIT_START( node );
     809
     810        if ( __visit_children() ) {
     811                {
     812                        guard_symtab guard { *this };
     813                        maybe_accept( node, &InlineMemberDecl::type );
     814                }
     815        }
     816
     817        VISIT_END( DeclWithType, node );
    802818}
    803819
  • src/AST/Print.cpp

    rb77f0e1 r63be3387  
    398398        virtual const ast::Decl * visit( const ast::StructDecl * node ) override final {
    399399                print(node);
     400                return node;
     401        }
     402
     403        virtual const ast::DeclWithType * visit( const ast::InlineMemberDecl * node ) override final {
     404                os << "inline ";
     405                if ( ! node->name.empty() ) os << node->name;
     406
    400407                return node;
    401408        }
  • src/AST/Type.cpp

    rb77f0e1 r63be3387  
    147147// --- TypeInstType
    148148
     149bool TypeInstType::operator==( const TypeInstType & other ) const {
     150        return base == other.base
     151                && formal_usage == other.formal_usage
     152                && expr_id == other.expr_id;
     153}
     154
    149155TypeInstType::TypeInstType( const TypeDecl * b,
    150156        CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
     
    157163
    158164bool TypeInstType::isComplete() const { return base->sized; }
     165
     166std::string TypeInstType::TypeEnvKey::typeString() const {
     167        return std::string("_") + std::to_string(formal_usage)
     168                + "_" + std::to_string(expr_id) + "_" + base->name;
     169}
     170
     171bool TypeInstType::TypeEnvKey::operator==(
     172                const TypeInstType::TypeEnvKey & other ) const {
     173        return base == other.base
     174                && formal_usage == other.formal_usage
     175                && expr_id == other.expr_id;
     176}
     177
     178bool TypeInstType::TypeEnvKey::operator<(
     179                const TypeInstType::TypeEnvKey & other ) const {
     180        // TypeEnvKey ordering is an arbitrary total ordering.
     181        // It doesn't mean anything but allows for a sorting.
     182        if ( base < other.base ) {
     183                return true;
     184        } else if ( other.base < base ) {
     185                return false;
     186        } else if ( formal_usage < other.formal_usage ) {
     187                return true;
     188        } else if ( other.formal_usage < formal_usage ) {
     189                return false;
     190        } else {
     191                return expr_id < other.expr_id;
     192        }
     193}
    159194
    160195// --- TupleType
  • src/AST/Type.hpp

    rb77f0e1 r63be3387  
    408408
    409409                TypeEnvKey() = default;
    410                 TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {}
    411                 TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
    412                 std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
    413                 bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
     410                TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0)
     411                : base(base), formal_usage(formal_usage), expr_id(expr_id) {}
     412                TypeEnvKey(const TypeInstType & inst)
     413                : base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
     414                std::string typeString() const;
     415                bool operator==(const TypeEnvKey & other) const;
     416                bool operator<(const TypeEnvKey & other) const;
    414417        };
    415418
    416         bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
     419        bool operator==(const TypeInstType & other) const;
    417420
    418421        TypeInstType(
  • src/AST/Visitor.hpp

    rb77f0e1 r63be3387  
    3333    virtual const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) = 0;
    3434    virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) = 0;
     35    virtual const ast::DeclWithType *     visit( const ast::InlineMemberDecl     * ) = 0;
    3536    virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) = 0;
    3637    virtual const ast::Stmt *             visit( const ast::ExprStmt             * ) = 0;
  • src/Common/CodeLocationTools.cpp

    rb77f0e1 r63be3387  
    111111    macro(DirectiveDecl, DirectiveDecl) \
    112112    macro(StaticAssertDecl, StaticAssertDecl) \
     113    macro(InlineMemberDecl, DeclWithType) \
    113114    macro(CompoundStmt, CompoundStmt) \
    114115    macro(ExprStmt, Stmt) \
  • src/Common/PassVisitor.h

    rb77f0e1 r63be3387  
    8181        virtual void visit( StaticAssertDecl * assertDecl ) override final;
    8282        virtual void visit( const StaticAssertDecl * assertDecl ) override final;
     83        virtual void visit( InlineMemberDecl * valueDecl ) override final;
     84        virtual void visit( const InlineMemberDecl * valueDecl ) override final;
    8385
    8486        virtual void visit( CompoundStmt * compoundStmt ) override final;
     
    273275        virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final;
    274276        virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final;
     277        virtual DeclarationWithType * mutate( InlineMemberDecl * valueDecl ) override final;
    275278
    276279        virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) override final;
  • src/Common/PassVisitor.impl.h

    rb77f0e1 r63be3387  
    607607                        indexerAddId( &func );
    608608                        maybeMutate_impl( node->type, *this );
     609                        maybeMutate_impl( node->attributes, *this );
    609610                        // First remember that we are now within a function.
    610611                        ValueGuard< bool > oldInFunction( inFunction );
     
    615616                        atFunctionTop = true;
    616617                        maybeMutate_impl( node->statements, *this );
    617                         maybeMutate_impl( node->attributes, *this );
    618618                }
    619619        }
     
    10441044
    10451045        MUTATE_END( StaticAssertDecl, node );
     1046}
     1047
     1048//--------------------------------------------------------------------------
     1049// InlineMemberDecl
     1050template< typename pass_type >
     1051void PassVisitor< pass_type >::visit( InlineMemberDecl * node ) {
     1052        VISIT_START( node );
     1053
     1054        maybeAccept_impl( node->type, *this );
     1055
     1056        VISIT_END( node );
     1057}
     1058
     1059template< typename pass_type >
     1060void PassVisitor< pass_type >::visit( const InlineMemberDecl * node ) {
     1061        VISIT_START( node );
     1062
     1063        maybeAccept_impl( node->type, *this );
     1064
     1065        VISIT_END( node );
     1066}
     1067
     1068template< typename pass_type >
     1069DeclarationWithType * PassVisitor< pass_type >::mutate( InlineMemberDecl * node ) {
     1070        MUTATE_START( node );
     1071
     1072        maybeMutate_impl( node->type, *this );
     1073
     1074        MUTATE_END( DeclarationWithType, node );
    10461075}
    10471076
  • src/Common/utility.h

    rb77f0e1 r63be3387  
    452452
    453453// -----------------------------------------------------------------------------
    454 // Helper struct and function to support
    455 // for ( val : group_iterate( container1, container2, ... ) ) {}
    456 // syntax to have a for each that iterates multiple containers of the same length
    457 // TODO: update to use variadic arguments
    458 
    459 template< typename T1, typename T2 >
    460 struct group_iterate_t {
    461 private:
    462         std::tuple<T1, T2> args;
     454// Helper struct and function to support:
     455// for ( auto val : group_iterate( container1, container2, ... ) ) { ... }
     456// This iteraters through multiple containers of the same size.
     457
     458template<typename... Args>
     459class group_iterate_t {
     460        using Iterables = std::tuple<Args...>;
     461        Iterables iterables;
     462
     463        // Getting the iterator and value types this way preserves const.
     464        template<size_t I> using Iter = decltype(std::get<I>(iterables).begin());
     465        template<size_t I> using Data = decltype(*std::get<I>(iterables).begin());
     466        template<typename> struct base_iterator;
     467
     468        // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1`
     469        // into a pack. These are the indexes into the tuples, so unpacking can
     470        // go over each element of the tuple.
     471        // The std::integer_sequence is just used to build that sequence.
     472        // A library reference will probably explain it better than I can.
     473        template<std::size_t... Indices>
     474        struct base_iterator<std::integer_sequence<std::size_t, Indices...>> {
     475                using value_type = std::tuple< Data<Indices>... >;
     476                std::tuple<Iter<Indices>...> iterators;
     477
     478                base_iterator( Iter<Indices>... is ) : iterators( is... ) {}
     479                base_iterator operator++() {
     480                        return base_iterator( ++std::get<Indices>( iterators )... );
     481                }
     482                bool operator!=( const base_iterator& other ) const {
     483                        return iterators != other.iterators;
     484                }
     485                value_type operator*() const {
     486                        return std::tie( *std::get<Indices>( iterators )... );
     487                }
     488
     489                static base_iterator make_begin( Iterables & data ) {
     490                        return base_iterator( std::get<Indices>( data ).begin()... );
     491                }
     492                static base_iterator make_end( Iterables & data ) {
     493                        return base_iterator( std::get<Indices>( data ).end()... );
     494                }
     495        };
     496
    463497public:
    464         group_iterate_t( bool skipBoundsCheck, const T1 & v1, const T2 & v2 ) : args(v1, v2) {
    465                 assertf(skipBoundsCheck || v1.size() == v2.size(), "group iteration requires containers of the same size: <%zd, %zd>.", v1.size(), v2.size());
    466         };
    467 
    468         typedef std::tuple<decltype(*std::get<0>(args).begin()), decltype(*std::get<1>(args).begin())> value_type;
    469         typedef decltype(std::get<0>(args).begin()) T1Iter;
    470         typedef decltype(std::get<1>(args).begin()) T2Iter;
    471 
    472         struct iterator {
    473                 typedef std::tuple<T1Iter, T2Iter> IterTuple;
    474                 IterTuple it;
    475                 iterator( T1Iter i1, T2Iter i2 ) : it( i1, i2 ) {}
    476                 iterator operator++() {
    477                         return iterator( ++std::get<0>(it), ++std::get<1>(it) );
    478                 }
    479                 bool operator!=( const iterator &other ) const { return it != other.it; }
    480                 value_type operator*() const { return std::tie( *std::get<0>(it), *std::get<1>(it) ); }
    481         };
    482 
    483         iterator begin() { return iterator( std::get<0>(args).begin(), std::get<1>(args).begin() ); }
    484         iterator end() { return iterator( std::get<0>(args).end(), std::get<1>(args).end() ); }
    485 };
    486 
    487 /// performs bounds check to ensure that all arguments are of the same length.
     498        group_iterate_t( const Args &... args ) : iterables( args... ) {}
     499
     500        using iterator = base_iterator<decltype(
     501                std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
     502
     503        iterator begin() { return iterator::make_begin( iterables ); }
     504        iterator end() { return iterator::make_end( iterables ); }
     505};
     506
     507// Helpers for the bounds checks (the non-varatic part of group_iterate):
     508static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
     509        assertf( size0 == size1,
     510                "group iteration requires containers of the same size: <%zd, %zd>.",
     511                size0, size1 );
     512}
     513
     514static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
     515        assertf( size0 == size1 && size1 == size2,
     516                "group iteration requires containers of the same size: <%zd, %zd, %zd>.",
     517                size0, size1, size2 );
     518}
     519
     520/// Performs bounds check to ensure that all arguments are of the same length.
    488521template< typename... Args >
    489522group_iterate_t<Args...> group_iterate( Args &&... args ) {
    490         return group_iterate_t<Args...>(false, std::forward<Args>( args )...);
    491 }
    492 
    493 /// does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
     523        runGroupBoundsCheck( args.size()... );
     524        return group_iterate_t<Args...>( std::forward<Args>( args )... );
     525}
     526
     527/// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
    494528template< typename... Args >
    495529group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
    496         return group_iterate_t<Args...>(true, std::forward<Args>( args )...);
     530        return group_iterate_t<Args...>( std::forward<Args>( args )... );
    497531}
    498532
  • src/GenPoly/Box.cc

    rb77f0e1 r63be3387  
    5858namespace GenPoly {
    5959        namespace {
    60                 FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );
     60                FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars );
    6161
    6262                class BoxPass {
     
    6868                /// Adds layout-generation functions to polymorphic types.
    6969                class LayoutFunctionBuilder final : public WithDeclsToAdd, public WithVisitorRef<LayoutFunctionBuilder>, public WithShortCircuiting {
    70                         // Current level of nested functions:
    71                         unsigned int functionNesting = 0;
    7270                public:
    73                         void previsit( FunctionDecl *functionDecl );
    7471                        void previsit( StructDecl *structDecl );
    7572                        void previsit( UnionDecl *unionDecl );
     
    10097                        void passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes );
    10198                        /// passes extra type parameters into a polymorphic function application
    102                         void passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
     99                        /// Returns an iterator to the first argument after the added
     100                        /// arguments, which are added at the beginning.
     101                        std::list< Expression *>::iterator passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars );
    103102                        /// wraps a function application with a new temporary for the out-parameter return value
    104                         Expression *addRetParam( ApplicationExpr *appExpr, Type *retType, std::list< Expression *>::iterator &arg );
    105                         /// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment
    106                         void replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params );
    107                         /// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete).
    108                         /// If `doClone` is set to false, will not clone interior types
    109                         Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true );
     103                        /// The new out-parameter is the new first parameter.
     104                        Expression *addRetParam( ApplicationExpr *appExpr, Type *retType );
    110105                        /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value
    111                         Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType, std::list< Expression *>::iterator &arg );
    112                         Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
    113                         void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars );
    114                         void boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
    115                         void addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars );
     106                        Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType );
     107                        /// Converts a function call into a call of the adapter with the
     108                        /// original function as the first argument (all other arguments
     109                        /// are pushed back). May adjust return value.
     110                        Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function );
     111                        /// Modifies the `arg`, replacing it with a boxed expression
     112                        /// that matches `formal` under the current TyVarMap.
     113                        void boxParam( Expression *&arg, Type *formal, const TyVarMap &exprTyVars );
     114                        /// Box an argument of `appExpr` for each parameter in `function`
     115                        /// starting at `arg`.
     116                        /// `exprTyVars` is the function's type variables.
     117                        void boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars );
     118                        /// Boxes each assertion and inserts them into `appExpr` at
     119                        /// `arg`. `exprTyVars` is the function's type variables.
     120                        void addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars );
    116121                        /// Stores assignment operators from assertion list in local map of assignment operations
    117122                        void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars );
    118                         FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
     123                        /// Creates an adapter definition from `adaptee` to `realType`, using
     124                        /// `mangleName` as the base name for the adapter. `tyVars` is the map of
     125                        /// type variables for the function type of the adapted expression.
     126                        FunctionDecl *makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
    119127                        /// Replaces intrinsic operator functions with their arithmetic desugaring
    120128                        Expression *handleIntrinsics( ApplicationExpr *appExpr );
     
    182190                        ObjectDecl *makeVar( const std::string &name, Type *type, Initializer *init = 0 );
    183191                        /// returns true if the type has a dynamic layout; such a layout will be stored in appropriately-named local variables when the function returns
    184                         bool findGeneric( Type *ty );
     192                        bool findGeneric( Type const *ty );
    185193                        /// adds type parameters to the layout call; will generate the appropriate parameters if needed
    186194                        void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams );
     
    221229        } // anonymous namespace
    222230
    223         /// version of mutateAll with special handling for translation unit so you can check the end of the prelude when debugging
    224         template< typename MutatorType >
    225         inline void mutateTranslationUnit( std::list< Declaration* > &translationUnit, MutatorType &mutator ) {
    226                 bool seenIntrinsic = false;
    227                 SemanticErrorException errors;
    228                 for ( typename std::list< Declaration* >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
    229                         try {
    230                                 if ( *i ) {
    231                                         if ( (*i)->get_linkage() == LinkageSpec::Intrinsic ) {
    232                                                 seenIntrinsic = true;
    233                                         } else if ( seenIntrinsic ) {
    234                                                 seenIntrinsic = false; // break on this line when debugging for end of prelude
    235                                         }
    236 
    237                                         *i = dynamic_cast< Declaration* >( (*i)->acceptMutator( mutator ) );
    238                                         assert( *i );
    239                                 } // if
    240                         } catch( SemanticErrorException &e ) {
    241                                 errors.append( e );
    242                         } // try
    243                 } // for
    244                 if ( ! errors.isEmpty() ) {
    245                         throw errors;
    246                 } // if
    247         }
    248 
    249231        void box( std::list< Declaration *>& translationUnit ) {
    250232                PassVisitor<LayoutFunctionBuilder> layoutBuilder;
     
    263245        ////////////////////////////////// LayoutFunctionBuilder ////////////////////////////////////////////
    264246
    265         void LayoutFunctionBuilder::previsit( FunctionDecl *functionDecl ) {
    266                 visit_children = false;
    267                 maybeAccept( functionDecl->get_functionType(), *visitor );
    268                 ++functionNesting;
    269                 maybeAccept( functionDecl->get_statements(), *visitor );
    270                 --functionNesting;
    271         }
    272 
    273247        /// Get a list of type declarations that will affect a layout function
    274248        std::list< TypeDecl* > takeOtypeOnly( std::list< TypeDecl* > &decls ) {
    275249                std::list< TypeDecl * > otypeDecls;
    276250
    277                 for ( std::list< TypeDecl* >::const_iterator decl = decls.begin(); decl != decls.end(); ++decl ) {
    278                         if ( (*decl)->isComplete() ) {
    279                                 otypeDecls.push_back( *decl );
     251                for ( TypeDecl * const decl : decls ) {
     252                        if ( decl->isComplete() ) {
     253                                otypeDecls.push_back( decl );
    280254                        }
    281255                }
     
    288262                BasicType sizeAlignType( Type::Qualifiers(), BasicType::LongUnsignedInt );
    289263
    290                 for ( std::list< TypeDecl* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) {
    291                         TypeInstType paramType( Type::Qualifiers(), (*param)->get_name(), *param );
     264                for ( TypeDecl * const param : otypeParams ) {
     265                        TypeInstType paramType( Type::Qualifiers(), param->get_name(), param );
    292266                        std::string paramName = mangleType( &paramType );
    293267                        layoutFnType->get_parameters().push_back( new ObjectDecl( sizeofName( paramName ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignType.clone(), 0 ) );
     
    297271
    298272        /// Builds a layout function declaration
    299         FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, unsigned int functionNesting, FunctionType *layoutFnType ) {
     273        FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, bool isInFunction, FunctionType *layoutFnType ) {
    300274                // Routines at global scope marked "static" to prevent multiple definitions is separate translation units
    301275                // because each unit generates copies of the default routines for each aggregate.
    302276                FunctionDecl *layoutDecl = new FunctionDecl( layoutofName( typeDecl ),
    303                                                                                                          functionNesting > 0 ? Type::StorageClasses() : Type::StorageClasses( Type::Static ),
     277                                                                                                         isInFunction ? Type::StorageClasses() : Type::StorageClasses( Type::Static ),
    304278                                                                                                         LinkageSpec::AutoGen, layoutFnType, new CompoundStmt(),
    305279                                                                                                         std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) );
    306280                layoutDecl->fixUniqueId();
    307281                return layoutDecl;
    308         }
    309 
    310         /// Makes a unary operation
    311         Expression *makeOp( const std::string &name, Expression *arg ) {
    312                 UntypedExpr *expr = new UntypedExpr( new NameExpr( name ) );
    313                 expr->args.push_back( arg );
    314                 return expr;
    315282        }
    316283
     
    380347
    381348                // build function decl
    382                 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, functionNesting, layoutFnType );
     349                FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, isInFunction(), layoutFnType );
    383350
    384351                // calculate struct layout in function body
     
    387354                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 0 ) ) ) );
    388355                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    389                 unsigned long n_members = 0;
    390                 bool firstMember = true;
    391                 for ( Declaration* member : structDecl->get_members() ) {
    392                         DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member );
     356                for ( auto index_member : enumerate( structDecl->members ) ) {
     357                        DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( index_member.val );
    393358                        assert( dwt );
    394359                        Type *memberType = dwt->get_type();
    395360
    396                         if ( firstMember ) {
    397                                 firstMember = false;
    398                         } else {
     361                        if ( 0 < index_member.idx ) {
    399362                                // make sure all members after the first (automatically aligned at 0) are properly padded for alignment
    400363                                addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), new AlignofExpr( memberType->clone() ) ) );
     
    402365
    403366                        // place current size in the current offset index
    404                         addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( n_members ) ) ),
     367                        addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( index_member.idx ) ) ),
    405368                                                                              derefVar( sizeParam ) ) );
    406                         ++n_members;
    407369
    408370                        // add member size to current size
     
    439401
    440402                // build function decl
    441                 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, functionNesting, layoutFnType );
     403                FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, isInFunction(), layoutFnType );
    442404
    443405                // calculate union layout in function body
    444406                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    445407                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    446                 for ( std::list< Declaration* >::const_iterator member = unionDecl->get_members().begin(); member != unionDecl->get_members().end(); ++member ) {
    447                         DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( *member );
     408                for ( Declaration * const member : unionDecl->members ) {
     409                        DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member );
    448410                        assert( dwt );
    449411                        Type *memberType = dwt->get_type();
     
    464426
    465427        namespace {
    466                 std::string makePolyMonoSuffix( FunctionType * function, const TyVarMap &tyVars ) {
     428                std::string makePolyMonoSuffix( FunctionType const * function, const TyVarMap &tyVars ) {
    467429                        std::stringstream name;
    468430
     
    473435                        // to take those polymorphic types as pointers. Therefore, there can be two different functions
    474436                        // with the same mangled name, so we need to further mangle the names.
    475                         for ( std::list< DeclarationWithType *>::iterator retval = function->get_returnVals().begin(); retval != function->get_returnVals().end(); ++retval ) {
    476                                 if ( isPolyType( (*retval)->get_type(), tyVars ) ) {
     437                        for ( DeclarationWithType const * const ret : function->returnVals ) {
     438                                if ( isPolyType( ret->get_type(), tyVars ) ) {
    477439                                        name << "P";
    478440                                } else {
     
    481443                        }
    482444                        name << "_";
    483                         std::list< DeclarationWithType *> &paramList = function->get_parameters();
    484                         for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
    485                                 if ( isPolyType( (*arg)->get_type(), tyVars ) ) {
     445                        for ( DeclarationWithType const * const arg : function->parameters ) {
     446                                if ( isPolyType( arg->get_type(), tyVars ) ) {
    486447                                        name << "P";
    487448                                } else {
     
    492453                }
    493454
    494                 std::string mangleAdapterName( FunctionType * function, const TyVarMap &tyVars ) {
     455                std::string mangleAdapterName( FunctionType const * function, const TyVarMap &tyVars ) {
    495456                        return SymTab::Mangler::mangle( function ) + makePolyMonoSuffix( function, tyVars );
    496457                }
     
    499460                        return "_adapter" + mangleName;
    500461                }
     462
     463                /// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete).
     464                /// If `doClone` is set to false, will not clone interior types
     465                Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone = true );
    501466
    502467                Pass1::Pass1() : tempNamer( "_temp" ) {}
     
    524489
    525490                                std::list< DeclarationWithType *> &paramList = functionType->parameters;
    526                                 std::list< FunctionType *> functions;
    527                                 for ( Type::ForallList::iterator tyVar = functionType->forall.begin(); tyVar != functionType->forall.end(); ++tyVar ) {
    528                                         for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->assertions.begin(); assert != (*tyVar)->assertions.end(); ++assert ) {
    529                                                 findFunction( (*assert)->get_type(), functions, scopeTyVars, needsAdapter );
     491                                std::list< FunctionType const *> functions;
     492                                for ( TypeDecl * const tyVar : functionType->forall ) {
     493                                        for ( DeclarationWithType * const assert : tyVar->assertions ) {
     494                                                findFunction( assert->get_type(), functions, scopeTyVars, needsAdapter );
    530495                                        } // for
    531496                                } // for
    532                                 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
    533                                         findFunction( (*arg)->get_type(), functions, scopeTyVars, needsAdapter );
     497                                for ( DeclarationWithType * const arg : paramList ) {
     498                                        findFunction( arg->get_type(), functions, scopeTyVars, needsAdapter );
    534499                                } // for
    535500
    536                                 for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
    537                                         std::string mangleName = mangleAdapterName( *funType, scopeTyVars );
     501                                for ( FunctionType const * const funType : functions ) {
     502                                        std::string mangleName = mangleAdapterName( funType, scopeTyVars );
    538503                                        if ( adapters.find( mangleName ) == adapters.end() ) {
    539504                                                std::string adapterName = makeAdapterName( mangleName );
    540                                                 adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), nullptr ) ) );
     505                                                adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), nullptr ) ) );
    541506                                        } // if
    542507                                } // for
     
    593558                }
    594559
    595                 void Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
     560                std::list< Expression *>::iterator Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars ) {
     561                        assert( env );
     562                        std::list< Expression *>::iterator arg = appExpr->args.begin();
    596563                        // pass size/align for type variables
    597                         for ( TyVarMap::const_iterator tyParm = exprTyVars.begin(); tyParm != exprTyVars.end(); ++tyParm ) {
     564                        for ( std::pair<std::string, TypeDecl::Data> const & tyParam : exprTyVars ) {
    598565                                ResolvExpr::EqvClass eqvClass;
    599                                 assert( env );
    600                                 if ( tyParm->second.isComplete ) {
    601                                         Type *concrete = env->lookup( tyParm->first );
    602                                         if ( concrete ) {
    603                                                 arg = appExpr->get_args().insert( arg, new SizeofExpr( concrete->clone() ) );
    604                                                 arg++;
    605                                                 arg = appExpr->get_args().insert( arg, new AlignofExpr( concrete->clone() ) );
    606                                                 arg++;
    607                                         } else {
    608                                                 // xxx - should this be an assertion?
    609                                                 SemanticError( appExpr, toString( *env, "\nunbound type variable: ", tyParm->first, " in application " ) );
    610                                         } // if
     566                                if ( tyParam.second.isComplete ) {
     567                                        Type *concrete = env->lookup( tyParam.first );
     568                                        // If there is an unbound type variable, it should have detected already.
     569                                        assertf( concrete, "Unbound type variable: %s in: %s",
     570                                                toCString( tyParam.first ), toCString( *env ) );
     571
     572                                        arg = appExpr->get_args().insert( arg, new SizeofExpr( concrete->clone() ) );
     573                                        arg++;
     574                                        arg = appExpr->get_args().insert( arg, new AlignofExpr( concrete->clone() ) );
     575                                        arg++;
    611576                                } // if
    612577                        } // for
    613578
    614579                        // add size/align for generic types to parameter list
    615                         if ( ! appExpr->get_function()->result ) return;
     580                        if ( ! appExpr->get_function()->result ) return arg;
    616581                        FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result() );
    617582                        assert( funcType );
    618583
     584                        // These iterators don't advance in unison.
    619585                        std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin();
    620586                        std::list< Expression* >::const_iterator fnArg = arg;
     
    623589                        // a polymorphic return type may need to be added to the argument list
    624590                        if ( polyRetType ) {
    625                                 Type *concRetType = replaceWithConcrete( appExpr, polyRetType );
     591                                Type *concRetType = replaceWithConcrete( polyRetType, env );
    626592                                passArgTypeVars( appExpr, polyRetType, concRetType, arg, exprTyVars, seenTypes );
    627593                                ++fnArg; // skip the return parameter in the argument list
     
    634600                                passArgTypeVars( appExpr, (*fnParm)->get_type(), argType, arg, exprTyVars, seenTypes );
    635601                        }
     602                        return arg;
    636603                }
    637604
     
    642609                }
    643610
    644                 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType, std::list< Expression *>::iterator &arg ) {
     611                Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType ) {
    645612                        // Create temporary to hold return value of polymorphic function and produce that temporary as a result
    646613                        // using a comma expression.
     
    662629                                paramExpr = new AddressExpr( paramExpr );
    663630                        } // if
    664                         arg = appExpr->args.insert( arg, paramExpr ); // add argument to function call
    665                         arg++;
     631                        // Add argument to function call.
     632                        appExpr->args.push_front( paramExpr );
    666633                        // Build a comma expression to call the function and emulate a normal return.
    667634                        CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr );
     
    671638                }
    672639
    673                 void Pass1::replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params ) {
    674                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    675                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
     640                /// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment
     641                void replaceParametersWithConcrete( std::list< Expression* >& params, TypeSubstitution const * env ) {
     642                        for ( Expression * const param : params ) {
     643                                TypeExpr *paramType = dynamic_cast< TypeExpr* >( param );
    676644                                assertf(paramType, "Aggregate parameters should be type expressions");
    677                                 paramType->set_type( replaceWithConcrete( appExpr, paramType->get_type(), false ) );
    678                         }
    679                 }
    680 
    681                 Type *Pass1::replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone ) {
     645                                paramType->set_type( replaceWithConcrete( paramType->get_type(), env, false ) );
     646                        }
     647                }
     648
     649                // See forward definition.
     650                Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone ) {
     651                        assert( env );
    682652                        if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    683653                                Type *concrete = env->lookup( typeInst->get_name() );
     
    690660                                        structType = structType->clone();
    691661                                }
    692                                 replaceParametersWithConcrete( appExpr, structType->get_parameters() );
     662                                replaceParametersWithConcrete( structType->get_parameters(), env );
    693663                                return structType;
    694664                        } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
     
    696666                                        unionType = unionType->clone();
    697667                                }
    698                                 replaceParametersWithConcrete( appExpr, unionType->get_parameters() );
     668                                replaceParametersWithConcrete( unionType->get_parameters(), env );
    699669                                return unionType;
    700670                        }
     
    702672                }
    703673
    704                 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType, std::list< Expression *>::iterator &arg ) {
    705                         assert( env );
    706                         Type *concrete = replaceWithConcrete( appExpr, dynType );
     674                Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType ) {
     675                        Type *concrete = replaceWithConcrete( dynType, env );
    707676                        // add out-parameter for return value
    708                         return addRetParam( appExpr, concrete, arg );
    709                 }
    710 
    711                 Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) {
     677                        return addRetParam( appExpr, concrete );
     678                }
     679
     680                Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function ) {
    712681                        Expression *ret = appExpr;
    713682//                      if ( ! function->get_returnVals().empty() && isPolyType( function->get_returnVals().front()->get_type(), tyVars ) ) {
    714                         if ( isDynRet( function, tyVars ) ) {
    715                                 ret = addRetParam( appExpr, function->returnVals.front()->get_type(), arg );
     683                        if ( isDynRet( function, scopeTyVars ) ) {
     684                                ret = addRetParam( appExpr, function->returnVals.front()->get_type() );
    716685                        } // if
    717                         std::string mangleName = mangleAdapterName( function, tyVars );
     686                        std::string mangleName = mangleAdapterName( function, scopeTyVars );
    718687                        std::string adapterName = makeAdapterName( mangleName );
    719688
     
    724693
    725694                        return ret;
    726                 }
    727 
    728                 void Pass1::boxParam( Type *param, Expression *&arg, const TyVarMap &exprTyVars ) {
    729                         assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() );
    730                         if ( ! needsBoxing( param, arg->result, exprTyVars, env ) ) return;
    731 
    732                         if ( arg->get_lvalue() ) {
    733                                 // argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations.
    734                                 // if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) {
    735                                 //      if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){
    736                                 //              // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
    737                                 //              return;
    738                                 //      }
    739                                 // }
    740                                 arg =  generalizedLvalue( new AddressExpr( arg ) );
    741                                 if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) {
    742                                         // silence warnings by casting boxed parameters when the actual type does not match up with the formal type.
    743                                         arg = new CastExpr( arg, param->clone() );
    744                                 }
    745                         } else {
    746                                 // use type computed in unification to declare boxed variables
    747                                 Type * newType = param->clone();
    748                                 if ( env ) env->apply( newType );
    749                                 ObjectDecl *newObj = ObjectDecl::newObject( tempNamer.newName(), newType, nullptr );
    750                                 newObj->get_type()->get_qualifiers() = Type::Qualifiers(); // TODO: is this right???
    751                                 stmtsToAddBefore.push_back( new DeclStmt( newObj ) );
    752                                 UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) ); // TODO: why doesn't this just use initialization syntax?
    753                                 assign->get_args().push_back( new VariableExpr( newObj ) );
    754                                 assign->get_args().push_back( arg );
    755                                 stmtsToAddBefore.push_back( new ExprStmt( assign ) );
    756                                 arg = new AddressExpr( new VariableExpr( newObj ) );
    757                         } // if
    758695                }
    759696
     
    791728                }
    792729
    793                 void Pass1::boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
    794                         for ( std::list< DeclarationWithType *>::const_iterator param = function->get_parameters().begin(); param != function->parameters.end(); ++param, ++arg ) {
    795                                 assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( *param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() );
    796                                 addCast( *arg, (*param)->get_type(), exprTyVars );
    797                                 boxParam( (*param)->get_type(), *arg, exprTyVars );
     730                void Pass1::boxParam( Expression *&arg, Type *param, const TyVarMap &exprTyVars ) {
     731                        assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() );
     732                        addCast( arg, param, exprTyVars );
     733                        if ( ! needsBoxing( param, arg->result, exprTyVars, env ) ) return;
     734
     735                        if ( arg->get_lvalue() ) {
     736                                // argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations.
     737                                // if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) {
     738                                //      if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){
     739                                //              // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
     740                                //              return;
     741                                //      }
     742                                // }
     743                                arg = generalizedLvalue( new AddressExpr( arg ) );
     744                                if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) {
     745                                        // silence warnings by casting boxed parameters when the actual type does not match up with the formal type.
     746                                        arg = new CastExpr( arg, param->clone() );
     747                                }
     748                        } else {
     749                                // use type computed in unification to declare boxed variables
     750                                Type * newType = param->clone();
     751                                if ( env ) env->apply( newType );
     752                                ObjectDecl *newObj = makeTemporary( newType );
     753                                // TODO: is this right??? (Why wouldn't it be?)
     754                                newObj->get_type()->get_qualifiers() = Type::Qualifiers();
     755                                // TODO: why doesn't this just use initialization syntax?
     756                                // (Possibly to ensure code is run at the right time.)
     757                                UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) );
     758                                assign->get_args().push_back( new VariableExpr( newObj ) );
     759                                assign->get_args().push_back( arg );
     760                                stmtsToAddBefore.push_back( new ExprStmt( assign ) );
     761                                arg = new AddressExpr( new VariableExpr( newObj ) );
     762                        } // if
     763                }
     764
     765                void Pass1::boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars ) {
     766                        for ( DeclarationWithType * param : function->parameters ) {
     767                                assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() );
     768                                boxParam( *arg, param->get_type(), exprTyVars );
     769                                ++arg;
    798770                        } // for
    799771                }
    800772
    801                 void Pass1::addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) {
     773                void Pass1::addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ) {
    802774                        std::list< Expression *>::iterator cur = arg;
    803                         for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
    804                                 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->assertions.begin(); assert != (*tyVar)->assertions.end(); ++assert ) {
    805                                         InferredParams::const_iterator inferParam = appExpr->inferParams.find( (*assert)->get_uniqueId() );
    806                                         assertf( inferParam != appExpr->inferParams.end(), "addInferredParams missing inferred parameter: %s in: %s", toString( *assert ).c_str(), toString( appExpr ).c_str() );
     775                        for ( TypeDecl * const tyVar : functionType->forall ) {
     776                                for ( DeclarationWithType * const assert : tyVar->assertions ) {
     777                                        InferredParams::const_iterator inferParam = appExpr->inferParams.find( assert->get_uniqueId() );
     778                                        assertf( inferParam != appExpr->inferParams.end(), "addInferredParams missing inferred parameter: %s in: %s", toString( assert ).c_str(), toString( appExpr ).c_str() );
    807779                                        Expression *newExpr = inferParam->second.expr->clone();
    808                                         addCast( newExpr, (*assert)->get_type(), tyVars );
    809                                         boxParam( (*assert)->get_type(), newExpr, tyVars );
     780                                        boxParam( newExpr, assert->get_type(), tyVars );
    810781                                        appExpr->get_args().insert( cur, newExpr );
    811782                                } // for
     
    824795                }
    825796
    826                 FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars ) {
     797                FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars ) {
    827798                        // actually make the adapter type
    828799                        FunctionType *adapter = adaptee->clone();
     
    834805                }
    835806
    836                 Expression *makeAdapterArg( DeclarationWithType *param, DeclarationWithType *arg, DeclarationWithType *realParam, const TyVarMap &tyVars ) {
     807                Expression *makeAdapterArg(
     808                                DeclarationWithType *param,
     809                                DeclarationWithType const *arg,
     810                                DeclarationWithType const *realParam,
     811                                const TyVarMap &tyVars ) {
    837812                        assert( param );
    838813                        assert( arg );
    839                         if ( isPolyType( realParam->get_type(), tyVars ) ) {
    840                                 if ( ! isPolyType( arg->get_type() ) ) {
    841                                         UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
    842                                         deref->args.push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) );
    843                                         deref->result = arg->get_type()->clone();
    844                                         return deref;
    845                                 } // if
     814                        if ( isPolyType( realParam->get_type(), tyVars )
     815                                        && ! isPolyType( arg->get_type() ) ) {
     816                                UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
     817                                deref->args.push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) );
     818                                deref->result = arg->get_type()->clone();
     819                                return deref;
    846820                        } // if
    847821                        return new VariableExpr( param );
    848822                }
    849823
    850                 void addAdapterParams( ApplicationExpr *adapteeApp, std::list< DeclarationWithType *>::iterator arg, std::list< DeclarationWithType *>::iterator param, std::list< DeclarationWithType *>::iterator paramEnd, std::list< DeclarationWithType *>::iterator realParam, const TyVarMap &tyVars ) {
     824                void addAdapterParams(
     825                                ApplicationExpr *adapteeApp,
     826                                std::list< DeclarationWithType *>::const_iterator arg,
     827                                std::list< DeclarationWithType *>::const_iterator param,
     828                                std::list< DeclarationWithType *>::const_iterator paramEnd,
     829                                std::list< DeclarationWithType *>::const_iterator realParam,
     830                                const TyVarMap &tyVars ) {
    851831                        UniqueName paramNamer( "_p" );
    852832                        for ( ; param != paramEnd; ++param, ++arg, ++realParam ) {
     
    859839                }
    860840
    861                 FunctionDecl *Pass1::makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
     841                FunctionDecl *Pass1::makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
    862842                        FunctionType *adapterType = makeAdapterType( adaptee, tyVars );
    863843                        adapterType = ScrubTyVars::scrub( adapterType, tyVars );
     
    876856                        Statement *bodyStmt;
    877857
    878                         Type::ForallList::iterator tyArg = realType->get_forall().begin();
    879                         Type::ForallList::iterator tyParam = adapterType->get_forall().begin();
    880                         Type::ForallList::iterator realTyParam = adaptee->get_forall().begin();
    881                         for ( ; tyParam != adapterType->get_forall().end(); ++tyArg, ++tyParam, ++realTyParam ) {
    882                                 assert( tyArg != realType->get_forall().end() );
    883                                 std::list< DeclarationWithType *>::iterator assertArg = (*tyArg)->get_assertions().begin();
    884                                 std::list< DeclarationWithType *>::iterator assertParam = (*tyParam)->get_assertions().begin();
    885                                 std::list< DeclarationWithType *>::iterator realAssertParam = (*realTyParam)->get_assertions().begin();
    886                                 for ( ; assertParam != (*tyParam)->get_assertions().end(); ++assertArg, ++assertParam, ++realAssertParam ) {
    887                                         assert( assertArg != (*tyArg)->get_assertions().end() );
    888                                         adapteeApp->get_args().push_back( makeAdapterArg( *assertParam, *assertArg, *realAssertParam, tyVars ) );
     858                        for ( auto tys : group_iterate( realType->forall, adapterType->forall, adaptee->forall ) ) {
     859                                TypeDecl * tyArg = std::get<0>( tys );
     860                                TypeDecl * tyParam = std::get<1>( tys );
     861                                TypeDecl * realTyParam = std::get<2>( tys );
     862                                for ( auto asserts : group_iterate( tyArg->assertions, tyParam->assertions, realTyParam->assertions ) ) {
     863                                        DeclarationWithType * assertArg = std::get<0>( asserts );
     864                                        DeclarationWithType * assertParam = std::get<1>( asserts );
     865                                        DeclarationWithType * realAssertParam = std::get<2>( asserts );
     866                                        adapteeApp->args.push_back( makeAdapterArg( assertParam, assertArg, realAssertParam, tyVars ) );
    889867                                } // for
    890868                        } // for
    891869
    892                         std::list< DeclarationWithType *>::iterator arg = realType->get_parameters().begin();
    893                         std::list< DeclarationWithType *>::iterator param = adapterType->get_parameters().begin();
    894                         std::list< DeclarationWithType *>::iterator realParam = adaptee->get_parameters().begin();
     870                        std::list< DeclarationWithType *>::const_iterator arg = realType->parameters.begin();
     871                        std::list< DeclarationWithType *>::const_iterator param = adapterType->parameters.begin();
     872                        std::list< DeclarationWithType *>::const_iterator realParam = adaptee->parameters.begin();
    895873                        param++;                // skip adaptee parameter in the adapter type
    896874                        if ( realType->get_returnVals().empty() ) {
     
    898876                                addAdapterParams( adapteeApp, arg, param, adapterType->get_parameters().end(), realParam, tyVars );
    899877                                bodyStmt = new ExprStmt( adapteeApp );
    900                         } else if ( isDynType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {
     878                        } else if ( isDynType( adaptee->returnVals.front()->get_type(), tyVars ) ) {
    901879                                // return type T
    902880                                if ( (*param)->get_name() == "" ) {
     
    923901                void Pass1::passAdapters( ApplicationExpr * appExpr, FunctionType * functionType, const TyVarMap & exprTyVars ) {
    924902                        // collect a list of function types passed as parameters or implicit parameters (assertions)
    925                         std::list< DeclarationWithType *> &paramList = functionType->get_parameters();
    926                         std::list< FunctionType *> functions;
    927                         for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
    928                                 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) {
    929                                         findFunction( (*assert)->get_type(), functions, exprTyVars, needsAdapter );
     903                        std::list<FunctionType const *> functions;
     904                        for ( TypeDecl * const tyVar : functionType->get_forall() ) {
     905                                for ( DeclarationWithType * const assert : tyVar->get_assertions() ) {
     906                                        findFunction( assert->get_type(), functions, exprTyVars, needsAdapter );
    930907                                } // for
    931908                        } // for
    932                         for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
    933                                 findFunction( (*arg)->get_type(), functions, exprTyVars, needsAdapter );
     909                        for ( DeclarationWithType * const arg : functionType->get_parameters() ) {
     910                                findFunction( arg->get_type(), functions, exprTyVars, needsAdapter );
    934911                        } // for
    935912
     
    938915                        std::set< std::string > adaptersDone;
    939916
    940                         for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
    941                                 FunctionType *originalFunction = (*funType)->clone();
    942                                 FunctionType *realFunction = (*funType)->clone();
     917                        for ( FunctionType const * const funType : functions ) {
     918                                FunctionType *originalFunction = funType->clone();
     919                                FunctionType *realFunction = funType->clone();
    943920                                std::string mangleName = SymTab::Mangler::mangle( realFunction );
    944921
     
    958935                                        if ( adapter == adapters.end() ) {
    959936                                                // adapter has not been created yet in the current scope, so define it
    960                                                 FunctionDecl *newAdapter = makeAdapter( *funType, realFunction, mangleName, exprTyVars );
     937                                                FunctionDecl *newAdapter = makeAdapter( funType, realFunction, mangleName, exprTyVars );
    961938                                                std::pair< AdapterIter, bool > answer = adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, newAdapter ) );
    962939                                                adapter = answer.first;
     
    972949
    973950                Expression *makeIncrDecrExpr( ApplicationExpr *appExpr, Type *polyType, bool isIncr ) {
    974                         NameExpr *opExpr;
    975                         if ( isIncr ) {
    976                                 opExpr = new NameExpr( "?+=?" );
    977                         } else {
    978                                 opExpr = new NameExpr( "?-=?" );
    979                         } // if
     951                        NameExpr *opExpr = new NameExpr( ( isIncr ) ? "?+=?" : "?-=?" );
    980952                        UntypedExpr *addAssign = new UntypedExpr( opExpr );
    981953                        if ( AddressExpr *address = dynamic_cast< AddressExpr *>( appExpr->get_args().front() ) ) {
     
    11201092                Expression *Pass1::postmutate( ApplicationExpr *appExpr ) {
    11211093                        // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl;
    1122                         // for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i ) {
    1123                         //      std::cerr << i->first << " ";
     1094                        // for ( auto tyVar : scopeTyVars ) {
     1095                        //      std::cerr << tyVar.first << " ";
    11241096                        // }
    11251097                        // std::cerr << "\n";
     
    11341106
    11351107                        Expression *ret = appExpr;
    1136 
    1137                         std::list< Expression *>::iterator arg = appExpr->get_args().begin();
    11381108                        std::list< Expression *>::iterator paramBegin = appExpr->get_args().begin();
    11391109
     
    11561126                                // std::cerr << "dynRetType: " << dynRetType << std::endl;
    11571127                                Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result();
    1158                                 ret = addDynRetParam( appExpr, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType
     1128                                ret = addDynRetParam( appExpr, concRetType ); // xxx - used to use dynRetType instead of concRetType
    11591129                        } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...?
    11601130                                // xxx - the ! needsAdapter check may be incorrect. It seems there is some situation where an adapter is applied where it shouldn't be, and this fixes it for some cases. More investigation is needed.
     
    11641134                                // std::cerr << *env << std::endl;
    11651135                                // change the application so it calls the adapter rather than the passed function
    1166                                 ret = applyAdapter( appExpr, function, arg, scopeTyVars );
     1136                                ret = applyAdapter( appExpr, function );
    11671137                        } // if
    1168                         arg = appExpr->get_args().begin();
    1169 
    1170                         Type *concRetType = replaceWithConcrete( appExpr, dynRetType );
    1171                         passTypeVars( appExpr, concRetType, arg, exprTyVars ); // xxx - used to use dynRetType instead of concRetType; this changed so that the correct type paramaters are passed for return types (it should be the concrete type's parameters, not the formal type's)
    1172                         addInferredParams( appExpr, function, arg, exprTyVars );
    1173 
    1174                         arg = paramBegin;
    1175 
    1176                         boxParams( appExpr, function, arg, exprTyVars );
     1138
     1139                        Type *concRetType = replaceWithConcrete( dynRetType, env );
     1140                        std::list< Expression *>::iterator arg =
     1141                                passTypeVars( appExpr, concRetType, exprTyVars ); // xxx - used to use dynRetType instead of concRetType; this changed so that the correct type paramaters are passed for return types (it should be the concrete type's parameters, not the formal type's)
     1142                        addInferredParams( appExpr, arg, function, exprTyVars );
     1143
     1144                        // This needs to point at the original first argument.
     1145                        boxParams( appExpr, paramBegin, function, exprTyVars );
     1146
    11771147                        passAdapters( appExpr, function, exprTyVars );
    11781148
     
    11801150                }
    11811151
    1182                 Expression * Pass1::postmutate( UntypedExpr *expr ) {
     1152                bool isPolyDeref( UntypedExpr const * expr, TyVarMap const & scopeTyVars, TypeSubstitution const * env ) {
    11831153                        if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
    1184                                 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
     1154                                if ( auto name = dynamic_cast<NameExpr const *>( expr->function ) ) {
    11851155                                        if ( name->name == "*?" ) {
    1186                                                 Expression *ret = expr->args.front();
    1187                                                 expr->args.clear();
    1188                                                 delete expr;
    1189                                                 return ret;
     1156                                                return true;
    11901157                                        } // if
    11911158                                } // if
    11921159                        } // if
     1160                        return false;
     1161                }
     1162
     1163                Expression * Pass1::postmutate( UntypedExpr *expr ) {
     1164                        if ( isPolyDeref( expr, scopeTyVars, env ) ) {
     1165                                Expression *ret = expr->args.front();
     1166                                expr->args.clear();
     1167                                delete expr;
     1168                                return ret;
     1169                        }
    11931170                        return expr;
    11941171                }
     
    12001177                        bool needs = false;
    12011178                        if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->arg ) ) {
    1202                                 if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
    1203                                         if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
    1204                                                 if ( name->name == "*?" ) {
    1205                                                         if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) {
    1206                                                                 assert( appExpr->function->result );
    1207                                                                 FunctionType *function = getFunctionType( appExpr->function->result );
    1208                                                                 assert( function );
    1209                                                                 needs = needsAdapter( function, scopeTyVars );
    1210                                                         } // if
    1211                                                 } // if
     1179                                if ( isPolyDeref( expr, scopeTyVars, env ) ) {
     1180                                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) {
     1181                                                assert( appExpr->function->result );
     1182                                                FunctionType *function = getFunctionType( appExpr->function->result );
     1183                                                assert( function );
     1184                                                needs = needsAdapter( function, scopeTyVars );
    12121185                                        } // if
    12131186                                } // if
     
    12601233                void Pass2::addAdapters( FunctionType *functionType ) {
    12611234                        std::list< DeclarationWithType *> &paramList = functionType->parameters;
    1262                         std::list< FunctionType *> functions;
    1263                         for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
    1264                                 Type *orig = (*arg)->get_type();
     1235                        std::list< FunctionType const *> functions;
     1236                        for ( DeclarationWithType * const arg : functionType->parameters ) {
     1237                                Type *orig = arg->get_type();
    12651238                                findAndReplaceFunction( orig, functions, scopeTyVars, needsAdapter );
    1266                                 (*arg)->set_type( orig );
     1239                                arg->set_type( orig );
    12671240                        }
    12681241                        std::set< std::string > adaptersDone;
    1269                         for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
    1270                                 std::string mangleName = mangleAdapterName( *funType, scopeTyVars );
     1242                        for ( FunctionType const * const funType : functions ) {
     1243                                std::string mangleName = mangleAdapterName( funType, scopeTyVars );
    12711244                                if ( adaptersDone.find( mangleName ) == adaptersDone.end() ) {
    12721245                                        std::string adapterName = makeAdapterName( mangleName );
    12731246                                        // adapter may not be used in body, pass along with unused attribute.
    1274                                         paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) );
     1247                                        paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) );
    12751248                                        adaptersDone.insert( adaptersDone.begin(), mangleName );
    12761249                                }
     
    13491322                        ObjectDecl newPtr( "", Type::StorageClasses(), LinkageSpec::C, 0,
    13501323                                           new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 );
    1351                         for ( Type::ForallList::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {
     1324                        for ( TypeDecl * const tyParam : funcType->get_forall() ) {
    13521325                                ObjectDecl *sizeParm, *alignParm;
    13531326                                // add all size and alignment parameters to parameter list
    1354                                 if ( (*tyParm)->isComplete() ) {
    1355                                         TypeInstType parmType( Type::Qualifiers(), (*tyParm)->get_name(), *tyParm );
     1327                                if ( tyParam->isComplete() ) {
     1328                                        TypeInstType parmType( Type::Qualifiers(), tyParam->get_name(), tyParam );
    13561329                                        std::string parmName = mangleType( &parmType );
    13571330
     
    13671340                                }
    13681341                                // move all assertions into parameter list
    1369                                 for ( std::list< DeclarationWithType *>::iterator assert = (*tyParm)->get_assertions().begin(); assert != (*tyParm)->get_assertions().end(); ++assert ) {
     1342                                for ( DeclarationWithType * const assert : tyParam->get_assertions() ) {
    13701343                                        // assertion parameters may not be used in body, pass along with unused attribute.
    1371                                         (*assert)->get_attributes().push_back( new Attribute( "unused" ) );
    1372                                         inferredParams.push_back( *assert );
    1373                                 }
    1374                                 (*tyParm)->get_assertions().clear();
     1344                                        assert->get_attributes().push_back( new Attribute( "unused" ) );
     1345                                        inferredParams.push_back( assert );
     1346                                }
     1347                                tyParam->get_assertions().clear();
    13751348                        }
    13761349
    13771350                        // add size/align for generic parameter types to parameter list
    13781351                        std::set< std::string > seenTypes; // sizeofName for generic types we've seen
    1379                         for ( std::list< DeclarationWithType* >::const_iterator fnParm = last; fnParm != funcType->get_parameters().end(); ++fnParm ) {
    1380                                 Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars );
     1352                        for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) {
     1353                                Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );
    13811354                                if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
    13821355                                        std::string typeName = mangleType( polyType );
     
    14821455
    14831456                        if(!expect_func_type) {
    1484                                 GuardAction( [this]() {
    1485                                         knownLayouts.endScope();
    1486                                         knownOffsets.endScope();
    1487                                 });
    14881457                                // If this is the first function type we see
    14891458                                // Then it's the type of the declaration and we care about it
    1490                                 knownLayouts.beginScope();
    1491                                 knownOffsets.beginScope();
     1459                                GuardScope( *this );
    14921460                        }
    14931461
     
    14971465
    14981466                        // make sure that any type information passed into the function is accounted for
    1499                         for ( std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin(); fnParm != funcType->get_parameters().end(); ++fnParm ) {
     1467                        for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) {
    15001468                                // condition here duplicates that in Pass2::mutate( FunctionType* )
    1501                                 Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars );
     1469                                Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );
    15021470                                if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
    15031471                                        knownLayouts.insert( mangleType( polyType ) );
     
    15071475
    15081476                /// converts polymorphic type T into a suitable monomorphic representation, currently: __attribute__((aligned(8)) char[size_T]
    1509                 Type * polyToMonoType( Type * declType ) {
     1477                Type * polyToMonoType( Type const * declType ) {
    15101478                        Type * charType = new BasicType( Type::Qualifiers(), BasicType::Kind::Char);
    15111479                        Expression * size = new NameExpr( sizeofName( mangleType(declType) ) );
     
    15721540                /// Finds the member in the base list that matches the given declaration; returns its index, or -1 if not present
    15731541                long findMember( DeclarationWithType *memberDecl, std::list< Declaration* > &baseDecls ) {
    1574                         long i = 0;
    1575                         for(std::list< Declaration* >::const_iterator decl = baseDecls.begin(); decl != baseDecls.end(); ++decl, ++i ) {
    1576                                 if ( memberDecl->get_name() != (*decl)->get_name() )
     1542                        for ( auto pair : enumerate( baseDecls ) ) {
     1543                                Declaration * decl = pair.val;
     1544                                size_t i = pair.idx;
     1545                                if ( memberDecl->get_name() != decl->get_name() )
    15771546                                        continue;
    15781547
    15791548                                if ( memberDecl->get_name().empty() ) {
    15801549                                        // plan-9 field: match on unique_id
    1581                                         if ( memberDecl->get_uniqueId() == (*decl)->get_uniqueId() )
     1550                                        if ( memberDecl->get_uniqueId() == decl->get_uniqueId() )
    15821551                                                return i;
    15831552                                        else
     
    15851554                                }
    15861555
    1587                                 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( *decl );
     1556                                DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl );
    15881557
    15891558                                if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) {
     
    16031572
    16041573                /// Returns an index expression into the offset array for a type
    1605                 Expression *makeOffsetIndex( Type *objectType, long i ) {
     1574                Expression *makeOffsetIndex( Type const *objectType, long i ) {
    16061575                        ConstantExpr *fieldIndex = new ConstantExpr( Constant::from_ulong( i ) );
    16071576                        UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) );
     
    16961665
    16971666                void PolyGenericCalculator::addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ) {
    1698                         for ( std::list< Type* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) {
    1699                                 if ( findGeneric( *param ) ) {
     1667                        for ( Type * const param : otypeParams ) {
     1668                                if ( findGeneric( param ) ) {
    17001669                                        // push size/align vars for a generic parameter back
    1701                                         std::string paramName = mangleType( *param );
     1670                                        std::string paramName = mangleType( param );
    17021671                                        layoutCall->get_args().push_back( new NameExpr( sizeofName( paramName ) ) );
    17031672                                        layoutCall->get_args().push_back( new NameExpr( alignofName( paramName ) ) );
    17041673                                } else {
    1705                                         layoutCall->get_args().push_back( new SizeofExpr( (*param)->clone() ) );
    1706                                         layoutCall->get_args().push_back( new AlignofExpr( (*param)->clone() ) );
     1674                                        layoutCall->get_args().push_back( new SizeofExpr( param->clone() ) );
     1675                                        layoutCall->get_args().push_back( new AlignofExpr( param->clone() ) );
    17071676                                }
    17081677                        }
     
    17101679
    17111680                /// returns true if any of the otype parameters have a dynamic layout and puts all otype parameters in the output list
    1712                 bool findGenericParams( std::list< TypeDecl* > &baseParams, std::list< Expression* > &typeParams, std::list< Type* > &out ) {
     1681                bool findGenericParams( std::list< TypeDecl* > const &baseParams, std::list< Expression* > const &typeParams, std::list< Type* > &out ) {
    17131682                        bool hasDynamicLayout = false;
    17141683
    1715                         std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();
    1716                         std::list< Expression* >::const_iterator typeParam = typeParams.begin();
    1717                         for ( ; baseParam != baseParams.end() && typeParam != typeParams.end(); ++baseParam, ++typeParam ) {
     1684                        for ( auto paramPair : group_iterate( baseParams, typeParams ) ) {
     1685                                TypeDecl * baseParam = std::get<0>( paramPair );
     1686                                Expression * typeParam = std::get<1>( paramPair );
    17181687                                // skip non-otype parameters
    1719                                 if ( ! (*baseParam)->isComplete() ) continue;
    1720                                 TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( *typeParam );
     1688                                if ( ! baseParam->isComplete() ) continue;
     1689                                TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( typeParam );
    17211690                                assert( typeExpr && "all otype parameters should be type expressions" );
    17221691
     
    17251694                                if ( isPolyType( type ) ) hasDynamicLayout = true;
    17261695                        }
    1727                         assert( baseParam == baseParams.end() && typeParam == typeParams.end() );
    17281696
    17291697                        return hasDynamicLayout;
    17301698                }
    17311699
    1732                 bool PolyGenericCalculator::findGeneric( Type *ty ) {
     1700                bool PolyGenericCalculator::findGeneric( Type const *ty ) {
    17331701                        ty = replaceTypeInst( ty, env );
    17341702
    1735                         if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) {
     1703                        if ( auto typeInst = dynamic_cast< TypeInstType const * >( ty ) ) {
    17361704                                if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() ) {
    17371705                                        // NOTE assumes here that getting put in the scopeTyVars included having the layout variables set
     
    17391707                                }
    17401708                                return false;
    1741                         } else if ( StructInstType *structTy = dynamic_cast< StructInstType* >( ty ) ) {
     1709                        } else if ( auto structTy = dynamic_cast< StructInstType const * >( ty ) ) {
    17421710                                // check if this type already has a layout generated for it
    17431711                                std::string typeName = mangleType( ty );
     
    17461714                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
    17471715                                std::list< Type* > otypeParams;
    1748                                 if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->get_parameters(), otypeParams ) ) return false;
     1716                                if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->parameters, otypeParams ) ) return false;
    17491717
    17501718                                // insert local variables for layout and generate call to layout function
     
    17761744
    17771745                                return true;
    1778                         } else if ( UnionInstType *unionTy = dynamic_cast< UnionInstType* >( ty ) ) {
     1746                        } else if ( auto unionTy = dynamic_cast< UnionInstType const * >( ty ) ) {
    17791747                                // check if this type already has a layout generated for it
    17801748                                std::string typeName = mangleType( ty );
     
    17831751                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
    17841752                                std::list< Type* > otypeParams;
    1785                                 if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->get_parameters(), otypeParams ) ) return false;
     1753                                if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->parameters, otypeParams ) ) return false;
    17861754
    17871755                                // insert local variables for layout and generate call to layout function
     
    18811849                                        // build initializer list for offset array
    18821850                                        std::list< Initializer* > inits;
    1883                                         for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) {
    1884                                                 if ( DeclarationWithType *memberDecl = dynamic_cast< DeclarationWithType* >( *member ) ) {
    1885                                                         inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
    1886                                                 } else {
    1887                                                         assertf( false, "Requesting offset of Non-DWT member: %s", toString( *member ).c_str() );
    1888                                                 }
     1851                                        for ( Declaration * const member : baseMembers ) {
     1852                                                DeclarationWithType *memberDecl = dynamic_cast< DeclarationWithType* >( member );
     1853                                                assertf( memberDecl, "Requesting offset of Non-DWT member: %s", toString( member ).c_str() );
     1854                                                inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
    18891855                                        }
    18901856
     
    19651931// compile-command: "make install" //
    19661932// End: //
     1933
  • src/GenPoly/FindFunction.cc

    rb77f0e1 r63be3387  
    2929        class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting {
    3030          public:
    31                 FindFunction( std::list< FunctionType* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );
     31                FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );
    3232
    3333                void premutate( FunctionType * functionType );
     
    3737                void handleForall( const Type::ForallList &forall );
    3838
    39                 std::list< FunctionType* > &functions;
     39                std::list< FunctionType const * > & functions;
    4040                TyVarMap tyVars;
    4141                bool replaceMode;
     
    4343        };
    4444
    45         void findFunction( Type *type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
     45        void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    4646                PassVisitor<FindFunction> finder( functions, tyVars, false, predicate );
    4747                type->acceptMutator( finder );
    4848        }
    4949
    50         void findAndReplaceFunction( Type *&type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
     50        void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    5151                PassVisitor<FindFunction> finder( functions, tyVars, true, predicate );
    5252                type = type->acceptMutator( finder );
    5353        }
    5454
    55         FindFunction::FindFunction( std::list< FunctionType* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )
     55        FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )
    5656                : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) {
    5757        }
  • src/GenPoly/FindFunction.h

    rb77f0e1 r63be3387  
    2727
    2828        /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions`
    29         void findFunction( Type *type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
     29        void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    3030        /// like `findFunction`, but also replaces the function type with void ()(void)
    31         void findAndReplaceFunction( Type *&type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
     31        void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    3232} // namespace GenPoly
    3333
  • src/GenPoly/GenPoly.cc

    rb77f0e1 r63be3387  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct  7 15:25:00 2022
    13 // Update Count     : 16
     12// Last Modified On : Mon Oct 24 15:19:00 2022
     13// Update Count     : 17
    1414//
    1515
     
    118118        }
    119119
     120        const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) {
     121                if ( ! env ) return type;
     122                if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) {
     123                        Type *newType = env->lookup( typeInst->get_name() );
     124                        if ( newType ) return newType;
     125                }
     126                return type;
     127        }
     128
    120129        const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) {
    121130                if (!env) return type;
    122                 if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {
     131                if ( auto typeInst = dynamic_cast<const ast::TypeInstType*>(type) ) {
    123132                        auto newType = env->lookup(typeInst);
    124133                        if (newType) return newType;
     
    194203
    195204        if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    196                 if ( typeVars.find( inst->typeString() ) != typeVars.end() ) return type;
     205                if ( typeVars.find( *inst ) != typeVars.end() ) return type;
    197206        } else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) {
    198207                return isPolyType( array->base, subst );
     
    227236
    228237        if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
    229                 auto var = typeVars.find( inst->name );
     238                auto var = typeVars.find( *inst );
    230239                if ( var != typeVars.end() && var->second.isComplete ) {
    231 
     240                        return inst;
    232241                }
    233242        } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
     
    784793
    785794void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
    786         typeVars.insert( type->typeString(), ast::TypeDecl::Data( type->base ) );
     795        typeVars.insert( *type, ast::TypeDecl::Data( type->base ) );
    787796}
    788797
     
    816825        }
    817826
    818 void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars ) {
    819         for ( auto const & pair : typeVars ) {
    820                 os << pair.first << " (" << pair.second << ") ";
    821         } // for
    822         os << std::endl;
    823 }
    824 
    825827} // namespace GenPoly
    826828
  • src/GenPoly/GenPoly.h

    rb77f0e1 r63be3387  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct  7 15:06:00 2022
    13 // Update Count     : 9
     12// Last Modified On : Mon Oct 24 15:18:00 2022
     13// Update Count     : 11
    1414//
    1515
     
    2222#include "AST/Decl.hpp"           // for TypeDecl::Data
    2323#include "AST/Fwd.hpp"            // for ApplicationExpr, BaseInstType, Func...
     24#include "AST/Type.hpp"           // for TypeInstType::TypeEnvKey
    2425#include "SymTab/Mangler.h"       // for Mangler
    2526#include "SynTree/Declaration.h"  // for TypeDecl::Data, AggregateDecl, Type...
     
    2829namespace GenPoly {
    2930
    30         // TODO Via some tricks this works for ast::TypeDecl::Data as well.
    3131        typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    32         using TypeVarMap = ErasableScopedMap< std::string, ast::TypeDecl::Data >;
     32        using TypeVarMap = ErasableScopedMap< ast::TypeInstType::TypeEnvKey, ast::TypeDecl::Data >;
    3333
    3434        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    3535        Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
     36        const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env );
     37        const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * );
    3638
    3739        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
     
    5355        /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
    5456        ReferenceToType *isDynRet( FunctionType *function );
     57        const ast::BaseInstType *isDynRet( const ast::FunctionType * func );
    5558
    5659        /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type
     
    112115        /// Prints type variable map
    113116        void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
    114         void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars );
    115117
    116118        /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().
    117         inline std::string mangleType( Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
     119        inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
    118120
    119121        /// Gets the name of the sizeof parameter for the type, given its mangled name
     
    128130        /// Gets the name of the layout function for a given aggregate type, given its declaration
    129131        inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }
     132        inline std::string layoutofName( ast::AggregateDecl const * decl ) {
     133                return std::string( "_layoutof_" ) + decl->name;
     134        }
    130135
    131136} // namespace GenPoly
  • src/GenPoly/InstantiateGenericNew.cpp

    rb77f0e1 r63be3387  
    1010// Created On       : Tue Aug 16 10:51:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Sep 13 16:03:00 2022
    13 // Update Count     : 0
     12// Last Modified On : Mon Oct 31 16:48:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    378378                //   Ptr(int) p;
    379379                //   int i;
     380                // The original expression:
    380381                //   p.x = &i;
    381                 // becomes
    382                 //   int *& _dtype_static_member_0 = (int **)&p.x;
    383                 //   _dtype_static_member_0 = &i;
     382                // Becomes the expression/declaration:
     383                //   int *& _dtype_static_member_0;
     384                //   (_dtype_static_member_0 = (int**)&p.x,
     385                //    _dtype_static_member_0) = &i;
     386
     387                // The declaration is simple:
    384388                static UniqueName tmpNamer( "_dtype_static_member_" );
    385                 ast::Expr * init = new ast::CastExpr( location,
    386                         new ast::AddressExpr( location, memberExpr ),
    387                         new ast::PointerType( ast::deepCopy( concType ) ),
    388                         ast::ExplicitCast
    389                 );
    390389                ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
    391390                        tmpNamer.newName(),
    392391                        new ast::ReferenceType( concType ),
    393                         new ast::SingleInit( location, init ),
     392                        nullptr,
    394393                        ast::Storage::Classes(),
    395394                        ast::Linkage::C
    396395                );
    397396                stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
    398                 return new ast::VariableExpr( location, tmp );
     397
     398                // The expression is more complex, uses references and reference /
     399                // pointer parity. But breaking it up risks reordering.
     400                return new ast::CommaExpr( location,
     401                        ast::UntypedExpr::createAssign( location,
     402                                new ast::VariableExpr( location, tmp ),
     403                                new ast::CastExpr( location,
     404                                        new ast::AddressExpr( location, memberExpr ),
     405                                        new ast::PointerType( ast::deepCopy( concType ) ),
     406                                        ast::ExplicitCast
     407                                )
     408                        ),
     409                        new ast::VariableExpr( location, tmp )
     410                );
    399411        } else {
    400412                // Here, it can simply add a cast to actual types.
     
    476488};
    477489
    478 // I think this and the UnionInstType can be made into a template function.
    479490ast::Type const * GenericInstantiator::postvisit(
    480491                ast::StructInstType const * inst ) {
  • src/GenPoly/ScrubTyVars.cc

    rb77f0e1 r63be3387  
    2020#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it...
    2121#include "ScrubTyVars.h"
    22 #include "SymTab/Mangler.h"             // for mangle, typeMode
     22#include "SymTab/Mangler.h"             // for mangleType
    2323#include "SynTree/Declaration.h"        // for TypeDecl, TypeDecl::Data, Typ...
    2424#include "SynTree/Expression.h"         // for Expression (ptr only), NameExpr
     
    195195        }
    196196
    197         auto typeVar = typeVars->find( type->name );
     197        auto typeVar = typeVars->find( *type );
    198198        if ( typeVar == typeVars->end() ) {
    199199                return type;
     
    227227        if ( dynType ) {
    228228                return new ast::NameExpr( expr->location,
    229                         sizeofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) );
     229                        sizeofName( Mangle::mangleType( dynType ) ) );
    230230        } else {
    231231                return expr;
     
    237237        if ( dynType ) {
    238238                return new ast::NameExpr( expr->location,
    239                         alignofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) );
     239                        alignofName( Mangle::mangleType( dynType ) ) );
    240240        } else {
    241241                return expr;
  • src/Parser/DeclarationNode.cc

    rb77f0e1 r63be3387  
    2727#include "SynTree/LinkageSpec.h"   // for Spec, linkageName, Cforall
    2828#include "SynTree/Attribute.h"     // for Attribute
    29 #include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, Declaration
     29#include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, InlineMemberDecl, Declaration
    3030#include "SynTree/Expression.h"    // for Expression, ConstantExpr
    3131#include "SynTree/Statement.h"     // for AsmStmt
     
    11651165                SemanticError( this, "invalid function specifier for " );
    11661166        } // if
     1167        if ( enumInLine ) {
     1168                return new InlineMemberDecl( *name, storageClasses, linkage, nullptr );
     1169        } // if
    11671170        assertf( name, "ObjectDecl must a have name\n" );
    11681171        return (new ObjectDecl( *name, storageClasses, linkage, maybeBuild< Expression >( bitfieldWidth ), nullptr, maybeBuild< Initializer >( initializer ) ))->set_asmName( asmName )->set_extension( extension );
  • src/Parser/ExpressionNode.cc

    rb77f0e1 r63be3387  
    519519                }
    520520        }
    521         auto ret =  new QualifiedNameExpr( newDecl, name->name );
    522         if ( auto e = dynamic_cast<EnumDecl*>(newDecl) ) {
    523                 auto enumInst = new EnumInstType( Type::Qualifiers(), e );
    524                 auto obj = new ObjectDecl( name->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, enumInst, nullptr );
    525         }
    526         return ret;
     521        return new QualifiedNameExpr( newDecl, name->name );
    527522}
    528523
  • src/Parser/ParseNode.h

    rb77f0e1 r63be3387  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Oct 18 16:22:15 2022
    13 // Update Count     : 937
     12// Last Modified On : Wed Nov  2 21:27:07 2022
     13// Update Count     : 939
    1414//
    1515
     
    168168        Ctor, Dtor,
    169169}; // OperKinds
     170
     171enum class EnumHiding { Visible, Hide };
    170172
    171173struct LabelNode {
  • src/Parser/TypeData.cc

    rb77f0e1 r63be3387  
    925925        for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
    926926                if ( cur->enumInLine ) {
    927                         // Tell the compiler this is a inline value placeholder
    928                         ObjectDecl * member = dynamic_cast< ObjectDecl* >(* members);
    929                         member->enumInLine = true;
    930                 }
    931                 if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
     927                        // Do Nothing
     928                } else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
    932929                        SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
    933930                } else if ( cur->has_enumeratorValue() ) {
  • src/Parser/parser.yy

    rb77f0e1 r63be3387  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct 14 14:04:43 2022
    13 // Update Count     : 5751
     12// Last Modified On : Wed Nov  2 21:31:21 2022
     13// Update Count     : 5810
    1414//
    1515
     
    278278
    279279// Types declaration for productions
     280
    280281%union {
    281282        Token tok;
     
    290291        CondCtl * ifctl;
    291292        ForCtrl * fctl;
    292         enum OperKinds compop;
     293        OperKinds compop;
    293294        LabelNode * label;
    294295        InitializerNode * in;
     
    296297        std::string * str;
    297298        bool flag;
     299        EnumHiding hide;
    298300        CatchStmt::Kind catch_kind;
    299301        GenericExpr * genexpr;
     
    364366%type<constant> string_literal
    365367%type<str> string_literal_list
     368
     369%type<hide> hide_opt                                    visible_hide_opt
    366370
    367371// expressions
     
    25532557        | ENUM attribute_list_opt identifier
    25542558                { typedefTable.makeTypedef( *$3 ); }
    2555           '{' enumerator_list comma_opt '}'
    2556                 { $$ = DeclarationNode::newEnum( $3, $6, true, false )->addQualifiers( $2 ); }
     2559          hide_opt '{' enumerator_list comma_opt '}'
     2560          { $$ = DeclarationNode::newEnum( $3, $7, true, false )->addQualifiers( $2 ); }
    25572561        | ENUM attribute_list_opt typedef_name                          // unqualified type name
    2558           '{' enumerator_list comma_opt '}'
    2559                 { $$ = DeclarationNode::newEnum( $3->name, $5, true, false )->addQualifiers( $2 ); }
     2562          hide_opt '{' enumerator_list comma_opt '}'
     2563                { $$ = DeclarationNode::newEnum( $3->name, $6, true, false )->addQualifiers( $2 ); }
    25602564        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
    25612565                {
     
    25742578                        typedefTable.makeTypedef( *$6 );
    25752579                }
    2576           '{' enumerator_list comma_opt '}'
    2577                 {
    2578                         $$ = DeclarationNode::newEnum( $6, $10, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
     2580          hide_opt '{' enumerator_list comma_opt '}'
     2581                {
     2582                        $$ = DeclarationNode::newEnum( $6, $11, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
    25792583                }
    25802584        | ENUM '(' ')' attribute_list_opt identifier attribute_list_opt
    2581           '{' enumerator_list comma_opt '}'
    2582                 {
    2583                         $$ = DeclarationNode::newEnum( $5, $8, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
    2584                 }
    2585         | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
    2586                 {
    2587                         $$ = DeclarationNode::newEnum( $6->name, $9, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
    2588                 }
    2589         | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
    2590                 {
    2591                         $$ = DeclarationNode::newEnum( $5->name, $8, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
     2585          hide_opt '{' enumerator_list comma_opt '}'
     2586                {
     2587                        $$ = DeclarationNode::newEnum( $5, $9, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
     2588                }
     2589        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt
     2590          hide_opt '{' enumerator_list comma_opt '}'
     2591                {
     2592                        $$ = DeclarationNode::newEnum( $6->name, $10, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
     2593                }
     2594        | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt
     2595          hide_opt '{' enumerator_list comma_opt '}'
     2596                {
     2597                        $$ = DeclarationNode::newEnum( $5->name, $9, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
    25922598                }
    25932599        | enum_type_nobody
     2600        ;
     2601
     2602hide_opt:
     2603        // empty
     2604                { $$ = EnumHiding::Visible; }
     2605        | '!'
     2606                { $$ = EnumHiding::Hide; }
    25942607        ;
    25952608
     
    26022615
    26032616enumerator_list:
    2604         identifier_or_type_name enumerator_value_opt
    2605                 { $$ = DeclarationNode::newEnumValueGeneric( $1, $2 ); }
     2617        visible_hide_opt identifier_or_type_name enumerator_value_opt
     2618                { $$ = DeclarationNode::newEnumValueGeneric( $2, $3 ); }
    26062619        | INLINE type_name
    26072620                { $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); }
    2608         | enumerator_list ',' identifier_or_type_name enumerator_value_opt
    2609                 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $3, $4 ) ); }
     2621        | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
     2622                { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
    26102623        | enumerator_list ',' INLINE type_name enumerator_value_opt
    26112624                { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
     2625        ;
     2626
     2627visible_hide_opt:
     2628        hide_opt
     2629        | '^'
     2630                { $$ = EnumHiding::Visible; }
    26122631        ;
    26132632
  • src/ResolvExpr/CommonType.cc

    rb77f0e1 r63be3387  
    991991                                add_qualifiers( result, type2->qualifiers );
    992992                        } else {
    993                                 // xxx - does unifying a ref with typed enumInst makes sense?
    994993                                if (!dynamic_cast<const ast::EnumInstType *>(type2))
    995994                                        result = commonType( type2, ref, tenv, need, have, open, widen, symtab );
     
    10101009
    10111010                void postvisit( const ast::EnumInstType * enumInst ) {
    1012                         // reuse BasicType/EnumInstType common type by swapping
    1013                         // xxx - is this already handled by unify?
    10141011                        if (!dynamic_cast<const ast::EnumInstType *>(type2))
    10151012                                result = commonType( type2, enumInst, tenv, need, have, open, widen, symtab);
  • src/ResolvExpr/ConversionCost.cc

    rb77f0e1 r63be3387  
    720720                costCalc( baseType, dst, srcIsLvalue, symtab, env );
    721721        } else {
    722                 (void)enumInstType;
    723722                static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
    724723                cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
  • src/ResolvExpr/SatisfyAssertions.cpp

    rb77f0e1 r63be3387  
    268268                ast::ptr< ast::Type > resType = cand.expr->result;
    269269                cand.env.apply( resType );
    270                 return Mangle::mangle( resType, Mangle::typeMode() );
     270                return Mangle::mangleType( resType );
    271271        }
    272272
  • src/SymTab/Mangler.cc

    rb77f0e1 r63be3387  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:40:29 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 11 21:56:06 2021
    13 // Update Count     : 74
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct 21 16:18:00 2022
     13// Update Count     : 75
    1414//
    1515#include "Mangler.h"
     
    418418                        void postvisit( const ast::QualifiedType * qualType );
    419419
    420                         std::string get_mangleName() { return mangleName; }
     420                        /// The result is the current constructed mangled name.
     421                        std::string result() const { return mangleName; }
    421422                  private:
    422423                        std::string mangleName;         ///< Mangled name being constructed
     
    444445        } // namespace
    445446
    446 
    447447        std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
    448                 ast::Pass<Mangler_new> mangler( mode );
    449                 maybeAccept( decl, mangler );
    450                 return mangler.core.get_mangleName();
     448                return ast::Pass<Mangler_new>::read( decl, mode );
    451449        }
    452450
     
    689687                                        } // for
    690688                                        for ( auto & assert : ptype->assertions ) {
    691                                                 ast::Pass<Mangler_new> sub_mangler(
    692                                                         mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    693                                                 assert->var->accept( sub_mangler );
    694                                                 assertionNames.push_back( sub_mangler.core.get_mangleName() );
     689                                                assertionNames.push_back( ast::Pass<Mangler_new>::read(
     690                                                        assert->var.get(),
     691                                                        mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
    695692                                                acount++;
    696693                                        } // for
  • src/SymTab/Mangler.h

    rb77f0e1 r63be3387  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:44:03 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:45:30 2017
    13 // Update Count     : 15
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Oct 27 11:58:00 2022
     13// Update Count     : 16
    1414//
    1515
     
    2222
    2323#include "AST/Bitfield.hpp"
    24 #include "AST/Fwd.hpp"
    2524#include "SynTree/SynTree.h"  // for Types
    2625#include "SynTree/Visitor.h"  // for Visitor, maybeAccept
     
    3332// * Currently name compression is not implemented.
    3433
     34namespace ast {
     35        class Node;
     36}
    3537namespace ResolvExpr {
    3638        class TypeEnvironment;
     
    101103        using Mode = bitfield<mangle_flags>;
    102104
    103         static inline Mode typeMode() { return NoOverrideable | Type; }
     105        /// Mangle declaration name.
     106        std::string mangle( const ast::Node * decl, Mode mode = {} );
    104107
    105         /// Mangle declaration name
    106         std::string mangle( const ast::Node * decl, Mode mode = {} );
     108        /// Most common mangle configuration for types.
     109        static inline std::string mangleType( const ast::Node * type ) {
     110                return mangle( type, { NoOverrideable | Type } );
     111        }
    107112
    108113        namespace Encoding {
  • src/SymTab/Validate.cc

    rb77f0e1 r63be3387  
    4747#include <utility>                     // for pair
    4848
    49 #include "AST/Chain.hpp"
    50 #include "AST/Decl.hpp"
    51 #include "AST/Node.hpp"
    52 #include "AST/Pass.hpp"
    53 #include "AST/SymbolTable.hpp"
    54 #include "AST/Type.hpp"
    55 #include "AST/TypeSubstitution.hpp"
    5649#include "CodeGen/CodeGenerator.h"     // for genName
    5750#include "CodeGen/OperatorTable.h"     // for isCtorDtor, isCtorDtorAssign
     
    13261319        }
    13271320
    1328 namespace {
    1329         /// Replaces enum types by int, and function/array types in function parameter and return
    1330         /// lists by appropriate pointers
    1331         /*
    1332         struct EnumAndPointerDecay_new {
    1333                 const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) {
    1334                         // set the type of each member of the enumeration to be EnumConstant
    1335                         for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {
    1336                                 // build new version of object with EnumConstant
    1337                                 ast::ptr< ast::ObjectDecl > obj =
    1338                                         enumDecl->members[i].strict_as< ast::ObjectDecl >();
    1339                                 obj.get_and_mutate()->type =
    1340                                         new ast::EnumInstType{ enumDecl->name, ast::CV::Const };
    1341 
    1342                                 // set into decl
    1343                                 ast::EnumDecl * mut = mutate( enumDecl );
    1344                                 mut->members[i] = obj.get();
    1345                                 enumDecl = mut;
    1346                         }
    1347                         return enumDecl;
    1348                 }
    1349 
    1350                 static const ast::FunctionType * fixFunctionList(
    1351                         const ast::FunctionType * func,
    1352                         std::vector< ast::ptr< ast::DeclWithType > > ast::FunctionType::* field,
    1353                         ast::ArgumentFlag isVarArgs = ast::FixedArgs
    1354                 ) {
    1355                         const auto & dwts = func->* field;
    1356                         unsigned nvals = dwts.size();
    1357                         bool hasVoid = false;
    1358                         for ( unsigned i = 0; i < nvals; ++i ) {
    1359                                 func = ast::mutate_field_index( func, field, i, fixFunction( dwts[i], hasVoid ) );
    1360                         }
    1361 
    1362                         // the only case in which "void" is valid is where it is the only one in the list
    1363                         if ( hasVoid && ( nvals > 1 || isVarArgs ) ) {
    1364                                 SemanticError(
    1365                                         dwts.front()->location, func, "invalid type void in function type" );
    1366                         }
    1367 
    1368                         // one void is the only thing in the list, remove it
    1369                         if ( hasVoid ) {
    1370                                 func = ast::mutate_field(
    1371                                         func, field, std::vector< ast::ptr< ast::DeclWithType > >{} );
    1372                         }
    1373 
    1374                         return func;
    1375                 }
    1376 
    1377                 const ast::FunctionType * previsit( const ast::FunctionType * func ) {
    1378                         func = fixFunctionList( func, &ast::FunctionType::params, func->isVarArgs );
    1379                         return fixFunctionList( func, &ast::FunctionType::returns );
    1380                 }
    1381         };
    1382 
    1383         /// expand assertions from a trait instance, performing appropriate type variable substitutions
    1384         void expandAssertions(
    1385                 const ast::TraitInstType * inst, std::vector< ast::ptr< ast::DeclWithType > > & out
    1386         ) {
    1387                 assertf( inst->base, "Trait instance not linked to base trait: %s", toCString( inst ) );
    1388 
    1389                 // build list of trait members, substituting trait decl parameters for instance parameters
    1390                 ast::TypeSubstitution sub{
    1391                         inst->base->params.begin(), inst->base->params.end(), inst->params.begin() };
    1392                 // deliberately take ast::ptr by-value to ensure this does not mutate inst->base
    1393                 for ( ast::ptr< ast::Decl > decl : inst->base->members ) {
    1394                         auto member = decl.strict_as< ast::DeclWithType >();
    1395                         sub.apply( member );
    1396                         out.emplace_back( member );
    1397                 }
    1398         }
    1399 
    1400         /// Associates forward declarations of aggregates with their definitions
    1401         class LinkReferenceToTypes_new final
    1402         : public ast::WithSymbolTable, public ast::WithGuards, public
    1403           ast::WithVisitorRef<LinkReferenceToTypes_new>, public ast::WithShortCircuiting {
    1404 
    1405                 // these maps of uses of forward declarations of types need to have the actual type
    1406                 // declaration switched in * after * they have been traversed. To enable this in the
    1407                 // ast::Pass framework, any node that needs to be so mutated has mutate() called on it
    1408                 // before it is placed in the map, properly updating its parents in the usual traversal,
    1409                 // then can have the actual mutation applied later
    1410                 using ForwardEnumsType = std::unordered_multimap< std::string, ast::EnumInstType * >;
    1411                 using ForwardStructsType = std::unordered_multimap< std::string, ast::StructInstType * >;
    1412                 using ForwardUnionsType = std::unordered_multimap< std::string, ast::UnionInstType * >;
    1413 
    1414                 const CodeLocation & location;
    1415                 const ast::SymbolTable * localSymtab;
    1416 
    1417                 ForwardEnumsType forwardEnums;
    1418                 ForwardStructsType forwardStructs;
    1419                 ForwardUnionsType forwardUnions;
    1420 
    1421                 /// true if currently in a generic type body, so that type parameter instances can be
    1422                 /// renamed appropriately
    1423                 bool inGeneric = false;
    1424 
    1425         public:
    1426                 /// contstruct using running symbol table
    1427                 LinkReferenceToTypes_new( const CodeLocation & loc )
    1428                 : location( loc ), localSymtab( &symtab ) {}
    1429 
    1430                 /// construct using provided symbol table
    1431                 LinkReferenceToTypes_new( const CodeLocation & loc, const ast::SymbolTable & syms )
    1432                 : location( loc ), localSymtab( &syms ) {}
    1433 
    1434                 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
    1435                         // ensure generic parameter instances are renamed like the base type
    1436                         if ( inGeneric && typeInst->base ) {
    1437                                 typeInst = ast::mutate_field(
    1438                                         typeInst, &ast::TypeInstType::name, typeInst->base->name );
    1439                         }
    1440 
    1441                         if (
    1442                                 auto typeDecl = dynamic_cast< const ast::TypeDecl * >(
    1443                                         localSymtab->lookupType( typeInst->name ) )
    1444                         ) {
    1445                                 typeInst = ast::mutate_field( typeInst, &ast::TypeInstType::kind, typeDecl->kind );
    1446                         }
    1447 
    1448                         return typeInst;
    1449                 }
    1450 
    1451                 const ast::Type * postvisit( const ast::EnumInstType * inst ) {
    1452                         const ast::EnumDecl * decl = localSymtab->lookupEnum( inst->name );
    1453                         // not a semantic error if the enum is not found, just an implicit forward declaration
    1454                         if ( decl ) {
    1455                                 inst = ast::mutate_field( inst, &ast::EnumInstType::base, decl );
    1456                         }
    1457                         if ( ! decl || ! decl->body ) {
    1458                                 // forward declaration
    1459                                 auto mut = mutate( inst );
    1460                                 forwardEnums.emplace( inst->name, mut );
    1461                                 inst = mut;
    1462                         }
    1463                         return inst;
    1464                 }
    1465 
    1466                 void checkGenericParameters( const ast::BaseInstType * inst ) {
    1467                         for ( const ast::Expr * param : inst->params ) {
    1468                                 if ( ! dynamic_cast< const ast::TypeExpr * >( param ) ) {
    1469                                         SemanticError(
    1470                                                 location, inst, "Expression parameters for generic types are currently "
    1471                                                 "unsupported: " );
    1472                                 }
    1473                         }
    1474                 }
    1475 
    1476                 const ast::StructInstType * postvisit( const ast::StructInstType * inst ) {
    1477                         const ast::StructDecl * decl = localSymtab->lookupStruct( inst->name );
    1478                         // not a semantic error if the struct is not found, just an implicit forward declaration
    1479                         if ( decl ) {
    1480                                 inst = ast::mutate_field( inst, &ast::StructInstType::base, decl );
    1481                         }
    1482                         if ( ! decl || ! decl->body ) {
    1483                                 // forward declaration
    1484                                 auto mut = mutate( inst );
    1485                                 forwardStructs.emplace( inst->name, mut );
    1486                                 inst = mut;
    1487                         }
    1488                         checkGenericParameters( inst );
    1489                         return inst;
    1490                 }
    1491 
    1492                 const ast::UnionInstType * postvisit( const ast::UnionInstType * inst ) {
    1493                         const ast::UnionDecl * decl = localSymtab->lookupUnion( inst->name );
    1494                         // not a semantic error if the struct is not found, just an implicit forward declaration
    1495                         if ( decl ) {
    1496                                 inst = ast::mutate_field( inst, &ast::UnionInstType::base, decl );
    1497                         }
    1498                         if ( ! decl || ! decl->body ) {
    1499                                 // forward declaration
    1500                                 auto mut = mutate( inst );
    1501                                 forwardUnions.emplace( inst->name, mut );
    1502                                 inst = mut;
    1503                         }
    1504                         checkGenericParameters( inst );
    1505                         return inst;
    1506                 }
    1507 
    1508                 const ast::Type * postvisit( const ast::TraitInstType * traitInst ) {
    1509                         // handle other traits
    1510                         const ast::TraitDecl * traitDecl = localSymtab->lookupTrait( traitInst->name );
    1511                         if ( ! traitDecl )       {
    1512                                 SemanticError( location, "use of undeclared trait " + traitInst->name );
    1513                         }
    1514                         if ( traitDecl->params.size() != traitInst->params.size() ) {
    1515                                 SemanticError( location, traitInst, "incorrect number of trait parameters: " );
    1516                         }
    1517                         traitInst = ast::mutate_field( traitInst, &ast::TraitInstType::base, traitDecl );
    1518 
    1519                         // need to carry over the "sized" status of each decl in the instance
    1520                         for ( unsigned i = 0; i < traitDecl->params.size(); ++i ) {
    1521                                 auto expr = traitInst->params[i].as< ast::TypeExpr >();
    1522                                 if ( ! expr ) {
    1523                                         SemanticError(
    1524                                                 traitInst->params[i].get(), "Expression parameters for trait instances "
    1525                                                 "are currently unsupported: " );
    1526                                 }
    1527 
    1528                                 if ( auto inst = expr->type.as< ast::TypeInstType >() ) {
    1529                                         if ( traitDecl->params[i]->sized && ! inst->base->sized ) {
    1530                                                 // traitInst = ast::mutate_field_index(
    1531                                                 //      traitInst, &ast::TraitInstType::params, i,
    1532                                                 //      ...
    1533                                                 // );
    1534                                                 ast::TraitInstType * mut = ast::mutate( traitInst );
    1535                                                 ast::chain_mutate( mut->params[i] )
    1536                                                         ( &ast::TypeExpr::type )
    1537                                                                 ( &ast::TypeInstType::base )->sized = true;
    1538                                                 traitInst = mut;
    1539                                         }
    1540                                 }
    1541                         }
    1542 
    1543                         return traitInst;
    1544                 }
    1545 
    1546                 void previsit( const ast::QualifiedType * ) { visit_children = false; }
    1547 
    1548                 const ast::Type * postvisit( const ast::QualifiedType * qualType ) {
    1549                         // linking only makes sense for the "oldest ancestor" of the qualified type
    1550                         return ast::mutate_field(
    1551                                 qualType, &ast::QualifiedType::parent, qualType->parent->accept( * visitor ) );
    1552                 }
    1553 
    1554                 const ast::Decl * postvisit( const ast::EnumDecl * enumDecl ) {
    1555                         // visit enum members first so that the types of self-referencing members are updated
    1556                         // properly
    1557                         if ( ! enumDecl->body ) return enumDecl;
    1558 
    1559                         // update forward declarations to point here
    1560                         auto fwds = forwardEnums.equal_range( enumDecl->name );
    1561                         if ( fwds.first != fwds.second ) {
    1562                                 auto inst = fwds.first;
    1563                                 do {
    1564                                         // forward decl is stored * mutably * in map, can thus be updated
    1565                                         inst->second->base = enumDecl;
    1566                                 } while ( ++inst != fwds.second );
    1567                                 forwardEnums.erase( fwds.first, fwds.second );
    1568                         }
    1569 
    1570                         // ensure that enumerator initializers are properly set
    1571                         for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {
    1572                                 auto field = enumDecl->members[i].strict_as< ast::ObjectDecl >();
    1573                                 if ( field->init ) {
    1574                                         // need to resolve enumerator initializers early so that other passes that
    1575                                         // determine if an expression is constexpr have appropriate information
    1576                                         auto init = field->init.strict_as< ast::SingleInit >();
    1577 
    1578                                         enumDecl = ast::mutate_field_index(
    1579                                                 enumDecl, &ast::EnumDecl::members, i,
    1580                                                 ast::mutate_field( field, &ast::ObjectDecl::init,
    1581                                                         ast::mutate_field( init, &ast::SingleInit::value,
    1582                                                                 ResolvExpr::findSingleExpression(
    1583                                                                         init->value, new ast::BasicType{ ast::BasicType::SignedInt },
    1584                                                                         symtab ) ) ) );
    1585                                 }
    1586                         }
    1587 
    1588                         return enumDecl;
    1589                 }
    1590 
    1591                 /// rename generic type parameters uniquely so that they do not conflict with user defined
    1592                 /// function forall parameters, e.g. the T in Box and the T in f, below
    1593                 ///   forall(otype T)
    1594                 ///   struct Box {
    1595                 ///     T x;
    1596                 ///   };
    1597                 ///   forall(otype T)
    1598                 ///   void f(Box(T) b) {
    1599                 ///     ...
    1600                 ///   }
    1601                 template< typename AggrDecl >
    1602                 const AggrDecl * renameGenericParams( const AggrDecl * aggr ) {
    1603                         GuardValue( inGeneric );
    1604                         inGeneric = ! aggr->params.empty();
    1605 
    1606                         for ( unsigned i = 0; i < aggr->params.size(); ++i ) {
    1607                                 const ast::TypeDecl * td = aggr->params[i];
    1608 
    1609                                 aggr = ast::mutate_field_index(
    1610                                         aggr, &AggrDecl::params, i,
    1611                                         ast::mutate_field( td, &ast::TypeDecl::name, "__" + td->name + "_generic_" ) );
    1612                         }
    1613                         return aggr;
    1614                 }
    1615 
    1616                 const ast::StructDecl * previsit( const ast::StructDecl * structDecl ) {
    1617                         return renameGenericParams( structDecl );
    1618                 }
    1619 
    1620                 void postvisit( const ast::StructDecl * structDecl ) {
    1621                         // visit struct members first so that the types of self-referencing members are
    1622                         // updated properly
    1623                         if ( ! structDecl->body ) return;
    1624 
    1625                         // update forward declarations to point here
    1626                         auto fwds = forwardStructs.equal_range( structDecl->name );
    1627                         if ( fwds.first != fwds.second ) {
    1628                                 auto inst = fwds.first;
    1629                                 do {
    1630                                         // forward decl is stored * mutably * in map, can thus be updated
    1631                                         inst->second->base = structDecl;
    1632                                 } while ( ++inst != fwds.second );
    1633                                 forwardStructs.erase( fwds.first, fwds.second );
    1634                         }
    1635                 }
    1636 
    1637                 const ast::UnionDecl * previsit( const ast::UnionDecl * unionDecl ) {
    1638                         return renameGenericParams( unionDecl );
    1639                 }
    1640 
    1641                 void postvisit( const ast::UnionDecl * unionDecl ) {
    1642                         // visit union members first so that the types of self-referencing members are updated
    1643                         // properly
    1644                         if ( ! unionDecl->body ) return;
    1645 
    1646                         // update forward declarations to point here
    1647                         auto fwds = forwardUnions.equal_range( unionDecl->name );
    1648                         if ( fwds.first != fwds.second ) {
    1649                                 auto inst = fwds.first;
    1650                                 do {
    1651                                         // forward decl is stored * mutably * in map, can thus be updated
    1652                                         inst->second->base = unionDecl;
    1653                                 } while ( ++inst != fwds.second );
    1654                                 forwardUnions.erase( fwds.first, fwds.second );
    1655                         }
    1656                 }
    1657 
    1658                 const ast::Decl * postvisit( const ast::TraitDecl * traitDecl ) {
    1659                         // set the "sized" status for the special "sized" trait
    1660                         if ( traitDecl->name == "sized" ) {
    1661                                 assertf( traitDecl->params.size() == 1, "Built-in trait 'sized' has incorrect "
    1662                                         "number of parameters: %zd", traitDecl->params.size() );
    1663 
    1664                                 traitDecl = ast::mutate_field_index(
    1665                                         traitDecl, &ast::TraitDecl::params, 0,
    1666                                         ast::mutate_field(
    1667                                                 traitDecl->params.front().get(), &ast::TypeDecl::sized, true ) );
    1668                         }
    1669 
    1670                         // move assertions from type parameters into the body of the trait
    1671                         std::vector< ast::ptr< ast::DeclWithType > > added;
    1672                         for ( const ast::TypeDecl * td : traitDecl->params ) {
    1673                                 for ( const ast::DeclWithType * assn : td->assertions ) {
    1674                                         auto inst = dynamic_cast< const ast::TraitInstType * >( assn->get_type() );
    1675                                         if ( inst ) {
    1676                                                 expandAssertions( inst, added );
    1677                                         } else {
    1678                                                 added.emplace_back( assn );
    1679                                         }
    1680                                 }
    1681                         }
    1682                         if ( ! added.empty() ) {
    1683                                 auto mut = mutate( traitDecl );
    1684                                 for ( const ast::DeclWithType * decl : added ) {
    1685                       &