Changeset fc12f05


Ignore:
Timestamp:
Nov 13, 2023, 3:43:43 AM (23 months ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
25f2798
Parents:
0030b508 (diff), 2174191 (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:
5 added
114 deleted
134 edited
3 moved

Legend:

Unmodified
Added
Removed
  • doc/bibliography/pl.bib

    r0030b508 rfc12f05  
    41084108}
    41094109
    4110 @article{Buhr22,
     4110@article{Buhr23,
    41114111    contributer = {pabuhr@plg},
    41124112    author      = {Peter A. Buhr and Colby A. Parsons and Thierry Delisle and He Nan Li},
     
    41144114    journal     = spe,
    41154115    year        = 2023,
    4116     month       = sep,
    4117     note        = {\url{https://onlinelibrary.wiley.com/doi/pdf/10.1002/spe.3262}}
     4116    month       = dec,
     4117    volume      = 53,
     4118    number      = 12,
     4119    pages       = {2463-2500},
     4120    note        = {\url{https://onlinelibrary.wiley.com/doi/10.1002/spe.3262},
    41184121}
    41194122
     
    41334136    journal     = spe,
    41344137    year        = 1983,
     4138    month       = jul,
    41354139    volume      = 13,
    41364140    number      = 7,
    41374141    pages       = {577-596},
    4138     month       = jul
    41394142}
    41404143
  • driver/as.cc

    r0030b508 rfc12f05  
    1111// Created On       : Wed Aug  1 10:49:42 2018
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Wed Dec  8 07:56:12 2021
    14 // Update Count     : 136
     13// Last Modified On : Tue Oct 24 20:45:06 2023
     14// Update Count     : 159
    1515//
    1616
     
    4545                char * dcursor;
    4646                if ( (dcursor = strstr( start, ".Ldebug_info0:" ) ) ) { // debug information ?
    47 
     47                        // fprintf( stderr, "found .Ldebug_info0:\n" );
     48#if defined( __i386 ) || defined( __x86_64 )
    4849                        if ( char * cursor = strstr( dcursor, ".long\t.LASF" ) ) { // language code ?
     50                                // fprintf( stderr, ".long\t.LASF\n" );
     51#elif defined( __aarch64__ )
     52                        if ( char * cursor = strstr( dcursor, ".4byte\t.LASF" ) ) { // language code ?
     53                                // fprintf( stderr, ".4byte\t.LASF\n" );
     54#else
     55        #error unsupported architecture
     56#endif
    4957                                for ( int i = 0; i < 2; i += 1 ) {              // move N (magic) lines forward
    5058                                        cursor = strstr( cursor, "\n" ) + 1;
     
    5563                                if ( *(cursor - 2) == '0' && *(cursor - 1) == 'x' &&
    5664                                         (*cursor == 'c' || *cursor == '1' || *cursor == '2') ) { // C99/C89/C
     65                                        // fprintf( stderr, "language code C99/C89/C %c\n", *cursor );
    5766                                        // Expand file by one byte to hold 2 character Cforall language code.
    5867                                        if ( ftruncate( fd, size + 1 ) ) { perror( "ftruncate" ); exit( EXIT_FAILURE ); };
    5968                                        memmove( cursor + 2, cursor + 1, start + size - cursor - 1 ); // move remaining text 1 character right
    6069                                } else if ( *(cursor - 3) == '0' && *(cursor - 2) == 'x' && *(cursor - 1) == '1' && *cursor == 'd' ) { // C11
     70                                        // fprintf( stderr, "language code C11 %c\n", *cursor );
    6171                                } else {
    6272                                        for ( int i = 0; i < 6; i += 1 ) {      // move N (magic) lines forward
  • libcfa/prelude/Makefile.am

    r0030b508 rfc12f05  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Thu Jan 13 17:06:27 2022
    14 ## Update Count     : 215
     13## Last Modified On : Wed Nov  1 21:09:25 2023
     14## Update Count     : 221
    1515###############################################################################
    1616
     
    2121# put into lib for now
    2222cfalibdir = ${CFA_LIBDIR}
    23 cfalib_DATA = gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c defines.hfa
     23cfalib_DATA = gcc-builtins.cfa builtins.cfa extras.cfa prelude.cfa bootloader.c defines.hfa
    2424
    25 EXTRA_DIST = bootloader.cf builtins.c builtins.def extras.c extras.regx extras.regx2 prelude-gen.cc prototypes.awk prototypes.c prototypes.sed sync-builtins.cf
     25EXTRA_DIST = bootloader.cfa builtins.c builtins.def extras.c extras.regx extras.regx2 prelude-gen.cc prototypes.awk prototypes.c prototypes.sed sync-builtins.cfa
    2626
    2727CC = @LOCAL_CFACC@
     
    3636
    3737# create extra forward types/declarations to reduce inclusion of library files
    38 extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
     38extras.cfa : ${srcdir}/extras.regx ${srcdir}/extras.c
    3939        @echo '# 2 "${@}"  // needed for error messages from this file' > ${@}
    4040        ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx >> ${@}
     
    4242
    4343# create forward declarations for gcc builtins
    44 gcc-builtins.cf : gcc-builtins.c ${srcdir}/prototypes.sed
     44gcc-builtins.cfa : gcc-builtins.c ${srcdir}/prototypes.sed
    4545        @echo '# 2 "${@}"  // needed for error messages from this file' > ${@}
    4646        ${AM_V_GEN}gcc -I${srcdir} -E -P $< | sed -r -f ${srcdir}/prototypes.sed >> ${@}
    4747
    48 gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cf ${srcdir}/prototypes.c
     48gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cfa ${srcdir}/prototypes.c
    4949        ${AM_V_GEN}gcc -I${srcdir} -E ${srcdir}/prototypes.c | awk -f ${srcdir}/prototypes.awk > ${@}
    5050
     
    5959
    6060# create forward declarations for cfa builtins
    61 builtins.cf : builtins.c @LOCAL_CFACC@
     61builtins.cfa : builtins.c @LOCAL_CFACC@
    6262        ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po -D__cforall
    63         ${AM_V_at}sed -i 's/builtins.o/builtins.cf/g' $(DEPDIR)/builtins.Po
     63        ${AM_V_at}sed -i 's/builtins.o/builtins.cfa/g' $(DEPDIR)/builtins.Po
    6464
    6565include $(DEPDIR)/builtins.Po
    6666
    67 bootloader.c : ${srcdir}/bootloader.cf prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACPP@
    68         ${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cf ${@}  # use src/cfa-cpp as not in lib until after install
     67bootloader.c : ${srcdir}/bootloader.cfa prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @CFACPP@
     68        ${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cfa ${@}  # use src/cfa-cpp as not in lib until after install
    6969
    7070maintainer-clean-local :
    7171        rm -rf $(DEPDIR)
    7272
    73 MOSTLYCLEANFILES = bootloader.c builtins.cf extras.cf gcc-builtins.c gcc-builtins.cf prelude.cfa
     73MOSTLYCLEANFILES = bootloader.c builtins.cfa extras.cfa gcc-builtins.c gcc-builtins.cfa prelude.cfa
    7474DISTCLEANFILES = $(DEPDIR)/builtins.Po
    7575MAINTAINERCLEANFILES = ${addprefix ${libdir}/,${cfalib_DATA}} ${addprefix ${libdir}/,${lib_LIBRARIES}}
    7676
    7777if ENABLE_DISTCC
    78 distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ defines.hfa gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh
     78distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ defines.hfa gcc-builtins.cfa builtins.cfa extras.cfa prelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh
    7979        ${AM_V_GEN}$(srcdir)/../../tools/build/push2dist.sh @CFADIR_HASH@ @DIST_BWLIMIT@
    8080        @echo "Dummy file to track distribution to remote hosts" > ${@}
  • libcfa/prelude/prototypes.awk

    r0030b508 rfc12f05  
    1010# Created On       : Sat May 16 07:57:37 2015
    1111# Last Modified By : Peter A. Buhr
    12 # Last Modified On : Sat Feb  8 09:46:58 2020
    13 # Update Count     : 36
     12# Last Modified On : Wed Nov  1 20:44:04 2023
     13# Update Count     : 37
    1414#
    1515
     
    150150        # extras
    151151        printf( "\n#include \"builtins.def\"\n\n" );
    152         printf( "\n#include \"sync-builtins.cf\"\n\n" );
     152        printf( "\n#include \"sync-builtins.cfa\"\n\n" );
    153153        printf( "extern const char *__PRETTY_FUNCTION__;\n" );
    154154        printf( "float _Complex __builtin_complex( float, float );\n" );
  • libcfa/src/Makefile.am

    r0030b508 rfc12f05  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Sep 18 17:06:56 2023
    14 ## Update Count     : 264
     13## Last Modified On : Wed Nov  1 19:03:42 2023
     14## Update Count     : 266
    1515###############################################################################
    1616
     
    195195if ENABLE_DISTCC
    196196
    197 ../prelude/distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ ../prelude/defines.hfa ../prelude/gcc-builtins.cf ../prelude/builtins.cf ../prelude/extras.cf ../prelude/prelude.cfa ../prelude/bootloader.c $(srcdir)/../../tools/build/push2dist.sh
     197../prelude/distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ ../prelude/defines.hfa ../prelude/gcc-builtins.cfa ../prelude/builtins.cfa ../prelude/extras.cfa ../prelude/prelude.cfa ../prelude/bootloader.c $(srcdir)/../../tools/build/push2dist.sh
    198198        @+make -C ../prelude distribution
    199199
     
    202202endif ENABLE_DISTCC
    203203
    204 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
     204prelude.o : prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @LOCAL_CFACC@ @CFACPP@
    205205        ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@}
    206206
    207 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
     207prelude.lo: prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @LOCAL_CFACC@ @CFACPP@
    208208        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    209209        $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@}
  • libcfa/src/collections/string.cfa

    r0030b508 rfc12f05  
    1010// Created On       : Fri Sep 03 11:00:00 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Sep  2 12:05:57 2023
    13 // Update Count     : 206
     12// Last Modified On : Wed Oct 18 21:52:09 2023
     13// Update Count     : 208
    1414//
    1515
     
    138138
    139139void ?|?( ifstream & in, _Istream_Sstr f ) {
    140     (ifstream &)(in | f); ends( in );
     140    (ifstream &)(in | f);
    141141}
    142142
  • libcfa/src/collections/string_res.cfa

    r0030b508 rfc12f05  
    1010// Created On       : Fri Sep 03 11:00:00 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 14 18:06:01 2023
    13 // Update Count     : 12
     12// Last Modified On : Wed Oct 18 21:54:54 2023
     13// Update Count     : 15
    1414//
    1515
     
    236236        // get bytes
    237237        try {
     238                        *(temp.Handle.ulink->EndVbyte) = '\0';   // pre-assign empty cstring
    238239            in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
    239240        } catch (cstring_length*) {
     
    247248    }
    248249
    249     s = temp;
     250        if ( temp.Handle.lnth > 0 ) s = temp;
    250251    return in;
    251252}
    252253
    253254void ?|?( ifstream & in, string_res & this ) {
    254     (ifstream &)(in | this); ends( in );
     255    (ifstream &)(in | this);
    255256}
    256257
     
    268269        cstr[wd] = '\0';                                                                        // guard null terminate string
    269270        try {
     271                cstr[0] = '\0';                                                                 // pre-assign as empty cstring
    270272                is | cf;
    271273        } catch( cstring_length * ) {
    272274                cont = true;
    273275        } finally {
    274         if ( ! cf.flags.ignore ) *(f.s) = cstr;                 // ok to initialize string
     276                if ( ! cf.flags.ignore &&                                               // ok to initialize string
     277                                cstr[0] != '\0' ) {                                             // something was read
     278                        *(f.s) = cstr;
     279                }
    275280        } // try
    276281        for ( ; cont; )  {                                                                      // overflow read ?
    277282                cont = false;
    278283                try {
     284                        cstr[0] = '\0';                                                         // pre-assign as empty cstring
    279285                        is | cf;
    280286                } catch( cstring_length * ) {
    281287                        cont = true;                                                            // continue not allowed
    282288                } finally {
    283                         if ( ! cf.flags.ignore ) *(f.s) += cstr;        // build string chunk at a time
     289                        if ( ! cf.flags.ignore &&
     290                                        cstr[0] != '\0' ) {                                     // something was read
     291                                *(f.s) += cstr;                                                 // build string chunk at a time
     292                        }
    284293                } // try
    285294        } // for
     
    288297
    289298void ?|?( ifstream & in, _Istream_Rstr f ) {
    290     (ifstream &)(in | f); ends( in );
     299    (ifstream &)(in | f);
    291300}
    292301
  • libcfa/src/concurrency/channel.hfa

    r0030b508 rfc12f05  
    130130static inline void __cons_handoff( channel(T) & chan, T & elem ) with(chan) {
    131131    memcpy( cons`first.extra, (void *)&elem, sizeof(T) ); // do waiting consumer work
    132     __atomic_thread_fence( __ATOMIC_SEQ_CST );
    133132    wake_one( cons );
    134133}
     
    137136static inline void __prods_handoff( channel(T) & chan, T & retval ) with(chan) {
    138137    memcpy( (void *)&retval, prods`first.extra, sizeof(T) );
    139     __atomic_thread_fence( __ATOMIC_SEQ_CST );
    140138    wake_one( prods );
    141139}
  • libcfa/src/concurrency/cofor.cfa

    r0030b508 rfc12f05  
    44// cofor ( uC++ COFOR )
    55
    6 thread cofor_runner {
     6thread cofor_task {
    77        ssize_t low, high;
    88        __cofor_body_t loop_body;
    99};
    1010
    11 static void ?{}( cofor_runner & this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) {
     11static void ?{}( cofor_task & this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) {
    1212        this.low = low;
    1313        this.high = high;
     
    1515}
    1616
    17 void main( cofor_runner & this ) with( this ) {
     17void main( cofor_task & this ) with( this ) {
    1818        for ( ssize_t i = low; i < high; i++ )
    1919                loop_body(i);
     
    2929        ssize_t i = 0;
    3030        ssize_t stride_iter = low;
    31         cofor_runner * runners[ threads ];
     31        cofor_task * runners[ threads ];
    3232        for ( i; threads ) {
    3333                runners[i] = alloc();
  • libcfa/src/concurrency/cofor.hfa

    r0030b508 rfc12f05  
    11#include <thread.hfa>
     2#include <locks.hfa>
     3#include <list.hfa>
    24
    35//////////////////////////////////////////////////////////////////////////////////////////
     
    1416                __Cofor__( low, high, __CFA_loopLambda__ ); \
    1517        }
     18
     19struct runner_node {
     20    void * value;
     21    inline dlink(runner_node);
     22};
     23P9_EMBEDDED( runner_node, dlink(runner_node) )
     24
     25thread cofor_runner {
     26        go_mutex mutex_lock;              // MX lock
     27    dlist( runner_node ) items;
     28    void (*func)(void *);
     29    volatile bool done;
     30};
     31
     32void ?{}( cofor_runner & this ) { this.done = false; }
     33
     34void main( cofor_runner & this ) with(this) {
     35    while ( !done || !items`isEmpty ) {
     36                lock( mutex_lock );
     37        runner_node * node = &try_pop_front( items );
     38                unlock( mutex_lock );
     39        func( node->value );
     40        free( node->value );
     41        free( node );
     42    }
     43}
     44
     45void start_runners( cofor_runner * thds, unsigned nprocs, void (*func)(void *) ) {
     46        for ( i; nprocs ) {
     47                thds[i].func = func;
     48        }
     49}
     50
     51void end_runners( cofor_runner * thds, unsigned nprocs ) {
     52        for ( i; nprocs ) {
     53                thds[i].done = true;
     54        }
     55}
     56
     57void send_work( cofor_runner * thds, unsigned nprocs, unsigned & curr_proc, void * value ) {
     58        runner_node * node = malloc();
     59        (*node){};
     60        node->value = value;
     61        lock( thds[curr_proc].mutex_lock );
     62        insert_last( thds[curr_proc].items, *node );
     63        unlock( thds[curr_proc].mutex_lock );
     64        curr_proc = ( curr_proc + 1 ) % nprocs;
     65}
    1666
    1767//////////////////////////////////////////////////////////////////////////////////////////
     
    4292    delete( this.runner );
    4393}
    44 
  • libcfa/src/concurrency/kernel.hfa

    r0030b508 rfc12f05  
    303303// gets the number of constructed processors on the cluster
    304304static inline unsigned get_proc_count( cluster & this ) { return this.procs.constructed; }
     305static inline unsigned get_proc_count() { return publicTLS_get( this_processor )->cltr->procs.constructed; }
    305306
    306307// set the number of internal processors
  • libcfa/src/concurrency/locks.hfa

    r0030b508 rfc12f05  
    182182static inline void lock( mcs_spin_lock & l, mcs_spin_node & n ) {
    183183    n.locked = true;
     184
     185        #if defined(__ARM_ARCH)
     186        __asm__ __volatile__ ( "DMB ISH" ::: );
     187        #endif
     188
    184189        mcs_spin_node * prev = __atomic_exchange_n(&l.queue.tail, &n, __ATOMIC_SEQ_CST);
    185190        if( prev == 0p ) return;
    186191        prev->next = &n;
     192       
     193        #if defined(__ARM_ARCH)
     194        __asm__ __volatile__ ( "DMB ISH" ::: );
     195        #endif
     196
    187197        while( __atomic_load_n(&n.locked, __ATOMIC_RELAXED) ) Pause();
     198
     199        #if defined(__ARM_ARCH)
     200        __asm__ __volatile__ ( "DMB ISH" ::: );
     201        #endif
    188202}
    189203
    190204static inline void unlock(mcs_spin_lock & l, mcs_spin_node & n) {
     205        #if defined(__ARM_ARCH)
     206        __asm__ __volatile__ ( "DMB ISH" ::: );
     207        #endif
     208
    191209        mcs_spin_node * n_ptr = &n;
    192210        if (__atomic_compare_exchange_n(&l.queue.tail, &n_ptr, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return;
    193211        while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) Pause();
     212
     213        #if defined(__ARM_ARCH)
     214        __asm__ __volatile__ ( "DMB ISH" ::: );
     215        #endif
     216
    194217        n.next->locked = false;
    195218}
  • libcfa/src/fstream.cfa

    r0030b508 rfc12f05  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 18 10:41:17 2023
    13 // Update Count     : 541
     12// Last Modified On : Wed Oct 18 22:05:54 2023
     13// Update Count     : 549
    1414//
    1515
     
    230230void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
    231231
    232 void ends( ifstream & is ) {}
    233 
    234232bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; }
    235233
     
    311309        } // if
    312310        va_end( args );
     311//      if ( len == 0 ) throw ExceptionInst( missing_data );
    313312        return len;
    314313} // fmt
  • libcfa/src/fstream.hfa

    r0030b508 rfc12f05  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 18 10:41:15 2023
    13 // Update Count     : 258
     12// Last Modified On : Wed Oct 18 20:30:12 2023
     13// Update Count     : 261
    1414//
    1515
     
    117117void nlOn( ifstream & );
    118118void nlOff( ifstream & );
    119 void ends( ifstream & );
    120119int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     120ifstream & ungetc( ifstream & is, char c );
     121bool eof( ifstream & is );
    121122
    122123bool fail( ifstream & is );
    123124void clear( ifstream & );
    124 bool eof( ifstream & is );
    125125void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"
    126126void open( ifstream & is, const char name[] );
    127127void close( ifstream & is );
    128 
    129128ifstream & read( ifstream & is, char data[], size_t size );
    130 ifstream & ungetc( ifstream & is, char c );
    131129
    132130void ?{}( ifstream & is );
  • libcfa/src/iostream.cfa

    r0030b508 rfc12f05  
    1 
    21//
    32// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
     
    1110// Created On       : Wed May 27 17:56:53 2015
    1211// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Sun Oct  8 12:10:21 2023
    14 // Update Count     : 1564
     12// Last Modified On : Sat Nov 11 07:06:27 2023
     13// Update Count     : 1803
    1514//
    1615
     
    785784                return is;
    786785        } // ?|?
    787         ISTYPE_VOID_IMPL( bool & )
    788786
    789787        istype & ?|?( istype & is, char & c ) {
     
    797795                return is;
    798796        } // ?|?
    799         ISTYPE_VOID_IMPL( char & )
    800797
    801798        istype & ?|?( istype & is, signed char & sc ) {
     
    803800                return is;
    804801        } // ?|?
    805         ISTYPE_VOID_IMPL( signed char & )
    806802
    807803        istype & ?|?( istype & is, unsigned char & usc ) {
     
    809805                return is;
    810806        } // ?|?
    811         ISTYPE_VOID_IMPL( unsigned char & )
    812807
    813808        istype & ?|?( istype & is, short int & si ) {
     
    815810                return is;
    816811        } // ?|?
    817         ISTYPE_VOID_IMPL( short int & )
    818812
    819813        istype & ?|?( istype & is, unsigned short int & usi ) {
     
    821815                return is;
    822816        } // ?|?
    823         ISTYPE_VOID_IMPL( unsigned short int & )
    824817
    825818        istype & ?|?( istype & is, int & i ) {
     
    827820                return is;
    828821        } // ?|?
    829         ISTYPE_VOID_IMPL( int & )
    830822
    831823        istype & ?|?( istype & is, unsigned int & ui ) {
     
    833825                return is;
    834826        } // ?|?
    835         ISTYPE_VOID_IMPL( unsigned int & )
    836827
    837828        istype & ?|?( istype & is, long int & li ) {
     
    839830                return is;
    840831        } // ?|?
    841         ISTYPE_VOID_IMPL( long int & )
    842832
    843833        istype & ?|?( istype & is, unsigned long int & ulli ) {
     
    845835                return is;
    846836        } // ?|?
    847         ISTYPE_VOID_IMPL( unsigned long int & )
    848837
    849838        istype & ?|?( istype & is, long long int & lli ) {
     
    851840                return is;
    852841        } // ?|?
    853         ISTYPE_VOID_IMPL( long long int & )
    854842
    855843        istype & ?|?( istype & is, unsigned long long int & ulli ) {
     
    857845                return is;
    858846        } // ?|?
    859         ISTYPE_VOID_IMPL( unsigned long long int & )
    860847
    861848        #if defined( __SIZEOF_INT128__ )
     
    863850                return (istype &)(is | (unsigned int128 &)llli);
    864851        } // ?|?
    865         ISTYPE_VOID_IMPL( int128 & )
    866852
    867853        istype & ?|?( istype & is, unsigned int128 & ullli ) {
     
    880866                return is;
    881867        } // ?|?
    882         ISTYPE_VOID_IMPL( unsigned int128 & )
    883868        #endif // __SIZEOF_INT128__
    884869
     
    887872                return is;
    888873        } // ?|?
    889         ISTYPE_VOID_IMPL( float & )
    890874
    891875        istype & ?|?( istype & is, double & d ) {
     
    893877                return is;
    894878        } // ?|?
    895         ISTYPE_VOID_IMPL( double & )
    896879
    897880        istype & ?|?( istype & is, long double & ld ) {
     
    899882                return is;
    900883        } // ?|?
    901         ISTYPE_VOID_IMPL( long double & )
    902884
    903885        istype & ?|?( istype & is, float _Complex & fc ) {
     
    907889                return is;
    908890        } // ?|?
    909         ISTYPE_VOID_IMPL( float _Complex & )
    910891
    911892        istype & ?|?( istype & is, double _Complex & dc ) {
     
    915896                return is;
    916897        } // ?|?
    917         ISTYPE_VOID_IMPL( double _Complex & )
    918898
    919899        istype & ?|?( istype & is, long double _Complex & ldc ) {
     
    923903                return is;
    924904        } // ?|?
    925         ISTYPE_VOID_IMPL( long double _Complex & )
    926905
    927906        istype & ?|?( istype & is, const char fmt[] ) {
     
    929908                return is;
    930909        } // ?|?
    931         ISTYPE_VOID_IMPL( const char * )
    932910
    933911        // manipulators
     
    937915
    938916        void ?|?( istype & is, istype & (* manip)( istype & ) ) {
    939                 manip( is ); ends( is );
     917                manip( is );
    940918        } // ?|?
    941919
     
    966944                        char fmtstr[ sizeof("%*[]") + nscanset ];
    967945                        int pos = 0;
    968                         fmtstr[pos] = '%';                  pos += 1;
    969                         fmtstr[pos] = '*';                  pos += 1;
    970                         fmtstr[pos] = '[';                  pos += 1;
     946                        strcpy( &fmtstr[pos], "%*[" );  pos += 3;
    971947                        strcpy( &fmtstr[pos], f.scanset );  pos += nscanset;
    972                         fmtstr[pos] = ']';                  pos += 1;
    973                         fmtstr[pos] = '\0';
    974                         fmt( is, fmtstr, (void*)0 );  // last arg is dummy: suppress gcc warning
    975                 }
    976                 else for ( f.wd ) fmt( is, "%*c" );
     948                        strcpy( &fmtstr[pos], "]" );
     949                        fmt( is, fmtstr, "" );                                          // skip scanset
     950                } else {
     951                        char ch;
     952//                      fprintf( stderr, "skip " );
     953                        for ( f.wd ) {                                                          // skip N characters
     954                          if ( eof( is ) ) break;
     955                                fmt( is, "%c", &ch );
     956//                              fprintf( stderr, "`%c' ", ch );
     957                        } // for
     958                } // if
    977959                return is;
    978960        }
    979         ISTYPE_VOID_IMPL( _Istream_Cskip )
    980961
    981962        istype & ?|?( istype & is, _Istream_Cstr f ) {
    982                 const char * scanset = f.scanset;
     963                const char * scanset;
     964                size_t nscanset = 0;
    983965                if ( f.flags.delimiter ) scanset = f.delimiter; // getline ?
    984 
    985                 size_t len = 0;
    986                 if ( scanset ) len = strlen( scanset );
    987                 char fmtstr[len + 16];
    988                 int start = 1;
     966                else scanset = f.scanset;
     967                if ( scanset ) nscanset = strlen( scanset );
     968
     969                char fmtstr[nscanset + 32];                                             // storage for scanset and format codes
    989970                fmtstr[0] = '%';
    990                 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; }
    991                 // no maximum width necessary because text ignored => width is read width
    992                 if ( f.wd != -1 ) {
     971
     972                int pos = 1;
     973                int args;
     974                bool check = true;
     975
     976                if ( f.flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; }
     977                int rwd = f.wd;
     978                if ( f.wd != -1 ) {                                                             // => just ignore versus ignore with width
    993979                        // wd is buffer bytes available (for input chars + null terminator)
    994980                        // rwd is count of input chars
    995                         int rwd;
    996                         if (f.flags.rwd) {
    997                                 verify (f.wd >= 0);
    998                                 rwd = f.wd;
     981                        // no maximum width necessary because text ignored => width is read width
     982                        if ( f.flags.rwd ) check = false;
     983                        else rwd = f.wd - 1;
     984                        pos += sprintf( &fmtstr[pos], "%d", rwd );
     985                } // if
     986
     987                if ( ! scanset ) {                                                              // %s, %*s, %ws, %*ws
     988//                      fprintf( stderr, "cstr %s\n", f.s );
     989                        strcpy( &fmtstr[pos], "s%n" );
     990                        int len = 0;                                                            // may not be set in fmt
     991                        if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
     992                        else args = fmt( is, fmtstr, f.s, &len );
     993//                      fprintf( stderr, "cstr %s %d %d %d %s\n", fmtstr, args, len, f.wd, f.s );
     994                        if ( check && len >= rwd && ! eof( is ) ) {     // might not fit
     995                                char peek;
     996                                fmt( is, "%c", &peek );                                 // check for whitespace terminator
     997//                              fprintf( stderr, "peek %d '%c'\n", args, peek );
     998                                if ( ! eof( is ) ) {
     999                                        ungetc( is, peek );
     1000                                        if ( ! isspace( peek ) ) throw ExceptionInst( cstring_length );
     1001                                } // if
     1002                        } // if
     1003                        // FIX ME: CFA strings need to be modified to NOT change the argument for this case, then this can be removed.
     1004                        if ( rwd > 0 && args == 0 ) f.s[0]= '\0';       // read failed => no pattern match => set string to null
     1005                } else {
     1006                        if ( f.flags.delimiter ) {                                      // getline
     1007//                              fprintf( stderr, "getline\n" );
     1008                                sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset );
     1009//                              fprintf( stderr, "getline %s %d\n", fmtstr, f.wd );
     1010                                int len = 0;                                                    // may not be set in fmt
     1011                                if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
     1012                                else args = fmt( is, fmtstr, f.s, &len );
     1013//                              fprintf( stderr, "getline %s %d %d %d\n", fmtstr, args, f.wd, eof( is ) );
     1014                                if ( check && len == rwd && ! eof( is ) ) {     // might not fit
     1015                                        char peek;
     1016                                        fmt( is, "%c", &peek );                         // check for delimiter
     1017//                                      fprintf( stderr, "peek %d '%c'\n", args, peek );
     1018                                        if ( ! eof( is ) ) {
     1019                                                if ( peek != f.delimiter[0] ) {
     1020                                                        ungetc( is, peek );
     1021                                                        throw ExceptionInst( cstring_length );
     1022                                                } // if
     1023                                        } // if
     1024                                } else fmt( is, "%*c" );                                //  remove delimiter
    9991025                        } else {
    1000                                 verify (f.wd >= 1);
    1001                                 rwd = f.wd - 1;
     1026                                // incl %[xxx],  %*[xxx],  %w[xxx],  %*w[xxx]
     1027                                // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
     1028                                sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset );
     1029//                              fprintf( stderr, "incl/excl %s %d\n", fmtstr, f.wd );
     1030                                int len = 0;                                                    // may not be set in fmt
     1031                                if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
     1032                                else args = fmt( is, fmtstr, f.s, &len );
     1033//                              fprintf( stderr, "incl/excl %s \"%s\" %d %d %d %d %d %c\n", fmtstr, f.s, args, f.wd, len, eof( is ), check, f.s[f.wd] );
     1034                                if ( check && len == rwd && ! eof( is ) ) {     // might not fit
     1035//                                      fprintf( stderr, "overflow\n" );
     1036                                        char peek;
     1037                                        fmt( is, "%c", &peek );                         // check for whitespace terminator
     1038//                                      fprintf( stderr, "peek %d '%c'\n", args, peek );
     1039                                        if ( ! eof( is ) ) {
     1040                                                ungetc( is, peek );
     1041                                                if ( f.flags.inex ^ strchr( f.scanset, peek ) != 0p ) throw ExceptionInst( cstring_length );
     1042                                        } // if
     1043                                } // if
    10021044                        } // if
    1003                         start += sprintf( &fmtstr[start], "%d", rwd );
    1004                 }
    1005 
    1006                 if ( ! scanset ) {
    1007                         // %s, %*s, %ws, %*ws
    1008                         fmtstr[start] = 's'; fmtstr[start + 1] = '\0';
    1009                         // printf( "cstr %s\n", fmtstr );
    1010                 } else {
    1011                         // incl %[xxx],  %*[xxx],  %w[xxx],  %*w[xxx]
    1012                         // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
    1013                         fmtstr[start] = '['; start += 1;
    1014                         if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; }
    1015                         strcpy( &fmtstr[start], scanset );                      // copy includes '\0'
    1016                         len += start;
    1017                         fmtstr[len] = ']'; fmtstr[len + 1] = '\0';
    1018                         // printf( "incl/excl %s\n", fmtstr );
    1019                 } // if
    1020 
    1021                 int check = f.wd - 2;
    1022                 if (! f.flags.ignore ) {
    1023                         f.s[0] = '\0';
    1024                         if ( ! f.flags.rwd ) f.s[check] = '\0';         // insert sentinel
    1025                 }
    1026                 len = fmt( is, fmtstr, f.s );
    1027                 //fprintf( stderr, "KK %s %zd %d %c %s\n", fmtstr, len, check, f.s[check], f.s );
    1028 
    1029                 if ( ! f.flags.ignore && ! f.flags.rwd && f.s[check] != '\0' ) { // sentinel overwritten ?
    1030                         // buffer filled, but would we have kept going?
    1031                         if ( ! eof( is ) ) {
    1032                                 char peek;
    1033                                 fmt( is, "%c", &peek );
    1034                                 ungetc( is, peek );
    1035                                 bool hasMore;
    1036                                 if (f.flags.delimiter) { // getline
    1037                                         hasMore = (peek != f.delimiter[0]);
    1038                                 } else if (f.scanset) { // incl/excl
    1039                                         bool peekMatch = strchr(f.scanset, peek) != 0p;
    1040                                         hasMore = f.flags.inex ? (!peekMatch) : (peekMatch);
    1041                                 } else { // %s
    1042                                         hasMore = !isspace(peek);
    1043                                 }
    1044                                 if (hasMore) throw (cstring_length){ &cstring_length_vt };
    1045                         } // if
    1046                 } // if
    1047 
    1048                 if ( f.flags.delimiter ) {                                              // getline ?
    1049                         if ( len == 0 ) f.s[0] = '\0';                          // empty read => argument unchanged => set empty
    1050                         if ( ! eof( is ) ) {                                            // ignore delimiter, may not be present because of width
    1051                                 char delimiter;
    1052                                 fmt( is, "%c", &delimiter );
    1053                                 if ( delimiter != f.delimiter[0] ) ungetc( is, delimiter );
    1054                         } // if
    1055                 } //if
    1056                 return is;
    1057         } // ?|?
    1058         ISTYPE_VOID_IMPL( _Istream_Cstr )
     1045                        if ( rwd > 0 && args == 0 ) f.s[0]= '\0';       // read failed => no pattern match => set string to null
     1046                } // if
     1047                if ( args == 1 && eof( is ) ) {                                 // data but scan ended at EOF
     1048//                      fprintf( stderr, "clear\n" );
     1049                        clear( is );                                                            // => reset EOF => detect again on next read
     1050                } // if
     1051                return is;
     1052        } // ?|?
    10591053
    10601054        istype & ?|?( istype & is, _Istream_Char f ) {
     
    10621056                return is;
    10631057        } // ?|?
    1064         ISTYPE_VOID_IMPL( _Istream_Char )
    10651058} // distribution
    10661059
     
    10791072                return is; \
    10801073        } /* ?|? */ \
    1081         ISTYPE_VOID_IMPL( _Istream_Manip(T) ) \
    10821074} // distribution
    10831075
     
    11071099                return is;
    11081100        } // ?|?
    1109         ISTYPE_VOID_IMPL( _Istream_Manip(float _Complex) )
    11101101
    11111102        istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
     
    11181109                return is;
    11191110        } // ?|?
    1120         ISTYPE_VOID_IMPL( _Istream_Manip(double _Complex) )
    11211111
    11221112        istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
     
    11291119                return is;
    11301120        } // ?|?
    1131         ISTYPE_VOID_IMPL( _Istream_Manip(long double _Complex) )
    11321121} // distribution
    11331122
  • libcfa/src/iostream.hfa

    r0030b508 rfc12f05  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct  8 12:02:55 2023
    13 // Update Count     : 568
     12// Last Modified On : Wed Oct 18 21:21:20 2023
     13// Update Count     : 583
    1414//
    1515
     
    306306// *********************************** istream ***********************************
    307307
    308 #define ISTYPE_VOID( T ) void ?|?( istype &, T )
    309 #define ISTYPE_VOID_IMPL( T ) \
    310         void ?|?( istype & is, T t ) { \
    311                 (istype &)(is | t); ends( is ); \
    312         } // ?|?
    313 
    314308forall( istype & )
    315309trait basic_istream {
     
    320314        void nlOn( istype & );                                                          // read newline
    321315        void nlOff( istype & );                                                         // scan newline
    322         void ends( istype & os );                                                       // end of output statement
    323316        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    324317        istype & ungetc( istype &, char );
    325318        bool eof( istype & );
     319        void clear( istype & );
    326320}; // basic_istream
    327321
     
    329323trait istream {
    330324        bool fail( istype & );
    331         void clear( istype & );
     325        void open( istype & is, const char name[], const char mode[] );
    332326        void open( istype & is, const char name[] );
    333327        void close( istype & is );
     
    342336forall( istype & | basic_istream( istype ) ) {
    343337        istype & ?|?( istype &, bool & );
    344         ISTYPE_VOID( bool & );
    345338
    346339        istype & ?|?( istype &, char & );
    347         ISTYPE_VOID( char & );
    348340        istype & ?|?( istype &, signed char & );
    349         ISTYPE_VOID( signed char & );
    350341        istype & ?|?( istype &, unsigned char & );
    351         ISTYPE_VOID( unsigned char & );
    352342
    353343        istype & ?|?( istype &, short int & );
    354         ISTYPE_VOID( short int & );
    355344        istype & ?|?( istype &, unsigned short int & );
    356         ISTYPE_VOID( unsigned short int & );
    357345        istype & ?|?( istype &, int & );
    358         ISTYPE_VOID( int & );
    359346        istype & ?|?( istype &, unsigned int & );
    360         ISTYPE_VOID( unsigned int & );
    361347        istype & ?|?( istype &, long int & );
    362         ISTYPE_VOID( long int & );
    363348        istype & ?|?( istype &, unsigned long int & );
    364         ISTYPE_VOID( unsigned long int & );
    365349        istype & ?|?( istype &, long long int & );
    366         ISTYPE_VOID( long long int & );
    367350        istype & ?|?( istype &, unsigned long long int & );
    368         ISTYPE_VOID( unsigned long long int & );
    369351        #if defined( __SIZEOF_INT128__ )
    370352        istype & ?|?( istype &, int128 & );
    371         ISTYPE_VOID( int128 & );
    372353        istype & ?|?( istype &, unsigned int128 & );
    373         ISTYPE_VOID( unsigned int128 & );
    374354        #endif // __SIZEOF_INT128__
    375355
    376356        istype & ?|?( istype &, float & );
    377         ISTYPE_VOID( float & );
    378357        istype & ?|?( istype &, double & );
    379         ISTYPE_VOID( double & );
    380358        istype & ?|?( istype &, long double & );
    381         ISTYPE_VOID( long double & );
    382359
    383360        istype & ?|?( istype &, float _Complex & );
    384         ISTYPE_VOID( float _Complex & );
    385361        istype & ?|?( istype &, double _Complex & );
    386         ISTYPE_VOID( double _Complex & );
    387362        istype & ?|?( istype &, long double _Complex & );
    388         ISTYPE_VOID( long double _Complex & );
    389363
    390364        istype & ?|?( istype &, const char [] );
    391         ISTYPE_VOID( const char [] );
    392365
    393366        // manipulators
    394367        istype & ?|?( istype &, istype & (*)( istype & ) );
    395         ISTYPE_VOID( istype & (*)( istype & ) );
    396368        istype & nl( istype & is );
    397369        istype & nlOn( istype & );
     
    402374
    403375ExceptionDecl( cstring_length );
     376ExceptionDecl( missing_data );
    404377
    405378// *********************************** manipulators ***********************************
    406379
     380// skip does not compose with other C string manipulators.
    407381struct _Istream_Cskip {
    408382        const char * scanset;
     
    416390forall( istype & | basic_istream( istype ) ) {
    417391        istype & ?|?( istype & is, _Istream_Cskip f );
    418         ISTYPE_VOID( _Istream_Cskip );
    419392}
    420393
     
    458431forall( istype & | basic_istream( istype ) ) {
    459432        istype & ?|?( istype & is, _Istream_Cstr f );
    460         ISTYPE_VOID( _Istream_Cstr );
    461433}
    462434
     
    471443forall( istype & | basic_istream( istype ) ) {
    472444        istype & ?|?( istype & is, _Istream_Char f );
    473         ISTYPE_VOID( _Istream_Char );
    474445}
    475446
     
    490461forall( istype & | basic_istream( istype ) ) { \
    491462        istype & ?|?( istype & is, _Istream_Manip(T) f ); \
    492         ISTYPE_VOID( _Istream_Manip(T) ); \
    493463} // ?|?
    494464
  • src/AST/Decl.hpp

    r0030b508 rfc12f05  
    125125
    126126/// Object declaration `int foo()`
    127 class FunctionDecl : public DeclWithType {
     127class FunctionDecl final : public DeclWithType {
    128128public:
    129129        std::vector<ptr<TypeDecl>> type_params;
     
    314314class EnumDecl final : public AggregateDecl {
    315315public:
    316         bool isTyped; // isTyped indicated if the enum has a declaration like:
     316        // isTyped indicated if the enum has a declaration like:
    317317        // enum (type_optional) Name {...}
    318         ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
     318        bool isTyped;
     319        // if isTyped == true && base.get() == nullptr, it is a "void" type enum
     320        ptr<Type> base;
    319321        enum class EnumHiding { Visible, Hide } hide;
    320322
     
    374376
    375377/// Assembly declaration: `asm ... ( "..." : ... )`
    376 class AsmDecl : public Decl {
     378class AsmDecl final : public Decl {
    377379public:
    378380        ptr<AsmStmt> stmt;
    379381
    380382        AsmDecl( const CodeLocation & loc, AsmStmt * stmt )
    381         : Decl( loc, "", {}, {} ), stmt(stmt) {}
     383        : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {}
    382384
    383385        const AsmDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    388390
    389391/// C-preprocessor directive `#...`
    390 class DirectiveDecl : public Decl {
     392class DirectiveDecl final : public Decl {
    391393public:
    392394        ptr<DirectiveStmt> stmt;
    393395
    394396        DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt )
    395         : Decl( loc, "", {}, {} ), stmt(stmt) {}
     397        : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {}
    396398
    397399        const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    402404
    403405/// Static Assertion `_Static_assert( ... , ... );`
    404 class StaticAssertDecl : public Decl {
     406class StaticAssertDecl final : public Decl {
    405407public:
    406408        ptr<Expr> cond;
     
    408410
    409411        StaticAssertDecl( const CodeLocation & loc, const Expr * condition, const ConstantExpr * msg )
    410         : Decl( loc, "", {}, {} ), cond( condition ), msg( msg ) {}
     412        : Decl( loc, "", {}, Linkage::C ), cond( condition ), msg( msg ) {}
    411413
    412414        const StaticAssertDecl * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

    r0030b508 rfc12f05  
    6868class MutexStmt;
    6969class CorunStmt;
     70class CoforStmt;
    7071
    7172class Expr;
  • src/AST/Node.cpp

    r0030b508 rfc12f05  
    194194template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::weak >;
    195195template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::strong >;
     196template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::weak >;
     197template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::strong >;
    196198template class ast::ptr_base< ast::Expr, ast::Node::ref_type::weak >;
    197199template class ast::ptr_base< ast::Expr, ast::Node::ref_type::strong >;
  • src/AST/Pass.cpp

    r0030b508 rfc12f05  
    1919
    2020PassVisitorStats pass_visitor_stats;
     21// TODO: There was a counter for every syntax node created.
     22//   This has not been translated to the new ast.
    2123// Stats::Counters::SimpleCounter * BaseSyntaxNode::new_nodes = nullptr;
    2224
  • src/AST/Pass.hpp

    r0030b508 rfc12f05  
    172172        const ast::Stmt *             visit( const ast::MutexStmt            * ) override final;
    173173        const ast::Stmt *             visit( const ast::CorunStmt            * ) override final;
     174        const ast::Stmt *             visit( const ast::CoforStmt            * ) override final;
    174175        const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
    175176        const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
  • src/AST/Pass.impl.hpp

    r0030b508 rfc12f05  
    11341134
    11351135//--------------------------------------------------------------------------
     1136// CoforStmt
     1137template< typename core_t >
     1138const ast::Stmt * ast::Pass< core_t >::visit( const ast::CoforStmt * node ) {
     1139        VISIT_START( node );
     1140
     1141        if ( __visit_children() ) {
     1142                // for statements introduce a level of scope (for the initialization)
     1143                guard_symtab guard { *this };
     1144                maybe_accept( node, &CoforStmt::inits );
     1145                maybe_accept_top( node, &CoforStmt::cond  );
     1146                maybe_accept_top( node, &CoforStmt::inc   );
     1147                maybe_accept_as_compound( node, &CoforStmt::body  );
     1148        }
     1149
     1150        VISIT_END( Stmt, node );
     1151}
     1152
     1153//--------------------------------------------------------------------------
    11361154// ApplicationExpr
    11371155template< typename core_t >
  • src/AST/Print.cpp

    r0030b508 rfc12f05  
    934934        }
    935935
     936        virtual const ast::Stmt * visit( const ast::CoforStmt * node ) override final {
     937                os << "Cofor Statement" << endl;
     938
     939                if ( ! node->inits.empty() ) {
     940                        os << indent << "... initialization:" << endl;
     941                        ++indent;
     942                        for ( const ast::Stmt * stmt : node->inits ) {
     943                                os << indent+1;
     944                                safe_print( stmt );
     945                        }
     946                        --indent;
     947                }
     948
     949                if ( node->cond ) {
     950                        os << indent << "... condition:" << endl;
     951                        ++indent;
     952                        os << indent;
     953                        node->cond->accept( *this );
     954                        --indent;
     955                }
     956
     957                if ( node->inc ) {
     958                        os << indent << "... increment:" << endl;
     959                        ++indent;
     960                        os << indent;
     961                        node->inc->accept( *this );
     962                        --indent;
     963                }
     964
     965                if ( node->body ) {
     966                        os << indent << "... with body:" << endl;
     967                        ++indent;
     968                        os << indent;
     969                        node->body->accept( *this );
     970                        --indent;
     971                }
     972                os << endl;
     973                print( node->labels );
     974
     975                return node;
     976        }
     977
    936978        virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) override final {
    937979                ++indent;
  • src/AST/Stmt.hpp

    r0030b508 rfc12f05  
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    2929#define MUTATE_FRIEND                                                                                                   \
    30     template<typename node_t> friend node_t * mutate(const node_t * node); \
     30        template<typename node_t> friend node_t * mutate(const node_t * node); \
    3131        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3232
     
    340340
    341341        CatchClause( const CodeLocation & loc, ExceptionKind kind, const Decl * decl, const Expr * cond,
    342                            const Stmt * body )
     342                        const Stmt * body )
    343343                : StmtClause(loc), decl(decl), cond(cond), body(body), kind(kind) {}
    344344
     
    380380// Base class of WaitFor/WaitUntil statements
    381381// form: KEYWORD(...) ... timeout(...) ... else ...
    382 class WaitStmt : public Stmt { 
    383   public:
    384     ptr<Expr> timeout_time;
     382class WaitStmt : public Stmt {
     383  public:
     384        ptr<Expr> timeout_time;
    385385        ptr<Stmt> timeout_stmt;
    386386        ptr<Expr> timeout_cond;
     
    388388        ptr<Expr> else_cond;
    389389
    390     WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
     390        WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    391391                : Stmt(loc, std::move(labels)) {}
    392392
    393393  private:
    394     WaitStmt * clone() const override = 0;
     394        WaitStmt * clone() const override = 0;
    395395        MUTATE_FRIEND
    396396};
     
    444444class WaitUntilStmt final : public WaitStmt {
    445445  public:
    446     // Non-ast node used during compilation to store data needed to generate predicates
    447     //    and set initial status values for clauses
    448     // Used to create a tree corresponding to the structure of the clauses in a WaitUntil
    449     struct ClauseNode {
    450         enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag
    451         // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing
    452 
    453         ClauseNode * left;
    454         ClauseNode * right;
    455         WhenClause * leaf;  // only set if this node is a leaf (points into vector of clauses)
    456 
    457         bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses
    458         bool whenState;     // used to track if when_cond is toggled on or off for generating init values
    459         bool childOfAnd;      // true on leaf nodes that are children of AND, false otherwise
    460 
    461         ClauseNode( Op op, ClauseNode * left, ClauseNode * right )
    462             : op(op), left(left), right(right), leaf(nullptr),
    463             ambiguousWhen(false), whenState(true), childOfAnd(false) {}
    464         ClauseNode( Op op, WhenClause * leaf )
    465             : op(op), left(nullptr), right(nullptr), leaf(leaf),
    466             ambiguousWhen(false), whenState(true), childOfAnd(false) {}
    467         ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}
    468        
    469         ~ClauseNode() {
    470             if ( left ) delete left;
    471             if ( right ) delete right;
    472         }
    473     };
     446        // Non-ast node used during compilation to store data needed to generate predicates
     447        //    and set initial status values for clauses
     448        // Used to create a tree corresponding to the structure of the clauses in a WaitUntil
     449        struct ClauseNode {
     450                enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag
     451                // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing
     452
     453                ClauseNode * left;
     454                ClauseNode * right;
     455                WhenClause * leaf;  // only set if this node is a leaf (points into vector of clauses)
     456
     457                bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses
     458                bool whenState;     // used to track if when_cond is toggled on or off for generating init values
     459                bool childOfAnd;      // true on leaf nodes that are children of AND, false otherwise
     460
     461                ClauseNode( Op op, ClauseNode * left, ClauseNode * right )
     462                        : op(op), left(left), right(right), leaf(nullptr),
     463                        ambiguousWhen(false), whenState(true), childOfAnd(false) {}
     464                ClauseNode( Op op, WhenClause * leaf )
     465                        : op(op), left(nullptr), right(nullptr), leaf(leaf),
     466                        ambiguousWhen(false), whenState(true), childOfAnd(false) {}
     467                ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}
     468
     469                ~ClauseNode() {
     470                        if ( left ) delete left;
     471                        if ( right ) delete right;
     472                }
     473        };
    474474
    475475        std::vector<ptr<WhenClause>> clauses;
    476     ClauseNode * predicateTree;
     476        ClauseNode * predicateTree;
    477477
    478478        WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    479479                : WaitStmt(loc, std::move(labels)) {}
    480480
    481     ~WaitUntilStmt() { delete predicateTree; }
     481        ~WaitUntilStmt() { delete predicateTree; }
    482482
    483483        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    522522        std::vector<ptr<Expr>> mutexObjs;
    523523
    524         MutexStmt( const CodeLocation & loc, const Stmt * stmt, 
     524        MutexStmt( const CodeLocation & loc, const Stmt * stmt,
    525525                           const std::vector<ptr<Expr>> && mutexes, const std::vector<Label> && labels = {} )
    526526                : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {}
     
    543543  private:
    544544        CorunStmt * clone() const override { return new CorunStmt{ *this }; }
     545        MUTATE_FRIEND
     546};
     547
     548// Corun Statement
     549class CoforStmt final : public Stmt {
     550  public:
     551        std::vector<ptr<Stmt>> inits;
     552        ptr<Expr> cond;
     553        ptr<Expr> inc;
     554        ptr<Stmt> body;
     555
     556        CoforStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond,
     557                         const Expr * inc, const Stmt * body, const std::vector<Label> && label = {} )
     558                : Stmt(loc, std::move(label)), inits(std::move(inits)), cond(cond), inc(inc), body(body) {}
     559
     560        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     561  private:
     562        CoforStmt * clone() const override { return new CoforStmt{ *this }; }
    545563        MUTATE_FRIEND
    546564};
  • src/AST/Type.hpp

    r0030b508 rfc12f05  
    3434
    3535namespace ast {
    36 
    37 template< typename T > class Pass;
    3836
    3937class Type : public Node {
  • src/AST/Visitor.hpp

    r0030b508 rfc12f05  
    6060    virtual const ast::Stmt *             visit( const ast::MutexStmt            * ) = 0;
    6161    virtual const ast::Stmt *             visit( const ast::CorunStmt            * ) = 0;
     62    virtual const ast::Stmt *             visit( const ast::CoforStmt            * ) = 0;
    6263    virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) = 0;
    6364    virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) = 0;
  • src/AST/module.mk

    r0030b508 rfc12f05  
    2020        AST/Bitfield.hpp \
    2121        AST/Chain.hpp \
    22         AST/Convert.cpp \
    23         AST/Convert.hpp \
    2422        AST/Copy.cpp \
    2523        AST/Copy.hpp \
  • src/BasicTypes-gen.cc

    r0030b508 rfc12f05  
    117117        // { LongDoubleImaginary, "LongDoubleImaginary", "LDI", "long double _Imaginary", "Ie", false, LongDoubleComplex, -1, -1, 17 },
    118118
    119         { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 }, 
     119        { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 },
    120120        { uFloat128xComplex, "uFloat128xComplex", "_FLDXC", "_Float128x _Complex", "CDF128x_", Floating, -1, -1, -1, 18 }
    121121}; // graph
     
    127127void generateCosts( int row ) {
    128128        bool seen[NUMBER_OF_BASIC_TYPES] = { false /*, ... */ };
    129        
     129
    130130        struct el_cost {
    131131                int i;
    132132                int path;
    133133                int sign;
    134                
     134
    135135                el_cost( int i = 0, int p = 0, int s = 0 ) : i(i), path(p), sign(s) {}
    136                
     136
    137137                // reverse the sense for use in largest-on-top priority queue
    138138                bool operator< (const el_cost& o) const {
     
    195195                        return;
    196196                } // if
    197                
     197
    198198                i = graph[col].middle;
    199199                if ( i == -1 ) assert("invalid ancestor assumption");
     
    272272        size_t start, end;
    273273
    274 
    275         #define TypeH TOP_SRCDIR "src/SynTree/Type.h"
    276         resetInput( file, TypeH, buffer, code, str );
    277 
    278         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH );
     274        #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp"
     275        resetInput( file, TypeH_AST, buffer, code, str );
     276
     277        if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST );
    279278        start += sizeof( STARTMK );                                                     // includes newline
    280279        code << str.substr( 0, start );
     
    284283        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    285284                code << "\t\t" << graph[r].name << "," << endl;
    286         } // for       
     285        } // for
    287286        code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;
    288287        code << "\t} kind;" << endl;
    289288        code << "\t";                                                                           // indentation for end marker
    290289
    291         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );
     290        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST );
    292291        code << str.substr( start );
    293292
    294         output( file, TypeH, code );
     293        output( file, TypeH_AST, code );
    295294        // cout << code.str();
    296295
    297296
    298         #define TypeC TOP_SRCDIR "src/SynTree/Type.cc"
    299         resetInput( file, TypeC, buffer, code, str );
    300 
    301         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC );
     297        #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp"
     298        resetInput( file, TypeC_AST, buffer, code, str );
     299
     300        if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST );
    302301        start += sizeof( STARTMK );                                                     // includes newline
    303302        code << str.substr( 0, start );
     
    307306        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    308307                code << "\t\"" << graph[r].type << "\"," << endl;
    309         } // for       
    310         code << "};" << endl;
    311 
    312         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC );
    313         code << str.substr( start );
    314 
    315         output( file, TypeC, code );
    316         // cout << code.str();
    317 
    318 
    319         // TEMPORARY DURING CHANGE OVER
    320         #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp"
    321         resetInput( file, TypeH_AST, buffer, code, str );
    322 
    323         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST );
    324         start += sizeof( STARTMK );                                                     // includes newline
    325         code << str.substr( 0, start );
    326 
    327         code << "\t" << BYMK << endl;
    328         code << "\tenum Kind {" << endl;
    329         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    330                 code << "\t\t" << graph[r].name << "," << endl;
    331         } // for       
    332         code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;
    333         code << "\t} kind;" << endl;
    334         code << "\t";                                                                           // indentation for end marker
    335 
    336         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST );
    337         code << str.substr( start );
    338 
    339         output( file, TypeH_AST, code );
    340         // cout << code.str();
    341 
    342 
    343         #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp"
    344         resetInput( file, TypeC_AST, buffer, code, str );
    345 
    346         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST );
    347         start += sizeof( STARTMK );                                                     // includes newline
    348         code << str.substr( 0, start );
    349 
    350         code << BYMK << endl;
    351         code << "const char * BasicType::typeNames[] = {" << endl;
    352         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    353                 code << "\t\"" << graph[r].type << "\"," << endl;
    354         } // for       
     308        } // for
    355309        code << "};" << endl;
    356310
     
    391345        end += sizeof( STARTMK );
    392346        code << str.substr( start, end - start );
    393        
     347
    394348        code << "\t" << BYMK << endl;
    395         code << "\tstatic const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl
     349        code << "\tstatic const int costMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl
    396350                 << "\t\t/*           ";
    397351        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    411365        code << "\tstatic const int maxIntCost = " << *max_element(costMatrix[SignedInt], costMatrix[SignedInt] + NUMBER_OF_BASIC_TYPES) << ";" << endl;
    412366        code << "\t";                                                                           // indentation for end marker
    413        
     367
    414368        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ConversionCost );
    415369        if ( (end = str.find( STARTMK, start + 1 )) == string::npos ) Abort( "start", ConversionCost );
     
    418372
    419373        code << "\t" << BYMK << endl;
    420         code << "\tstatic const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl
     374        code << "\tstatic const int signMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl
    421375                 << "\t\t/*           ";
    422376        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    450404        enum { PER_ROW = 6 };
    451405        code << "\t" << BYMK << endl;
    452         code << "\t#define BT BasicType::" << endl;
    453         code << "\tstatic const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
     406        code << "\t#define BT ast::BasicType::" << endl;
     407        code << "\tstatic const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
    454408             << "\t\t/*\t\t ";
    455409        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    505459                "\t\t\t//   - \"Di\" char32_t\n"
    506460                "\t\t\t//   - \"Ds\" char16_t\n";
    507                
    508         code << "\t\t\tconst std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
     461
     462        code << "\t\t\tconst std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
    509463        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    510464                code << "\t\t\t\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl;
    511         } // for       
     465        } // for
    512466        code << "\t\t\t}; // basicTypes" << endl;
    513467        code << "\t\t\t";                                                                       // indentation for end marker
  • src/CodeGen/FixMain.cc

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.cc --
     7// FixMain.cc -- Tools to change a Cforall main into a C main.
    88//
    99// Author           : Thierry Delisle
     
    1313// Update Count     : 0
    1414//
    15 
    1615
    1716#include "FixMain.h"
     
    2322
    2423#include "AST/Decl.hpp"
     24#include "AST/Pass.hpp"
    2525#include "AST/Type.hpp"
    26 #include "Common/PassVisitor.h"
     26#include "AST/Vector.hpp"
    2727#include "Common/SemanticError.h"  // for SemanticError
    2828#include "CodeGen/GenType.h"       // for GenType
    29 #include "SynTree/Declaration.h"   // for FunctionDecl, operator<<
    30 #include "SynTree/Type.h"          // for FunctionType
    3129#include "SymTab/Mangler.h"
    3230
     
    3533namespace {
    3634
    37 struct FindMainCore {
    38         FunctionDecl * main_signature = nullptr;
     35struct FindMainCore final {
     36        ast::FunctionDecl const * main_declaration = nullptr;
    3937
    40         void previsit( FunctionDecl * decl ) {
    41                 if ( FixMain::isMain( decl ) ) {
    42                         if ( main_signature ) {
     38        void previsit( ast::FunctionDecl const * decl ) {
     39                if ( isMain( decl ) ) {
     40                        if ( main_declaration ) {
    4341                                SemanticError( decl, "Multiple definition of main routine\n" );
    4442                        }
    45                         main_signature = decl;
     43                        main_declaration = decl;
    4644                }
    4745        }
    4846};
    4947
     48std::string genTypeAt( const ast::vector<ast::Type> & types, size_t at ) {
     49        return genType( types[at], "", Options( false, false, false, false ) );
    5050}
    5151
    52         template<typename container>
    53         std::string genTypeAt(const container& p, size_t idx) {
    54                 return genType((*std::next(p.begin(), idx))->get_type(), "");
    55         }
    56 
    57         void FixMain::fix( std::list< Declaration * > & translationUnit,
    58                         std::ostream &os, const char* bootloader_filename ) {
    59                 PassVisitor< FindMainCore > main_finder;
    60                 acceptAll( translationUnit, main_finder );
    61                 FunctionDecl * main_signature = main_finder.pass.main_signature;
    62 
    63                 if( main_signature ) {
    64                         os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
    65                         main_signature->mangleName = SymTab::Mangler::mangle(main_signature);
    66 
    67                         os << main_signature->get_scopedMangleName() << "(";
    68                         const auto& params = main_signature->get_functionType()->get_parameters();
    69                         switch(params.size()) {
    70                                 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;
    71                                 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;
    72                                 case 0: break;
    73                                 default : assert(false);
    74                         }
    75                         os << "); }\n";
    76 
    77                         std::ifstream bootloader(bootloader_filename, std::ios::in);
    78                         assertf( bootloader.is_open(), "cannot open bootloader.c\n" );
    79                         os << bootloader.rdbuf();
    80                 }
    81         }
    82 
    83 namespace {
    84 
    85 ObjectDecl * signedIntObj() {
    86         return new ObjectDecl(
    87                 "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
    88                 new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr );
     52ast::ObjectDecl * makeIntObj(){
     53        return new ast::ObjectDecl( CodeLocation(), "",
     54                new ast::BasicType( ast::BasicType::SignedInt ) );
    8955}
    9056
    91 ObjectDecl * makeArgvObj() {
    92         return new ObjectDecl(
    93                 "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
    94                 new PointerType( Type::Qualifiers(),
    95                         new PointerType( Type::Qualifiers(),
    96                                 new BasicType( Type::Qualifiers(), BasicType::Char ) ) ),
    97                 nullptr );
     57ast::ObjectDecl * makeCharStarStarObj() {
     58        return new ast::ObjectDecl( CodeLocation(), "",
     59                new ast::PointerType(
     60                        new ast::PointerType(
     61                                new ast::BasicType( ast::BasicType::Char ) ) ) );
    9862}
    9963
    100 std::string create_mangled_main_function_name( FunctionType * function_type ) {
    101         std::unique_ptr<FunctionDecl> decl( new FunctionDecl(
    102                 "main", Type::StorageClasses(), LinkageSpec::Cforall,
    103                 function_type, nullptr ) );
    104         return SymTab::Mangler::mangle( decl.get() );
     64std::string getMangledNameOfMain(
     65                ast::vector<ast::DeclWithType> && params, ast::ArgumentFlag isVarArgs ) {
     66        ast::ptr<ast::FunctionDecl> decl = new ast::FunctionDecl(
     67                CodeLocation(),
     68                "main",
     69                ast::vector<ast::TypeDecl>(),
     70                ast::vector<ast::DeclWithType>(),
     71                std::move( params ),
     72                { makeIntObj() },
     73                nullptr,
     74                ast::Storage::Classes(),
     75                ast::Linkage::Spec(),
     76                ast::vector<ast::Attribute>(),
     77                ast::Function::Specs(),
     78                isVarArgs
     79        );
     80        return Mangle::mangle( decl.get() );
    10581}
    10682
    107 std::string mangled_0_argument_main() {
    108         FunctionType* main_type = new FunctionType( Type::Qualifiers(), true );
    109         main_type->get_returnVals().push_back( signedIntObj() );
    110         return create_mangled_main_function_name( main_type );
     83std::string getMangledNameOf0ParameterMain() {
     84        return getMangledNameOfMain( {}, ast::VariableArgs );
    11185}
    11286
    113 std::string mangled_2_argument_main() {
    114         FunctionType* main_type = new FunctionType( Type::Qualifiers(), false );
    115         main_type->get_returnVals().push_back( signedIntObj() );
    116         main_type->get_parameters().push_back( signedIntObj() );
    117         main_type->get_parameters().push_back( makeArgvObj() );
    118         return create_mangled_main_function_name( main_type );
     87std::string getMangledNameOf2ParameterMain() {
     88        return getMangledNameOfMain( {
     89                makeIntObj(),
     90                makeCharStarStarObj(),
     91        }, ast::FixedArgs );
    11992}
    12093
     
    12295        // This breaks if you move it out of the function.
    12396        static const std::string mangled_mains[] = {
    124                 mangled_0_argument_main(),
    125                 mangled_2_argument_main(),
    126                 //mangled_3_argument_main(),
     97                getMangledNameOf0ParameterMain(),
     98                getMangledNameOf2ParameterMain(),
     99                //getMangledNameOf3ParameterMain(),
    127100        };
    128101
     
    133106}
    134107
     108struct FixLinkageCore final {
     109        ast::Linkage::Spec const spec;
     110        FixLinkageCore( ast::Linkage::Spec spec ) : spec( spec ) {}
     111
     112        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ) {
     113                if ( decl->name != "main" ) return decl;
     114                return ast::mutate_field( decl, &ast::FunctionDecl::linkage, spec );
     115        }
     116};
     117
    135118} // namespace
    136119
    137 bool FixMain::isMain( FunctionDecl * decl ) {
    138         if ( std::string("main") != decl->name ) {
    139                 return false;
    140         }
    141         return is_main( SymTab::Mangler::mangle( decl, true, true ) );
    142 }
    143 
    144 bool FixMain::isMain( const ast::FunctionDecl * decl ) {
     120bool isMain( const ast::FunctionDecl * decl ) {
    145121        if ( std::string("main") != decl->name ) {
    146122                return false;
     
    149125}
    150126
    151 };
     127void fixMainLinkage( ast::TranslationUnit & translationUnit,
     128                bool replace_main ) {
     129        ast::Linkage::Spec const spec =
     130                ( replace_main ) ? ast::Linkage::Cforall : ast::Linkage::C;
     131        ast::Pass<FixLinkageCore>::run( translationUnit, spec );
     132}
     133
     134void fixMainInvoke( ast::TranslationUnit & translationUnit,
     135                std::ostream &os, const char * bootloader_filename ) {
     136
     137        ast::Pass<FindMainCore> main_finder;
     138        ast::accept_all( translationUnit, main_finder );
     139        if ( nullptr == main_finder.core.main_declaration ) return;
     140
     141        ast::FunctionDecl * main_declaration =
     142                ast::mutate( main_finder.core.main_declaration );
     143
     144        main_declaration->mangleName = Mangle::mangle( main_declaration );
     145
     146        os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
     147        os << main_declaration->scopedMangleName() << "(";
     148        const auto& params = main_declaration->type->params;
     149        switch ( params.size() ) {
     150                case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;
     151                case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;
     152                case 0: break;
     153                default : assert(false);
     154        }
     155        os << "); }\n";
     156
     157        std::ifstream bootloader( bootloader_filename, std::ios::in );
     158        assertf( bootloader.is_open(), "cannot open bootloader.c\n" );
     159        os << bootloader.rdbuf();
     160}
     161
     162} // namespace CodeGen
  • src/CodeGen/FixMain.h

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.h --
     7// FixMain.h -- Tools to change a Cforall main into a C main.
    88//
    99// Author           : Thierry Delisle
     
    1717
    1818#include <iosfwd>
    19 #include <memory>
    20 #include <list>
    2119
    22 #include "SynTree/LinkageSpec.h"
    23 
    24 class Declaration;
    25 class FunctionDecl;
    2620namespace ast {
    2721        class FunctionDecl;
     22        class TranslationUnit;
    2823}
    2924
    3025namespace CodeGen {
    3126
    32 class FixMain {
    33 public :
    34         static inline LinkageSpec::Spec mainLinkage() {
    35                 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;
    36         }
     27/// Is this function a program main function?
     28bool isMain( const ast::FunctionDecl * decl );
    3729
    38         static inline void setReplaceMain(bool val) {
    39                 replace_main = val;
    40         }
     30/// Adjust the linkage of main functions.
     31void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain );
    4132
    42         static bool isMain(FunctionDecl* decl);
    43         static bool isMain(const ast::FunctionDecl * decl);
    44 
    45         static void fix( std::list< Declaration * > & decls,
    46                         std::ostream &os, const char* bootloader_filename );
    47 
    48 private:
    49         static bool replace_main;
    50 };
     33/// Add a wrapper around to run the Cforall main.
     34void fixMainInvoke( ast::TranslationUnit & transUnit,
     35                std::ostream & os, const char * bootloaderFilename );
    5136
    5237} // namespace CodeGen
  • src/CodeGen/FixNames.cc

    r0030b508 rfc12f05  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
    24 #include "Common/PassVisitor.h"
    2524#include "Common/SemanticError.h"  // for SemanticError
    2625#include "FixMain.h"               // for FixMain
    2726#include "SymTab/Mangler.h"        // for Mangler
    28 #include "SynTree/LinkageSpec.h"   // for Cforall, isMangled
    29 #include "SynTree/Constant.h"      // for Constant
    30 #include "SynTree/Declaration.h"   // for FunctionDecl, ObjectDecl, Declarat...
    31 #include "SynTree/Expression.h"    // for ConstantExpr
    32 #include "SynTree/Label.h"         // for Label, noLabels
    33 #include "SynTree/Statement.h"     // for ReturnStmt, CompoundStmt
    34 #include "SynTree/Type.h"          // for Type, BasicType, Type::Qualifiers
    35 #include "SynTree/Visitor.h"       // for Visitor, acceptAll
    3627#include "CompilationState.h"
    3728
    3829namespace CodeGen {
    39         class FixNames : public WithGuards {
    40           public:
    41                 void postvisit( ObjectDecl *objectDecl );
    42                 void postvisit( FunctionDecl *functionDecl );
    4330
    44                 void previsit( CompoundStmt *compoundStmt );
    45           private:
    46                 int scopeLevel = 1;
    47 
    48                 void fixDWT( DeclarationWithType *dwt );
    49         };
    50 
    51         void fixNames( std::list< Declaration* > & translationUnit ) {
    52                 PassVisitor<FixNames> fixer;
    53                 acceptAll( translationUnit, fixer );
    54         }
    55 
    56         void FixNames::fixDWT( DeclarationWithType * dwt ) {
    57                 if ( dwt->get_name() != "" ) {
    58                         if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) {
    59                                 if (!useNewAST) {
    60                                         dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
    61                                 }
    62                                 dwt->set_scopeLevel( scopeLevel );
    63                         } // if
    64                 } // if
    65         }
    66 
    67         void FixNames::postvisit( ObjectDecl * objectDecl ) {
    68                 fixDWT( objectDecl );
    69         }
    70 
    71         void FixNames::postvisit( FunctionDecl * functionDecl ) {
    72                 fixDWT( functionDecl );
    73 
    74                 if ( FixMain::isMain( functionDecl ) ) {
    75                         int nargs = functionDecl->get_functionType()->get_parameters().size();
    76                         if( !(nargs == 0 || nargs == 2 || nargs == 3) ) {
    77                                 SemanticError(functionDecl, "Main expected to have 0, 2 or 3 arguments\n");
    78                         }
    79                         functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) );
    80                 }
    81         }
    82 
    83         void FixNames::previsit( CompoundStmt * ) {
    84                 scopeLevel++;
    85                 GuardAction( [this](){ scopeLevel--; } );
    86         }
     31namespace {
    8732
    8833/// Does work with the main function and scopeLevels.
    89 class FixNames_new final {
     34class FixNames final {
    9035        int scopeLevel = 1;
    9136
     
    10348
    10449        const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) {
    105                 if ( FixMain::isMain( functionDecl ) ) {
     50                if ( isMain( functionDecl ) ) {
    10651                        auto mutDecl = ast::mutate( functionDecl );
    10752
     
    13883};
    13984
     85} // namespace
     86
    14087void fixNames( ast::TranslationUnit & translationUnit ) {
    141         ast::Pass<FixNames_new>::run( translationUnit );
     88        ast::Pass<FixNames>::run( translationUnit );
    14289}
    14390
  • src/CodeGen/FixNames.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>  // for list
    19 
    20 class Declaration;
    2118namespace ast {
    2219        class TranslationUnit;
     
    2421
    2522namespace CodeGen {
    26         /// mangles object and function names
    27         void fixNames( std::list< Declaration* > & translationUnit );
     23
    2824/// Sets scope levels and fills in main's default return.
    2925void fixNames( ast::TranslationUnit & translationUnit );
     26
    3027} // namespace CodeGen
    3128
  • src/CodeGen/GenType.cc

    r0030b508 rfc12f05  
    1919#include <sstream>                // for operator<<, ostringstream, basic_os...
    2020
    21 #include "CodeGenerator.h"        // for CodeGenerator
    22 #include "SynTree/Declaration.h"  // for DeclarationWithType
    23 #include "SynTree/Expression.h"   // for Expression
    24 #include "SynTree/Type.h"         // for PointerType, Type, FunctionType
    25 #include "SynTree/Visitor.h"      // for Visitor
     21#include "AST/Print.hpp"          // for print
     22#include "AST/Vector.hpp"         // for vector
     23#include "CodeGeneratorNew.hpp"   // for CodeGenerator_new
     24#include "Common/UniqueName.h"    // for UniqueName
    2625
    2726namespace CodeGen {
    28         struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    29                 std::string typeString;
    30                 GenType( const std::string &typeString, const Options &options );
    31 
    32                 void previsit( BaseSyntaxNode * );
    33                 void postvisit( BaseSyntaxNode * );
    34 
    35                 void postvisit( FunctionType * funcType );
    36                 void postvisit( VoidType * voidType );
    37                 void postvisit( BasicType * basicType );
    38                 void postvisit( PointerType * pointerType );
    39                 void postvisit( ArrayType * arrayType );
    40                 void postvisit( ReferenceType * refType );
    41                 void postvisit( StructInstType * structInst );
    42                 void postvisit( UnionInstType * unionInst );
    43                 void postvisit( EnumInstType * enumInst );
    44                 void postvisit( TypeInstType * typeInst );
    45                 void postvisit( TupleType  * tupleType );
    46                 void postvisit( VarArgsType * varArgsType );
    47                 void postvisit( ZeroType * zeroType );
    48                 void postvisit( OneType * oneType );
    49                 void postvisit( GlobalScopeType * globalType );
    50                 void postvisit( TraitInstType * inst );
    51                 void postvisit( TypeofType * typeof );
    52                 void postvisit( VTableType * vtable );
    53                 void postvisit( QualifiedType * qualType );
    54 
    55           private:
    56                 void handleQualifiers( Type *type );
    57                 std::string handleGeneric( ReferenceToType * refType );
    58                 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    59 
    60                 Options options;
    61         };
    62 
    63         std::string genType( Type *type, const std::string &baseString, const Options &options ) {
    64                 PassVisitor<GenType> gt( baseString, options );
     27
     28namespace {
     29
     30#warning Remove the _new when old version is removed.
     31struct GenType_new :
     32                public ast::WithShortCircuiting,
     33                public ast::WithVisitorRef<GenType_new> {
     34        std::string result;
     35        GenType_new( const std::string &typeString, const Options &options );
     36
     37        void previsit( ast::Node const * );
     38        void postvisit( ast::Node const * );
     39
     40        void postvisit( ast::FunctionType const * type );
     41        void postvisit( ast::VoidType const * type );
     42        void postvisit( ast::BasicType const * type );
     43        void postvisit( ast::PointerType const * type );
     44        void postvisit( ast::ArrayType const * type );
     45        void postvisit( ast::ReferenceType const * type );
     46        void postvisit( ast::StructInstType const * type );
     47        void postvisit( ast::UnionInstType const * type );
     48        void postvisit( ast::EnumInstType const * type );
     49        void postvisit( ast::TypeInstType const * type );
     50        void postvisit( ast::TupleType const * type );
     51        void postvisit( ast::VarArgsType const * type );
     52        void postvisit( ast::ZeroType const * type );
     53        void postvisit( ast::OneType const * type );
     54        void postvisit( ast::GlobalScopeType const * type );
     55        void postvisit( ast::TraitInstType const * type );
     56        void postvisit( ast::TypeofType const * type );
     57        void postvisit( ast::VTableType const * type );
     58        void postvisit( ast::QualifiedType const * type );
     59
     60private:
     61        void handleQualifiers( ast::Type const *type );
     62        std::string handleGeneric( ast::BaseInstType const * type );
     63        void genArray( const ast::CV::Qualifiers &qualifiers, ast::Type const *base, ast::Expr const *dimension, bool isVarLen, bool isStatic );
     64        std::string genParamList( const ast::vector<ast::Type> & );
     65
     66        Options options;
     67};
     68
     69GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}
     70
     71void GenType_new::previsit( ast::Node const * ) {
     72        // Turn off automatic recursion for all nodes, to allow each visitor to
     73        // precisely control the order in which its children are visited.
     74        visit_children = false;
     75}
     76
     77void GenType_new::postvisit( ast::Node const * node ) {
     78        std::stringstream ss;
     79        ast::print( ss, node );
     80        assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
     81}
     82
     83void GenType_new::postvisit( ast::VoidType const * type ) {
     84        result = "void " + result;
     85        handleQualifiers( type );
     86}
     87
     88void GenType_new::postvisit( ast::BasicType const * type ) {
     89        ast::BasicType::Kind kind = type->kind;
     90        assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES );
     91        result = std::string( ast::BasicType::typeNames[kind] ) + " " + result;
     92        handleQualifiers( type );
     93}
     94
     95void GenType_new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {
     96        std::ostringstream os;
     97        if ( result != "" ) {
     98                if ( result[ 0 ] == '*' ) {
     99                        os << "(" << result << ")";
     100                } else {
     101                        os << result;
     102                }
     103        }
     104        os << "[";
     105        if ( isStatic ) {
     106                os << "static ";
     107        }
     108        if ( qualifiers.is_const ) {
     109                os << "const ";
     110        }
     111        if ( qualifiers.is_volatile ) {
     112                os << "volatile ";
     113        }
     114        if ( qualifiers.is_restrict ) {
     115                os << "__restrict ";
     116        }
     117        if ( qualifiers.is_atomic ) {
     118                os << "_Atomic ";
     119        }
     120        if ( dimension != 0 ) {
     121                ast::Pass<CodeGenerator_new>::read( dimension, os, options );
     122        } else if ( isVarLen ) {
     123                // no dimension expression on a VLA means it came in with the * token
     124                os << "*";
     125        }
     126        os << "]";
     127
     128        result = os.str();
     129
     130        base->accept( *visitor );
     131}
     132
     133void GenType_new::postvisit( ast::PointerType const * type ) {
     134        if ( type->isStatic || type->isVarLen || type->dimension ) {
     135                genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
     136        } else {
     137                handleQualifiers( type );
     138                if ( result[ 0 ] == '?' ) {
     139                        result = "* " + result;
     140                } else {
     141                        result = "*" + result;
     142                }
     143                type->base->accept( *visitor );
     144        }
     145}
     146
     147void GenType_new::postvisit( ast::ArrayType const * type ) {
     148        genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
     149}
     150
     151void GenType_new::postvisit( ast::ReferenceType const * type ) {
     152        assertf( !options.genC, "Reference types should not reach code generation." );
     153        handleQualifiers( type );
     154        result = "&" + result;
     155        type->base->accept( *visitor );
     156}
     157
     158void GenType_new::postvisit( ast::FunctionType const * type ) {
     159        std::ostringstream os;
     160
     161        if ( result != "" ) {
     162                if ( result[ 0 ] == '*' ) {
     163                        os << "(" << result << ")";
     164                } else {
     165                        os << result;
     166                }
     167        }
     168
     169        if ( type->params.empty() ) {
     170                if ( type->isVarArgs ) {
     171                        os << "()";
     172                } else {
     173                        os << "(void)";
     174                }
     175        } else {
     176                os << "(" ;
     177
     178                os << genParamList( type->params );
     179
     180                if ( type->isVarArgs ) {
     181                        os << ", ...";
     182                }
     183                os << ")";
     184        }
     185
     186        result = os.str();
     187
     188        if ( type->returns.size() == 0 ) {
     189                result = "void " + result;
     190        } else {
     191                type->returns.front()->accept( *visitor );
     192        }
     193
     194        // Add forall clause.
     195        if( !type->forall.empty() && !options.genC ) {
     196                //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." );
    65197                std::ostringstream os;
    66 
    67                 if ( ! type->get_attributes().empty() ) {
    68                         PassVisitor<CodeGenerator> cg( os, options );
    69                         cg.pass.genAttributes( type->get_attributes() );
    70                 } // if
    71 
    72                 type->accept( gt );
    73                 return os.str() + gt.pass.typeString;
    74         }
    75 
    76         std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
    77                 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) );
    78         }
    79 
    80         std::string genPrettyType( Type * type, const std::string & baseString ) {
    81                 return genType( type, baseString, true, false );
    82         }
    83 
    84         GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {}
    85 
    86         // *** BaseSyntaxNode
    87         void GenType::previsit( BaseSyntaxNode * ) {
    88                 // turn off automatic recursion for all nodes, to allow each visitor to
    89                 // precisely control the order in which its children are visited.
    90                 visit_children = false;
    91         }
    92 
    93         void GenType::postvisit( BaseSyntaxNode * node ) {
    94                 std::stringstream ss;
    95                 node->print( ss );
    96                 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
    97         }
    98 
    99         void GenType::postvisit( VoidType * voidType ) {
    100                 typeString = "void " + typeString;
    101                 handleQualifiers( voidType );
    102         }
    103 
    104         void GenType::postvisit( BasicType * basicType ) {
    105                 BasicType::Kind kind = basicType->kind;
    106                 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
    107                 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
    108                 handleQualifiers( basicType );
    109         }
    110 
    111         void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {
     198                ast::Pass<CodeGenerator_new> cg( os, options );
     199                os << "forall(";
     200                cg.core.genCommaList( type->forall );
     201                os << ")" << std::endl;
     202                result = os.str() + result;
     203        }
     204}
     205
     206std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) {
     207        if ( !type->params.empty() ) {
    112208                std::ostringstream os;
    113                 if ( typeString != "" ) {
    114                         if ( typeString[ 0 ] == '*' ) {
    115                                 os << "(" << typeString << ")";
    116                         } else {
    117                                 os << typeString;
    118                         } // if
    119                 } // if
    120                 os << "[";
    121 
    122                 if ( isStatic ) {
    123                         os << "static ";
    124                 } // if
    125                 if ( qualifiers.is_const ) {
    126                         os << "const ";
    127                 } // if
    128                 if ( qualifiers.is_volatile ) {
    129                         os << "volatile ";
    130                 } // if
    131                 if ( qualifiers.is_restrict ) {
    132                         os << "__restrict ";
    133                 } // if
    134                 if ( qualifiers.is_atomic ) {
    135                         os << "_Atomic ";
    136                 } // if
    137                 if ( dimension != 0 ) {
    138                         PassVisitor<CodeGenerator> cg( os, options );
    139                         dimension->accept( cg );
    140                 } else if ( isVarLen ) {
    141                         // no dimension expression on a VLA means it came in with the * token
    142                         os << "*";
    143                 } // if
    144                 os << "]";
    145 
    146                 typeString = os.str();
    147 
    148                 base->accept( *visitor );
    149         }
    150 
    151         void GenType::postvisit( PointerType * pointerType ) {
    152                 assert( pointerType->base != 0);
    153                 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
    154                         genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
    155                 } else {
    156                         handleQualifiers( pointerType );
    157                         if ( typeString[ 0 ] == '?' ) {
    158                                 typeString = "* " + typeString;
    159                         } else {
    160                                 typeString = "*" + typeString;
    161                         } // if
    162                         pointerType->base->accept( *visitor );
    163                 } // if
    164         }
    165 
    166         void GenType::postvisit( ArrayType * arrayType ) {
    167                 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
    168         }
    169 
    170         void GenType::postvisit( ReferenceType * refType ) {
    171                 assert( 0 != refType->base );
    172                 assertf( ! options.genC, "Reference types should not reach code generation." );
    173                 handleQualifiers( refType );
    174                 typeString = "&" + typeString;
    175                 refType->base->accept( *visitor );
    176         }
    177 
    178         void GenType::postvisit( FunctionType * funcType ) {
    179                 std::ostringstream os;
    180 
    181                 if ( typeString != "" ) {
    182                         if ( typeString[ 0 ] == '*' ) {
    183                                 os << "(" << typeString << ")";
    184                         } else {
    185                                 os << typeString;
    186                         } // if
    187                 } // if
    188 
    189                 /************* parameters ***************/
    190 
    191                 const std::list<DeclarationWithType *> &pars = funcType->parameters;
    192 
    193                 if ( pars.empty() ) {
    194                         if ( funcType->get_isVarArgs() ) {
    195                                 os << "()";
    196                         } else {
    197                                 os << "(void)";
    198                         } // if
    199                 } else {
    200                         PassVisitor<CodeGenerator> cg( os, options );
    201                         os << "(" ;
    202 
    203                         cg.pass.genCommaList( pars.begin(), pars.end() );
    204 
    205                         if ( funcType->get_isVarArgs() ) {
    206                                 os << ", ...";
    207                         } // if
    208                         os << ")";
    209                 } // if
    210 
    211                 typeString = os.str();
    212 
    213                 if ( funcType->returnVals.size() == 0 ) {
    214                         typeString = "void " + typeString;
    215                 } else {
    216                         funcType->returnVals.front()->get_type()->accept( *visitor );
    217                 } // if
    218 
    219                 // add forall
    220                 if( ! funcType->forall.empty() && ! options.genC ) {
    221                         // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
    222                         std::ostringstream os;
    223                         PassVisitor<CodeGenerator> cg( os, options );
    224                         os << "forall(";
    225                         cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
    226                         os << ")" << std::endl;
    227                         typeString = os.str() + typeString;
    228                 }
    229         }
    230 
    231         std::string GenType::handleGeneric( ReferenceToType * refType ) {
    232                 if ( ! refType->parameters.empty() ) {
    233                         std::ostringstream os;
    234                         PassVisitor<CodeGenerator> cg( os, options );
    235                         os << "(";
    236                         cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
    237                         os << ") ";
    238                         return os.str();
    239                 }
    240                 return "";
    241         }
    242 
    243         void GenType::postvisit( StructInstType * structInst )  {
    244                 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
    245                 if ( options.genC ) typeString = "struct " + typeString;
    246                 handleQualifiers( structInst );
    247         }
    248 
    249         void GenType::postvisit( UnionInstType * unionInst ) {
    250                 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    251                 if ( options.genC ) typeString = "union " + typeString;
    252                 handleQualifiers( unionInst );
    253         }
    254 
    255         void GenType::postvisit( EnumInstType * enumInst ) {
    256                 if ( enumInst->baseEnum && enumInst->baseEnum->base ) {
    257                         typeString = genType(enumInst->baseEnum->base, typeString, options);
    258                 } else {
    259                         typeString = enumInst->name + " " + typeString;
    260                         if ( options.genC ) {
    261                                 typeString = "enum " + typeString;
    262                         }
    263                 }
    264                 handleQualifiers( enumInst );
    265         }
    266 
    267         void GenType::postvisit( TypeInstType * typeInst ) {
    268                 assertf( ! options.genC, "Type instance types should not reach code generation." );
    269                 typeString = typeInst->name + " " + typeString;
    270                 handleQualifiers( typeInst );
    271         }
    272 
    273         void GenType::postvisit( TupleType * tupleType ) {
    274                 assertf( ! options.genC, "Tuple types should not reach code generation." );
    275                 unsigned int i = 0;
    276                 std::ostringstream os;
    277                 os << "[";
    278                 for ( Type * t : *tupleType ) {
    279                         i++;
    280                         os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");
    281                 }
    282                 os << "] ";
    283                 typeString = os.str() + typeString;
    284         }
    285 
    286         void GenType::postvisit( VarArgsType * varArgsType ) {
    287                 typeString = "__builtin_va_list " + typeString;
    288                 handleQualifiers( varArgsType );
    289         }
    290 
    291         void GenType::postvisit( ZeroType * zeroType ) {
    292                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    293                 typeString = (options.pretty ? "zero_t " : "long int ") + typeString;
    294                 handleQualifiers( zeroType );
    295         }
    296 
    297         void GenType::postvisit( OneType * oneType ) {
    298                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    299                 typeString = (options.pretty ? "one_t " : "long int ") + typeString;
    300                 handleQualifiers( oneType );
    301         }
    302 
    303         void GenType::postvisit( GlobalScopeType * globalType ) {
    304                 assertf( ! options.genC, "Global scope type should not reach code generation." );
    305                 handleQualifiers( globalType );
    306         }
    307 
    308         void GenType::postvisit( TraitInstType * inst ) {
    309                 assertf( ! options.genC, "Trait types should not reach code generation." );
    310                 typeString = inst->name + " " + typeString;
    311                 handleQualifiers( inst );
    312         }
    313 
    314         void GenType::postvisit( TypeofType * typeof ) {
    315                 std::ostringstream os;
    316                 PassVisitor<CodeGenerator> cg( os, options );
    317                 os << "typeof(";
    318                 typeof->expr->accept( cg );
    319                 os << ") " << typeString;
    320                 typeString = os.str();
    321                 handleQualifiers( typeof );
    322         }
    323 
    324         void GenType::postvisit( VTableType * vtable ) {
    325                 assertf( ! options.genC, "Virtual table types should not reach code generation." );
    326                 std::ostringstream os;
    327                 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString;
    328                 typeString = os.str();
    329                 handleQualifiers( vtable );
    330         }
    331 
    332         void GenType::postvisit( QualifiedType * qualType ) {
    333                 assertf( ! options.genC, "Qualified types should not reach code generation." );
    334                 std::ostringstream os;
    335                 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString;
    336                 typeString = os.str();
    337                 handleQualifiers( qualType );
    338         }
    339 
    340         void GenType::handleQualifiers( Type * type ) {
    341                 if ( type->get_const() ) {
    342                         typeString = "const " + typeString;
    343                 } // if
    344                 if ( type->get_volatile() ) {
    345                         typeString = "volatile " + typeString;
    346                 } // if
    347                 if ( type->get_restrict() ) {
    348                         typeString = "__restrict " + typeString;
    349                 } // if
    350                 if ( type->get_atomic() ) {
    351                         typeString = "_Atomic " + typeString;
    352                 } // if
    353         }
     209                ast::Pass<CodeGenerator_new> cg( os, options );
     210                os << "(";
     211                cg.core.genCommaList( type->params );
     212                os << ") ";
     213                return os.str();
     214        }
     215        return "";
     216}
     217
     218void GenType_new::postvisit( ast::StructInstType const * type )  {
     219        result = type->name + handleGeneric( type ) + " " + result;
     220        if ( options.genC ) result = "struct " + result;
     221        handleQualifiers( type );
     222}
     223
     224void GenType_new::postvisit( ast::UnionInstType const * type ) {
     225        result = type->name + handleGeneric( type ) + " " + result;
     226        if ( options.genC ) result = "union " + result;
     227        handleQualifiers( type );
     228}
     229
     230void GenType_new::postvisit( ast::EnumInstType const * type ) {
     231        if ( type->base && type->base->base ) {
     232                result = genType( type->base->base, result, options );
     233        } else {
     234                result = type->name + " " + result;
     235                if ( options.genC ) {
     236                        result = "enum " + result;
     237                }
     238        }
     239        handleQualifiers( type );
     240}
     241
     242void GenType_new::postvisit( ast::TypeInstType const * type ) {
     243        assertf( !options.genC, "TypeInstType should not reach code generation." );
     244        result = type->name + " " + result;
     245        handleQualifiers( type );
     246}
     247
     248void GenType_new::postvisit( ast::TupleType const * type ) {
     249        assertf( !options.genC, "TupleType should not reach code generation." );
     250        unsigned int i = 0;
     251        std::ostringstream os;
     252        os << "[";
     253        for ( ast::ptr<ast::Type> const & t : type->types ) {
     254                i++;
     255                os << genType( t, "", options ) << (i == type->size() ? "" : ", ");
     256        }
     257        os << "] ";
     258        result = os.str() + result;
     259}
     260
     261void GenType_new::postvisit( ast::VarArgsType const * type ) {
     262        result = "__builtin_va_list " + result;
     263        handleQualifiers( type );
     264}
     265
     266void GenType_new::postvisit( ast::ZeroType const * type ) {
     267        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
     268        result = (options.pretty ? "zero_t " : "long int ") + result;
     269        handleQualifiers( type );
     270}
     271
     272void GenType_new::postvisit( ast::OneType const * type ) {
     273        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
     274        result = (options.pretty ? "one_t " : "long int ") + result;
     275        handleQualifiers( type );
     276}
     277
     278void GenType_new::postvisit( ast::GlobalScopeType const * type ) {
     279        assertf( !options.genC, "GlobalScopeType should not reach code generation." );
     280        handleQualifiers( type );
     281}
     282
     283void GenType_new::postvisit( ast::TraitInstType const * type ) {
     284        assertf( !options.genC, "TraitInstType should not reach code generation." );
     285        result = type->name + " " + result;
     286        handleQualifiers( type );
     287}
     288
     289void GenType_new::postvisit( ast::TypeofType const * type ) {
     290        std::ostringstream os;
     291        os << "typeof(";
     292        ast::Pass<CodeGenerator_new>::read( type, os, options );
     293        os << ") " << result;
     294        result = os.str();
     295        handleQualifiers( type );
     296}
     297
     298void GenType_new::postvisit( ast::VTableType const * type ) {
     299        assertf( !options.genC, "Virtual table types should not reach code generation." );
     300        std::ostringstream os;
     301        os << "vtable(" << genType( type->base, "", options ) << ") " << result;
     302        result = os.str();
     303        handleQualifiers( type );
     304}
     305
     306void GenType_new::postvisit( ast::QualifiedType const * type ) {
     307        assertf( !options.genC, "QualifiedType should not reach code generation." );
     308        std::ostringstream os;
     309        os << genType( type->parent, "", options ) << "." << genType( type->child, "", options ) << result;
     310        result = os.str();
     311        handleQualifiers( type );
     312}
     313
     314void GenType_new::handleQualifiers( ast::Type const * type ) {
     315        if ( type->is_const() ) {
     316                result = "const " + result;
     317        }
     318        if ( type->is_volatile() ) {
     319                result = "volatile " + result;
     320        }
     321        if ( type->is_restrict() ) {
     322                result = "__restrict " + result;
     323        }
     324        if ( type->is_atomic() ) {
     325                result = "_Atomic " + result;
     326        }
     327}
     328
     329std::string GenType_new::genParamList( const ast::vector<ast::Type> & range ) {
     330        auto cur = range.begin();
     331        auto end = range.end();
     332        if ( cur == end ) return "";
     333        std::ostringstream oss;
     334        UniqueName param( "__param_" );
     335        while ( true ) {
     336                oss << genType( *cur++, options.genC ? param.newName() : "", options );
     337                if ( cur == end ) break;
     338                oss << ", ";
     339        }
     340        return oss.str();
     341}
     342
     343} // namespace
     344
     345std::string genType( ast::Type const * type, const std::string & base, const Options & options ) {
     346        std::ostringstream os;
     347        if ( !type->attributes.empty() ) {
     348                ast::Pass<CodeGenerator_new> cg( os, options );
     349                cg.core.genAttributes( type->attributes );
     350        }
     351
     352        return os.str() + ast::Pass<GenType_new>::read( type, base, options );
     353}
     354
     355std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) {
     356        return ast::Pass<GenType_new>::read( type, base, options );
     357}
     358
    354359} // namespace CodeGen
    355360
  • src/CodeGen/GenType.h

    r0030b508 rfc12f05  
    2121
    2222class Type;
     23namespace ast {
     24        class Type;
     25}
    2326
    2427namespace CodeGen {
     
    2629        std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
    2730        std::string genPrettyType( Type * type, const std::string & baseString );
     31
     32std::string genType( ast::Type const * type, const std::string & base, const Options & options );
     33std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options );
     34
    2835} // namespace CodeGen
    2936
  • src/CodeGen/Generate.cc

    r0030b508 rfc12f05  
    1919#include <string>                    // for operator<<
    2020
    21 #include "CodeGenerator.h"           // for CodeGenerator, doSemicolon, oper...
     21#include "CodeGeneratorNew.hpp"      // for CodeGenerator_new, doSemicolon, ...
    2222#include "GenType.h"                 // for genPrettyType
    23 #include "Common/PassVisitor.h"      // for PassVisitor
    24 #include "SynTree/LinkageSpec.h"     // for isBuiltin, isGeneratable
    25 #include "SynTree/BaseSyntaxNode.h"  // for BaseSyntaxNode
    26 #include "SynTree/Declaration.h"     // for Declaration
    27 #include "SynTree/Type.h"            // for Type
    2823
    2924using namespace std;
    3025
    3126namespace CodeGen {
    32         namespace {
    33                 /// Removes misc. nodes that should not exist in CodeGen
    34                 struct TreeCleaner {
    35                         void premutate( CompoundStmt * stmt );
    36                         Statement * postmutate( ImplicitCtorDtorStmt * stmt );
    3727
    38                         static bool shouldClean( Declaration * );
    39                 };
    40 
    41                 void cleanTree( std::list< Declaration * > & translationUnit ) {
    42                         PassVisitor<TreeCleaner> cleaner;
    43                         filter( translationUnit, [](Declaration * decl) { return TreeCleaner::shouldClean(decl); }, false );
    44                         mutateAll( translationUnit, cleaner );
    45                 } // cleanTree
    46         } // namespace
    47 
    48         void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {
    49                 cleanTree( translationUnit );
    50 
    51                 PassVisitor<CodeGenerator> cgv( os, pretty, generateC, lineMarks, printExprTypes );
    52                 for ( auto & dcl : translationUnit ) {
    53                         if ( LinkageSpec::isGeneratable( dcl->get_linkage() ) && (doIntrinsics || ! LinkageSpec::isBuiltin( dcl->get_linkage() ) ) ) {
    54                                 cgv.pass.updateLocation( dcl );
    55                                 dcl->accept(cgv);
    56                                 if ( doSemicolon( dcl ) ) {
    57                                         os << ";";
    58                                 } // if
    59                                 os << cgv.pass.endl;
    60                         } // if
    61                 } // for
     28namespace {
     29        bool shouldClean( ast::Decl const * decl ) {
     30                return dynamic_cast<ast::TraitDecl const *>( decl );
    6231        }
    6332
    64         void generate( BaseSyntaxNode * node, std::ostream & os ) {
    65                 if ( Type * type = dynamic_cast< Type * >( node ) ) {
    66                         os << genPrettyType( type, "" );
    67                 } else {
    68                         PassVisitor<CodeGenerator> cgv( os, true, false, false, false );
    69                         node->accept( cgv );
    70                 }
    71                 os << std::endl;
    72         }
    73 
    74         namespace {
    75                 void TreeCleaner::premutate( CompoundStmt * cstmt ) {
    76                         filter( cstmt->kids, [](Statement * stmt) {
    77                                 if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( stmt ) ) {
    78                                         return shouldClean( declStmt->decl );
    79                                 }
    80                                 return false;
    81                         }, false );
     33        /// Removes various nodes that should not exist in CodeGen.
     34        struct TreeCleaner_new {
     35                ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) {
     36                        auto mutStmt = ast::mutate( stmt );
     37                        erase_if( mutStmt->kids, []( ast::Stmt const * stmt ){
     38                                auto declStmt = dynamic_cast<ast::DeclStmt const *>( stmt );
     39                                return ( declStmt ) ? shouldClean( declStmt->decl ) : false;
     40                        } );
     41                        return mutStmt;
    8242                }
    8343
    84                 Statement * TreeCleaner::postmutate( ImplicitCtorDtorStmt * stmt ) {
    85                         Statement * callStmt = nullptr;
    86                         std::swap( stmt->callStmt, callStmt );
    87                         delete stmt;
    88                         return callStmt;
     44                ast::Stmt const * postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
     45                        return stmt->callStmt;
    8946                }
     47        };
     48} // namespace
    9049
    91                 bool TreeCleaner::shouldClean( Declaration * decl ) {
    92                         return dynamic_cast< TraitDecl * >( decl );
     50void generate( ast::TranslationUnit & translationUnit, std::ostream & os, bool doIntrinsics,
     51                bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {
     52        erase_if( translationUnit.decls, shouldClean );
     53        ast::Pass<TreeCleaner_new>::run( translationUnit );
     54
     55        ast::Pass<CodeGenerator_new> cgv( os,
     56                        Options( pretty, generateC, lineMarks, printExprTypes ) );
     57        for ( auto & decl : translationUnit.decls ) {
     58                if ( decl->linkage.is_generatable && (doIntrinsics || !decl->linkage.is_builtin ) ) {
     59                        cgv.core.updateLocation( decl );
     60                        decl->accept( cgv );
     61                        if ( doSemicolon( decl ) ) {
     62                                os << ";";
     63                        }
     64                        os << cgv.core.endl;
    9365                }
    94         } // namespace
     66        }
     67}
     68
    9569} // namespace CodeGen
    9670
  • src/CodeGen/Generate.h

    r0030b508 rfc12f05  
    2222class Declaration;
    2323
     24namespace ast {
     25        class TranslationUnit;
     26}
     27
    2428namespace CodeGen {
    25         /// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.)
    26         void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC = false , bool lineMarks = false, bool printTypeExpr = false );
    2729
    28         /// Generate code for a single node -- helpful for debugging in gdb
    29         void generate( BaseSyntaxNode * node, std::ostream & os );
     30/// Generates all code in transUnit and writing it to the os.
     31/// doIntrinsics: Should intrinsic functions be printed?
     32/// pretty: Format output nicely (e.g., uses unmangled names, etc.).
     33/// generateC: Make sure the output only consists of C code (allows some assertions, etc.)
     34/// lineMarks: Output line marks (processed line directives) in the output.
     35/// printExprTypes: Print the types of expressions in comments.
     36void generate( ast::TranslationUnit & transUnit, std::ostream &os, bool doIntrinsics,
     37                bool pretty, bool generateC, bool lineMarks, bool printExprTypes );
     38
    3039} // namespace CodeGen
    3140
  • src/CodeGen/LinkOnce.cc

    r0030b508 rfc12f05  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
    24 #include "Common/PassVisitor.h"       // for PassVisitor, WithShortCircuiting
    2524
    2625namespace CodeGen {
    2726
    2827namespace {
    29 
    30 bool is_cfa_linkonce_old( Attribute const * attr ) {
    31         return std::string("cfa_linkonce") == attr->name;
    32 }
    33 
    34 bool is_section_attribute_old( Attribute const * attr ) {
    35         return std::string("section") == attr->name;
    36 }
    37 
    38 class LinkOnceVisitorCore : public WithShortCircuiting {
    39 public:
    40         void previsit( Declaration * ) {
    41                 visit_children = false;
    42         }
    43 
    44         void previsit( DeclarationWithType * decl ) {
    45                 std::list< Attribute * > & attributes = decl->attributes;
    46                 // See if we can find the element:
    47                 auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce_old );
    48                 if ( attributes.end() != found ) {
    49                         // Remove any other sections:
    50                         attributes.remove_if( is_section_attribute_old );
    51                         // Iterator to the cfa_linkonce attribute should still be valid.
    52                         Attribute * attribute = *found;
    53                         assert( attribute->parameters.empty() );
    54                         assert( !decl->mangleName.empty() );
    55                         // Overwrite the attribute in place.
    56                         const std::string section_name = ".gnu.linkonce." + decl->mangleName;
    57                         attribute->name = "section";
    58                         attribute->parameters.push_back(
    59                                 new ConstantExpr( Constant::from_string( section_name ) )
    60                         );
    61 
    62                         // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce
    63                         // visibility is a mess otherwise
    64                         attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));
    65 
    66                 }
    67                 visit_children = false;
    68         }
    69 };
    7028
    7129bool is_cfa_linkonce( ast::Attribute const * attr ) {
     
    12280} // namespace
    12381
    124 void translateLinkOnce( std::list< Declaration *> & translationUnit ) {
    125         PassVisitor<LinkOnceVisitorCore> translator;
    126         acceptAll( translationUnit, translator );
    127 }
    128 
    12982void translateLinkOnce( ast::TranslationUnit & translationUnit ) {
    13083        ast::Pass<LinkOnceCore>::run( translationUnit );
  • src/CodeGen/LinkOnce.h

    r0030b508 rfc12f05  
    2020// for now its almost the only attribute we handle.
    2121
    22 #include <list>  // for list
    2322
    24 class Declaration;
    2523namespace ast {
    2624        class TranslationUnit;
     
    2927namespace CodeGen {
    3028
    31 void translateLinkOnce( std::list< Declaration *> & translationUnit );
    3229void translateLinkOnce( ast::TranslationUnit & translationUnit );
    3330/* Convert the cfa_linkonce attribute on top level declaration into
  • src/CodeGen/OperatorTable.cc

    r0030b508 rfc12f05  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 18 15:55:01 2020
    13 // Update Count     : 55
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Nov  3 16:00:00 2023
     13// Update Count     : 56
    1414//
    1515
    16 #include <algorithm>  // for any_of
    17 #include <map>        // for map, _Rb_tree_const_iterator, map<>::const_iterator
    18 #include <utility>    // for pair
    19 using namespace std;
     16#include "OperatorTable.h"
    2017
    21 #include "OperatorTable.h"
    22 #include "Common/utility.h"
     18#include <cassert>         // for assert
     19#include <unordered_map>   // for unordered_map
    2320
    2421namespace CodeGen {
    25         const OperatorInfo CodeGen::tableValues[] = {
    26                 // inputName symbol   outputName                     friendlyName                  type
    27                 {       "?[?]",   "",     "_operator_index",             "Index",                      OT_INDEX          },
    28                 {       "?{}",    "=",    "_constructor",                "Constructor",                OT_CTOR           },
    29                 {       "^?{}",   "",     "_destructor",                 "Destructor",                 OT_DTOR           },
    30                 {       "?()",    "",     "_operator_call",              "Call Operator",              OT_CALL           },
    31                 {       "?++",    "++",   "_operator_postincr",          "Postfix Increment",          OT_POSTFIXASSIGN  },
    32                 {       "?--",    "--",   "_operator_postdecr",          "Postfix Decrement",          OT_POSTFIXASSIGN  },
    33                 {       "*?",     "*",    "_operator_deref",             "Dereference",                OT_PREFIX         },
    34                 {       "+?",     "+",    "_operator_unaryplus",         "Plus",                       OT_PREFIX         },
    35                 {       "-?",     "-",    "_operator_unaryminus",        "Minus",                      OT_PREFIX         },
    36                 {       "~?",     "~",    "_operator_bitnot",            "Bitwise Not",                OT_PREFIX         },
    37                 {       "!?",     "!",    "_operator_lognot",            "Logical Not",                OT_PREFIX         },
    38                 {       "++?",    "++",   "_operator_preincr",           "Prefix Increment",           OT_PREFIXASSIGN   },
    39                 {       "--?",    "--",   "_operator_predecr",           "Prefix Decrement",           OT_PREFIXASSIGN   },
    40                 {       "?\\?",   "\\",   "_operator_exponential",       "Exponentiation",             OT_INFIX          },
    41                 {       "?*?",    "*",    "_operator_multiply",          "Multiplication",             OT_INFIX          },
    42                 {       "?/?",    "/",    "_operator_divide",            "Division",                   OT_INFIX          },
    43                 {       "?%?",    "%",    "_operator_modulus",           "Modulo",                     OT_INFIX          },
    44                 {       "?+?",    "+",    "_operator_add",               "Addition",                   OT_INFIX          },
    45                 {       "?-?",    "-",    "_operator_subtract",          "Substraction",               OT_INFIX          },
    46                 {       "?<<?",   "<<",   "_operator_shiftleft",         "Shift Left",                 OT_INFIX          },
    47                 {       "?>>?",   ">>",   "_operator_shiftright",        "Shift Right",                OT_INFIX          },
    48                 {       "?<?",    "<",    "_operator_less",              "Less-than",                  OT_INFIX          },
    49                 {       "?>?",    ">",    "_operator_greater",           "Greater-than",               OT_INFIX          },
    50                 {       "?<=?",   "<=",   "_operator_lessequal",         "Less-than-or-Equal",         OT_INFIX          },
    51                 {       "?>=?",   ">=",   "_operator_greaterequal",      "Greater-than-or-Equal",      OT_INFIX          },
    52                 {       "?==?",   "==",   "_operator_equal",             "Equality",                   OT_INFIX          },
    53                 {       "?!=?",   "!=",   "_operator_notequal",          "Not-Equal",                  OT_INFIX          },
    54                 {       "?&?",    "&",    "_operator_bitand",            "Bitwise And",                OT_INFIX          },
    55                 {       "?^?",    "^",    "_operator_bitxor",            "Bitwise Xor",                OT_INFIX          },
    56                 {       "?|?",    "|",    "_operator_bitor",             "Bitwise Or",                 OT_INFIX          },
    57                 {       "?=?",    "=",    "_operator_assign",            "Assignment",                 OT_INFIXASSIGN    },
    58                 {       "?\\=?",  "\\=",  "_operator_expassign",         "Exponentiation Assignment",  OT_INFIXASSIGN    },
    59                 {       "?*=?",   "*=",   "_operator_multassign",        "Multiplication Assignment",  OT_INFIXASSIGN    },
    60                 {       "?/=?",   "/=",   "_operator_divassign",         "Division Assignment",        OT_INFIXASSIGN    },
    61                 {       "?%=?",   "%=",   "_operator_modassign",         "Modulo Assignment",          OT_INFIXASSIGN    },
    62                 {       "?+=?",   "+=",   "_operator_addassign",         "Addition Assignment",        OT_INFIXASSIGN    },
    63                 {       "?-=?",   "-=",   "_operator_subassign",         "Substrction Assignment",     OT_INFIXASSIGN    },
    64                 {       "?<<=?",  "<<=",  "_operator_shiftleftassign",   "Shift Left Assignment",      OT_INFIXASSIGN    },
    65                 {       "?>>=?",  ">>=",  "_operator_shiftrightassign",  "Shift Right Assignment",     OT_INFIXASSIGN    },
    66                 {       "?&=?",   "&=",   "_operator_bitandassign",      "Bitwise And Assignment",     OT_INFIXASSIGN    },
    67                 {       "?^=?",   "^=",   "_operator_bitxorassign",      "Bitwise Xor Assignment",     OT_INFIXASSIGN    },
    68                 {       "?|=?",   "|=",   "_operator_bitorassign",       "Bitwise Or Assignment",      OT_INFIXASSIGN    },
    69         }; // tableValues
    7022
    71         std::map< std::string, OperatorInfo > CodeGen::table;
     23static const OperatorInfo tableValues[] = {
     24        //  inputName symbol  outputName                     friendlyName                  type
     25        {       "?[?]",   "",     "_operator_index",             "Index",                      OT_INDEX          },
     26        {       "?{}",    "=",    "_constructor",                "Constructor",                OT_CTOR           },
     27        {       "^?{}",   "",     "_destructor",                 "Destructor",                 OT_DTOR           },
     28        {       "?()",    "",     "_operator_call",              "Call Operator",              OT_CALL           },
     29        {       "?++",    "++",   "_operator_postincr",          "Postfix Increment",          OT_POSTFIXASSIGN  },
     30        {       "?--",    "--",   "_operator_postdecr",          "Postfix Decrement",          OT_POSTFIXASSIGN  },
     31        {       "*?",     "*",    "_operator_deref",             "Dereference",                OT_PREFIX         },
     32        {       "+?",     "+",    "_operator_unaryplus",         "Plus",                       OT_PREFIX         },
     33        {       "-?",     "-",    "_operator_unaryminus",        "Minus",                      OT_PREFIX         },
     34        {       "~?",     "~",    "_operator_bitnot",            "Bitwise Not",                OT_PREFIX         },
     35        {       "!?",     "!",    "_operator_lognot",            "Logical Not",                OT_PREFIX         },
     36        {       "++?",    "++",   "_operator_preincr",           "Prefix Increment",           OT_PREFIXASSIGN   },
     37        {       "--?",    "--",   "_operator_predecr",           "Prefix Decrement",           OT_PREFIXASSIGN   },
     38        {       "?\\?",   "\\",   "_operator_exponential",       "Exponentiation",             OT_INFIX          },
     39        {       "?*?",    "*",    "_operator_multiply",          "Multiplication",             OT_INFIX          },
     40        {       "?/?",    "/",    "_operator_divide",            "Division",                   OT_INFIX          },
     41        {       "?%?",    "%",    "_operator_modulus",           "Modulo",                     OT_INFIX          },
     42        {       "?+?",    "+",    "_operator_add",               "Addition",                   OT_INFIX          },
     43        {       "?-?",    "-",    "_operator_subtract",          "Substraction",               OT_INFIX          },
     44        {       "?<<?",   "<<",   "_operator_shiftleft",         "Shift Left",                 OT_INFIX          },
     45        {       "?>>?",   ">>",   "_operator_shiftright",        "Shift Right",                OT_INFIX          },
     46        {       "?<?",    "<",    "_operator_less",              "Less-than",                  OT_INFIX          },
     47        {       "?>?",    ">",    "_operator_greater",           "Greater-than",               OT_INFIX          },
     48        {       "?<=?",   "<=",   "_operator_lessequal",         "Less-than-or-Equal",         OT_INFIX          },
     49        {       "?>=?",   ">=",   "_operator_greaterequal",      "Greater-than-or-Equal",      OT_INFIX          },
     50        {       "?==?",   "==",   "_operator_equal",             "Equality",                   OT_INFIX          },
     51        {       "?!=?",   "!=",   "_operator_notequal",          "Not-Equal",                  OT_INFIX          },
     52        {       "?&?",    "&",    "_operator_bitand",            "Bitwise And",                OT_INFIX          },
     53        {       "?^?",    "^",    "_operator_bitxor",            "Bitwise Xor",                OT_INFIX          },
     54        {       "?|?",    "|",    "_operator_bitor",             "Bitwise Or",                 OT_INFIX          },
     55        {       "?=?",    "=",    "_operator_assign",            "Assignment",                 OT_INFIXASSIGN    },
     56        {       "?\\=?",  "\\=",  "_operator_expassign",         "Exponentiation Assignment",  OT_INFIXASSIGN    },
     57        {       "?*=?",   "*=",   "_operator_multassign",        "Multiplication Assignment",  OT_INFIXASSIGN    },
     58        {       "?/=?",   "/=",   "_operator_divassign",         "Division Assignment",        OT_INFIXASSIGN    },
     59        {       "?%=?",   "%=",   "_operator_modassign",         "Modulo Assignment",          OT_INFIXASSIGN    },
     60        {       "?+=?",   "+=",   "_operator_addassign",         "Addition Assignment",        OT_INFIXASSIGN    },
     61        {       "?-=?",   "-=",   "_operator_subassign",         "Substrction Assignment",     OT_INFIXASSIGN    },
     62        {       "?<<=?",  "<<=",  "_operator_shiftleftassign",   "Shift Left Assignment",      OT_INFIXASSIGN    },
     63        {       "?>>=?",  ">>=",  "_operator_shiftrightassign",  "Shift Right Assignment",     OT_INFIXASSIGN    },
     64        {       "?&=?",   "&=",   "_operator_bitandassign",      "Bitwise And Assignment",     OT_INFIXASSIGN    },
     65        {       "?^=?",   "^=",   "_operator_bitxorassign",      "Bitwise Xor Assignment",     OT_INFIXASSIGN    },
     66        {       "?|=?",   "|=",   "_operator_bitorassign",       "Bitwise Or Assignment",      OT_INFIXASSIGN    },
     67}; // tableValues
    7268
    73         CodeGen::CodeGen() {
    74                 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
    75                 for ( int i = 0; i < numOps; i += 1 ) {
    76                         table[ tableValues[i].inputName ] = tableValues[i];
    77                 } // for
     69enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
     70
     71const OperatorInfo * operatorLookup( const std::string & inputName ) {
     72        // Static information set up:
     73        static std::unordered_map<std::string, const OperatorInfo *> inputTable;
     74        if ( inputTable.empty() ) for ( const OperatorInfo & op : tableValues ) {
     75                inputTable[ op.inputName ] = &op;
    7876        }
    7977
    80         const OperatorInfo * operatorLookup( const string & funcName ) {
    81                 if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter
    82                 const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table
    83                 assert( ret );
    84                 return ret;
     78        if ( inputName.find_first_of( "?^*+-!", 0, 1 ) == std::string::npos ) return nullptr; // prefilter
     79        const OperatorInfo * ret = inputTable.find( inputName )->second;
     80        // This can only happen if an invalid identifier name has been used.
     81        assert( ret );
     82        return ret;
     83}
     84
     85bool isOperator( const std::string & inputName ) {
     86        return operatorLookup( inputName ) != nullptr;
     87}
     88
     89std::string operatorFriendlyName( const std::string & inputName ) {
     90        const OperatorInfo * info = operatorLookup( inputName );
     91        if ( info ) return info->friendlyName;
     92        return "";
     93}
     94
     95// This is only used in the demangler, so it is smaller (and only maybe slow).
     96const OperatorInfo * operatorLookupByOutput( const std::string & outputName ) {
     97        if ( '_' != outputName[0] ) return nullptr;
     98        for ( const OperatorInfo & op : tableValues ) {
     99                if ( outputName == op.outputName ) {
     100                        return &op;
     101                }
    85102        }
     103        return nullptr;
     104}
    86105
    87         bool isOperator( const string & funcName ) {
    88                 return operatorLookup( funcName ) != nullptr;
    89         }
     106bool isConstructor( const std::string & inputName ) {
     107        const OperatorInfo * info = operatorLookup( inputName );
     108        if ( info ) return info->type == OT_CTOR;
     109        return false;
     110}
    90111
    91         string operatorFriendlyName( const string & funcName ) {
    92                 const OperatorInfo * info = operatorLookup( funcName );
    93                 if ( info ) return info->friendlyName;
    94                 return "";
    95         }
     112bool isDestructor( const std::string & inputName ) {
     113        const OperatorInfo * info = operatorLookup( inputName );
     114        if ( info ) return info->type == OT_DTOR;
     115        return false;
     116}
    96117
    97         bool isConstructor( const string & funcName ) {
    98                 const OperatorInfo * info = operatorLookup( funcName );
    99                 if ( info ) return info->type == OT_CTOR;
    100                 return false;
    101         }
     118bool isCtorDtor( const std::string & inputName ) {
     119        const OperatorInfo * info = operatorLookup( inputName );
     120        if ( info ) return info->type <= OT_CONSTRUCTOR;
     121        return false;
     122}
    102123
    103         bool isDestructor( const string & funcName ) {
    104                 const OperatorInfo * info = operatorLookup( funcName );
    105                 if ( info ) return info->type == OT_DTOR;
    106                 return false;
    107         }
     124bool isAssignment( const std::string & inputName ) {
     125        const OperatorInfo * info = operatorLookup( inputName );
     126        if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;
     127        return false;
     128}
    108129
    109         bool isCtorDtor( const string & funcName ) {
    110                 const OperatorInfo * info = operatorLookup( funcName );
    111                 if ( info ) return info->type <= OT_CONSTRUCTOR;
    112                 return false;
    113         }
     130bool isCtorDtorAssign( const std::string & inputName ) {
     131        const OperatorInfo * info = operatorLookup( inputName );
     132        if ( info ) return info->type <= OT_ASSIGNMENT;
     133        return false;
     134}
    114135
    115         bool isAssignment( const string & funcName ) {
    116                 const OperatorInfo * info = operatorLookup( funcName );
    117                 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;
    118                 return false;
    119         }
    120 
    121         bool isCtorDtorAssign( const string & funcName ) {
    122                 const OperatorInfo * info = operatorLookup( funcName );
    123                 if ( info ) return info->type <= OT_ASSIGNMENT;
    124                 return false;
    125         }
    126 
    127         CodeGen codegen;                                                                        // initialize singleton package
    128136} // namespace CodeGen
    129137
  • src/CodeGen/OperatorTable.h

    r0030b508 rfc12f05  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 08:13:34 2020
    13 // Update Count     : 26
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Nov  3 14:53:00 2023
     13// Update Count     : 27
    1414//
    1515
     
    1717
    1818#include <string>
    19 #include <map>
    2019
    2120namespace CodeGen {
    22         enum OperatorType {
    23                 OT_CTOR,
    24                 OT_DTOR,
    25                 OT_CONSTRUCTOR = OT_DTOR,
    26                 OT_PREFIXASSIGN,
    27                 OT_POSTFIXASSIGN,
    28                 OT_INFIXASSIGN,
    29                 OT_ASSIGNMENT = OT_INFIXASSIGN,
    30                 OT_CALL,
    31                 OT_PREFIX,
    32                 OT_INFIX,
    33                 OT_POSTFIX,
    34                 OT_INDEX,
    35                 OT_LABELADDRESS,
    36                 OT_CONSTANT
    37         };
    3821
    39         struct OperatorInfo {
    40                 std::string inputName;
    41                 std::string symbol;
    42                 std::string outputName;
    43                 std::string friendlyName;
    44                 OperatorType type;
    45         };
     22enum OperatorType {
     23        OT_CTOR,
     24        OT_DTOR,
     25        OT_CONSTRUCTOR = OT_DTOR,
     26        OT_PREFIXASSIGN,
     27        OT_POSTFIXASSIGN,
     28        OT_INFIXASSIGN,
     29        OT_ASSIGNMENT = OT_INFIXASSIGN,
     30        OT_CALL,
     31        OT_PREFIX,
     32        OT_INFIX,
     33        OT_POSTFIX,
     34        OT_INDEX,
     35        OT_LABELADDRESS,
     36        OT_CONSTANT
     37};
    4638
    47         class CodeGen {
    48                 friend const OperatorInfo * operatorLookup( const std::string & funcName );
     39struct OperatorInfo {
     40        // The Cforall special function name.
     41        std::string inputName;
     42        // The string used when the operator is used as an operator.
     43        std::string symbol;
     44        // The base name used in the mangled name.
     45        std::string outputName;
     46        // Human-readable name of the operator.
     47        std::string friendlyName;
     48        // The type of operator shows how it is used as an operator.
     49        OperatorType type;
     50};
    4951
    50                 static const OperatorInfo tableValues[];
    51                 static std::map< std::string, OperatorInfo > table;
    52           public:
    53                 CodeGen();
    54         }; // CodeGen
     52// Look up the operator (by inputName), return nullptr if no such operator.
     53const OperatorInfo * operatorLookup( const std::string & inputName );
     54// Is there an operator with this name?
     55bool isOperator( const std::string & inputName );
     56// Get the friendlyName of the operator with the inputName
     57std::string operatorFriendlyName( const std::string & inputName );
     58// Get the OperatorInfo with the given outputName, if one exists.
     59const OperatorInfo * operatorLookupByOutput( const std::string & outputName );
    5560
    56         bool isOperator( const std::string & funcName );
    57         const OperatorInfo * operatorLookup( const std::string & funcName );
    58         std::string operatorFriendlyName( const std::string & funcName );
     61// Is the operator a constructor, destructor or any form of assignment.
     62// (Last two are "or" combinations of the first three.)
     63bool isConstructor( const std::string & );
     64bool isDestructor( const std::string & );
     65bool isAssignment( const std::string & );
     66bool isCtorDtor( const std::string & );
     67bool isCtorDtorAssign( const std::string & );
    5968
    60         bool isConstructor( const std::string & );
    61         bool isDestructor( const std::string & );
    62         bool isAssignment( const std::string & );
    63         bool isCtorDtor( const std::string & );
    64         bool isCtorDtorAssign( const std::string & );
    6569} // namespace CodeGen
    6670
  • src/CodeGen/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC_CODEGEN = \
    18         CodeGen/FixMain2.cc \
    19         CodeGen/FixMain.h \
     18        CodeGen/CodeGeneratorNew.cpp \
     19        CodeGen/CodeGeneratorNew.hpp \
     20        CodeGen/GenType.cc \
     21        CodeGen/GenType.h \
    2022        CodeGen/OperatorTable.cc \
    2123        CodeGen/OperatorTable.h
    2224
    2325SRC += $(SRC_CODEGEN) \
    24         CodeGen/CodeGenerator.cc \
    25         CodeGen/CodeGenerator.h \
    2626        CodeGen/Generate.cc \
    2727        CodeGen/Generate.h \
    2828        CodeGen/FixMain.cc \
     29        CodeGen/FixMain.h \
    2930        CodeGen/FixNames.cc \
    3031        CodeGen/FixNames.h \
    31         CodeGen/GenType.cc \
    32         CodeGen/GenType.h \
    3332        CodeGen/LinkOnce.cc \
    3433        CodeGen/LinkOnce.h \
  • src/Common/CodeLocationTools.cpp

    r0030b508 rfc12f05  
    138138    macro(MutexStmt, Stmt) \
    139139    macro(CorunStmt, Stmt) \
     140        macro(CoforStmt, Stmt) \
    140141    macro(ApplicationExpr, Expr) \
    141142    macro(UntypedExpr, Expr) \
  • src/Common/Eval.cc

    r0030b508 rfc12f05  
    1919
    2020#include "AST/Inspect.hpp"
    21 #include "Common/PassVisitor.h"
    2221#include "CodeGen/OperatorTable.h"                                              // access: OperatorInfo
    2322#include "AST/Pass.hpp"
    2423#include "InitTweak/InitTweak.h"
    25 #include "SynTree/Expression.h"
    26 
    27 //-------------------------------------------------------------
    28 // Old AST
    29 struct EvalOld : public WithShortCircuiting {
    30         long long int value = 0;                                                        // compose the result of the constant expression
    31         bool valid = true;                                                                      // true => constant expression and value is the result
    32                                                                                                                 // false => not constant expression, e.g., ++i
    33         bool cfavalid = true;                                                           // true => constant expression and value computable
    34                                                                                                                 // false => constant expression but value not computable, e.g., sizeof(int)
    35 
    36         void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    37         void postvisit( const BaseSyntaxNode * ) { valid = false; }
    38 
    39         void postvisit( const SizeofExpr * ) {
    40         }
    41 
    42         void postvisit( const ConstantExpr * expr ) {
    43                 value = expr->intValue();
    44         }
    45 
    46         void postvisit( const CastExpr * expr ) {
    47                 auto arg = eval(expr->arg);
    48                 valid = arg.second;
    49                 value = arg.first;
    50                 // TODO: perform type conversion on value if valid
    51         }
    52 
    53         void postvisit( const VariableExpr * const expr ) {
    54                 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) {
    55                         if ( EnumDecl * decl = inst->baseEnum ) {
    56                                 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
    57                                         return;
    58                                 }
    59                         }
    60                 }
    61                 valid = false;
    62         }
    63 
    64         void postvisit( const ApplicationExpr * expr ) {
    65                 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr));
    66                 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; }
    67                 const std::string & fname = function->name;
    68                 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
    69                 std::pair<long long int, bool> arg1, arg2;
    70                 arg1 = eval(expr->args.front());
    71                 valid = valid && arg1.second;
    72                 if ( ! valid ) return;
    73                 if ( expr->args.size() == 2 ) {
    74                         arg2 = eval(expr->args.back());
    75                         valid = valid && arg2.second;
    76                         if ( ! valid ) return;
    77                 }
    78                 if (fname == "?+?") {
    79                         value = arg1.first + arg2.first;
    80                 } else if (fname == "?-?") {
    81                         value = arg1.first - arg2.first;
    82                 } else if (fname == "?*?") {
    83                         value = arg1.first * arg2.first;
    84                 } else if (fname == "?/?") {
    85                         value = arg1.first / arg2.first;
    86                 } else if (fname == "?%?") {
    87                         value = arg1.first % arg2.first;
    88                 } else {
    89                         valid = false;
    90                 }
    91                 // TODO: implement other intrinsic functions
    92         }
    93 };
    94 
    95 //-------------------------------------------------------------
    96 // New AST
     24
    9725struct EvalNew : public ast::WithShortCircuiting {
    9826        Evaluation result = { 0, true, true };
     
    270198};
    271199
    272 std::pair<long long int, bool> eval( const Expression * expr ) {
    273         PassVisitor<EvalOld> ev;
    274         if ( expr ) {
    275                 expr->accept( ev );
    276                 return std::make_pair( ev.pass.value, ev.pass.valid );
    277         } else {
    278                 return std::make_pair( 0, false );
    279         }
    280 }
    281 
    282200Evaluation eval( const ast::Expr * expr ) {
    283201        if ( expr ) {
  • src/Common/Eval.h

    r0030b508 rfc12f05  
    3030
    3131/// Evaluates expr as a long long int.
    32 /// If second is false, expr could not be evaluated.
    33 std::pair<long long int, bool> eval(const Expression * expr);
    3432Evaluation eval(const ast::Expr * expr);
    3533
  • src/Common/Examine.cc

    r0030b508 rfc12f05  
    1919#include "CodeGen/OperatorTable.h"
    2020#include "InitTweak/InitTweak.h"
    21 
    22 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {
    23         if (func->name != "main") return nullptr;
    24         if (func->type->parameters.size() != 1) return nullptr;
    25 
    26         auto param = func->type->parameters.front();
    27 
    28         auto type = dynamic_cast<ReferenceType * >(param->get_type());
    29         if (!type) return nullptr;
    30 
    31         auto obj = dynamic_cast<StructInstType *>(type->base);
    32         if (!obj) return nullptr;
    33 
    34         if (kind != obj->baseStruct->kind) return nullptr;
    35 
    36         return param;
    37 }
    3821
    3922namespace {
     
    6952
    7053namespace {
    71         Type * getDestructorParam( FunctionDecl * func ) {
    72                 if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
    73 
    74                 auto params = func->type->parameters;
    75                 if ( 1 != params.size() ) return nullptr;
    76 
    77                 auto ref = dynamic_cast<ReferenceType *>( params.front()->get_type() );
    78                 if ( ref ) {
    79                         return ref->base;
    80                 }
    81                 return nullptr;
    82         }
    8354
    8455const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
     
    8859}
    8960
    90 }
    91 
    92 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ) {
    93         if ( Type * type = getDestructorParam( func ) ) {
    94                 auto stype = dynamic_cast<StructInstType *>( type );
    95                 return stype && stype->baseStruct == type_decl;
    96         }
    97         return false;
    9861}
    9962
  • src/Common/Examine.h

    r0030b508 rfc12f05  
    1515
    1616#include "AST/Decl.hpp"
    17 #include "SynTree/Declaration.h"
    1817
    1918/// Check if this is a main function for a type of an aggregate kind.
    20 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );
    2119const ast::DeclWithType * isMainFor(
    2220        const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind );
     
    2422
    2523/// Check if this function is a destructor for the given structure.
    26 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );
    2724bool isDestructorFor(
    2825        const ast::FunctionDecl * func, const ast::StructDecl * type );
  • src/Common/UniqueName.cc

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // UniqueName.cc --
     7// UniqueName.cc -- Create a unique variants of a base name with a counter.
    88//
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jun  8 14:47:49 2015
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Nov  7 15:04:00 2023
     13// Update Count     : 4
    1414//
    1515
    16 #include <string>
    17 #include <sstream>
     16#include "UniqueName.h"
    1817
    19 #include "UniqueName.h"
     18#include "Common/ToString.hpp"
    2019
    2120UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) {
     
    2322
    2423std::string UniqueName::newName( const std::string &additional ) {
    25         std::ostringstream os;
    26         os << base << additional << count++;
    27         return os.str();
     24        return toString( base, additional, count++ );
    2825}
    2926
  • src/Common/UniqueName.h

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // UniqueName.h --
     7// UniqueName.h -- Create a unique variants of a base name with a counter.
    88//
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 22:18:45 2017
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Nov  7 15:00:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    1919
    2020class UniqueName {
    21   public:
    22         UniqueName( const std::string &base = "" );
     21public:
     22        UniqueName( const std::string &base );
    2323        std::string newName( const std::string &additional = "" );
    24   private:
     24private:
    2525        std::string base;
    2626        int count;
  • src/Common/module.mk

    r0030b508 rfc12f05  
    3131        Common/Indenter.cc \
    3232        Common/Iterate.hpp \
    33         Common/PassVisitor.cc \
    34         Common/PassVisitor.h \
    35         Common/PassVisitor.impl.h \
    36         Common/PassVisitor.proto.h \
    3733        Common/PersistentMap.h \
    3834        Common/ResolvProtoDump.hpp \
  • src/Concurrency/Corun.cpp

    r0030b508 rfc12f05  
    2727struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> {
    2828    UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
     29    UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
     30    // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
    2931    UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
     32   
     33    string coforArgName = "__CFA_cofor_lambda_arg";
     34    string numProcsName = "__CFA_cofor_num_procs";
     35    string currProcsName = "__CFA_cofor_curr_procs";
     36    string thdArrName = "__CFA_cofor_thread_array";
     37    string loopTempName = "__CFA_cofor_loop_temp";
     38   
    3039
    3140    const StructDecl * runnerBlockDecl = nullptr;
    32 
    33     // Finds select_node decl
     41    const StructDecl * coforRunnerDecl = nullptr;
     42
     43    // Finds runner_block (corun task) and cofor_runner (cofor task) decls
    3444    void previsit( const StructDecl * decl ) {
    3545        if ( !decl->body ) {
     
    3848            assert( !runnerBlockDecl );
    3949            runnerBlockDecl = decl;
     50        } else if ( "cofor_runner" == decl->name ) {
     51            assert( !coforRunnerDecl );
     52            coforRunnerDecl = decl;
    4053        }
    4154    }
    4255
     56    // codegen for cofor statements
     57    Stmt * postvisit( const CoforStmt * stmt ) {
     58        if ( !runnerBlockDecl || !coforRunnerDecl )
     59            SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>\n" );
     60
     61        if ( stmt->inits.size() != 1 )
     62            SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control\n" );
     63
     64        if ( !stmt->body )
     65            return nullptr;
     66
     67        const CodeLocation & loc = stmt->location;
     68        const string fnName = CoforFnNamer.newName();
     69
     70        CompoundStmt * body = new CompoundStmt( loc );
     71
     72        // push back cofor initializer to generated body
     73        body->push_back( deepCopy( stmt->inits.at(0) ) );
     74
     75        CompoundStmt * fnBody = new CompoundStmt( loc );
     76
     77        const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
     78        if ( ! declStmtPtr )
     79            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?\n" );
     80
     81        const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
     82        if ( ! declPtr )
     83            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?\n" );
     84
     85        Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
     86
     87        // Generates:
     88        // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     89        fnBody->push_back( new DeclStmt( loc,
     90            new ObjectDecl( loc,
     91                declPtr->name,
     92                initType,
     93                new SingleInit( loc,
     94                    UntypedExpr::createDeref( loc,
     95                        new CastExpr( loc,
     96                            new NameExpr( loc, coforArgName ),
     97                            new PointerType( initType ), ExplicitCast
     98                        )
     99                    )
     100                )
     101            )
     102        ));
     103
     104        // push rest of cofor body into loop lambda
     105        fnBody->push_back( deepCopy( stmt->body ) );
     106
     107        // Generates:
     108        // void __CFA_cofor_lambda_() {
     109        //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     110        //    stmt->body;
     111        // }
     112        Stmt * coforLambda = new DeclStmt( loc,
     113            new FunctionDecl( loc,
     114                fnName,                                             // name
     115                {},                                                 // forall
     116                {
     117                    new ObjectDecl( loc,
     118                        coforArgName,
     119                        new ast::PointerType( new ast::VoidType() )
     120                    )
     121                },                                                  // params
     122                {},                                                 // return
     123                fnBody   // body
     124            )
     125        );
     126        body->push_back( coforLambda );
     127
     128        // Generates:
     129        // unsigned __CFA_cofor_num_procs = get_proc_count();
     130        body->push_back( new DeclStmt( loc,
     131                new ObjectDecl( loc,
     132                    numProcsName,
     133                    new BasicType( BasicType::Kind::UnsignedInt ),
     134                    new SingleInit( loc,
     135                        new UntypedExpr( loc,
     136                            new NameExpr( loc, "get_proc_count" ),
     137                            {}
     138                        )
     139                    )
     140                )
     141            )
     142        );
     143
     144        // Generates:
     145        // unsigned __CFA_cofor_curr_procs = 0;
     146        body->push_back( new DeclStmt( loc,
     147                new ObjectDecl( loc,
     148                    currProcsName,
     149                    new BasicType( BasicType::Kind::UnsignedInt ),
     150                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     151                )
     152            )
     153        );
     154
     155        // Generates:
     156        // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
     157        body->push_back( new DeclStmt( loc,
     158                new ObjectDecl( loc,
     159                    thdArrName,
     160                    new ast::ArrayType(
     161                        new StructInstType( coforRunnerDecl ),
     162                        new NameExpr( loc, numProcsName ),
     163                        ast::FixedLen,
     164                        ast::DynamicDim
     165                    )
     166                )
     167            )
     168        );
     169
     170        // Generates:
     171        // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
     172        body->push_back( new ExprStmt( loc,
     173            new UntypedExpr( loc,
     174                new NameExpr( loc, "start_runners" ),
     175                {
     176                    new NameExpr( loc, thdArrName ),
     177                    new NameExpr( loc, numProcsName ),
     178                    new NameExpr( loc, fnName )
     179                }
     180            )
     181        ));
     182
     183        // Generates:
     184        // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
     185        CompoundStmt * forLoopBody = new CompoundStmt( loc );
     186        forLoopBody->push_back( new DeclStmt( loc,
     187                new ObjectDecl( loc,
     188                    loopTempName,
     189                    new PointerType( initType ),
     190                    new SingleInit( loc,
     191                        new UntypedExpr( loc,
     192                            new NameExpr( loc, "malloc" ),
     193                            {}
     194                        )
     195                    )
     196                )
     197            )
     198        );
     199
     200        // Generates:
     201        // *__CFA_cofor_loop_temp = initializer;
     202        forLoopBody->push_back( new ExprStmt( loc,
     203            UntypedExpr::createAssign( loc,
     204                UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
     205                new NameExpr( loc, declPtr->name )
     206            )
     207        ));
     208
     209        // Generates:
     210        // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
     211        //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
     212        forLoopBody->push_back( new ExprStmt( loc,
     213            new UntypedExpr( loc,
     214                new NameExpr( loc, "send_work" ),
     215                {
     216                    new NameExpr( loc, thdArrName ),
     217                    new NameExpr( loc, numProcsName ),
     218                    new NameExpr( loc, currProcsName ),
     219                    new NameExpr( loc, loopTempName )
     220                }
     221            )
     222        ));
     223
     224        body->push_back( new ForStmt( loc,
     225            {},
     226            deepCopy( stmt->cond ),
     227            deepCopy( stmt->inc ),
     228            forLoopBody
     229        ));
     230
     231        // Generates:
     232        // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
     233        body->push_back( new ExprStmt( loc,
     234            new UntypedExpr( loc,
     235                new NameExpr( loc, "end_runners" ),
     236                {
     237                    new NameExpr( loc, thdArrName ),
     238                    new NameExpr( loc, numProcsName )
     239                }
     240            )
     241        ));
     242
     243        return body;
     244    }
     245
     246    // codegen for corun statements
    43247    Stmt * postvisit( const CorunStmt * stmt ) {
    44         if ( !runnerBlockDecl )
     248        if ( !runnerBlockDecl || !coforRunnerDecl )
    45249            SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>\n" );
    46250
  • src/Concurrency/module.mk

    r0030b508 rfc12f05  
    2121        Concurrency/Corun.hpp \
    2222        Concurrency/KeywordsNew.cpp \
    23         Concurrency/Keywords.cc \
    2423        Concurrency/Keywords.h \
    2524        Concurrency/WaitforNew.cpp \
    26         Concurrency/Waitfor.cc \
    2725        Concurrency/Waitfor.h \
    2826        Concurrency/Waituntil.cpp \
  • src/ControlStruct/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC += \
    18         ControlStruct/ExceptDecl.cc \
    1918        ControlStruct/ExceptDeclNew.cpp \
    2019        ControlStruct/ExceptDecl.h \
    2120        ControlStruct/ExceptTranslateNew.cpp \
    22         ControlStruct/ExceptTranslate.cc \
    2321        ControlStruct/ExceptTranslate.h \
    2422        ControlStruct/FixLabels.cpp \
    2523        ControlStruct/FixLabels.hpp \
    26         ControlStruct/ForExprMutator.cc \
    27         ControlStruct/ForExprMutator.h \
    2824        ControlStruct/HoistControlDecls.cpp \
    2925        ControlStruct/HoistControlDecls.hpp \
    30         ControlStruct/LabelFixer.cc \
    31         ControlStruct/LabelFixer.h \
    32         ControlStruct/LabelGenerator.cc \
    33         ControlStruct/LabelGenerator.h \
    3426        ControlStruct/LabelGeneratorNew.cpp \
    3527        ControlStruct/LabelGeneratorNew.hpp \
    36         ControlStruct/MLEMutator.cc \
    37         ControlStruct/MLEMutator.h \
    3828        ControlStruct/MultiLevelExit.cpp \
    39         ControlStruct/MultiLevelExit.hpp \
    40         ControlStruct/Mutate.cc \
    41         ControlStruct/Mutate.h
     29        ControlStruct/MultiLevelExit.hpp
    4230
  • src/GenPoly/BoxNew.cpp

    r0030b508 rfc12f05  
    3939
    4040namespace {
    41 
    42 /// Common field of several sub-passes of box.
    43 struct BoxPass {
    44         TypeVarMap scopeTypeVars;
    45         BoxPass() : scopeTypeVars( ast::TypeData() ) {}
    46 };
    47 
    48 // TODO: Could this be a common helper somewhere?
    49 ast::FunctionType * makeFunctionType( ast::FunctionDecl const * decl ) {
    50         ast::FunctionType * type = new ast::FunctionType(
    51                 decl->type->isVarArgs, decl->type->qualifiers
    52         );
    53         for ( auto type_param : decl->type_params ) {
    54                 type->forall.emplace_back( new ast::TypeInstType( type_param ) );
    55         }
    56         for ( auto assertion : decl->assertions ) {
    57                 type->assertions.emplace_back( new ast::VariableExpr(
    58                         assertion->location, assertion ) );
    59         }
    60         for ( auto param : decl->params ) {
    61                 type->params.emplace_back( param->get_type() );
    62         }
    63         for ( auto retval : decl->returns ) {
    64                 type->returns.emplace_back( retval->get_type() );
    65         }
    66         return type;
    67 }
    6841
    6942// --------------------------------------------------------------------------
     
    359332/// * Adds appropriate type variables to the function calls.
    360333struct CallAdapter final :
    361                 public BoxPass,
    362334                public ast::WithConstTypeSubstitution,
    363335                public ast::WithGuards,
     
    376348        ast::Expr const * postvisit( ast::AddressExpr const * expr );
    377349        ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
    378         void previsit( ast::PointerType const * type );
    379         void previsit( ast::FunctionType const * type );
    380350
    381351        void beginScope();
     
    440410                CodeLocation const & location, ast::Type const * type );
    441411
    442         /// Set of adapter functions in the current scope.
     412        TypeVarMap scopeTypeVars;
    443413        ScopedMap< std::string, ast::DeclWithType const * > adapters;
    444414        std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
     
    553523
    554524ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
     525        // Prevent type declaration information from leaking out.
     526        GuardScope( scopeTypeVars );
     527
    555528        if ( nullptr == decl->stmts ) {
    556                 // This may keep TypeDecls we don't ever want from sneaking in.
    557                 // Not visiting child nodes might just be faster.
    558                 GuardScope( scopeTypeVars );
    559529                return decl;
    560530        }
    561531
    562         GuardScope( scopeTypeVars );
    563532        GuardValue( retval );
    564533
     
    662631        ptrdiff_t initArgCount = mutExpr->args.size();
    663632
    664         TypeVarMap exprTypeVars = { ast::TypeData() };
     633        TypeVarMap exprTypeVars;
    665634        // TODO: Should this take into account the variables already bound in
    666635        // scopeTypeVars ([ex] remove them from exprTypeVars)?
     
    687656
    688657        assert( typeSubs );
    689         ast::Type const * concRetType = replaceWithConcrete( dynRetType, *typeSubs );
    690         // Used to use dynRetType instead of concRetType; this changed so that
    691         // the correct type parameters are passed for return types (it should be
    692         // the concrete type's parameters, not the formal type's).
    693658        ast::vector<ast::Expr>::iterator argIt =
    694659                passTypeVars( mutExpr, function );
     
    768733        }
    769734        return stmt;
    770 }
    771 
    772 void CallAdapter::previsit( ast::PointerType const * type ) {
    773         GuardScope( scopeTypeVars );
    774         makeTypeVarMap( type, scopeTypeVars );
    775 }
    776 
    777 void CallAdapter::previsit( ast::FunctionType const * type ) {
    778         GuardScope( scopeTypeVars );
    779         makeTypeVarMap( type, scopeTypeVars );
    780735}
    781736
     
    14271382
    14281383ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
    1429         TypeVarMap localTypeVars = { ast::TypeData() };
     1384        TypeVarMap localTypeVars;
    14301385        makeTypeVarMap( decl, localTypeVars );
    14311386
     
    14581413                        layoutParams.emplace_back( alignParam );
    14591414                }
    1460                 // TODO: These should possibly all be gone.
    1461                 // More all assertions into parameter list.
    1462                 for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) {
    1463                         // Assertion parameters may not be used in body,
    1464                         // pass along with unused attribute.
    1465                         assert.get_and_mutate()->attributes.push_back(
    1466                                 new ast::Attribute( "unused" ) );
    1467                         inferredParams.push_back( assert );
    1468                 }
    1469                 mutParam->assertions.clear();
     1415                // Assertions should be stored in the main list.
     1416                assert( mutParam->assertions.empty() );
    14701417                typeParam = mutParam;
    14711418        }
    1472         // TODO: New version of inner loop.
    14731419        for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
    14741420                // Assertion parameters may not be used in body,
     
    14851431        spliceBegin( mutDecl->params, layoutParams );
    14861432        addAdapters( mutDecl, localTypeVars );
     1433
     1434        // Now have to update the type to match the declaration.
     1435        ast::FunctionType * type = new ast::FunctionType(
     1436                mutDecl->type->isVarArgs, mutDecl->type->qualifiers );
     1437        for ( auto type_param : mutDecl->type_params ) {
     1438                type->forall.emplace_back( new ast::TypeInstType( type_param ) );
     1439        }
     1440        for ( auto param : mutDecl->params ) {
     1441                type->params.emplace_back( param->get_type() );
     1442        }
     1443        for ( auto retval : mutDecl->returns ) {
     1444                type->returns.emplace_back( retval->get_type() );
     1445        }
     1446        mutDecl->type = type;
    14871447
    14881448        return mutDecl;
     
    15181478                }
    15191479        }
    1520         // TODO: Can this be updated as we go along?
    1521         mutDecl->type = makeFunctionType( mutDecl );
    15221480        return mutDecl;
    15231481}
     
    15751533        assertf( it != adapters.end(), "Could not correct floating node." );
    15761534        return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
    1577 
    15781535}
    15791536
     
    15871544/// * Inserts dynamic calculation of polymorphic type layouts where needed.
    15881545struct PolyGenericCalculator final :
    1589                 public BoxPass,
    15901546                public ast::WithConstTypeSubstitution,
    15911547                public ast::WithDeclsToAdd<>,
     
    15951551        PolyGenericCalculator();
    15961552
    1597         void previsit( ast::ObjectDecl const * decl );
    15981553        void previsit( ast::FunctionDecl const * decl );
    15991554        void previsit( ast::TypedefDecl const * decl );
     
    16021557        ast::StructDecl const * previsit( ast::StructDecl const * decl );
    16031558        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
    1604         void previsit( ast::PointerType const * type );
    1605         void previsit( ast::FunctionType const * type );
    16061559        ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
    16071560        ast::Expr const * postvisit( ast::MemberExpr const * expr );
     
    16351588        /// C sizeof().
    16361589        ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
    1637 
    16381590        /// Enters a new scope for type-variables,
    16391591        /// adding the type variables from the provided type.
    16401592        void beginTypeScope( ast::Type const * );
    1641         /// Enters a new scope for known layouts and offsets, and queues exit calls.
    1642         void beginGenericScope();
    1643 
     1593
     1594        /// The type variables and polymorphic parameters currently in scope.
     1595        TypeVarMap scopeTypeVars;
    16441596        /// Set of generic type layouts known in the current scope,
    16451597        /// indexed by sizeofName.
     
    16521604        /// If the argument of an AddressExpr is MemberExpr, it is stored here.
    16531605        ast::MemberExpr const * addrMember = nullptr;
    1654         /// Used to avoid recursing too deep in type declarations.
    1655         bool expect_func_type = false;
    16561606};
    16571607
     
    16751625}
    16761626
    1677 void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
    1678         beginTypeScope( decl->type );
    1679 }
    1680 
    16811627void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
    1682         beginGenericScope();
     1628        GuardScope( *this );
    16831629        beginTypeScope( decl->type );
    16841630}
     
    16961642                ast::TypeDecl const * decl ) {
    16971643        ast::Type const * base = decl->base;
    1698         if ( nullptr == base) return decl;
     1644        if ( nullptr == base ) return decl;
    16991645
    17001646        // Add size/align variables for opaque type declarations.
     
    17211667        alignDecl->accept( *visitor );
    17221668
    1723         // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
    1724         // can occur at global scope.
     1669        // A little trick to replace this with two declarations.
     1670        // Adding after makes sure that there is no conflict with adding stmts.
    17251671        declsToAddAfter.push_back( alignDecl );
    1726         // replace with sizeDecl.
    17271672        return sizeDecl;
    17281673}
     
    17421687}
    17431688
    1744 void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
    1745         beginTypeScope( type );
    1746 }
    1747 
    1748 void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {
    1749         beginTypeScope( type );
    1750 
    1751         GuardValue( expect_func_type );
    1752         GuardScope( *this );
    1753 
    1754         // The other functions type we will see in this scope are probably
    1755         // function parameters they don't help us with the layout and offsets so
    1756         // don't mark them as known in this scope.
    1757         expect_func_type = false;
    1758 }
    1759 
    1760 //void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
    17611689ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
    17621690        ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
     
    17661694
    17671695        // Change initialization of a polymorphic value object to allocate via a
    1768         // variable-length-array (alloca was previouly used, but it cannot be
    1769         // safely used in loops).
     1696        // variable-length-array (alloca cannot be safely used in loops).
    17701697        ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
    17711698                bufNamer.newName(),
     
    22482175}
    22492176
    2250 void PolyGenericCalculator::beginGenericScope() {
    2251         GuardScope( *this );
    2252         // We expect the first function type see to be the type relating to this
    2253         // scope but any further type is probably some unrelated function pointer
    2254         // keep track of whrich is the first.
    2255         GuardValue( expect_func_type ) = true;
    2256 }
    2257 
    22582177// --------------------------------------------------------------------------
    2259 /// No common theme found.
     2178/// Removes unneeded or incorrect type information.
    22602179/// * Replaces initialization of polymorphic values with alloca.
    22612180/// * Replaces declaration of dtype/ftype with appropriate void expression.
     
    22632182/// * Strips fields from generic structure declarations.
    22642183struct Eraser final :
    2265                 public BoxPass,
    22662184                public ast::WithGuards {
    22672185        void guardTypeVarMap( ast::Type const * type ) {
     
    22782196        void previsit( ast::PointerType const * type );
    22792197        void previsit( ast::FunctionType const * type );
     2198public:
     2199        TypeVarMap scopeTypeVars;
    22802200};
    22812201
  • src/GenPoly/FindFunction.cc

    r0030b508 rfc12f05  
    2020#include "AST/Pass.hpp"                 // for Pass
    2121#include "AST/Type.hpp"
    22 #include "Common/PassVisitor.h"         // for PassVisitor
    2322#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::iterator
    2423#include "GenPoly/GenPoly.h"            // for TyVarMap
    2524#include "ScrubTyVars.h"                // for ScrubTyVars
    26 #include "SynTree/Declaration.h"        // for DeclarationWithType, TypeDecl
    27 #include "SynTree/Mutator.h"            // for Mutator, mutateAll
    28 #include "SynTree/Type.h"               // for FunctionType, Type, Type::For...
    2925
    3026namespace GenPoly {
    31         class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting {
    32           public:
    33                 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );
    34 
    35                 void premutate( FunctionType * functionType );
    36                 Type * postmutate( FunctionType * functionType );
    37                 void premutate( PointerType * pointerType );
    38           private:
    39                 void handleForall( const Type::ForallList &forall );
    40 
    41                 std::list< FunctionType const * > & functions;
    42                 TyVarMap tyVars;
    43                 bool replaceMode;
    44                 FindFunctionPredicate predicate;
    45         };
    46 
    47         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    48                 PassVisitor<FindFunction> finder( functions, tyVars, false, predicate );
    49                 type->acceptMutator( finder );
    50         }
    51 
    52         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    53                 PassVisitor<FindFunction> finder( functions, tyVars, true, predicate );
    54                 type = type->acceptMutator( finder );
    55         }
    56 
    57         FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )
    58                 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) {
    59         }
    60 
    61         void FindFunction::handleForall( const Type::ForallList &forall ) {
    62                 for ( const Declaration * td : forall ) {
    63                         TyVarMap::iterator var = tyVars.find( td->name );
    64                         if ( var != tyVars.end() ) {
    65                                 tyVars.erase( var->first );
    66                         } // if
    67                 } // for
    68         }
    69 
    70         void FindFunction::premutate( FunctionType * functionType ) {
    71                 visit_children = false;
    72                 GuardScope( tyVars );
    73                 handleForall( functionType->get_forall() );
    74                 mutateAll( functionType->get_returnVals(), *visitor );
    75         }
    76 
    77         Type * FindFunction::postmutate( FunctionType * functionType ) {
    78                 Type *ret = functionType;
    79                 if ( predicate( functionType, tyVars ) ) {
    80                         functions.push_back( functionType );
    81                         if ( replaceMode ) {
    82                                 // replace type parameters in function type with void*
    83                                 ret = ScrubTyVars::scrub( functionType->clone(), tyVars );
    84                         } // if
    85                 } // if
    86                 return ret;
    87         }
    88 
    89         void FindFunction::premutate( PointerType * pointerType ) {
    90                 GuardScope( tyVars );
    91                 handleForall( pointerType->get_forall() );
    92         }
    9327
    9428namespace {
     
    15488void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) {
    15589        GuardScope( typeVars );
    156         //handleForall( type->forall );
    15790}
    15891
     
    16497        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false );
    16598        type->accept( pass );
    166         //(void)type;
    167         //(void)functions;
    168         //(void)typeVars;
    169         //(void)predicate;
    17099}
    171100
     
    175104        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true );
    176105        return type->accept( pass );
    177         //(void)functions;
    178         //(void)typeVars;
    179         //(void)predicate;
    180         //return type;
    181106}
    182107
  • src/GenPoly/FindFunction.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>       // for list
    19 
    2018#include "GenPoly.h"  // for TyVarMap
    2119
    22 class FunctionType;
    23 class Type;
    24 
    2520namespace GenPoly {
    26         typedef bool (*FindFunctionPredicate)( FunctionType*, const TyVarMap& );
    27 
    28         /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions`
    29         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    30         /// like `findFunction`, but also replaces the function type with void ()(void)
    31         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    3221
    3322typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & );
  • src/GenPoly/GenPoly.cc

    r0030b508 rfc12f05  
    2929#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it...
    3030#include "ResolvExpr/typeops.h"         // for flatten
    31 #include "SynTree/Constant.h"           // for Constant
    32 #include "SynTree/Expression.h"         // for Expression, TypeExpr, Constan...
    33 #include "SynTree/Type.h"               // for Type, StructInstType, UnionIn...
    34 #include "SynTree/TypeSubstitution.h"   // for TypeSubstitution
    3531
    3632using namespace std;
     
    3935        namespace {
    4036                /// Checks a parameter list for polymorphic parameters; will substitute according to env if present
    41                 bool hasPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {
    42                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    43                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    44                                 assertf(paramType, "Aggregate parameters should be type expressions");
    45                                 if ( isPolyType( paramType->get_type(), env ) ) return true;
    46                         }
    47                         return false;
    48                 }
    49 
    5037                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) {
    5138                        for ( auto &param : params ) {
     
    5845
    5946                /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present
    60                 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    61                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    62                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    63                                 assertf(paramType, "Aggregate parameters should be type expressions");
    64                                 if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true;
    65                         }
    66                         return false;
    67                 }
    68 
    6947                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) {
    7048                        for ( auto & param : params ) {
     
    7755
    7856                /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
    79                 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    80                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    81                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    82                                 assertf(paramType, "Aggregate parameters should be type expressions");
    83                                 if ( isDynType( paramType->get_type(), tyVars, env ) ) return true;
    84                         }
    85                         return false;
    86                 }
    87 
    8857                bool hasDynParams(
    8958                                const std::vector<ast::ptr<ast::Expr>> & params,
     
    9968                        return false;
    10069                }
    101 
    102                 /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present
    103                 bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {
    104                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    105                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    106                                 assertf(paramType, "Aggregate parameters should be type expressions");
    107                                 if ( includesPolyType( paramType->get_type(), env ) ) return true;
    108                         }
    109                         return false;
    110                 }
    111 
    112                 /// Checks a parameter list for inclusion of polymorphic parameters from tyVars; will substitute according to env if present
    113                 bool includesPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    114                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    115                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    116                                 assertf(paramType, "Aggregate parameters should be type expressions");
    117                                 if ( includesPolyType( paramType->get_type(), tyVars, env ) ) return true;
    118                         }
    119                         return false;
    120                 }
    121         }
    122 
    123         Type* replaceTypeInst( Type* type, const TypeSubstitution* env ) {
    124                 if ( ! env ) return type;
    125                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {
    126                         Type *newType = env->lookup( typeInst->get_name() );
    127                         if ( newType ) return newType;
    128                 }
    129                 return type;
    130         }
    131 
    132         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) {
    133                 if ( ! env ) return type;
    134                 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) {
    135                         Type *newType = env->lookup( typeInst->get_name() );
    136                         if ( newType ) return newType;
    137                 }
    138                 return type;
    13970        }
    14071
     
    14677                }
    14778                return type;
    148         }
    149 
    150         Type *isPolyType( Type *type, const TypeSubstitution *env ) {
    151                 type = replaceTypeInst( type, env );
    152 
    153                 if ( dynamic_cast< TypeInstType * >( type ) ) {
    154                         return type;
    155                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    156                         return isPolyType( arrayType->base, env );
    157                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    158                         if ( hasPolyParams( structType->get_parameters(), env ) ) return type;
    159                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    160                         if ( hasPolyParams( unionType->get_parameters(), env ) ) return type;
    161                 }
    162                 return 0;
    16379        }
    16480
     
    17894        }
    17995
    180         Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    181                 type = replaceTypeInst( type, env );
    182 
    183                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    184                         if ( tyVars.contains( typeInst->get_name() ) ) {
    185                                 return type;
    186                         }
    187                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    188                         return isPolyType( arrayType->base, tyVars, env );
    189                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    190                         if ( hasPolyParams( structType->get_parameters(), tyVars, env ) ) return type;
    191                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    192                         if ( hasPolyParams( unionType->get_parameters(), tyVars, env ) ) return type;
    193                 }
    194                 return 0;
    195         }
    196 
    19796const ast::Type * isPolyType( const ast::Type * type,
    19897                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    211110}
    212111
    213         ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    214                 type = replaceTypeInst( type, env );
    215 
    216                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    217                         auto var = tyVars.find( typeInst->get_name() );
    218                         if ( var != tyVars.end() && var->second.isComplete ) {
    219                                 return typeInst;
    220                         }
    221                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    222                         if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType;
    223                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    224                         if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType;
    225                 }
    226                 return 0;
    227         }
    228 
    229112const ast::BaseInstType * isDynType(
    230113                const ast::Type * type, const TypeVarMap & typeVars,
     
    249132}
    250133
    251         ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) {
    252                 if ( function->get_returnVals().empty() ) return 0;
    253 
    254                 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
    255         }
    256 
    257134const ast::BaseInstType *isDynRet(
    258135                const ast::FunctionType * type, const TypeVarMap & typeVars ) {
     
    262139}
    263140
    264         ReferenceToType *isDynRet( FunctionType *function ) {
    265                 if ( function->get_returnVals().empty() ) return 0;
    266 
    267                 TyVarMap forallTypes( TypeDecl::Data{} );
    268                 makeTyVarMap( function, forallTypes );
    269                 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
    270         }
    271 
    272141const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) {
    273142        if ( func->returns.empty() ) return nullptr;
    274143
    275         TypeVarMap forallTypes = { ast::TypeData() };
     144        TypeVarMap forallTypes;
    276145        makeTypeVarMap( func, forallTypes );
    277146        return isDynType( func->returns.front(), forallTypes );
    278147}
    279 
    280         bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {
    281 //              if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {
    282 //                      return true;
    283 //              } // if
    284                 if ( isDynRet( adaptee, tyVars ) ) return true;
    285 
    286                 for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) {
    287 //                      if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) {
    288                         if ( isDynType( (*innerArg)->get_type(), tyVars ) ) {
    289                                 return true;
    290                         } // if
    291                 } // for
    292                 return false;
    293         }
    294148
    295149bool needsAdapter(
     
    304158        return false;
    305159}
    306 
    307         Type *isPolyPtr( Type *type, const TypeSubstitution *env ) {
    308                 type = replaceTypeInst( type, env );
    309 
    310                 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    311                         return isPolyType( ptr->get_base(), env );
    312                 }
    313                 return 0;
    314         }
    315 
    316         Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    317                 type = replaceTypeInst( type, env );
    318 
    319                 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    320                         return isPolyType( ptr->get_base(), tyVars, env );
    321                 }
    322                 return 0;
    323         }
    324160
    325161const ast::Type * isPolyPtr(
     
    333169        return nullptr;
    334170}
    335 
    336         Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {
    337                 int dummy;
    338                 if ( ! levels ) { levels = &dummy; }
    339                 *levels = 0;
    340 
    341                 while ( true ) {
    342                         type = replaceTypeInst( type, env );
    343 
    344                         if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    345                                 type = ptr->get_base();
    346                                 ++(*levels);
    347                         } else break;
    348                 }
    349 
    350                 return isPolyType( type, env );
    351         }
    352 
    353         Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) {
    354                 int dummy;
    355                 if ( ! levels ) { levels = &dummy; }
    356                 *levels = 0;
    357 
    358                 while ( true ) {
    359                         type = replaceTypeInst( type, env );
    360 
    361                         if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    362                                 type = ptr->get_base();
    363                                 ++(*levels);
    364                         } else break;
    365                 }
    366 
    367                 return isPolyType( type, tyVars, env );
    368         }
    369171
    370172ast::Type const * hasPolyBase(
     
    388190}
    389191
    390         bool includesPolyType( Type *type, const TypeSubstitution *env ) {
    391                 type = replaceTypeInst( type, env );
    392 
    393                 if ( dynamic_cast< TypeInstType * >( type ) ) {
    394                         return true;
    395                 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {
    396                         if ( includesPolyType( pointerType->get_base(), env ) ) return true;
    397                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    398                         if ( includesPolyParams( structType->get_parameters(), env ) ) return true;
    399                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    400                         if ( includesPolyParams( unionType->get_parameters(), env ) ) return true;
    401                 }
    402                 return false;
    403         }
    404 
    405         bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    406                 type = replaceTypeInst( type, env );
    407 
    408                 if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) {
    409                         if ( tyVars.contains( typeInstType->get_name() ) ) {
    410                                 return true;
    411                         }
    412                 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {
    413                         if ( includesPolyType( pointerType->get_base(), tyVars, env ) ) return true;
    414                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    415                         if ( includesPolyParams( structType->get_parameters(), tyVars, env ) ) return true;
    416                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    417                         if ( includesPolyParams( unionType->get_parameters(), tyVars, env ) ) return true;
    418                 }
    419                 return false;
    420         }
    421 
    422         FunctionType * getFunctionType( Type *ty ) {
    423                 PointerType *ptrType;
    424                 if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) {
    425                         return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise
    426                 } else {
    427                         return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise
    428                 }
    429         }
    430 
    431192        const ast::FunctionType * getFunctionType( const ast::Type * ty ) {
    432193                if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) {
     
    437198        }
    438199
    439         VariableExpr * getBaseVar( Expression *expr, int *levels ) {
    440                 int dummy;
    441                 if ( ! levels ) { levels = &dummy; }
    442                 *levels = 0;
    443 
    444                 while ( true ) {
    445                         if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) {
    446                                 return varExpr;
    447                         } else if ( MemberExpr *memberExpr = dynamic_cast< MemberExpr* >( expr ) ) {
    448                                 expr = memberExpr->get_aggregate();
    449                         } else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) {
    450                                 expr = addressExpr->get_arg();
    451                         } else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) {
    452                                 // look for compiler-inserted dereference operator
    453                                 NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() );
    454                                 if ( ! fn || fn->get_name() != std::string("*?") ) return 0;
    455                                 expr = *untypedExpr->begin_args();
    456                         } else if ( CommaExpr *commaExpr = dynamic_cast< CommaExpr* >( expr ) ) {
    457                                 // copy constructors insert comma exprs, look at second argument which contains the variable
    458                                 expr = commaExpr->get_arg2();
    459                                 continue;
    460                         } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( expr ) ) {
    461                                 int lvl1;
    462                                 int lvl2;
    463                                 VariableExpr * var1 = getBaseVar( condExpr->get_arg2(), &lvl1 );
    464                                 VariableExpr * var2 = getBaseVar( condExpr->get_arg3(), &lvl2 );
    465                                 if ( lvl1 == lvl2 && var1 && var2 && var1->get_var() == var2->get_var() ) {
    466                                         *levels = lvl1;
    467                                         return var1;
    468                                 }
    469                                 break;
    470                         } else break;
    471 
    472                         ++(*levels);
    473                 }
    474 
    475                 return 0;
    476         }
    477 
    478200        namespace {
    479201                /// Checks if is a pointer to D
     
    488210                inline D const * as( B const * p ) {
    489211                        return reinterpret_cast<D const *>( p );
    490                 }
    491 
    492                 /// Flattens a declaration list
    493                 template<typename Output>
    494                 void flattenList( list< DeclarationWithType* > src, Output out ) {
    495                         for ( DeclarationWithType* decl : src ) {
    496                                 ResolvExpr::flatten( decl->get_type(), out );
    497                         }
    498                 }
    499 
    500                 /// Flattens a list of types
    501                 template<typename Output>
    502                 void flattenList( list< Type* > src, Output out ) {
    503                         for ( Type* ty : src ) {
    504                                 ResolvExpr::flatten( ty, out );
    505                         }
    506212                }
    507213
     
    515221                }
    516222
    517                 /// Checks if two lists of parameters are equal up to polymorphic substitution.
    518                 bool paramListsPolyCompatible( const list< Expression* >& aparams, const list< Expression* >& bparams ) {
    519                         if ( aparams.size() != bparams.size() ) return false;
    520 
    521                         for ( list< Expression* >::const_iterator at = aparams.begin(), bt = bparams.begin();
    522                                         at != aparams.end(); ++at, ++bt ) {
    523                                 TypeExpr *aparam = dynamic_cast< TypeExpr* >(*at);
    524                                 assertf(aparam, "Aggregate parameters should be type expressions");
    525                                 TypeExpr *bparam = dynamic_cast< TypeExpr* >(*bt);
    526                                 assertf(bparam, "Aggregate parameters should be type expressions");
    527 
    528                                 // xxx - might need to let VoidType be a wildcard here too; could have some voids
    529                                 // stuffed in for dtype-statics.
    530                                 // if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue;
    531                                 if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false;
    532                         }
    533 
    534                         return true;
    535                 }
    536 
    537223                bool paramListsPolyCompatible(
    538224                                std::vector<ast::ptr<ast::Expr>> const & lparams,
     
    559245                        return true;
    560246                }
    561         }
    562 
    563         bool typesPolyCompatible( Type *a, Type *b ) {
    564                 type_index aid{ typeid(*a) };
    565                 // polymorphic types always match
    566                 if ( aid == type_index{typeid(TypeInstType)} ) return true;
    567 
    568                 type_index bid{ typeid(*b) };
    569                 // polymorphic types always match
    570                 if ( bid == type_index{typeid(TypeInstType)} ) return true;
    571 
    572                 // can't match otherwise if different types
    573                 if ( aid != bid ) return false;
    574 
    575                 // recurse through type structure (conditions borrowed from Unify.cc)
    576                 if ( aid == type_index{typeid(BasicType)} ) {
    577                         return as<BasicType>(a)->get_kind() == as<BasicType>(b)->get_kind();
    578                 } else if ( aid == type_index{typeid(PointerType)} ) {
    579                         PointerType *ap = as<PointerType>(a), *bp = as<PointerType>(b);
    580 
    581                         // void pointers should match any other pointer type
    582                         return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
    583                                 || typesPolyCompatible( ap->get_base(), bp->get_base() );
    584                 } else if ( aid == type_index{typeid(ReferenceType)} ) {
    585                         ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b);
    586                         return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
    587                                 || typesPolyCompatible( ap->get_base(), bp->get_base() );
    588                 } else if ( aid == type_index{typeid(ArrayType)} ) {
    589                         ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b);
    590 
    591                         if ( aa->get_isVarLen() ) {
    592                                 if ( ! ba->get_isVarLen() ) return false;
    593                         } else {
    594                                 if ( ba->get_isVarLen() ) return false;
    595 
    596                                 ConstantExpr *ad = dynamic_cast<ConstantExpr*>( aa->get_dimension() );
    597                                 ConstantExpr *bd = dynamic_cast<ConstantExpr*>( ba->get_dimension() );
    598                                 if ( ad && bd
    599                                                 && ad->get_constant()->get_value() != bd->get_constant()->get_value() )
    600                                         return false;
    601                         }
    602 
    603                         return typesPolyCompatible( aa->get_base(), ba->get_base() );
    604                 } else if ( aid == type_index{typeid(FunctionType)} ) {
    605                         FunctionType *af = as<FunctionType>(a), *bf = as<FunctionType>(b);
    606 
    607                         vector<Type*> aparams, bparams;
    608                         flattenList( af->get_parameters(), back_inserter( aparams ) );
    609                         flattenList( bf->get_parameters(), back_inserter( bparams ) );
    610                         if ( aparams.size() != bparams.size() ) return false;
    611 
    612                         vector<Type*> areturns, breturns;
    613                         flattenList( af->get_returnVals(), back_inserter( areturns ) );
    614                         flattenList( bf->get_returnVals(), back_inserter( breturns ) );
    615                         if ( areturns.size() != breturns.size() ) return false;
    616 
    617                         for ( unsigned i = 0; i < aparams.size(); ++i ) {
    618                                 if ( ! typesPolyCompatible( aparams[i], bparams[i] ) ) return false;
    619                         }
    620                         for ( unsigned i = 0; i < areturns.size(); ++i ) {
    621                                 if ( ! typesPolyCompatible( areturns[i], breturns[i] ) ) return false;
    622                         }
    623                         return true;
    624                 } else if ( aid == type_index{typeid(StructInstType)} ) {
    625                         StructInstType *aa = as<StructInstType>(a), *ba = as<StructInstType>(b);
    626 
    627                         if ( aa->get_name() != ba->get_name() ) return false;
    628                         return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );
    629                 } else if ( aid == type_index{typeid(UnionInstType)} ) {
    630                         UnionInstType *aa = as<UnionInstType>(a), *ba = as<UnionInstType>(b);
    631 
    632                         if ( aa->get_name() != ba->get_name() ) return false;
    633                         return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );
    634                 } else if ( aid == type_index{typeid(EnumInstType)} ) {
    635                         return as<EnumInstType>(a)->get_name() == as<EnumInstType>(b)->get_name();
    636                 } else if ( aid == type_index{typeid(TraitInstType)} ) {
    637                         return as<TraitInstType>(a)->get_name() == as<TraitInstType>(b)->get_name();
    638                 } else if ( aid == type_index{typeid(TupleType)} ) {
    639                         TupleType *at = as<TupleType>(a), *bt = as<TupleType>(b);
    640 
    641                         vector<Type*> atypes, btypes;
    642                         flattenList( at->get_types(), back_inserter( atypes ) );
    643                         flattenList( bt->get_types(), back_inserter( btypes ) );
    644                         if ( atypes.size() != btypes.size() ) return false;
    645 
    646                         for ( unsigned i = 0; i < atypes.size(); ++i ) {
    647                                 if ( ! typesPolyCompatible( atypes[i], btypes[i] ) ) return false;
    648                         }
    649                         return true;
    650                 } else return true; // VoidType, VarArgsType, ZeroType & OneType just need the same type
    651247        }
    652248
     
    763359}
    764360
    765         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
    766                 // is parameter is not polymorphic, don't need to box
    767                 if ( ! isPolyType( param, exprTyVars ) ) return false;
    768                 Type * newType = arg->clone();
    769                 if ( env ) env->apply( newType );
    770                 std::unique_ptr<Type> manager( newType );
    771                 // if the argument's type is polymorphic, we don't need to box again!
    772                 return ! isPolyType( newType );
    773         }
    774 
    775361bool needsBoxing( const ast::Type * param, const ast::Type * arg,
    776362                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    786372        return !isPolyType( newType );
    787373}
    788 
    789         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
    790                 FunctionType * function = getFunctionType( appExpr->function->result );
    791                 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );
    792                 TyVarMap exprTyVars( TypeDecl::Data{} );
    793                 makeTyVarMap( function, exprTyVars );
    794                 return needsBoxing( param, arg, exprTyVars, env );
    795         }
    796374
    797375bool needsBoxing(
     
    801379        const ast::FunctionType * function = getFunctionType( expr->func->result );
    802380        assertf( function, "ApplicationExpr has non-function type: %s", toString( expr->func->result ).c_str() );
    803         TypeVarMap exprTyVars = { ast::TypeData() };
     381        TypeVarMap exprTyVars;
    804382        makeTypeVarMap( function, exprTyVars );
    805383        return needsBoxing( param, arg, exprTyVars, subst );
    806384}
    807385
    808         void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    809                 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
    810         }
    811 
    812386void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) {
    813387        typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) );
     
    817391        typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) );
    818392}
    819 
    820         void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
    821                 for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
    822                         assert( *tyVar );
    823                         addToTyVarMap( *tyVar, tyVarMap );
    824                 }
    825                 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
    826                         makeTyVarMap( pointer->get_base(), tyVarMap );
    827                 }
    828         }
    829393
    830394void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) {
     
    846410}
    847411
    848         void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
    849                 for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {
    850                         os << i->first << " (" << i->second << ") ";
    851                 } // for
    852                 os << std::endl;
    853         }
    854 
    855412} // namespace GenPoly
    856413
  • src/GenPoly/GenPoly.h

    r0030b508 rfc12f05  
    2323#include "AST/Fwd.hpp"            // for ApplicationExpr, BaseInstType, Func...
    2424#include "SymTab/Mangler.h"       // for Mangler
    25 #include "SynTree/Declaration.h"  // for TypeDecl::Data, AggregateDecl, Type...
    26 #include "SynTree/SynTree.h"      // for Visitor Nodes
    2725
    2826namespace ast {
     
    3230namespace GenPoly {
    3331
    34         typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    35         using TypeVarMap = ErasableScopedMap< ast::TypeEnvKey, ast::TypeData >;
     32        struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> {
     33                TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {}
     34        };
    3635
    3736        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    38         Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
    39         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env );
    4037        const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * );
    4138
    4239        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
    43         Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );
    4440        const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);
    4541
    4642        /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    47         Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    4843        const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr );
    4944
    5045        /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
    51         ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    5246        const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 );
    5347
    5448        /// true iff function has dynamic-layout return type under the given type variable map
    55         ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );
    5649        const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars );
    5750
    5851        /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
    59         ReferenceToType *isDynRet( FunctionType *function );
    6052        const ast::BaseInstType *isDynRet( const ast::FunctionType * func );
    6153
    6254        /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type
    63         bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVarr );
    6455        bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars );
    6556
    66         /// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided
    67         Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 );
    68 
    6957        /// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    70         Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    7158        const ast::Type * isPolyPtr( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * env = 0 );
    72 
    73         /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise;
    74         /// N will be stored in levels, if provided, will look up substitution in env if provided
    75         Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 );
    7659
    7760        /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise;
    7861        /// N will be stored in levels, if provided, will look up substitution in env if provided
    79         Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 );
    8062        const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 );
    8163
    82         /// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one
    83         /// polymorphic parameter; will look up substitution in env if provided.
    84         bool includesPolyType( Type *type, const TypeSubstitution *env = 0 );
    85 
    86         /// true iff this type or some base of this type after dereferencing pointers is either polymorphic in tyVars, or a generic type with
    87         /// at least one polymorphic parameter in tyVars; will look up substitution in env if provided.
    88         bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    89 
    9064        /// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise
    91         FunctionType *getFunctionType( Type *ty );
    9265        const ast::FunctionType * getFunctionType( const ast::Type * ty );
    9366
    94         /// If expr (after dereferencing N >= 0 pointers) is a variable expression, returns the variable expression, NULL otherwise;
    95         /// N will be stored in levels, if provided
    96         VariableExpr *getBaseVar( Expression *expr, int *levels = 0 );
    97 
    9867        /// true iff types are structurally identical, where TypeInstType's match any type.
    99         bool typesPolyCompatible( Type *aty, Type *bty );
    10068        bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs );
    10169
    10270        /// true if arg requires boxing given exprTyVars
    103         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
    10471        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst );
    10572
    10673        /// true if arg requires boxing in the call to appExpr
    107         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
    10874        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst );
    10975
    11076        /// Adds the type variable `tyVar` to `tyVarMap`
    111         void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );
    11277        void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars );
    11378        void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars );
    11479
    11580        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    116         void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
    11781        void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
    11882        void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars );
    119 
    120         /// Prints type variable map
    121         void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
    122 
    123         /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().
    124         inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
    12583
    12684        /// Gets the name of the sizeof parameter for the type, given its mangled name
     
    13492
    13593        /// Gets the name of the layout function for a given aggregate type, given its declaration
    136         inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }
    13794        inline std::string layoutofName( ast::AggregateDecl const * decl ) {
    13895                return std::string( "_layoutof_" ) + decl->name;
  • src/GenPoly/ScrubTyVars.cc

    r0030b508 rfc12f05  
    2121#include "ScrubTyVars.h"
    2222#include "SymTab/Mangler.h"             // for mangleType
    23 #include "SynTree/Declaration.h"        // for TypeDecl, TypeDecl::Data, Typ...
    24 #include "SynTree/Expression.h"         // for Expression (ptr only), NameExpr
    25 #include "SynTree/Mutator.h"            // for Mutator
    26 #include "SynTree/Type.h"               // for PointerType, TypeInstType, Type
    2723
    2824namespace GenPoly {
    29         Type * ScrubTyVars::postmutate( TypeInstType * typeInst ) {
    30                 if ( ! tyVars ) {
    31                         if ( typeInst->get_isFtype() ) {
    32                                 delete typeInst;
    33                                 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
    34                         } else {
    35                                 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
    36                                 delete typeInst;
    37                                 return ret;
    38                         }
    39                 }
    40 
    41                 TyVarMap::const_iterator tyVar = tyVars->find( typeInst->name );
    42                 if ( tyVar != tyVars->end() ) {
    43                         switch ( tyVar->second.kind ) {
    44                           case TypeDecl::Dtype:
    45                           case TypeDecl::Ttype:
    46                                 {
    47                                         PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
    48                                         delete typeInst;
    49                                         return ret;
    50                                 }
    51                           case TypeDecl::Ftype:
    52                                 delete typeInst;
    53                                 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
    54                           default:
    55                                 assertf(false, "Unhandled tyvar kind: %d", tyVar->second.kind);
    56                         } // switch
    57                 } // if
    58                 return typeInst;
    59         }
    60 
    61         Type * ScrubTyVars::mutateAggregateType( Type * ty ) {
    62                 if ( shouldScrub( ty ) ) {
    63                         PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );
    64                         delete ty;
    65                         return ret;
    66                 }
    67                 return ty;
    68         }
    69 
    70         Type * ScrubTyVars::postmutate( StructInstType * structInst ) {
    71                 return mutateAggregateType( structInst );
    72         }
    73 
    74         Type * ScrubTyVars::postmutate( UnionInstType * unionInst ) {
    75                 return mutateAggregateType( unionInst );
    76         }
    77 
    78         void ScrubTyVars::primeBaseScrub( Type * type ) {
    79                 // need to determine whether type needs to be scrubbed to determine whether
    80                 // automatic recursion is necessary
    81                 if ( Type * t = shouldScrub( type ) ) {
    82                         visit_children = false;
    83                         GuardValue( dynType );
    84                         dynType = t;
    85                 }
    86         }
    87 
    88         Expression * ScrubTyVars::postmutate( SizeofExpr * szeof ) {
    89                 // sizeof( T ) => _sizeof_T parameter, which is the size of T
    90                 if ( dynType ) {
    91                         Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );
    92                         return expr;
    93                 } // if
    94                 return szeof;
    95         }
    96 
    97         Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) {
    98                 // alignof( T ) => _alignof_T parameter, which is the alignment of T
    99                 if ( dynType ) {
    100                         Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );
    101                         return expr;
    102                 } // if
    103                 return algnof;
    104         }
    105 
    106         Type * ScrubTyVars::postmutate( PointerType * pointer ) {
    107                 if ( dynType ) {
    108                         Type * ret = dynType->acceptMutator( *visitor );
    109                         ret->get_qualifiers() |= pointer->get_qualifiers();
    110                         pointer->base = nullptr;
    111                         delete pointer;
    112                         return ret;
    113                 }
    114                 return pointer;
    115         }
    11625
    11726namespace {
  • src/GenPoly/ScrubTyVars.h

    r0030b508 rfc12f05  
    1919
    2020#include "AST/Fwd.hpp"        // for Node
    21 #include "Common/PassVisitor.h"
    2221#include "GenPoly.h"          // for TyVarMap, isPolyType, isDynType
    23 #include "SynTree/Mutator.h"  // for Mutator
    24 #include "SynTree/Type.h"     // for Type (ptr only), PointerType (ptr only)
    25 
    26 class AlignofExpr;
    27 class Expression;
    28 class SizeofExpr;
    2922
    3023namespace GenPoly {
    31         struct ScrubTyVars : public WithVisitorRef<ScrubTyVars>, public WithShortCircuiting, public WithGuards {
    32                 /// Whether to scrub all type variables from the provided map, dynamic type variables from the provided map, or all type variables
    33                 enum ScrubMode { FromMap, DynamicFromMap, All };
    34 
    35                 ScrubTyVars() : tyVars(nullptr), mode( All ) {}
    36 
    37                 ScrubTyVars( const TyVarMap &tyVars, ScrubMode mode = FromMap ): tyVars( &tyVars ), mode( mode ) {}
    38 
    39         public:
    40                 /// For all polymorphic types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,
    41                 /// and sizeof/alignof expressions with the proper variable
    42                 template< typename SynTreeClass >
    43                 static SynTreeClass *scrub( SynTreeClass *target, const TyVarMap &tyVars );
    44 
    45                 /// For all dynamic-layout types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,
    46                 /// and sizeof/alignof expressions with the proper variable
    47                 template< typename SynTreeClass >
    48                 static SynTreeClass *scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars );
    49 
    50                 /// For all polymorphic types, replaces generic types, dtypes, and ftypes with the appropriate void type,
    51                 /// and sizeof/alignof expressions with the proper variable
    52                 template< typename SynTreeClass >
    53                 static SynTreeClass *scrubAll( SynTreeClass *target );
    54 
    55                 /// determine if children should be visited based on whether base type should be scrubbed.
    56                 void primeBaseScrub( Type * );
    57 
    58                 void premutate( TypeInstType * ) { visit_children = false; }
    59                 void premutate( StructInstType * ) { visit_children = false; }
    60                 void premutate( UnionInstType * ) { visit_children = false; }
    61                 void premutate( SizeofExpr * szeof ) { primeBaseScrub( szeof->type ); }
    62                 void premutate( AlignofExpr * algnof ) { primeBaseScrub( algnof->type ); }
    63                 void premutate( PointerType * pointer ) { primeBaseScrub( pointer->base ); }
    64 
    65                 Type * postmutate( TypeInstType * typeInst );
    66                 Type * postmutate( StructInstType * structInst );
    67                 Type * postmutate( UnionInstType * unionInst );
    68                 Expression * postmutate( SizeofExpr * szeof );
    69                 Expression * postmutate( AlignofExpr * algnof );
    70                 Type * postmutate( PointerType * pointer );
    71 
    72           private:
    73                 /// Returns the type if it should be scrubbed, NULL otherwise.
    74                 Type* shouldScrub( Type *ty ) {
    75                         switch ( mode ) {
    76                         case FromMap: return isPolyType( ty, *tyVars );
    77                         case DynamicFromMap: return isDynType( ty, *tyVars );
    78                         case All: return isPolyType( ty );
    79                         }
    80                         assert(false); return nullptr; // unreachable
    81                         // return dynamicOnly ? isDynType( ty, tyVars ) : isPolyType( ty, tyVars );
    82                 }
    83 
    84                 /// Mutates (possibly generic) aggregate types appropriately
    85                 Type* mutateAggregateType( Type *ty );
    86 
    87                 const TyVarMap *tyVars;  ///< Type variables to scrub
    88                 ScrubMode mode;          ///< which type variables to scrub? [FromMap]
    89 
    90                 Type * dynType = nullptr; ///< result of shouldScrub
    91         };
    92 
    93         template< typename SynTreeClass >
    94         SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) {
    95                 PassVisitor<ScrubTyVars> scrubber( tyVars );
    96                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    97         }
    98 
    99         template< typename SynTreeClass >
    100         SynTreeClass * ScrubTyVars::scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ) {
    101                 PassVisitor<ScrubTyVars> scrubber( tyVars, ScrubTyVars::DynamicFromMap );
    102                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    103         }
    104 
    105         template< typename SynTreeClass >
    106         SynTreeClass * ScrubTyVars::scrubAll( SynTreeClass *target ) {
    107                 PassVisitor<ScrubTyVars> scrubber;
    108                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    109         }
    11024
    11125// ScrubMode and scrubTypeVarsBase are internal.
  • src/GenPoly/SpecializeNew.cpp

    r0030b508 rfc12f05  
    2323#include "GenPoly/GenPoly.h"             // for getFunctionType
    2424#include "ResolvExpr/FindOpenVars.h"     // for findOpenVars
    25 #include "ResolvExpr/TypeEnvironment.h"  // for FirstOpen, FirstClosed
    2625
    2726namespace GenPoly {
     
    8180}
    8281
    83 // The number of elements in a type if it is a flattened tuple.
    84 size_t flatTupleSize( const ast::Type * type ) {
    85         if ( auto tuple = dynamic_cast<const ast::TupleType *>( type ) ) {
    86                 size_t sum = 0;
    87                 for ( auto t : *tuple ) {
    88                         sum += flatTupleSize( t );
    89                 }
    90                 return sum;
    91         } else {
    92                 return 1;
    93         }
     82// The number of elements in a list, if all tuples had been flattened.
     83size_t flatTypeListSize( const std::vector<ast::ptr<ast::Type>> & types ) {
     84        size_t sum = 0;
     85        for ( const ast::ptr<ast::Type> & type : types ) {
     86                if ( const ast::TupleType * tuple = type.as<ast::TupleType>() ) {
     87                        sum += flatTypeListSize( tuple->types );
     88                } else {
     89                        sum += 1;
     90                }
     91        }
     92        return sum;
    9493}
    9594
    9695// Find the total number of components in a parameter list.
    9796size_t functionParameterSize( const ast::FunctionType * type ) {
    98         size_t sum = 0;
    99         for ( auto param : type->params ) {
    100                 sum += flatTupleSize( param );
    101         }
    102         return sum;
     97        return flatTypeListSize( type->params );
    10398}
    10499
  • src/GenPoly/module.mk

    r0030b508 rfc12f05  
    2323SRC += $(SRC_GENPOLY) \
    2424        GenPoly/BoxNew.cpp \
    25         GenPoly/Box.cc \
    2625        GenPoly/Box.h \
    2726        GenPoly/ErasableScopedMap.h \
     
    2928        GenPoly/FindFunction.h \
    3029        GenPoly/InstantiateGenericNew.cpp \
    31         GenPoly/InstantiateGeneric.cc \
    3230        GenPoly/InstantiateGeneric.h \
    3331        GenPoly/LvalueNew.cpp \
    34         GenPoly/Lvalue.cc \
    3532        GenPoly/ScopedSet.h \
    3633        GenPoly/ScrubTyVars.cc \
    3734        GenPoly/ScrubTyVars.h \
    38         GenPoly/Specialize.cc \
    3935        GenPoly/SpecializeNew.cpp \
    4036        GenPoly/Specialize.h
  • src/InitTweak/FixGlobalInit.cc

    r0030b508 rfc12f05  
    2020#include <algorithm>               // for replace_if
    2121
    22 #include "Common/PassVisitor.h"
    23 #include "Common/UniqueName.h"     // for UniqueName
    24 #include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    25 #include "SynTree/LinkageSpec.h"   // for C
    26 #include "SynTree/Attribute.h"     // for Attribute
    27 #include "SynTree/Constant.h"      // for Constant
    28 #include "SynTree/Declaration.h"   // for FunctionDecl, ObjectDecl, Declaration
    29 #include "SynTree/Expression.h"    // for ConstantExpr, Expression (ptr only)
    30 #include "SynTree/Initializer.h"   // for ConstructorInit, Initializer
    31 #include "SynTree/Label.h"         // for Label
    32 #include "SynTree/Statement.h"     // for CompoundStmt, Statement (ptr only)
    33 #include "SynTree/Type.h"          // for Type, Type::StorageClasses, Functi...
    34 #include "SynTree/Visitor.h"       // for acceptAll, Visitor
    35 
    3622#include "AST/Expr.hpp"
    3723#include "AST/Node.hpp"
    3824#include "AST/Pass.hpp"
     25#include "Common/UniqueName.h"     // for UniqueName
     26#include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    3927
    4028namespace InitTweak {
    41         class GlobalFixer : public WithShortCircuiting {
    42           public:
    43                 GlobalFixer( bool inLibrary );
    44 
    45                 void previsit( ObjectDecl *objDecl );
    46                 void previsit( FunctionDecl *functionDecl );
    47                 void previsit( StructDecl *aggregateDecl );
    48                 void previsit( UnionDecl *aggregateDecl );
    49                 void previsit( EnumDecl *aggregateDecl );
    50                 void previsit( TraitDecl *aggregateDecl );
    51                 void previsit( TypeDecl *typeDecl );
    52 
    53                 UniqueName tempNamer;
    54                 FunctionDecl * initFunction;
    55                 FunctionDecl * destroyFunction;
    56         };
    57 
    5829        class GlobalFixer_new : public ast::WithShortCircuiting {
    5930        public:
     
    6940                std::list< ast::ptr<ast::Stmt> > destroyStmts;
    7041        };
    71 
    72         void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ) {
    73                 PassVisitor<GlobalFixer> visitor( inLibrary );
    74                 acceptAll( translationUnit, visitor );
    75                 GlobalFixer & fixer = visitor.pass;
    76                 // don't need to include function if it's empty
    77                 if ( fixer.initFunction->get_statements()->get_kids().empty() ) {
    78                         delete fixer.initFunction;
    79                 } else {
    80                         translationUnit.push_back( fixer.initFunction );
    81                 } // if
    82 
    83                 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) {
    84                         delete fixer.destroyFunction;
    85                 } else {
    86                         translationUnit.push_back( fixer.destroyFunction );
    87                 } // if
    88         }
    89 
    90         GlobalFixer::GlobalFixer( bool inLibrary ) : tempNamer( "_global_init" ) {
    91                 std::list< Expression * > ctorParameters;
    92                 std::list< Expression * > dtorParameters;
    93                 if ( inLibrary ) {
    94                         // Constructor/destructor attributes take a single parameter which
    95                         // is the priority, with lower numbers meaning higher priority.
    96                         // Functions specified with priority are guaranteed to run before
    97                         // functions without a priority. To ensure that constructors and destructors
    98                         // for library code are run before constructors and destructors for user code,
    99                         // specify a priority when building the library. Priorities 0-100 are reserved by gcc.
    100                         // Priorities 101-200 are reserved by cfa, so use priority 200 for CFA library globals,
    101                         // allowing room for overriding with a higher priority.
    102                         ctorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );
    103                         dtorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );
    104                 }
    105                 initFunction = new FunctionDecl( "__global_init__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );
    106                 initFunction->get_attributes().push_back( new Attribute( "constructor", ctorParameters ) );
    107                 destroyFunction = new FunctionDecl( "__global_destroy__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );
    108                 destroyFunction->get_attributes().push_back( new Attribute( "destructor", dtorParameters ) );
    109         }
    11042
    11143        void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
     
    14173        }
    14274
    143         void GlobalFixer::previsit( ObjectDecl *objDecl ) {
    144                 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();
    145                 std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids();
    146 
    147                 // C allows you to initialize objects with constant expressions
    148                 // xxx - this is an optimization. Need to first resolve constructors before we decide
    149                 // to keep C-style initializer.
    150                 // if ( isConstExpr( objDecl->get_init() ) ) return;
    151 
    152                 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
    153                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    154                         assert( ! ctorInit->ctor || ! ctorInit->init );
    155 
    156                         Statement * dtor = ctorInit->dtor;
    157                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    158                                 // don't need to call intrinsic dtor, because it does nothing, but
    159                                 // non-intrinsic dtors must be called
    160                                 destroyStatements.push_front( dtor );
    161                                 ctorInit->dtor = nullptr;
    162                         } // if
    163                         if ( Statement * ctor = ctorInit->ctor ) {
    164                                 addDataSectionAttribute( objDecl );
    165                                 initStatements.push_back( ctor );
    166                                 objDecl->init = nullptr;
    167                                 ctorInit->ctor = nullptr;
    168                         } else if ( Initializer * init = ctorInit->init ) {
    169                                 objDecl->init = init;
    170                                 ctorInit->init = nullptr;
    171                         } else {
    172                                 // no constructor and no initializer, which is okay
    173                                 objDecl->init = nullptr;
    174                         } // if
    175                         delete ctorInit;
    176                 } // if
    177         }
    178 
    17975        void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) {
    18076                auto mutDecl = mutate(objDecl);
     
    207103        }
    208104
    209         // only modify global variables
    210         void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }
    211         void GlobalFixer::previsit( StructDecl * ) { visit_children = false; }
    212         void GlobalFixer::previsit( UnionDecl * ) { visit_children = false; }
    213         void GlobalFixer::previsit( EnumDecl * ) { visit_children = false; }
    214         void GlobalFixer::previsit( TraitDecl * ) { visit_children = false; }
    215         void GlobalFixer::previsit( TypeDecl * ) { visit_children = false; }
    216 
    217105} // namespace InitTweak
    218106
  • src/InitTweak/FixInitNew.cpp

    r0030b508 rfc12f05  
    3333#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3434
    35 extern bool ctordtorp; // print all debug
    36 extern bool ctorp; // print ctor debug
    37 extern bool cpctorp; // print copy ctor debug
    38 extern bool dtorp; // print dtor debug
     35bool ctordtorp = false; // print all debug
     36bool ctorp = false; // print ctor debug
     37bool cpctorp = false; // print copy ctor debug
     38bool dtorp = false; // print dtor debug
    3939#define PRINT( text ) if ( ctordtorp ) { text }
    4040#define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text }
     
    178178/// (currently by FixInit)
    179179struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> {
    180         typedef std::list< ObjectDecl * > OrderedDecls;
    181         typedef std::list< OrderedDecls > OrderedDeclsStack;
    182 
    183180        InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {}
    184181
     
    194191        ast::Pass<LabelFinder> & finder;
    195192        LabelFinder::LabelMap & labelVars;
    196         OrderedDeclsStack reverseDeclOrder;
    197193};
    198194
  • src/InitTweak/GenInit.cc

    r0030b508 rfc12f05  
    2929#include "CompilationState.h"
    3030#include "CodeGen/OperatorTable.h"
    31 #include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
    3231#include "Common/SemanticError.h"      // for SemanticError
    3332#include "Common/ToString.hpp"         // for toCString
     
    3837#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
    3938#include "ResolvExpr/Resolver.h"
    40 #include "SymTab/Autogen.h"            // for genImplicitCall
    4139#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4240#include "SymTab/Mangler.h"            // for Mangler
    43 #include "SynTree/LinkageSpec.h"       // for isOverridable, C
    44 #include "SynTree/Declaration.h"       // for ObjectDecl, DeclarationWithType
    45 #include "SynTree/Expression.h"        // for VariableExpr, UntypedExpr, Address...
    46 #include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit, Initi...
    47 #include "SynTree/Label.h"             // for Label
    48 #include "SynTree/Mutator.h"           // for mutateAll
    49 #include "SynTree/Statement.h"         // for CompoundStmt, ImplicitCtorDtorStmt
    50 #include "SynTree/Type.h"              // for Type, ArrayType, Type::Qualifiers
    51 #include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    5241#include "Tuples/Tuples.h"             // for maybeImpure
    5342#include "Validate/FindSpecialDecls.h" // for SizeType
    5443
    5544namespace InitTweak {
    56         namespace {
    57                 const std::list<Label> noLabels;
    58                 const std::list<Expression *> noDesignators;
    59         }
    60 
    61         struct ReturnFixer : public WithStmtsToAdd, public WithGuards {
    62                 /// consistently allocates a temporary variable for the return value
    63                 /// of a function so that anything which the resolver decides can be constructed
    64                 /// into the return type of a function can be returned.
    65                 static void makeReturnTemp( std::list< Declaration * > &translationUnit );
    66 
    67                 void premutate( FunctionDecl *functionDecl );
    68                 void premutate( ReturnStmt * returnStmt );
    69 
    70           protected:
    71                 FunctionType * ftype = nullptr;
    72                 std::string funcName;
    73         };
    74 
    75         struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor>  {
    76                 /// create constructor and destructor statements for object declarations.
    77                 /// the actual call statements will be added in after the resolver has run
    78                 /// so that the initializer expression is only removed if a constructor is found
    79                 /// and the same destructor call is inserted in all of the appropriate locations.
    80                 static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    81 
    82                 void previsit( ObjectDecl * );
    83                 void previsit( FunctionDecl *functionDecl );
    84 
    85                 // should not traverse into any of these declarations to find objects
    86                 // that need to be constructed or destructed
    87                 void previsit( StructDecl *aggregateDecl );
    88                 void previsit( AggregateDecl * ) { visit_children = false; }
    89                 void previsit( NamedTypeDecl * ) { visit_children = false; }
    90                 void previsit( FunctionType * ) { visit_children = false; }
    91 
    92                 void previsit( CompoundStmt * compoundStmt );
    93 
    94           private:
    95                 // set of mangled type names for which a constructor or destructor exists in the current scope.
    96                 // these types require a ConstructorInit node to be generated, anything else is a POD type and thus
    97                 // should not have a ConstructorInit generated.
    98 
    99                 ManagedTypes managedTypes;
    100                 bool inFunction = false;
    101         };
    102 
    103         struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {
    104                 /// hoist dimension from array types in object declaration so that it uses a single
    105                 /// const variable of type size_t, so that side effecting array dimensions are only
    106                 /// computed once.
    107                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    108 
    109                 void premutate( ObjectDecl * objectDecl );
    110                 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
    111                 void premutate( FunctionDecl *functionDecl );
    112                 // should not traverse into any of these declarations to find objects
    113                 // that need to be constructed or destructed
    114                 void premutate( AggregateDecl * ) { visit_children = false; }
    115                 void premutate( NamedTypeDecl * ) { visit_children = false; }
    116                 void premutate( FunctionType * ) { visit_children = false; }
    117 
    118                 // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)
    119                 void premutate( EnumDecl * ) {}
    120 
    121                 void hoist( Type * type );
    122 
    123                 Type::StorageClasses storageClasses;
    124                 bool inFunction = false;
    125         };
    126 
    127         struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
    128                 /// hoist dimension from array types in object declaration so that it uses a single
    129                 /// const variable of type size_t, so that side effecting array dimensions are only
    130                 /// computed once.
    131                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    132 
    133                 void premutate( ObjectDecl * objectDecl );
    134                 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
    135                 void premutate( FunctionDecl *functionDecl );
    136                 // should not traverse into any of these declarations to find objects
    137                 // that need to be constructed or destructed
    138                 void premutate( AggregateDecl * ) { visit_children = false; }
    139                 void premutate( NamedTypeDecl * ) { visit_children = false; }
    140                 void premutate( FunctionType * ) { visit_children = false; }
    141 
    142                 void hoist( Type * type );
    143 
    144                 Type::StorageClasses storageClasses;
    145                 bool inFunction = false;
    146         };
    147 
    148         void genInit( std::list< Declaration * > & translationUnit ) {
    149                 if (!useNewAST) {
    150                         HoistArrayDimension::hoistArrayDimension( translationUnit );
    151                 }
    152                 else {
    153                         HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
    154                 }
    155                 fixReturnStatements( translationUnit );
    156 
    157                 if (!useNewAST) {
    158                         CtorDtor::generateCtorDtor( translationUnit );
    159                 }
    160         }
    161 
    162         void fixReturnStatements( std::list< Declaration * > & translationUnit ) {
    163                 PassVisitor<ReturnFixer> fixer;
    164                 mutateAll( translationUnit, fixer );
    165         }
    166 
    167         void ReturnFixer::premutate( ReturnStmt *returnStmt ) {
    168                 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    169                 assert( returnVals.size() == 0 || returnVals.size() == 1 );
    170                 // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address
    171                 // is being returned
    172                 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {
    173                         // explicitly construct the return value using the return expression and the retVal object
    174                         assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() );
    175 
    176                         ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() );
    177                         if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) {
    178                                 // return statement has already been mutated - don't need to do it again
    179                                 if ( varExpr->var == retVal ) return;
    180                         }
    181                         Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );
    182                         assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );
    183                         stmtsToAddBefore.push_back( stmt );
    184 
    185                         // return the retVal object
    186                         returnStmt->expr = new VariableExpr( returnVals.front() );
    187                 } // if
    188         }
    189 
    190         void ReturnFixer::premutate( FunctionDecl *functionDecl ) {
    191                 GuardValue( ftype );
    192                 GuardValue( funcName );
    193 
    194                 ftype = functionDecl->type;
    195                 funcName = functionDecl->name;
    196         }
    197 
    198         // precompute array dimension expression, because constructor generation may duplicate it,
    199         // which would be incorrect if it is a side-effecting computation.
    200         void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    201                 PassVisitor<HoistArrayDimension> hoister;
    202                 mutateAll( translationUnit, hoister );
    203         }
    204 
    205         void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) {
    206                 GuardValue( storageClasses );
    207                 storageClasses = objectDecl->get_storageClasses();
    208         }
    209 
    210         DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) {
    211                 hoist( objectDecl->get_type() );
    212                 return objectDecl;
    213         }
    214 
    215         void HoistArrayDimension::hoist( Type * type ) {
    216                 // if in function, generate const size_t var
    217                 static UniqueName dimensionName( "_array_dim" );
    218 
    219                 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
    220                 if ( ! inFunction ) return;
    221                 if ( storageClasses.is_static ) return;
    222 
    223                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    224                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    225 
    226                         // need to resolve array dimensions in order to accurately determine if constexpr
    227                         ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
    228                         // array is variable-length when the dimension is not constexpr
    229                         arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
    230                         // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    231                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    232                         // still try to detect constant expressions
    233                         if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    234 
    235                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    236                         arrayDimension->get_type()->set_const( true );
    237 
    238                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    239                         declsToAddBefore.push_back( arrayDimension );
    240 
    241                         hoist( arrayType->get_base() );
    242                         return;
    243                 }
    244         }
    245 
    246         void HoistArrayDimension::premutate( FunctionDecl * ) {
    247                 GuardValue( inFunction );
    248                 inFunction = true;
    249         }
    250 
    251         // precompute array dimension expression, because constructor generation may duplicate it,
    252         // which would be incorrect if it is a side-effecting computation.
    253         void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    254                 PassVisitor<HoistArrayDimension_NoResolve> hoister;
    255                 mutateAll( translationUnit, hoister );
    256         }
    257 
    258         void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
    259                 GuardValue( storageClasses );
    260                 storageClasses = objectDecl->get_storageClasses();
    261         }
    262 
    263         DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
    264                 hoist( objectDecl->get_type() );
    265                 return objectDecl;
    266         }
    267 
    268         void HoistArrayDimension_NoResolve::hoist( Type * type ) {
    269                 // if in function, generate const size_t var
    270                 static UniqueName dimensionName( "_array_dim" );
    271 
    272                 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
    273                 if ( ! inFunction ) return;
    274                 if ( storageClasses.is_static ) return;
    275 
    276                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    277                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    278                         // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    279                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    280                         // still try to detect constant expressions
    281                         if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    282 
    283                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    284                         arrayDimension->get_type()->set_const( true );
    285 
    286                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    287                         declsToAddBefore.push_back( arrayDimension );
    288 
    289                         hoist( arrayType->get_base() );
    290                         return;
    291                 }
    292         }
    293 
    294         void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
    295                 GuardValue( inFunction );
    296                 inFunction = true;
    297         }
    29845
    29946namespace {
     
    526273        }
    527274
    528         void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
    529                 PassVisitor<CtorDtor> ctordtor;
    530                 acceptAll( translationUnit, ctordtor );
    531         }
    532 
    533         bool ManagedTypes::isManaged( Type * type ) const {
    534                 // references are never constructed
    535                 if ( dynamic_cast< ReferenceType * >( type ) ) return false;
    536                 // need to clear and reset qualifiers when determining if a type is managed
    537                 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
    538                 type->get_qualifiers() = Type::Qualifiers();
    539                 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
    540                         // tuple is also managed if any of its components are managed
    541                         if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) {
    542                                 return true;
    543                         }
    544                 }
    545                 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
    546                 return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );
    547         }
    548 
    549         bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const {
    550                 Type * type = objDecl->get_type();
    551                 while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    552                         // must always construct VLAs with an initializer, since this is an error in C
    553                         if ( at->isVarLen && objDecl->init ) return true;
    554                         type = at->get_base();
    555                 }
    556                 return isManaged( type );
    557         }
    558 
    559         // why is this not just on FunctionDecl?
    560         void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
    561                 // if this function is a user-defined constructor or destructor, mark down the type as "managed"
    562                 if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) {
    563                         std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters();
    564                         assert( ! params.empty() );
    565                         Type * type = InitTweak::getPointerBase( params.front()->get_type() );
    566                         assert( type );
    567                         managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) );
    568                 }
    569         }
    570 
    571         void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) {
    572                 // don't construct members, but need to take note if there is a managed member,
    573                 // because that means that this type is also managed
    574                 for ( Declaration * member : aggregateDecl->get_members() ) {
    575                         if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
    576                                 if ( isManaged( field ) ) {
    577                                         // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
    578                                         // polymorphic constructors make generic types managed types
    579                                         StructInstType inst( Type::Qualifiers(), aggregateDecl );
    580                                         managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) );
    581                                         break;
    582                                 }
    583                         }
    584                 }
    585         }
    586 
    587         void ManagedTypes::beginScope() { managedTypes.beginScope(); }
    588         void ManagedTypes::endScope() { managedTypes.endScope(); }
    589 
    590275        bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
    591276                // references are never constructed
     
    647332        void ManagedTypes_new::endScope() { managedTypes.endScope(); }
    648333
    649         ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
    650                 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    651                 assertf( objDecl, "genCtorDtor passed null objDecl" );
    652                 std::list< Statement * > stmts;
    653                 InitExpander_old srcParam( maybeClone( arg ) );
    654                 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );
    655                 assert( stmts.size() <= 1 );
    656                 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
    657 
    658         }
    659 
    660334        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
    661335                assertf(objDecl, "genCtorDtor passed null objDecl");
    662336                InitExpander_new srcParam(arg);
    663337                return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
    664         }
    665 
    666         ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
    667                 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    668                 // for each constructable object
    669                 std::list< Statement * > ctor;
    670                 std::list< Statement * > dtor;
    671 
    672                 InitExpander_old srcParam( objDecl->get_init() );
    673                 InitExpander_old nullParam( (Initializer *)NULL );
    674                 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    675                 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    676 
    677                 // Currently genImplicitCall produces a single Statement - a CompoundStmt
    678                 // which  wraps everything that needs to happen. As such, it's technically
    679                 // possible to use a Statement ** in the above calls, but this is inherently
    680                 // unsafe, so instead we take the slightly less efficient route, but will be
    681                 // immediately informed if somehow the above assumption is broken. In this case,
    682                 // we could always wrap the list of statements at this point with a CompoundStmt,
    683                 // but it seems reasonable at the moment for this to be done by genImplicitCall
    684                 // itself. It is possible that genImplicitCall produces no statements (e.g. if
    685                 // an array type does not have a dimension). In this case, it's fine to ignore
    686                 // the object for the purposes of construction.
    687                 assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
    688                 if ( ctor.size() == 1 ) {
    689                         // need to remember init expression, in case no ctors exist
    690                         // if ctor does exist, want to use ctor expression instead of init
    691                         // push this decision to the resolver
    692                         assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    693                         return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
    694                 }
    695                 return nullptr;
    696         }
    697 
    698         void CtorDtor::previsit( ObjectDecl * objDecl ) {
    699                 managedTypes.handleDWT( objDecl );
    700                 // hands off if @=, extern, builtin, etc.
    701                 // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C
    702                 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {
    703                         // constructed objects cannot be designated
    704                         if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
    705                         // constructed objects should not have initializers nested too deeply
    706                         if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " );
    707 
    708                         objDecl->set_init( genCtorInit( objDecl ) );
    709                 }
    710         }
    711 
    712         void CtorDtor::previsit( FunctionDecl *functionDecl ) {
    713                 visit_children = false;  // do not try and construct parameters or forall parameters
    714                 GuardValue( inFunction );
    715                 inFunction = true;
    716 
    717                 managedTypes.handleDWT( functionDecl );
    718 
    719                 GuardScope( managedTypes );
    720                 // go through assertions and recursively add seen ctor/dtors
    721                 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
    722                         for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
    723                                 managedTypes.handleDWT( assertion );
    724                         }
    725                 }
    726 
    727                 maybeAccept( functionDecl->get_statements(), *visitor );
    728         }
    729 
    730         void CtorDtor::previsit( StructDecl *aggregateDecl ) {
    731                 visit_children = false; // do not try to construct and destruct aggregate members
    732 
    733                 managedTypes.handleStruct( aggregateDecl );
    734         }
    735 
    736         void CtorDtor::previsit( CompoundStmt * ) {
    737                 GuardScope( managedTypes );
    738338        }
    739339
  • src/InitTweak/GenInit.h

    r0030b508 rfc12f05  
    2222#include "Common/CodeLocation.h"
    2323#include "GenPoly/ScopedSet.h" // for ScopedSet
    24 #include "SynTree/SynTree.h"   // for Visitor Nodes
    2524
    2625namespace InitTweak {
    2726        /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
    28         void genInit( std::list< Declaration * > & translationUnit );
    2927        void genInit( ast::TranslationUnit & translationUnit );
    3028
    3129        /// Converts return statements into copy constructor calls on the hidden return variable.
    3230        /// This pass must happen before auto-gen.
    33         void fixReturnStatements( std::list< Declaration * > & translationUnit );
    3431        void fixReturnStatements( ast::TranslationUnit & translationUnit );
    3532
    3633        /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    37         ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );
    3834        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3935
    4036        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
    41         ConstructorInit * genCtorInit( ObjectDecl * objDecl );
    4237        ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
    43 
    44         class ManagedTypes {
    45         public:
    46                 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed
    47                 bool isManaged( Type * type ) const; // determine if type is managed
    48 
    49                 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor
    50                 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed
    51 
    52                 void beginScope();
    53                 void endScope();
    54         private:
    55                 GenPoly::ScopedSet< std::string > managedTypes;
    56         };
    5738
    5839        class ManagedTypes_new {
  • src/InitTweak/InitTweak.cc

    r0030b508 rfc12f05  
    2929#include "AST/Type.hpp"
    3030#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
    31 #include "Common/PassVisitor.h"
    3231#include "Common/SemanticError.h"  // for SemanticError
    3332#include "Common/UniqueName.h"     // for UniqueName
     
    3635#include "InitTweak.h"
    3736#include "ResolvExpr/Unify.h"      // for typesCompatibleIgnoreQualifiers
    38 #include "SymTab/Autogen.h"
    39 #include "SymTab/Indexer.h"        // for Indexer
    40 #include "SynTree/LinkageSpec.h"   // for Spec, isBuiltin, Intrinsic
    41 #include "SynTree/Attribute.h"     // for Attribute
    42 #include "SynTree/Constant.h"      // for Constant
    43 #include "SynTree/Declaration.h"   // for ObjectDecl, DeclarationWithType
    44 #include "SynTree/Expression.h"    // for Expression, UntypedExpr, Applicati...
    45 #include "SynTree/Initializer.h"   // for Initializer, ListInit, Designation
    46 #include "SynTree/Label.h"         // for Label
    47 #include "SynTree/Statement.h"     // for CompoundStmt, ExprStmt, BranchStmt
    48 #include "SynTree/Type.h"          // for FunctionType, ArrayType, PointerType
    49 #include "SynTree/Visitor.h"       // for Visitor, maybeAccept
    5037#include "Tuples/Tuples.h"         // for Tuples::isTtype
    5138
    5239namespace InitTweak {
    5340        namespace {
    54                 struct HasDesignations : public WithShortCircuiting {
    55                         bool hasDesignations = false;
    56 
    57                         void previsit( BaseSyntaxNode * ) {
    58                                 // short circuit if we already know there are designations
    59                                 if ( hasDesignations ) visit_children = false;
    60                         }
    61 
    62                         void previsit( Designation * des ) {
    63                                 // short circuit if we already know there are designations
    64                                 if ( hasDesignations ) visit_children = false;
    65                                 else if ( ! des->get_designators().empty() ) {
    66                                         hasDesignations = true;
    67                                         visit_children = false;
    68                                 }
    69                         }
    70                 };
    71 
    72                 struct InitDepthChecker : public WithGuards {
    73                         bool depthOkay = true;
    74                         Type * type;
    75                         int curDepth = 0, maxDepth = 0;
    76                         InitDepthChecker( Type * type ) : type( type ) {
    77                                 Type * t = type;
    78                                 while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) {
    79                                         maxDepth++;
    80                                         t = at->get_base();
    81                                 }
    82                                 maxDepth++;
    83                         }
    84                         void previsit( ListInit * ) {
    85                                 curDepth++;
    86                                 GuardAction( [this]() { curDepth--; } );
    87                                 if ( curDepth > maxDepth ) depthOkay = false;
    88                         }
    89                 };
    90 
    9141                struct HasDesignations_new : public ast::WithShortCircuiting {
    9242                        bool result = false;
     
    10757                };
    10858
    109                 struct InitDepthChecker_new : public ast::WithGuards {
     59                struct InitDepthChecker_new {
    11060                        bool result = true;
    11161                        const ast::Type * type;
     
    11969                                maxDepth++;
    12070                        }
    121                         void previsit( ListInit * ) {
     71                        void previsit( ast::ListInit const * ) {
    12272                                curDepth++;
    123                                 GuardAction( [this]() { curDepth--; } );
    12473                                if ( curDepth > maxDepth ) result = false;
    12574                        }
    126                 };
    127 
    128                 struct InitFlattener_old : public WithShortCircuiting {
    129                         void previsit( SingleInit * singleInit ) {
    130                                 visit_children = false;
    131                                 argList.push_back( singleInit->value->clone() );
    132                         }
    133                         std::list< Expression * > argList;
     75                        void postvisit( ast::ListInit const * ) {
     76                                curDepth--;
     77                        }
    13478                };
    13579
     
    14488
    14589        } // anonymous namespace
    146 
    147         std::list< Expression * > makeInitList( Initializer * init ) {
    148                 PassVisitor<InitFlattener_old> flattener;
    149                 maybeAccept( init, flattener );
    150                 return flattener.pass.argList;
    151         }
    152 
    153         bool isDesignated( Initializer * init ) {
    154                 PassVisitor<HasDesignations> finder;
    155                 maybeAccept( init, finder );
    156                 return finder.pass.hasDesignations;
    157         }
    158 
    159         bool checkInitDepth( ObjectDecl * objDecl ) {
    160                 PassVisitor<InitDepthChecker> checker( objDecl->type );
    161                 maybeAccept( objDecl->init, checker );
    162                 return checker.pass.depthOkay;
    163         }
    16490
    16591        bool isDesignated( const ast::Init * init ) {
     
    180106        return std::move( flattener.core.argList );
    181107}
    182 
    183         class InitExpander_old::ExpanderImpl {
    184         public:
    185                 virtual ~ExpanderImpl() = default;
    186                 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;
    187                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;
    188         };
    189 
    190         class InitImpl_old : public InitExpander_old::ExpanderImpl {
    191         public:
    192                 InitImpl_old( Initializer * init ) : init( init ) {}
    193                 virtual ~InitImpl_old() = default;
    194 
    195                 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {
    196                         // this is wrong, but just a placeholder for now
    197                         // if ( ! flattened ) flatten( indices );
    198                         // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
    199                         return makeInitList( init );
    200                 }
    201 
    202                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    203         private:
    204                 Initializer * init;
    205         };
    206 
    207         class ExprImpl_old : public InitExpander_old::ExpanderImpl {
    208         public:
    209                 ExprImpl_old( Expression * expr ) : arg( expr ) {}
    210                 virtual ~ExprImpl_old() { delete arg; }
    211 
    212                 virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
    213                         std::list< Expression * > ret;
    214                         Expression * expr = maybeClone( arg );
    215                         if ( expr ) {
    216                                 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {
    217                                         // go through indices and layer on subscript exprs ?[?]
    218                                         ++it;
    219                                         UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );
    220                                         subscriptExpr->get_args().push_back( expr );
    221                                         subscriptExpr->get_args().push_back( (*it)->clone() );
    222                                         expr = subscriptExpr;
    223                                 }
    224                                 ret.push_back( expr );
    225                         }
    226                         return ret;
    227                 }
    228 
    229                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    230         private:
    231                 Expression * arg;
    232         };
    233 
    234         InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {}
    235 
    236         InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {}
    237 
    238         std::list< Expression * > InitExpander_old::operator*() {
    239                 return cur;
    240         }
    241 
    242         InitExpander_old & InitExpander_old::operator++() {
    243                 cur = expander->next( indices );
    244                 return *this;
    245         }
    246 
    247         // use array indices list to build switch statement
    248         void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) {
    249                 indices.push_back( index );
    250                 indices.push_back( dimension );
    251         }
    252 
    253         void InitExpander_old::clearArrayIndices() {
    254                 deleteAll( indices );
    255                 indices.clear();
    256         }
    257 
    258         bool InitExpander_old::addReference() {
    259                 bool added = false;
    260                 for ( Expression *& expr : cur ) {
    261                         expr = new AddressExpr( expr );
    262                         added = true;
    263                 }
    264                 return added;
    265         }
    266 
    267         namespace {
    268                 /// given index i, dimension d, initializer init, and callExpr f, generates
    269                 ///   if (i < d) f(..., init)
    270                 ///   ++i;
    271                 /// so that only elements within the range of the array are constructed
    272                 template< typename OutIterator >
    273                 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {
    274                         UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
    275                         cond->get_args().push_back( index->clone() );
    276                         cond->get_args().push_back( dimension->clone() );
    277 
    278                         std::list< Expression * > args = makeInitList( init );
    279                         callExpr->get_args().splice( callExpr->get_args().end(), args );
    280 
    281                         *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr );
    282 
    283                         UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
    284                         increment->get_args().push_back( index->clone() );
    285                         *out++ = new ExprStmt( increment );
    286                 }
    287 
    288                 template< typename OutIterator >
    289                 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
    290                         if ( idx == idxEnd ) return;
    291                         Expression * index = *idx++;
    292                         assert( idx != idxEnd );
    293                         Expression * dimension = *idx++;
    294 
    295                         // xxx - may want to eventually issue a warning here if we can detect
    296                         // that the number of elements exceeds to dimension of the array
    297                         if ( idx == idxEnd ) {
    298                                 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {
    299                                         for ( Initializer * init : *listInit ) {
    300                                                 buildCallExpr( callExpr->clone(), index, dimension, init, out );
    301                                         }
    302                                 } else {
    303                                         buildCallExpr( callExpr->clone(), index, dimension, init, out );
    304                                 }
    305                         } else {
    306                                 std::list< Statement * > branches;
    307 
    308                                 unsigned long cond = 0;
    309                                 ListInit * listInit = dynamic_cast< ListInit * >( init );
    310                                 if ( ! listInit ) {
    311                                         // xxx - this shouldn't be an error, but need a way to
    312                                         // terminate without creating output, so should catch this error
    313                                         SemanticError( init->location, "unbalanced list initializers" );
    314                                 }
    315 
    316                                 static UniqueName targetLabel( "L__autogen__" );
    317                                 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );
    318                                 for ( Initializer * init : *listInit ) {
    319                                         Expression * condition;
    320                                         // check for designations
    321                                         // if ( init-> ) {
    322                                                 condition = new ConstantExpr( Constant::from_ulong( cond ) );
    323                                                 ++cond;
    324                                         // } else {
    325                                         //      condition = // ... take designation
    326                                         //      cond = // ... take designation+1
    327                                         // }
    328                                         std::list< Statement * > stmts;
    329                                         build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );
    330                                         stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) );
    331                                         CaseStmt * caseStmt = new CaseStmt( condition, stmts );
    332                                         branches.push_back( caseStmt );
    333                                 }
    334                                 *out++ = new SwitchStmt( index->clone(), branches );
    335                                 *out++ = new NullStmt( { switchLabel } );
    336                         }
    337                 }
    338         }
    339 
    340         // if array came with an initializer list: initialize each element
    341         // may have more initializers than elements in the array - need to check at each index that
    342         // we haven't exceeded size.
    343         // may have fewer initializers than elements in the array - need to default construct
    344         // remaining elements.
    345         // To accomplish this, generate switch statement, consuming all of expander's elements
    346         Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
    347                 if ( ! init ) return nullptr;
    348                 CompoundStmt * block = new CompoundStmt();
    349                 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );
    350                 if ( block->get_kids().empty() ) {
    351                         delete block;
    352                         return nullptr;
    353                 } else {
    354                         init = nullptr; // init was consumed in creating the list init
    355                         return block;
    356                 }
    357         }
    358 
    359         Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
    360                 return nullptr;
    361         }
    362 
    363         Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) {
    364                 return expander->buildListInit( dst, indices );
    365         }
    366108
    367109class InitExpander_new::ExpanderImpl {
     
    535277}
    536278
    537         Type * getTypeofThis( FunctionType * ftype ) {
    538                 assertf( ftype, "getTypeofThis: nullptr ftype" );
    539                 ObjectDecl * thisParam = getParamThis( ftype );
    540                 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );
    541                 return refType->base;
    542         }
    543 
    544279        const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
    545280                assertf( ftype, "getTypeofThis: nullptr ftype" );
     
    552287        }
    553288
    554         ObjectDecl * getParamThis( FunctionType * ftype ) {
    555                 assertf( ftype, "getParamThis: nullptr ftype" );
    556                 auto & params = ftype->parameters;
    557                 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );
    558                 return strict_dynamic_cast< ObjectDecl * >( params.front() );
    559         }
    560 
    561289        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
    562290                assertf( func, "getParamThis: nullptr ftype" );
     
    564292                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
    565293                return params.front().strict_as<ast::ObjectDecl>();
    566         }
    567 
    568         bool tryConstruct( DeclarationWithType * dwt ) {
    569                 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
    570                 if ( ! objDecl ) return false;
    571                 return (objDecl->get_init() == nullptr ||
    572                                 ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() ))
    573                         && ! objDecl->get_storageClasses().is_extern
    574                         && isConstructable( objDecl->type );
    575         }
    576 
    577         bool isConstructable( Type * type ) {
    578                 return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type );
    579294        }
    580295
     
    593308        }
    594309
    595         struct CallFinder_old {
    596                 CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
    597 
    598                 void postvisit( ApplicationExpr * appExpr ) {
    599                         handleCallExpr( appExpr );
    600                 }
    601 
    602                 void postvisit( UntypedExpr * untypedExpr ) {
    603                         handleCallExpr( untypedExpr );
    604                 }
    605 
    606                 std::list< Expression * > * matches;
    607         private:
    608                 const std::list< std::string > names;
    609 
    610                 template< typename CallExpr >
    611                 void handleCallExpr( CallExpr * expr ) {
    612                         std::string fname = getFunctionName( expr );
    613                         if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
    614                                 matches->push_back( expr );
    615                         }
    616                 }
    617         };
    618 
    619310        struct CallFinder_new final {
    620311                std::vector< const ast::Expr * > matches;
     
    634325        };
    635326
    636         void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
    637                 static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );
    638                 finder.pass.matches = &matches;
    639                 maybeAccept( stmt, finder );
    640         }
    641 
    642327        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    643328                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
     
    646331        }
    647332
    648         Expression * getCtorDtorCall( Statement * stmt ) {
    649                 std::list< Expression * > matches;
    650                 collectCtorDtorCalls( stmt, matches );
    651                 assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() );
    652                 return matches.size() == 1 ? matches.front() : nullptr;
    653         }
    654 
    655333        namespace {
    656                 DeclarationWithType * getCalledFunction( Expression * expr );
    657 
    658                 template<typename CallExpr>
    659                 DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) {
    660                         // (*f)(x) => should get "f"
    661                         std::string name = getFunctionName( expr );
    662                         assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
    663                         assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" );
    664                         return getCalledFunction( expr->get_args().front() );
    665                 }
    666 
    667                 DeclarationWithType * getCalledFunction( Expression * expr ) {
    668                         assert( expr );
    669                         if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
    670                                 return varExpr->var;
    671                         } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {
    672                                 return memberExpr->member;
    673                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    674                                 return getCalledFunction( castExpr->arg );
    675                         } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) {
    676                                 return handleDerefCalledFunction( untypedExpr );
    677                         } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
    678                                 return handleDerefCalledFunction( appExpr );
    679                         } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
    680                                 return getCalledFunction( addrExpr->arg );
    681                         } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) {
    682                                 return getCalledFunction( commaExpr->arg2 );
    683                         }
    684                         return nullptr;
    685                 }
    686 
    687                 DeclarationWithType * getFunctionCore( const Expression * expr ) {
    688                         if ( const auto * appExpr = dynamic_cast< const ApplicationExpr * >( expr ) ) {
    689                                 return getCalledFunction( appExpr->function );
    690                         } else if ( const auto * untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {
    691                                 return getCalledFunction( untyped->function );
    692                         }
    693                         assertf( false, "getFunction with unknown expression: %s", toString( expr ).c_str() );
    694                 }
    695         }
    696 
    697         DeclarationWithType * getFunction( Expression * expr ) {
    698                 return getFunctionCore( expr );
    699         }
    700 
    701         const DeclarationWithType * getFunction( const Expression * expr ) {
    702                 return getFunctionCore( expr );
    703         }
    704 
    705         ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {
    706                 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );
    707                 if ( ! appExpr ) return nullptr;
    708                 DeclarationWithType * function = getCalledFunction( appExpr->get_function() );
    709                 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );
    710                 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor
    711                 // will call all member dtors, and some members may have a user defined dtor.
    712                 return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr;
    713         }
    714 
    715         namespace {
    716                 template <typename Predicate>
    717                 bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {
    718                         std::list< Expression * > callExprs;
    719                         collectCtorDtorCalls( stmt, callExprs );
    720                         return std::all_of( callExprs.begin(), callExprs.end(), pred);
    721                 }
    722 
    723334                template <typename Predicate>
    724335                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
     
    726337                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    727338                }
    728         }
    729 
    730         bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {
    731                 return allofCtorDtor( stmt, []( Expression * callExpr ){
    732                         if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
    733                                 FunctionType *funcType = GenPoly::getFunctionType( appExpr->function->result );
    734                                 assert( funcType );
    735                                 return funcType->get_parameters().size() == 1;
    736                         }
    737                         return false;
    738                 });
    739339        }
    740340
     
    749349                        return false;
    750350                });
    751         }
    752 
    753         bool isIntrinsicCallStmt( Statement * stmt ) {
    754                 return allofCtorDtor( stmt, []( Expression * callExpr ) {
    755                         return isIntrinsicCallExpr( callExpr );
    756                 });
    757         }
    758 
    759         namespace {
    760                 template<typename CallExpr>
    761                 Expression *& callArg( CallExpr * callExpr, unsigned int pos ) {
    762                         if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() );
    763                         for ( Expression *& arg : callExpr->get_args() ) {
    764                                 if ( pos == 0 ) return arg;
    765                                 pos--;
    766                         }
    767                         assert( false );
    768                 }
    769         }
    770 
    771         Expression *& getCallArg( Expression * callExpr, unsigned int pos ) {
    772                 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) {
    773                         return callArg( appExpr, pos );
    774                 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {
    775                         return callArg( untypedExpr, pos );
    776                 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {
    777                         std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();
    778                         assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );
    779                         ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() );
    780                         TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() );
    781                         assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );
    782                         return getCallArg( tuple->get_exprs().front(), pos );
    783                 } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) {
    784                         return getCallArg( copyCtor->callExpr, pos );
    785                 } else {
    786                         assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );
    787                 }
    788         }
    789 
    790         namespace {
    791                 std::string funcName( Expression * func );
    792 
    793                 template<typename CallExpr>
    794                 std::string handleDerefName( CallExpr * expr ) {
    795                         // (*f)(x) => should get name "f"
    796                         std::string name = getFunctionName( expr );
    797                         assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
    798                         assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );
    799                         return funcName( expr->get_args().front() );
    800                 }
    801 
    802                 std::string funcName( Expression * func ) {
    803                         if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) {
    804                                 return nameExpr->get_name();
    805                         } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {
    806                                 return varExpr->get_var()->get_name();
    807                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {
    808                                 return funcName( castExpr->get_arg() );
    809                         } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {
    810                                 return memberExpr->get_member()->get_name();
    811                         } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {
    812                                 return funcName( memberExpr->get_member() );
    813                         } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) {
    814                                 return handleDerefName( untypedExpr );
    815                         } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) {
    816                                 return handleDerefName( appExpr );
    817                         } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) {
    818                                 return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) );
    819                         } else {
    820                                 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
    821                         }
    822                 }
    823         }
    824 
    825         std::string getFunctionName( Expression * expr ) {
    826                 // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and
    827                 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction
    828                 // can't possibly do anything reasonable.
    829                 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {
    830                         return funcName( appExpr->get_function() );
    831                 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {
    832                         return funcName( untypedExpr->get_function() );
    833                 } else {
    834                         std::cerr << expr << std::endl;
    835                         assertf( false, "Unexpected expression type passed to getFunctionName" );
    836                 }
    837         }
    838 
    839         Type * getPointerBase( Type * type ) {
    840                 if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {
    841                         return ptrType->get_base();
    842                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    843                         return arrayType->get_base();
    844                 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {
    845                         return refType->get_base();
    846                 } else {
    847                         return nullptr;
    848                 }
    849         }
    850 
    851         Type * isPointerType( Type * type ) {
    852                 return getPointerBase( type ) ? type : nullptr;
    853         }
    854 
    855         ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {
    856                 static FunctionDecl * assign = nullptr;
    857                 if ( ! assign ) {
    858                         // temporary? Generate a fake assignment operator to represent bitwise assignments.
    859                         // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.
    860                         TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );
    861                         assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );
    862                 }
    863                 if ( dynamic_cast< ReferenceType * >( dst->result ) ) {
    864                         for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
    865                                 dst = new AddressExpr( dst );
    866                         }
    867                 } else {
    868                         dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );
    869                 }
    870                 if ( dynamic_cast< ReferenceType * >( src->result ) ) {
    871                         for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
    872                                 src = new AddressExpr( src );
    873                         }
    874                 }
    875                 return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );
    876351        }
    877352
     
    905380                return app;
    906381        }
    907 
    908         struct ConstExprChecker : public WithShortCircuiting {
    909                 // most expressions are not const expr
    910                 void previsit( Expression * ) { isConstExpr = false; visit_children = false; }
    911 
    912                 void previsit( AddressExpr *addressExpr ) {
    913                         visit_children = false;
    914 
    915                         // address of a variable or member expression is constexpr
    916                         Expression * arg = addressExpr->get_arg();
    917                         if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false;
    918                 }
    919 
    920                 // these expressions may be const expr, depending on their children
    921                 void previsit( SizeofExpr * ) {}
    922                 void previsit( AlignofExpr * ) {}
    923                 void previsit( UntypedOffsetofExpr * ) {}
    924                 void previsit( OffsetofExpr * ) {}
    925                 void previsit( OffsetPackExpr * ) {}
    926                 void previsit( CommaExpr * ) {}
    927                 void previsit( LogicalExpr * ) {}
    928                 void previsit( ConditionalExpr * ) {}
    929                 void previsit( CastExpr * ) {}
    930                 void previsit( ConstantExpr * ) {}
    931 
    932                 void previsit( VariableExpr * varExpr ) {
    933                         visit_children = false;
    934 
    935                         if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) {
    936                                 long long int value;
    937                                 if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
    938                                         // enumerators are const expr
    939                                         return;
    940                                 }
    941                         }
    942                         isConstExpr = false;
    943                 }
    944 
    945                 bool isConstExpr = true;
    946         };
    947382
    948383        struct ConstExprChecker_new : public ast::WithShortCircuiting {
     
    989424        };
    990425
    991         bool isConstExpr( Expression * expr ) {
    992                 if ( expr ) {
    993                         PassVisitor<ConstExprChecker> checker;
    994                         expr->accept( checker );
    995                         return checker.pass.isConstExpr;
    996                 }
    997                 return true;
    998         }
    999 
    1000         bool isConstExpr( Initializer * init ) {
    1001                 if ( init ) {
    1002                         PassVisitor<ConstExprChecker> checker;
    1003                         init->accept( checker );
    1004                         return checker.pass.isConstExpr;
    1005                 } // if
    1006                 // for all intents and purposes, no initializer means const expr
    1007                 return true;
    1008         }
    1009 
    1010426        bool isConstExpr( const ast::Expr * expr ) {
    1011427                if ( expr ) {
     
    1027443        }
    1028444
    1029         const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) {
    1030                 const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl );
    1031                 if ( ! function ) return nullptr;
    1032                 if ( function->name != fname ) return nullptr;
    1033                 FunctionType * ftype = function->type;
    1034                 if ( ftype->parameters.size() != 2 ) return nullptr;
    1035 
    1036                 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() );
    1037                 Type * t2 = ftype->parameters.back()->get_type();
    1038                 assert( t1 );
    1039 
    1040                 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) {
    1041                         return function;
    1042                 } else {
    1043                         return nullptr;
    1044                 }
    1045         }
    1046 
    1047445bool isAssignment( const ast::FunctionDecl * decl ) {
    1048446        return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
     
    1071469        return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
    1072470}
    1073 
    1074 
    1075         const FunctionDecl * isAssignment( const Declaration * decl ) {
    1076                 return isCopyFunction( decl, "?=?" );
    1077         }
    1078         const FunctionDecl * isDestructor( const Declaration * decl ) {
    1079                 if ( CodeGen::isDestructor( decl->name ) ) {
    1080                         return dynamic_cast< const FunctionDecl * >( decl );
    1081                 }
    1082                 return nullptr;
    1083         }
    1084         const FunctionDecl * isDefaultConstructor( const Declaration * decl ) {
    1085                 if ( CodeGen::isConstructor( decl->name ) ) {
    1086                         if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {
    1087                                 if ( func->type->parameters.size() == 1 ) {
    1088                                         return func;
    1089                                 }
    1090                         }
    1091                 }
    1092                 return nullptr;
    1093         }
    1094         const FunctionDecl * isCopyConstructor( const Declaration * decl ) {
    1095                 return isCopyFunction( decl, "?{}" );
    1096         }
    1097471
    1098472        #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
     
    1103477        static const char * const data_section =  ".data" ASM_COMMENT;
    1104478        static const char * const tlsd_section = ".tdata" ASM_COMMENT;
    1105         void addDataSectionAttribute( ObjectDecl * objDecl ) {
    1106                 const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any();
    1107                 const char * section = is_tls ? tlsd_section : data_section;
    1108                 objDecl->attributes.push_back(new Attribute("section", {
    1109                         new ConstantExpr( Constant::from_string( section ) )
    1110                 }));
    1111         }
    1112479
    1113480        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
  • src/InitTweak/InitTweak.h

    r0030b508 rfc12f05  
    2222
    2323#include "AST/Fwd.hpp"        // for AST nodes
    24 #include "SynTree/SynTree.h"  // for Visitor Nodes
    2524
    2625// helper functions for initialization
    2726namespace InitTweak {
    28         const FunctionDecl * isAssignment( const Declaration * decl );
    29         const FunctionDecl * isDestructor( const Declaration * decl );
    30         const FunctionDecl * isDefaultConstructor( const Declaration * decl );
    31         const FunctionDecl * isCopyConstructor( const Declaration * decl );
    32         const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname );
    3327        bool isAssignment( const ast::FunctionDecl * decl );
    3428        bool isDestructor( const ast::FunctionDecl * decl );
     
    3832
    3933        /// returns the base type of the first parameter to a constructor/destructor/assignment function
    40         Type * getTypeofThis( FunctionType * ftype );
    4134        const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
    4235
    4336        /// returns the first parameter of a constructor/destructor/assignment function
    44         ObjectDecl * getParamThis( FunctionType * ftype );
    4537        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4638
    4739        /// generate a bitwise assignment operation.
    48         ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
    49 
    5040        ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    5141
    5242        /// transform Initializer into an argument list that can be passed to a call expression
    53         std::list< Expression * > makeInitList( Initializer * init );
    5443        std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
    5544
    5645        /// True if the resolver should try to construct dwt
    57         bool tryConstruct( DeclarationWithType * dwt );
    5846        bool tryConstruct( const ast::DeclWithType * dwt );
    5947
    6048        /// True if the type can have a user-defined constructor
    61         bool isConstructable( Type * t );
    6249        bool isConstructable( const ast::Type * t );
    6350
    6451        /// True if the Initializer contains designations
    65         bool isDesignated( Initializer * init );
    6652        bool isDesignated( const ast::Init * init );
    6753
    6854        /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
    6955        /// type, where the depth of its type is the number of nested ArrayTypes + 1
    70         bool checkInitDepth( ObjectDecl * objDecl );
    7156        bool checkInitDepth( const ast::ObjectDecl * objDecl );
    72 
    73         /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
    74         DeclarationWithType * getFunction( Expression * expr );
    75         const DeclarationWithType * getFunction( const Expression * expr );
    76 
    77         /// Non-Null if expr is a call expression whose target function is intrinsic
    78         ApplicationExpr * isIntrinsicCallExpr( Expression * expr );
    7957
    8058        /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
    8159        /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
    8260        /// Currently has assertions that make it less than fully general.
    83         bool isIntrinsicSingleArgCallStmt( Statement * stmt );
    8461        bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
    8562
    86         /// True if stmt is a call statement where the function called is intrinsic.
    87         bool isIntrinsicCallStmt( Statement * stmt );
    88 
    8963        /// get all Ctor/Dtor call expressions from a Statement
    90         void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    9164        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
    9265
    93         /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
    94         Expression * getCtorDtorCall( Statement * stmt );
    95 
    96         /// returns the name of the function being called
    97         std::string getFunctionName( Expression * expr );
    98 
    99         /// returns the argument to a call expression in position N indexed from 0
    100         Expression *& getCallArg( Expression * callExpr, unsigned int pos );
    101 
    102         /// returns the base type of a PointerType or ArrayType, else returns NULL
    103         Type * getPointerBase( Type * );
    104 
    105         /// returns the argument if it is a PointerType or ArrayType, else returns NULL
    106         Type * isPointerType( Type * );
    107 
    10866        /// returns true if expr is trivially a compile-time constant
    109         bool isConstExpr( Expression * expr );
    110         bool isConstExpr( Initializer * init );
    111 
    11267        bool isConstExpr( const ast::Expr * expr );
    11368        bool isConstExpr( const ast::Init * init );
     
    12277        ///    .section .data#,"a"
    12378        /// to avoid assembler warning "ignoring changed section attributes for .data"
    124         void addDataSectionAttribute( ObjectDecl * objDecl );
    125 
    12679        void addDataSectionAttribute( ast::ObjectDecl * objDecl );
    127 
    128         class InitExpander_old {
    129         public:
    130                 // expand by stepping through init to get each list of arguments
    131                 InitExpander_old( Initializer * init );
    132 
    133                 // always expand to expr
    134                 InitExpander_old( Expression * expr );
    135 
    136                 // iterator-like interface
    137                 std::list< Expression * > operator*();
    138                 InitExpander_old & operator++();
    139 
    140                 // builds statement which has the same semantics as a C-style list initializer
    141                 // (for array initializers) using callExpr as the base expression to perform initialization
    142                 Statement * buildListInit( UntypedExpr * callExpr );
    143                 void addArrayIndex( Expression * index, Expression * dimension );
    144                 void clearArrayIndices();
    145                 bool addReference();
    146 
    147                 class ExpanderImpl;
    148 
    149                 typedef std::list< Expression * > IndexList;
    150         private:
    151                 std::shared_ptr< ExpanderImpl > expander;
    152                 std::list< Expression * > cur;
    153 
    154                 // invariant: list of size 2N (elements come in pairs [index, dimension])
    155                 IndexList indices;
    156         };
    15780
    15881        class InitExpander_new {
  • src/InitTweak/module.mk

    r0030b508 rfc12f05  
    2424        InitTweak/FixGlobalInit.cc \
    2525        InitTweak/FixGlobalInit.h \
    26         InitTweak/FixInit.cc \
    2726        InitTweak/FixInit.h \
    2827        InitTweak/FixInitNew.cpp
  • src/MakeLibCfa.h

    r0030b508 rfc12f05  
    2424
    2525namespace LibCfa {
    26         void makeLibCfa( std::list< Declaration* > &prelude );
    2726        void makeLibCfa( ast::TranslationUnit & translationUnit );
    2827} // namespace LibCfa
  • src/Makefile.am

    r0030b508 rfc12f05  
    2222      CompilationState.cc \
    2323      CompilationState.h \
    24       MakeLibCfa.cc \
    2524          MakeLibCfaNew.cpp \
    2625        MakeLibCfa.h
     
    4241include AST/module.mk
    4342include CodeGen/module.mk
    44 include CodeTools/module.mk
    4543include Concurrency/module.mk
    4644include Common/module.mk
     
    5149include ResolvExpr/module.mk
    5250include SymTab/module.mk
    53 include SynTree/module.mk
    5451include Tuples/module.mk
    5552include Validate/module.mk
    5653include Virtual/module.mk
    5754
    58 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h
     55$(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/AST/Type.hpp
    5956
    6057$(srcdir)/AST/Type.hpp : BasicTypes-gen.cc
  • src/Parser/RunParser.cpp

    r0030b508 rfc12f05  
    1616#include "RunParser.hpp"
    1717
    18 #include "AST/Convert.hpp"                  // for convert
    1918#include "AST/TranslationUnit.hpp"          // for TranslationUnit
    20 #include "CodeTools/TrackLoc.h"             // for fillLocations
    2119#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    2220#include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
  • src/Parser/StatementNode.cc

    r0030b508 rfc12f05  
    503503} // build_corun
    504504
     505ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) {
     506        std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
     507        buildMoveList( forctl->init, astinit );
     508
     509        ast::Expr * astcond = nullptr;                                          // maybe empty
     510        astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
     511
     512        ast::Expr * astincr = nullptr;                                          // maybe empty
     513        astincr = maybeMoveBuild( forctl->change );
     514        delete forctl;
     515
     516        return new ast::CoforStmt( location,
     517                std::move( astinit ),
     518                astcond,
     519                astincr,
     520                buildMoveSingle( stmt )
     521        );
     522} // build_cofor
     523
    505524// Local Variables: //
    506525// tab-width: 4 //
  • src/Parser/StatementNode.h

    r0030b508 rfc12f05  
    106106ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
    107107ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt );
     108ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt );
  • src/Parser/parser.yy

    r0030b508 rfc12f05  
    4848using namespace std;
    4949
    50 #include "SynTree/Type.h"                               // for Type
    5150#include "DeclarationNode.h"                            // for DeclarationNode, ...
    5251#include "ExpressionNode.h"                             // for ExpressionNode, ...
     
    5857#include "Common/SemanticError.h"                                               // error_str
    5958#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
    60 
    61 #include "SynTree/Attribute.h"                                                  // for Attribute
    6259
    6360// lex uses __null in a boolean context, it's fine.
     
    17261723cofor_statement:
    17271724        COFOR '(' for_control_expression_list ')' statement
    1728                 { SemanticError( yylloc, "cofor statement is currently unimplemented." ); $$ = nullptr; }
     1725                { $$ = new StatementNode( build_cofor( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
    17291726        ;
    17301727
     
    21692166type_qualifier_name:
    21702167        CONST
    2171                 { $$ = DeclarationNode::newTypeQualifier( Type::Const ); }
     2168                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Const ); }
    21722169        | RESTRICT
    2173                 { $$ = DeclarationNode::newTypeQualifier( Type::Restrict ); }
     2170                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Restrict ); }
    21742171        | VOLATILE
    2175                 { $$ = DeclarationNode::newTypeQualifier( Type::Volatile ); }
     2172                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Volatile ); }
    21762173        | ATOMIC
    2177                 { $$ = DeclarationNode::newTypeQualifier( Type::Atomic ); }
     2174                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Atomic ); }
    21782175        | forall
    21792176                { $$ = DeclarationNode::newForall( $1 ); }
     
    22062203storage_class:
    22072204        EXTERN
    2208                 { $$ = DeclarationNode::newStorageClass( Type::Extern ); }
     2205                { $$ = DeclarationNode::newStorageClass( ast::Storage::Extern ); }
    22092206        | STATIC
    2210                 { $$ = DeclarationNode::newStorageClass( Type::Static ); }
     2207                { $$ = DeclarationNode::newStorageClass( ast::Storage::Static ); }
    22112208        | AUTO
    2212                 { $$ = DeclarationNode::newStorageClass( Type::Auto ); }
     2209                { $$ = DeclarationNode::newStorageClass( ast::Storage::Auto ); }
    22132210        | REGISTER
    2214                 { $$ = DeclarationNode::newStorageClass( Type::Register ); }
     2211                { $$ = DeclarationNode::newStorageClass( ast::Storage::Register ); }
    22152212        | THREADLOCALGCC                                                                                // GCC
    2216                 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalGcc ); }
     2213                { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalGcc ); }
    22172214        | THREADLOCALC11                                                                                // C11
    2218                 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalC11 ); }
     2215                { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalC11 ); }
    22192216                // Put function specifiers here to simplify parsing rules, but separate them semantically.
    22202217        | INLINE                                                                                        // C99
    2221                 { $$ = DeclarationNode::newFuncSpecifier( Type::Inline ); }
     2218                { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Inline ); }
    22222219        | FORTRAN                                                                                       // C99
    2223                 { $$ = DeclarationNode::newFuncSpecifier( Type::Fortran ); }
     2220                { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Fortran ); }
    22242221        | NORETURN                                                                                      // C11
    2225                 { $$ = DeclarationNode::newFuncSpecifier( Type::Noreturn ); }
     2222                { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Noreturn ); }
    22262223        ;
    22272224
     
    37173714                { $$ = $1->addQualifiers( $2 ); }
    37183715        | '&' MUTEX paren_identifier attribute_list_opt
    3719                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3716                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37203717        | identifier_parameter_ptr
    37213718        | identifier_parameter_array attribute_list_opt
     
    37673764                { $$ = $1->addQualifiers( $2 ); }
    37683765        | '&' MUTEX typedef_name attribute_list_opt
    3769                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3766                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37703767        | type_parameter_ptr
    37713768        | type_parameter_array attribute_list_opt
     
    39413938        abstract_parameter_ptr
    39423939        | '&' MUTEX attribute_list_opt
    3943                 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }
     3940                { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }
    39443941        | abstract_parameter_array attribute_list_opt
    39453942                { $$ = $1->addQualifiers( $2 ); }
  • src/ResolvExpr/AdjustExprType.cc

    r0030b508 rfc12f05  
    1919#include "AST/Type.hpp"
    2020#include "AST/TypeEnvironment.hpp"
    21 #include "Common/PassVisitor.h"
    22 #include "SymTab/Indexer.h"       // for Indexer
    23 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Kind::Ftype
    24 #include "SynTree/Mutator.h"      // for Mutator
    25 #include "SynTree/Type.h"         // for PointerType, TypeInstType, Type
    26 #include "TypeEnvironment.h"      // for EqvClass, TypeEnvironment
    2721
    2822namespace ResolvExpr {
    29 
    30 namespace {
    31         class AdjustExprType_old final : public WithShortCircuiting {
    32                 public:
    33                 AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );
    34                 void premutate( VoidType * ) { visit_children = false; }
    35                 void premutate( BasicType * ) { visit_children = false; }
    36                 void premutate( PointerType * ) { visit_children = false; }
    37                 void premutate( ArrayType * ) { visit_children = false; }
    38                 void premutate( FunctionType * ) { visit_children = false; }
    39                 void premutate( StructInstType * ) { visit_children = false; }
    40                 void premutate( UnionInstType * ) { visit_children = false; }
    41                 void premutate( EnumInstType * ) { visit_children = false; }
    42                 void premutate( TraitInstType * ) { visit_children = false; }
    43                 void premutate( TypeInstType * ) { visit_children = false; }
    44                 void premutate( TupleType * ) { visit_children = false; }
    45                 void premutate( VarArgsType * ) { visit_children = false; }
    46                 void premutate( ZeroType * ) { visit_children = false; }
    47                 void premutate( OneType * ) { visit_children = false; }
    48 
    49                 Type * postmutate( ArrayType * arrayType );
    50                 Type * postmutate( FunctionType * functionType );
    51                 Type * postmutate( TypeInstType * aggregateUseType );
    52 
    53                 private:
    54                 const TypeEnvironment & env;
    55                 const SymTab::Indexer & indexer;
    56         };
    57 
    58         AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )
    59                 : env( env ), indexer( indexer ) {
    60         }
    61 
    62         Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {
    63                 PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };
    64                 arrayType->base = nullptr;
    65                 delete arrayType;
    66                 return pointerType;
    67         }
    68 
    69         Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {
    70                 return new PointerType{ Type::Qualifiers(), functionType };
    71         }
    72 
    73         Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {
    74                 if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    75                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    76                                 return new PointerType{ Type::Qualifiers(), typeInst };
    77                         }
    78                 } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) {
    79                         if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) {
    80                                 if ( tyDecl->get_kind() == TypeDecl::Ftype ) {
    81                                         return new PointerType{ Type::Qualifiers(), typeInst };
    82                                 } // if
    83                         } // if
    84                 } // if
    85                 return typeInst;
    86         }
    87 } // anonymous namespace
    88 
    89 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    90         PassVisitor<AdjustExprType_old> adjuster( env, indexer );
    91         Type * newType = type->acceptMutator( adjuster );
    92         type = newType;
    93 }
    94 
    95 void adjustExprType( Type *& type ) {
    96         TypeEnvironment env;
    97         SymTab::Indexer indexer;
    98         adjustExprType( type, env, indexer );
    99 }
    10023
    10124namespace {
  • src/ResolvExpr/CandidateFinder.cpp

    r0030b508 rfc12f05  
    5757
    5858/// Unique identifier for matching expression resolutions to their requesting expression
    59 UniqueId globalResnSlot = 0;
     59ast::UniqueId globalResnSlot = 0;
    6060
    6161namespace {
     
    686686        void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) {
    687687                // Set need bindings for any unbound assertions
    688                 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
     688                ast::UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
    689689                for ( auto & assn : newCand->need ) {
    690690                        // skip already-matched assertions
  • src/ResolvExpr/CastCost.cc

    r0030b508 rfc12f05  
    2626#include "ResolvExpr/ConversionCost.h"   // for conversionCost
    2727#include "ResolvExpr/PtrsCastable.hpp"   // for ptrsCastable
    28 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment, EqvClass
    2928#include "ResolvExpr/typeops.h"          // for ptrsCastable
    3029#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    31 #include "SymTab/Indexer.h"              // for Indexer
    32 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    33 #include "SynTree/Type.h"                // for PointerType, Type, TypeInstType
    3430
    3531#if 0
     
    4036
    4137namespace ResolvExpr {
    42         struct CastCost_old : public ConversionCost {
    43           public:
    44                 CastCost_old( const Type * dest, bool srcIsLvalue,
    45                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );
    46 
    47                 using ConversionCost::previsit;
    48                 using ConversionCost::postvisit;
    49                 void postvisit( const BasicType * basicType );
    50                 void postvisit( const PointerType * pointerType );
    51         };
    52 
    53         Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,
    54                         const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    55                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    56                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    57                                 if ( eqvClass->type ) {
    58                                         return castCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    59                                 } else {
    60                                         return Cost::infinity;
    61                                 }
    62                         } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    63                                 // all typedefs should be gone by this point
    64                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType );
    65                                 if ( type->base ) {
    66                                         return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe;
    67                                 } // if
    68                         } // if
    69                 } // if
    70 
    71                 PRINT(
    72                         std::cerr << "castCost ::: src is ";
    73                         src->print( std::cerr );
    74                         std::cerr << std::endl << "dest is ";
    75                         dest->print( std::cerr );
    76                         std::cerr << std::endl << "env is" << std::endl;
    77                         env.print( std::cerr, 8 );
    78                 )
    79 
    80                 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    81                         PRINT( std::cerr << "compatible!" << std::endl; )
    82                         return Cost::zero;
    83                 } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    84                         return Cost::safe;
    85                 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    86                         PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    87                         return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    88                                 return ptrsCastable( t1, t2, env, indexer );
    89                         });
    90                 } else {
    91                         PassVisitor<CastCost_old> converter(
    92                                 dest, srcIsLvalue, indexer, env,
    93                                 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & ))
    94                                         castCost );
    95                         src->accept( converter );
    96                         if ( converter.pass.get_cost() == Cost::infinity ) {
    97                                 return Cost::infinity;
    98                         } else {
    99                                 // xxx - why are we adding cost 0 here?
    100                                 return converter.pass.get_cost() + Cost::zero;
    101                         } // if
    102                 } // if
    103         }
    104 
    105         CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue,
    106                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    107                 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) {
    108         }
    109 
    110         void CastCost_old::postvisit( const BasicType * basicType ) {
    111                 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest );
    112                 if ( destAsPointer && basicType->isInteger() ) {
    113                         // necessary for, e.g. unsigned long => void *
    114                         cost = Cost::unsafe;
    115                 } else {
    116                         cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env );
    117                 } // if
    118         }
    119 
    120         void CastCost_old::postvisit( const PointerType * pointerType ) {
    121                 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
    122                         if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    123                                 cost = Cost::safe;
    124                         } else {
    125                                 TypeEnvironment newEnv( env );
    126                                 newEnv.add( pointerType->forall );
    127                                 newEnv.add( pointerType->base->forall );
    128                                 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer );
    129                                 if ( castResult > 0 ) {
    130                                         cost = Cost::safe;
    131                                 } else if ( castResult < 0 ) {
    132                                         cost = Cost::infinity;
    133                                 } // if
    134                         } // if
    135                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    136                         if ( destAsBasic->isInteger() ) {
    137                                 // necessary for, e.g. void * => unsigned long
    138                                 cost = Cost::unsafe;
    139                         } // if
    140                 }
    141         }
    14238
    14339namespace {
     
    20096} // anonymous namespace
    20197
    202 
    203 
    20498Cost castCost(
    20599        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
  • src/ResolvExpr/CommonType.cc

    r0030b508 rfc12f05  
    2323#include "AST/Pass.hpp"
    2424#include "AST/Type.hpp"
    25 #include "Common/PassVisitor.h"
    26 #include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
    27 #include "SymTab/Indexer.h"              // for Indexer
    28 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl (ptr...
    29 #include "SynTree/Type.h"                // for BasicType, BasicType::Kind::...
    30 #include "SynTree/Visitor.h"             // for Visitor
    3125#include "Unify.h"                       // for unifyExact, WidenMode
    3226#include "typeops.h"                     // for isFtype
     
    4135
    4236namespace ResolvExpr {
    43         struct CommonType_old : public WithShortCircuiting {
    44                 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
    45                 Type * get_result() const { return result; }
    46 
    47                 void previsit( BaseSyntaxNode * ) { visit_children = false; }
    48 
    49                 void postvisit( VoidType * voidType );
    50                 void postvisit( BasicType * basicType );
    51                 void postvisit( PointerType * pointerType );
    52                 void postvisit( ArrayType * arrayType );
    53                 void postvisit( ReferenceType * refType );
    54                 void postvisit( FunctionType * functionType );
    55                 void postvisit( StructInstType * aggregateUseType );
    56                 void postvisit( UnionInstType * aggregateUseType );
    57                 void postvisit( EnumInstType * aggregateUseType );
    58                 void postvisit( TraitInstType * aggregateUseType );
    59                 void postvisit( TypeInstType * aggregateUseType );
    60                 void postvisit( TupleType * tupleType );
    61                 void postvisit( VarArgsType * varArgsType );
    62                 void postvisit( ZeroType * zeroType );
    63                 void postvisit( OneType * oneType );
    64 
    65           private:
    66                 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );
    67                 template< typename RefType > void handleRefType( RefType * inst, Type * other );
    68 
    69                 Type * result;
    70                 Type * type2;                           // inherited
    71                 bool widenFirst, widenSecond;
    72                 const SymTab::Indexer &indexer;
    73                 TypeEnvironment &env;
    74                 const OpenVarSet &openVars;
    75         };
    76 
    77         Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {
    78                 Type * common = nullptr;
    79                 AssertionSet have, need;
    80                 OpenVarSet newOpen( openVars );
    81                 // need unify to bind type variables
    82                 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) {
    83                         PRINT(
    84                                 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
    85                         )
    86                         if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {
    87                                 PRINT(
    88                                         std::cerr << "widen okay" << std::endl;
    89                                 )
    90                                 common->tq |= t1->tq;
    91                                 common->tq |= t2->tq;
    92                                 return common;
    93                         }
    94                 }
    95                 PRINT(
    96                         std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
    97                 )
    98                 return nullptr;
    99         }
    100 
    101         Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
    102                 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
    103 
    104                 int depth1 = type1->referenceDepth();
    105                 int depth2 = type2->referenceDepth();
    106                 if ( depth1 > 0 || depth2 > 0 ) {
    107                         int diff = depth1-depth2;
    108                         // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.
    109                         // if ( diff > 1 || diff < -1 ) return nullptr;
    110 
    111                         // special case where one type has a reference depth of 1 larger than the other
    112                         if ( diff > 0 || diff < 0 ) {
    113                                 PRINT(
    114                                         std::cerr << "reference depth diff: " << diff << std::endl;
    115                                 )
    116                                 Type * result = nullptr;
    117                                 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );
    118                                 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );
    119                                 if ( diff > 0 ) {
    120                                         // deeper on the left
    121                                         assert( ref1 );
    122                                         result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );
    123                                 } else {
    124                                         // deeper on the right
    125                                         assert( ref2 );
    126                                         result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );
    127                                 }
    128                                 if ( result && ref1 ) {
    129                                         // formal is reference, so result should be reference
    130                                         PRINT(
    131                                                 std::cerr << "formal is reference; result should be reference" << std::endl;
    132                                         )
    133                                         result = new ReferenceType( ref1->tq, result );
    134                                 }
    135                                 PRINT(
    136                                         std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;
    137                                 )
    138                                 return result;
    139                         }
    140                         // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.
    141                 }
    142 
    143                 type1->accept( visitor );
    144                 Type * result = visitor.pass.get_result();
    145                 if ( ! result ) {
    146                         // this appears to be handling for opaque type declarations
    147                         if ( widenSecond ) {
    148                                 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {
    149                                         if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {
    150                                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    151                                                 if ( type->get_base() ) {
    152                                                         Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;
    153                                                         AssertionSet have, need;
    154                                                         OpenVarSet newOpen( openVars );
    155                                                         type1->tq = Type::Qualifiers();
    156                                                         type->get_base()->tq = tq1;
    157                                                         if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {
    158                                                                 result = type1->clone();
    159                                                                 result->tq = tq1 | tq2;
    160                                                         } // if
    161                                                         type1->tq = tq1;
    162                                                         type->get_base()->tq = Type::Qualifiers();
    163                                                 } // if
    164                                         } // if
    165                                 } // if
    166                         } // if
    167                 } // if
    168 #ifdef DEBUG
    169                 std::cerr << "============= commonType" << std::endl << "type1 is ";
    170                 type1->print( std::cerr );
    171                 std::cerr << " type2 is ";
    172                 type2->print( std::cerr );
    173                 if ( result ) {
    174                         std::cerr << " common type is ";
    175                         result->print( std::cerr );
    176                 } else {
    177                         std::cerr << " no common type";
    178                 } // if
    179                 std::cerr << std::endl;
    180 #endif
    181                 return result;
    182         }
    18337
    18438        // GENERATED START, DO NOT EDIT
    18539        // GENERATED BY BasicTypes-gen.cc
    186         #define BT BasicType::
    187         static const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
     40        #define BT ast::BasicType::
     41        static const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
    18842                /*                                      B                       C                      SC                      UC                      SI                     SUI
    18943                                                        I                      UI                      LI                     LUI                     LLI                    LLUI
     
    485339        // GENERATED END
    486340        static_assert(
    487                 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     341                sizeof(commonTypes)/sizeof(commonTypes[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
    488342                "Each basic type kind should have a corresponding row in the combined type matrix"
    489343        );
    490 
    491         CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars )
    492                 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) {
    493         }
    494 
    495         void CommonType_old::postvisit( VoidType * ) {}
    496 
    497         void CommonType_old::postvisit( BasicType * basicType ) {
    498                 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) {
    499                         BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ];
    500                         if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) {
    501                                 result = new BasicType( basicType->tq | otherBasic->tq, newType );
    502                         } // if
    503                 } else if (  dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    504                         // use signed int in lieu of the enum/zero/one type
    505                         BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
    506                         if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
    507                                 result = new BasicType( basicType->tq | type2->tq, newType );
    508                         } // if
    509                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) {
    510                         const EnumDecl* enumDecl = enumInst->baseEnum;
    511                         if ( const Type* baseType = enumDecl->base ) {
    512                                 result = baseType->clone();
    513                         } else {
    514                                 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
    515                                 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
    516                                         result = new BasicType( basicType->tq | type2->tq, newType );
    517                                 } // if
    518                         }
    519                 }
    520         }
    521 
    522         template< typename Pointer >
    523         void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) {
    524                 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) {
    525                         OpenVarSet::const_iterator entry = openVars.find( var->get_name() );
    526                         if ( entry != openVars.end() ) {
    527                                 AssertionSet need, have;
    528                                 WidenMode widen( widenFirst, widenSecond );
    529                                 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;
    530                         }
    531                 }
    532                 result = voidPointer->clone();
    533                 result->tq |= otherPointer->tq;
    534         }
    535 
    536         void CommonType_old::postvisit( PointerType * pointerType ) {
    537                 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) {
    538                         // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;
    539                         if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
    540                                 getCommonWithVoidPointer( otherPointer, pointerType );
    541                         } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {
    542                                 getCommonWithVoidPointer( pointerType, otherPointer );
    543                         } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst )
    544                                            && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) {
    545                                 // std::cerr << "middle case" << std::endl;
    546                                 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq;
    547                                 pointerType->get_base()->tq = Type::Qualifiers();
    548                                 otherPointer->get_base()->tq = Type::Qualifiers();
    549                                 AssertionSet have, need;
    550                                 OpenVarSet newOpen( openVars );
    551                                 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) {
    552                                         // std::cerr << "unifyExact success" << std::endl;
    553                                         if ( tq1 < tq2 ) {
    554                                                 result = pointerType->clone();
    555                                         } else {
    556                                                 result = otherPointer->clone();
    557                                         } // if
    558                                         strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;
    559                                 } else {
    560                                         /// std::cerr << "place for ptr-to-type" << std::endl;
    561                                 } // if
    562                                 pointerType->get_base()->tq = tq1;
    563                                 otherPointer->get_base()->tq = tq2;
    564                         } // if
    565                 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    566                         result = pointerType->clone();
    567                         result->tq |= type2->tq;
    568                 } // if
    569         }
    570 
    571         void CommonType_old::postvisit( ArrayType * ) {}
    572 
    573         void CommonType_old::postvisit( ReferenceType * refType ) {
    574                 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) {
    575                         // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;
    576                         // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl;
    577                         if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {
    578                                 getCommonWithVoidPointer( otherRef, refType );
    579                         } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {
    580                                 getCommonWithVoidPointer( refType, otherRef );
    581                         } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst )
    582                                            && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) {
    583                                 // std::cerr << "middle case" << std::endl;
    584                                 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq;
    585                                 refType->get_base()->tq = Type::Qualifiers();
    586                                 otherRef->get_base()->tq = Type::Qualifiers();
    587                                 AssertionSet have, need;
    588                                 OpenVarSet newOpen( openVars );
    589                                 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) {
    590                                         if ( tq1 < tq2 ) {
    591                                                 result = refType->clone();
    592                                         } else {
    593                                                 result = otherRef->clone();
    594                                         } // if
    595                                         strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;
    596                                 } else {
    597                                         /// std::cerr << "place for ptr-to-type" << std::endl;
    598                                 } // if
    599                                 refType->get_base()->tq = tq1;
    600                                 otherRef->get_base()->tq = tq2;
    601                         } // if
    602                 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    603                         result = refType->clone();
    604                         result->tq |= type2->tq;
    605                 } // if
    606         }
    607 
    608         void CommonType_old::postvisit( FunctionType * ) {}
    609         void CommonType_old::postvisit( StructInstType * ) {}
    610         void CommonType_old::postvisit( UnionInstType * ) {}
    611 
    612         void CommonType_old::postvisit( EnumInstType * enumInstType ) {
    613                 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    614                         // reuse BasicType, EnumInstType code by swapping type2 with enumInstType
    615                         result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );
    616                 } // if
    617         }
    618 
    619         void CommonType_old::postvisit( TraitInstType * ) {
    620         }
    621 
    622         void CommonType_old::postvisit( TypeInstType * inst ) {
    623                 if ( widenFirst ) {
    624                         const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() );
    625                         if ( nt ) {
    626                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    627                                 if ( type->get_base() ) {
    628                                         Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq;
    629                                         AssertionSet have, need;
    630                                         OpenVarSet newOpen( openVars );
    631                                         type2->tq = Type::Qualifiers();
    632                                         type->get_base()->tq = tq1;
    633                                         if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) {
    634                                                 result = type2->clone();
    635                                                 result->tq = tq1 | tq2;
    636                                         } // if
    637                                         type2->tq = tq2;
    638                                         type->get_base()->tq = Type::Qualifiers();
    639                                 } // if
    640                         } // if
    641                 } // if
    642         }
    643 
    644         void CommonType_old::postvisit( TupleType * ) {}
    645         void CommonType_old::postvisit( VarArgsType * ) {}
    646 
    647         void CommonType_old::postvisit( ZeroType * zeroType ) {
    648                 if ( widenFirst ) {
    649                         if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
    650                                 if ( widenSecond || zeroType->tq <= type2->tq ) {
    651                                         result = type2->clone();
    652                                         result->tq |= zeroType->tq;
    653                                 }
    654                         } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) {
    655                                 result = new BasicType( zeroType->tq, BasicType::SignedInt );
    656                                 result->tq |= type2->tq;
    657                         }
    658                 }
    659         }
    660 
    661         void CommonType_old::postvisit( OneType * oneType ) {
    662                 if ( widenFirst ) {
    663                         if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
    664                                 if ( widenSecond || oneType->tq <= type2->tq ) {
    665                                         result = type2->clone();
    666                                         result->tq |= oneType->tq;
    667                                 }
    668                         } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    669                                 result = new BasicType( oneType->tq, BasicType::SignedInt );
    670                                 result->tq |= type2->tq;
    671                         }
    672                 }
    673         }
    674344
    675345        class CommonType_new final : public ast::WithShortCircuiting {
     
    700370                                else if (!widen.first) kind = basic->kind; // widen.second
    701371                                else if (!widen.second) kind = basic2->kind;
    702                                 else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
     372                                else kind = commonTypes[ basic->kind ][ basic2->kind ];
    703373                                // xxx - what does qualifiers even do here??
    704374                                if ( (basic->qualifiers >= basic2->qualifiers || widen.first)
     
    719389                                } else {
    720390                                        #warning remove casts when `commonTypes` moved to new AST
    721                                         ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
     391                                        ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
    722392                                        if (
    723393                                                ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
  • src/ResolvExpr/CommonType.hpp

    r0030b508 rfc12f05  
    1818#include "AST/Fwd.hpp"
    1919#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
    20 #include "TypeEnvironment.h"        // for AssertionSet, OpenVarSet
    2120#include "WidenMode.h"              // for WidenMode
    22 
    23 class Type;
    24 namespace SymTab {
    25         class Indexer;
    26 }
    2721
    2822namespace ResolvExpr {
    2923
    30 Type * commonType(
    31         Type * type1, Type * type2, bool widenFirst, bool widenSecond,
    32         const SymTab::Indexer & indexer, TypeEnvironment & env,
    33         const OpenVarSet & openVars );
    3424ast::ptr< ast::Type > commonType(
    3525        const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
  • src/ResolvExpr/ConversionCost.cc

    r0030b508 rfc12f05  
    2121
    2222#include "ResolvExpr/Cost.h"             // for Cost
    23 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2423#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    2524#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    26 #include "SymTab/Indexer.h"              // for Indexer
    27 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    28 #include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
    29 
    3025
    3126namespace ResolvExpr {
    32 #if 0
    33         const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0,  0 };
    34         const Cost Cost::infinity =  Cost{ -1, -1, -1, -1, -1,  1, -1 };
    35         const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0,  0 };
    36         const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0,  0 };
    37         const Cost Cost::safe =      Cost{  0,  0,  1,  0,  0,  0,  0 };
    38         const Cost Cost::sign =      Cost{  0,  0,  0,  1,  0,  0,  0 };
    39         const Cost Cost::var =       Cost{  0,  0,  0,  0,  1,  0,  0 };
    40         const Cost Cost::spec =      Cost{  0,  0,  0,  0,  0, -1,  0 };
    41         const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  0,  1 };
    42 #endif
    4327
    4428#if 0
     
    4731#define PRINT(x)
    4832#endif
    49 
    50         Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,
    51                         const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    52                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    53                         PRINT( std::cerr << "type inst " << destAsTypeInst->name; )
    54                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    55                                 if ( eqvClass->type ) {
    56                                         return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    57                                 } else {
    58                                         return Cost::infinity;
    59                                 }
    60                         } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    61                                 PRINT( std::cerr << " found" << std::endl; )
    62                                 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    63                                 // all typedefs should be gone by this point
    64                                 assert( type );
    65                                 if ( type->base ) {
    66                                         return conversionCost( src, type->base, srcIsLvalue, indexer, env )
    67                                                 + Cost::safe;
    68                                 } // if
    69                         } // if
    70                         PRINT( std::cerr << " not found" << std::endl; )
    71                 } // if
    72                 PRINT(
    73                         std::cerr << "src is ";
    74                         src->print( std::cerr );
    75                         std::cerr << std::endl << "dest is ";
    76                         dest->print( std::cerr );
    77                         std::cerr << std::endl << "env is" << std::endl;
    78                         env.print( std::cerr, 8 );
    79                 )
    80                 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    81                         PRINT( std::cerr << "compatible!" << std::endl; )
    82                         return Cost::zero;
    83                 } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    84                         return Cost::safe;
    85                 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    86                         PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    87                         return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){
    88                                 return ptrsAssignable( t1, t2, env );
    89                         });
    90                 } else {
    91                         PassVisitor<ConversionCost> converter(
    92                                 dest, srcIsLvalue, indexer, env,
    93                                 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
    94                                         conversionCost );
    95                         src->accept( converter );
    96                         if ( converter.pass.get_cost() == Cost::infinity ) {
    97                                 return Cost::infinity;
    98                         } else {
    99                                 return converter.pass.get_cost() + Cost::zero;
    100                         } // if
    101                 } // if
    102         }
    103 
    104         static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,
    105                         int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    106                 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )
    107                 if ( diff > 0 ) {
    108                         // TODO: document this
    109                         Cost cost = convertToReferenceCost(
    110                                 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,
    111                                 diff-1, indexer, env, func );
    112                         cost.incReference();
    113                         return cost;
    114                 } else if ( diff < -1 ) {
    115                         // TODO: document this
    116                         Cost cost = convertToReferenceCost(
    117                                 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,
    118                                 diff+1, indexer, env, func );
    119                         cost.incReference();
    120                         return cost;
    121                 } else if ( diff == 0 ) {
    122                         const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );
    123                         const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    124                         if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
    125                                 PRINT( std::cerr << "converting between references" << std::endl; )
    126                                 Type::Qualifiers tq1 = srcAsRef->base->tq;
    127                                 Type::Qualifiers tq2 = destAsRef->base->tq;
    128                                 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {
    129                                         PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
    130                                         if ( tq1 == tq2 ) {
    131                                                 // types are the same
    132                                                 return Cost::zero;
    133                                         } else {
    134                                                 // types are the same, except otherPointer has more qualifiers
    135                                                 return Cost::safe;
    136                                         }
    137                                 } else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
    138                                         int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );
    139                                         PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
    140                                         if ( assignResult > 0 ) {
    141                                                 return Cost::safe;
    142                                         } else if ( assignResult < 0 ) {
    143                                                 return Cost::unsafe;
    144                                         } // if
    145                                 } // if
    146                         } else {
    147                                 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
    148                                 PassVisitor<ConversionCost> converter(
    149                                         dest, srcIsLvalue, indexer, env,
    150                                         (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
    151                                                 conversionCost );
    152                                 src->accept( converter );
    153                                 return converter.pass.get_cost();
    154                         } // if
    155                 } else {
    156                         const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    157                         assert( diff == -1 && destAsRef );
    158                         PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )
    159                         if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {
    160                                 PRINT( std::cerr << "converting compatible base type" << std::endl; )
    161                                 if ( srcIsLvalue ) {
    162                                         PRINT(
    163                                                 std::cerr << "lvalue to reference conversion" << std::endl;
    164                                                 std::cerr << src << " => " << destAsRef << std::endl;
    165                                         )
    166                                         // lvalue-to-reference conversion:  cv lvalue T => cv T &
    167                                         if ( src->tq == destAsRef->base->tq ) {
    168                                                 return Cost::reference; // cost needs to be non-zero to add cast
    169                                         } if ( src->tq < destAsRef->base->tq ) {
    170                                                 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
    171                                         } else {
    172                                                 return Cost::unsafe;
    173                                         } // if
    174                                 } else if ( destAsRef->base->get_const() ) {
    175                                         PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
    176                                         // rvalue-to-const-reference conversion: T => const T &
    177                                         return Cost::safe;
    178                                 } else {
    179                                         PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
    180                                         // rvalue-to-reference conversion: T => T &
    181                                         return Cost::unsafe;
    182                                 } // if
    183                         } // if
    184                         PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
    185                 }
    186                 return Cost::infinity;
    187         }
    188 
    189         Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
    190                         const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    191                 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
    192                 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );
    193                 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )
    194                 return cost;
    195         }
    196 
    197         ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    198                 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {
    199         }
    20033
    20134        // GENERATED START, DO NOT EDIT
     
    22659        // GENERATED START, DO NOT EDIT
    22760        // GENERATED BY BasicTypes-gen.cc
    228         static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
     61        static const int costMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
    22962                /*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
    23063                /*      B */ {   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,  17,  16,  18,  17, },
     
    268101        // GENERATED END
    269102        static_assert(
    270                 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     103                sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
    271104                "Missing row in the cost matrix"
    272105        );
     
    274107        // GENERATED START, DO NOT EDIT
    275108        // GENERATED BY BasicTypes-gen.cc
    276         static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
     109        static const int signMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
    277110                /*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
    278111                /*      B */ {   0,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     
    315148        // GENERATED END
    316149        static_assert(
    317                 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     150                sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
    318151                "Missing row in the sign matrix"
    319152        );
    320 
    321         void ConversionCost::postvisit( const VoidType * ) {
    322                 cost = Cost::infinity;
    323         }
    324 
    325         // refactor for code resue
    326         void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {
    327                 int tableResult = costMatrix[ src->kind ][ dest->kind ];
    328                 if ( tableResult == -1 ) {
    329                         cost = Cost::unsafe;
    330                 } else {
    331                         cost = Cost::zero;
    332                         cost.incSafe( tableResult );
    333                         cost.incSign( signMatrix[ src->kind ][ dest->kind ] );
    334                 } // if
    335         } // ConversionCost::conversionCostFromBasicToBasic
    336 
    337         void ConversionCost::postvisit(const BasicType * basicType) {
    338                 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    339                         conversionCostFromBasicToBasic(basicType, destAsBasic);
    340                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {
    341                         const EnumDecl * base_enum = enumInst->baseEnum;
    342                         if ( const Type * base = base_enum->base ) {
    343                                 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {
    344                                         conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);
    345                                 } else {
    346                                         cost = Cost::infinity;
    347                                 } // if
    348                         } else {
    349                                 cost = Cost::unsafe;
    350                         } // if
    351                 } // if
    352                 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.
    353         }
    354 
    355         void ConversionCost::postvisit( const PointerType * pointerType ) {
    356                 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
    357                         PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )
    358                         Type::Qualifiers tq1 = pointerType->base->tq;
    359                         Type::Qualifiers tq2 = destAsPtr->base->tq;
    360                         if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    361                                 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
    362                                 if ( tq1 == tq2 ) {
    363                                         // types are the same
    364                                         cost = Cost::zero;
    365                                 } else {
    366                                         // types are the same, except otherPointer has more qualifiers
    367                                         cost = Cost::safe;
    368                                 } // if
    369                         } else {
    370                                 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
    371                                 PRINT( std::cerr << " :: " << assignResult << std::endl; )
    372                                 if ( assignResult > 0 && tq1 <= tq2 ) {
    373                                         // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?
    374                                         if ( tq1 == tq2 ) {
    375                                                 cost = Cost::safe;
    376                                         } else if ( tq1 < tq2 ) {
    377                                                 cost = Cost::safe+Cost::safe;
    378                                         }
    379                                 } else if ( assignResult < 0 ) {
    380                                         cost = Cost::unsafe;
    381                                 } // if
    382                                 // assignResult == 0 means Cost::Infinity
    383                         } // if
    384                         // case case for zero_t because it should not be possible to convert pointers to zero_t.
    385                 } // if
    386         }
    387 
    388         void ConversionCost::postvisit( const ArrayType * ) {}
    389 
    390         void ConversionCost::postvisit( const ReferenceType * refType ) {
    391                 // Note: dest can never be a reference, since it would have been caught in an earlier check
    392                 assert( ! dynamic_cast< const ReferenceType * >( dest ) );
    393                 // convert reference to rvalue: cv T1 & => T2
    394                 // recursively compute conversion cost from T1 to T2.
    395                 // cv can be safely dropped because of 'implicit dereference' behavior.
    396                 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );
    397                 if ( refType->base->tq == dest->tq ) {
    398                         cost.incReference();  // prefer exact qualifiers
    399                 } else if ( refType->base->tq < dest->tq ) {
    400                         cost.incSafe(); // then gaining qualifiers
    401                 } else {
    402                         cost.incUnsafe(); // lose qualifiers as last resort
    403                 }
    404                 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
    405         }
    406 
    407         void ConversionCost::postvisit( const FunctionType * ) {}
    408 
    409         void ConversionCost::postvisit( const EnumInstType * enumInst) {
    410                 const EnumDecl * enumDecl = enumInst -> baseEnum;
    411                 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum
    412                         cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );
    413                 } else {
    414                         static Type::Qualifiers q;
    415                         static BasicType integer( q, BasicType::SignedInt );
    416                         cost = costFunc( &integer, dest, srcIsLvalue, indexer, env );  // safe if dest >= int
    417                 } // if
    418                 if ( cost < Cost::unsafe ) {
    419                                 cost.incSafe();
    420                 } // if
    421         }
    422 
    423         void ConversionCost::postvisit( const TraitInstType * ) {}
    424 
    425         void ConversionCost::postvisit( const TypeInstType * inst ) {
    426                 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
    427                         cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );
    428                 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    429                         if ( inst->name == destAsInst->name ) {
    430                                 cost = Cost::zero;
    431                         }
    432                 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {
    433                         const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    434                         // all typedefs should be gone by this point
    435                         assert( type );
    436                         if ( type->base ) {
    437                                 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;
    438                         } // if
    439                 } // if
    440         }
    441 
    442         void ConversionCost::postvisit( const TupleType * tupleType ) {
    443                 Cost c = Cost::zero;
    444                 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {
    445                         std::list< Type * >::const_iterator srcIt = tupleType->types.begin();
    446                         std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();
    447                         while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {
    448                                 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );
    449                                 if ( newCost == Cost::infinity ) {
    450                                         return;
    451                                 } // if
    452                                 c += newCost;
    453                         } // while
    454                         if ( destIt != destAsTuple->types.end() ) {
    455                                 cost = Cost::infinity;
    456                         } else {
    457                                 cost = c;
    458                         } // if
    459                 } // if
    460         }
    461 
    462         void ConversionCost::postvisit( const VarArgsType * ) {
    463                 if ( dynamic_cast< const VarArgsType * >( dest ) ) {
    464                         cost = Cost::zero;
    465                 }
    466         }
    467 
    468         void ConversionCost::postvisit( const ZeroType * ) {
    469                 if ( dynamic_cast< const ZeroType * >( dest ) ) {
    470                         cost = Cost::zero;
    471                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    472                         // copied from visit(BasicType *) for signed int, but +1 for safe conversions
    473                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    474                         if ( tableResult == -1 ) {
    475                                 cost = Cost::unsafe;
    476                         } else {
    477                                 cost = Cost::zero;
    478                                 cost.incSafe( tableResult + 1 );
    479                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
    480                         } // if
    481                 } else if ( dynamic_cast< const PointerType * >( dest ) ) {
    482                         cost = Cost::zero;
    483                         cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
    484                 } // if
    485         }
    486 
    487         void ConversionCost::postvisit( const OneType * ) {
    488                 if ( dynamic_cast< const OneType * >( dest ) ) {
    489                         cost = Cost::zero;
    490                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    491                         // copied from visit(BasicType *) for signed int, but +1 for safe conversions
    492                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    493                         if ( tableResult == -1 ) {
    494                                 cost = Cost::unsafe;
    495                         } else {
    496                                 cost = Cost::zero;
    497                                 cost.incSafe( tableResult + 1 );
    498                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
    499                         } // if
    500                 } // if
    501         }
    502153
    503154namespace {
  • src/ResolvExpr/ConversionCost.h

    r0030b508 rfc12f05  
    2222#include "AST/Fwd.hpp"
    2323#include "AST/Pass.hpp"       // for WithShortCircuiting
    24 #include "Common/PassVisitor.h"
    25 #include "SynTree/Visitor.h"  // for Visitor
    26 #include "SynTree/SynTree.h"  // for Visitor Nodes
    2724
    2825namespace SymTab {
     
    3229namespace ResolvExpr {
    3330        class TypeEnvironment;
    34 
    35         Cost conversionCost(
    36                 const Type * src, const Type * dest, bool srcIsLvalue,
    37                 const SymTab::Indexer & indexer, const TypeEnvironment & env );
    38 
    39         typedef std::function<Cost(const Type *, const Type *, bool,
    40                 const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;
    41 
    42         struct ConversionCost : public WithShortCircuiting {
    43           public:
    44                 ConversionCost( const Type * dest, bool srcIsLvalue,
    45                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );
    46 
    47                 Cost get_cost() const { return cost; }
    48 
    49                 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    50 
    51                 void postvisit( const VoidType * voidType );
    52                 void postvisit( const BasicType * basicType );
    53                 void postvisit( const PointerType * pointerType );
    54                 void postvisit( const ArrayType * arrayType );
    55                 void postvisit( const ReferenceType * refType );
    56                 void postvisit( const FunctionType * functionType );
    57                 void postvisit( const EnumInstType * aggregateUseType );
    58                 void postvisit( const TraitInstType * aggregateUseType );
    59                 void postvisit( const TypeInstType * aggregateUseType );
    60                 void postvisit( const TupleType * tupleType );
    61                 void postvisit( const VarArgsType * varArgsType );
    62                 void postvisit( const ZeroType * zeroType );
    63                 void postvisit( const OneType * oneType );
    64           protected:
    65                 const Type * dest;
    66                 bool srcIsLvalue;
    67                 const SymTab::Indexer &indexer;
    68                 Cost cost;
    69                 const TypeEnvironment &env;
    70                 CostFunction costFunc;
    71           private:
    72                 // refactor for code resue
    73                 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest );
    74         };
    75 
    76         typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;
    77         Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
    78                 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );
    7931
    8032// Some function pointer types, differ in return type.
  • src/ResolvExpr/CurrentObject.cc

    r0030b508 rfc12f05  
    3333#include "Common/utility.h"            // for toString
    3434#include "CurrentObject.h"
    35 #include "SynTree/Constant.h"          // for Constant
    36 #include "SynTree/Declaration.h"       // for ObjectDecl, Declaration, Struc...
    37 #include "SynTree/Expression.h"        // for InitAlternative, VariableExpr
    38 #include "SynTree/Initializer.h"       // for Designation, operator<<
    39 #include "SynTree/Type.h"              // for Type, StructInstType, UnionIns...
    40 #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
    4135
    4236#if 0
     
    4539#define PRINT(x)
    4640#endif
    47 
    48 namespace ResolvExpr {
    49         template< typename AggrInst >
    50         TypeSubstitution makeGenericSubstitution( AggrInst * inst ) {
    51                 assert( inst );
    52                 assert( inst->get_baseParameters() );
    53                 std::list< TypeDecl * > baseParams = *inst->get_baseParameters();
    54                 std::list< Expression * > typeSubs = inst->get_parameters();
    55                 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );
    56                 return subs;
    57         }
    58 
    59         TypeSubstitution makeGenericSubstitution( Type * type ) {
    60                 if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) {
    61                         return makeGenericSubstitution( inst );
    62                 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) {
    63                         return makeGenericSubstitution( inst );
    64                 } else {
    65                         return TypeSubstitution();
    66                 }
    67         }
    68 
    69         class MemberIterator {
    70         public:
    71                 virtual ~MemberIterator() {}
    72 
    73                 /// walks the current object using the given designators as a guide
    74                 virtual void setPosition( std::list< Expression * > & designators ) = 0;
    75 
    76                 /// retrieve the list of possible Type/Designation pairs for the current position in the currect object
    77                 virtual std::list<InitAlternative> operator*() const = 0;
    78 
    79                 /// true if the iterator is not currently at the end
    80                 virtual operator bool() const = 0;
    81 
    82                 /// moves the iterator by one member in the current object
    83                 virtual MemberIterator & bigStep() = 0;
    84 
    85                 /// moves the iterator by one member in the current subobject
    86                 virtual MemberIterator & smallStep() = 0;
    87 
    88                 /// the type of the current object
    89                 virtual Type * getType() = 0;
    90 
    91                 /// the type of the current subobject
    92                 virtual Type * getNext() = 0;
    93 
    94                 /// printing for debug
    95                 virtual void print( std::ostream & out, Indenter indent ) const = 0;
    96 
    97                 /// helper for operator*; aggregates must add designator to each init alternative, but
    98                 /// adding designators in operator* creates duplicates.
    99                 virtual std::list<InitAlternative> first() const = 0; // should be protected
    100         };
    101 
    102         std::ostream & operator<<(std::ostream & out, const MemberIterator & it) {
    103                 Indenter indenter;
    104                 it.print( out, indenter );
    105                 return out;
    106         }
    107 
    108         /// create a new MemberIterator that traverses a type correctly
    109         MemberIterator * createMemberIterator( Type * type );
    110 
    111         /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry
    112         class SimpleIterator : public MemberIterator {
    113         public:
    114                 SimpleIterator( Type * type ) : type( type ) {}
    115 
    116                 virtual void setPosition( std::list< Expression * > & designators ) {
    117                         assertf( designators.empty(), "simple iterator given non-empty designator..." ); // xxx - might be semantic error
    118                 }
    119 
    120                 virtual std::list<InitAlternative> operator*() const { return first(); }
    121                 virtual operator bool() const { return type; }
    122 
    123                 // big step is the same as small step
    124                 virtual MemberIterator & bigStep() { return smallStep(); }
    125                 virtual MemberIterator & smallStep() {
    126                         type = nullptr;  // type is nullified on increment since SimpleIterators do not have members
    127                         return *this;
    128                 }
    129 
    130                 virtual void print( std::ostream & out, __attribute__((unused)) Indenter indent ) const {
    131                         out << "SimpleIterator(" << type << ")";
    132                 }
    133 
    134                 virtual Type * getType() { return type; }
    135                 virtual Type * getNext() { return type; }
    136 
    137         protected:
    138                 virtual std::list<InitAlternative> first() const {
    139                         if ( type ) return std::list<InitAlternative>{ { type->clone(), new Designation( {} ) } };
    140                         else return std::list<InitAlternative>{};
    141                 }
    142         private:
    143                 Type * type = nullptr;
    144         };
    145 
    146         class ArrayIterator : public MemberIterator {
    147         public:
    148                 ArrayIterator( ArrayType * at ) : array( at ) {
    149                         PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    150                         base = at->base;
    151                         memberIter = createMemberIterator( base );
    152                         if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " );
    153                         setSize( at->dimension );
    154                 }
    155 
    156                 ~ArrayIterator() {
    157                         delete memberIter;
    158                 }
    159 
    160         private:
    161                 void setSize( Expression * expr ) {
    162                         auto res = eval( expr );
    163                         if (res.second) {
    164                                 size = res.first;
    165                         } else {
    166                                 SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) );
    167                         }
    168                 }
    169 
    170         public:
    171                 void setPosition( Expression * expr ) {
    172                         // need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions
    173                         auto arg = eval( expr );
    174                         index = arg.first;
    175                         return;
    176 
    177                         // if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
    178                         //      try {
    179                         //              index = constExpr->intValue();
    180                         //      } catch( SemanticErrorException & ) {
    181                         //              SemanticError( expr, "Constant expression of non-integral type in array designator: " );
    182                         //      }
    183                         // } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    184                         //      setPosition( castExpr->get_arg() );
    185                         // } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
    186                         //      EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );
    187                         //      assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );
    188                         //      long long int value;
    189                         //      if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
    190                         //              index = value;
    191                         //      }
    192                         // } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {
    193                         //      index = 0; // xxx - get actual sizeof/alignof value?
    194                         // } else {
    195                         //      assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    196                         // }
    197                 }
    198 
    199                 virtual void setPosition( std::list< Expression * > & designators ) {
    200                         if ( ! designators.empty() ) {
    201                                 setPosition( designators.front() );
    202                                 designators.pop_front();
    203                                 memberIter->setPosition( designators );
    204                         }
    205                 }
    206 
    207                 virtual std::list<InitAlternative> operator*() const {
    208                         return first();
    209                 }
    210 
    211                 virtual operator bool() const { return index < size; }
    212 
    213                 virtual MemberIterator & bigStep() {
    214                         PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    215                         ++index;
    216                         delete memberIter;
    217                         if ( index < size ) memberIter = createMemberIterator( base );
    218                         else memberIter = nullptr;
    219                         return *this;
    220                 }
    221 
    222                 virtual MemberIterator & smallStep() {
    223                         PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    224                         if ( memberIter ) {
    225                                 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
    226                                 memberIter->smallStep();
    227                                 if ( *memberIter ) {
    228                                         PRINT( std::cerr << "has valid member iter" << std::endl; )
    229                                         return *this;
    230                                 }
    231                         }
    232                         return bigStep();
    233                 }
    234 
    235                 virtual Type * getType() { return array; }
    236                 virtual Type * getNext() { return base; }
    237 
    238                 virtual std::list<InitAlternative> first() const {
    239                         PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    240                         if ( memberIter && *memberIter ) {
    241                                 std::list<InitAlternative> ret = memberIter->first();
    242                                 for ( InitAlternative & alt : ret ) {
    243                                         alt.designation->get_designators().push_front( new ConstantExpr( Constant::from_ulong( index ) ) );
    244                                 }
    245                                 return ret;
    246                         }
    247                         return std::list<InitAlternative>();
    248                 }
    249 
    250                 virtual void print( std::ostream & out, Indenter indent ) const {
    251                         out << "ArrayIterator(Array of " << base << ")";
    252                         if ( memberIter ) {
    253                                 Indenter childIndent = indent+1;
    254                                 out << std::endl << childIndent;
    255                                 memberIter->print( out, childIndent );
    256                         }
    257                 }
    258 
    259         private:
    260                 ArrayType * array = nullptr;
    261                 Type * base = nullptr;
    262                 size_t index = 0;
    263                 size_t size = 0;
    264                 MemberIterator * memberIter = nullptr;
    265         };
    266 
    267         class AggregateIterator : public MemberIterator {
    268         public:
    269                 typedef std::list<Declaration *> MemberList;
    270                 typedef MemberList::const_iterator iterator;
    271                 std::string kind = ""; // for debug
    272                 std::string name;
    273                 Type * inst = nullptr;
    274                 const MemberList & members;
    275                 iterator curMember;
    276                 bool atbegin = true; // false at first {small,big}Step -- this aggr type is only added to the possibilities at the beginning
    277                 Type * curType = nullptr;
    278                 MemberIterator * memberIter = nullptr;
    279                 mutable TypeSubstitution sub;
    280 
    281                 AggregateIterator( const std::string & kind, const std::string & name, Type * inst, const MemberList & members ) : kind( kind ), name( name ), inst( inst ), members( members ), curMember( members.begin() ), sub( makeGenericSubstitution( inst ) ) {
    282                         PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
    283                         init();
    284                 }
    285 
    286                 virtual ~AggregateIterator() {
    287                         delete memberIter;
    288                 }
    289 
    290                 bool init() {
    291                         PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
    292                         if ( curMember != members.end() ) {
    293                                 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( *curMember ) ) {
    294                                         PRINT( std::cerr << "incremented to field: " << field << std::endl; )
    295                                         curType = field->get_type();
    296                                         memberIter = createMemberIterator( curType );
    297                                         return true;
    298                                 }
    299                         }
    300                         return false;
    301                 }
    302 
    303                 virtual std::list<InitAlternative> operator*() const {
    304                         if (memberIter && *memberIter) {
    305                                 std::list<InitAlternative> ret = memberIter->first();
    306                                 PRINT( std::cerr << "sub: " << sub << std::endl; )
    307                                 for ( InitAlternative & alt : ret ) {
    308                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    309                                         alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );
    310                                         // need to substitute for generic types, so that casts are to concrete types
    311                                         PRINT( std::cerr << "  type is: " << alt.type; )
    312                                         sub.apply( alt.type ); // also apply to designation??
    313                                         PRINT( std::cerr << " ==> " << alt.type << std::endl; )
    314                                 }
    315                                 return ret;
    316                         }
    317                         return std::list<InitAlternative>();
    318                 }
    319 
    320                 virtual void setPosition( std::list< Expression * > & designators ) {
    321                         if ( ! designators.empty() ) {
    322                                 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( designators.front() ) ) {
    323                                         for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
    324                                                 if ( *curMember == varExpr->get_var() ) {
    325                                                         designators.pop_front();
    326                                                         delete memberIter;
    327                                                         memberIter = createMemberIterator( varExpr->get_result() );
    328                                                         curType = varExpr->get_result();
    329                                                         atbegin = curMember == members.begin() && designators.empty(); // xxx - is this the right condition for atbegin??
    330                                                         memberIter->setPosition( designators );
    331                                                         return;
    332                                                 } // if
    333                                         } // for
    334                                         assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    335                                 } else {
    336                                         assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );
    337                                 } // if
    338                         } // if
    339                 }
    340 
    341                 virtual MemberIterator & smallStep() {
    342                         PRINT( std::cerr << "smallStep in " << kind << std::endl; )
    343                         atbegin = false;
    344                         if ( memberIter ) {
    345                                 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
    346                                 memberIter->smallStep();
    347                                 if ( *memberIter ) {
    348                                         PRINT( std::cerr << "success!" << std::endl; )
    349                                         return *this;
    350                                 }
    351                         }
    352                         return bigStep();
    353                 }
    354 
    355                 virtual Type * getType() { return inst; }
    356                 virtual Type * getNext() {
    357                         if ( memberIter && *memberIter ) return memberIter->getType(); // xxx - ??? recursive call???
    358                         return nullptr;
    359                 }
    360 
    361                 virtual std::list<InitAlternative> first() const {
    362                         std::list<InitAlternative> ret;
    363                         PRINT( std::cerr << "first " << kind << std::endl; )
    364                         if ( memberIter && *memberIter ) { // might not need *memberIter??
    365                                 PRINT( std::cerr << "adding children" << std::endl; )
    366                                 ret = memberIter->first();
    367                                 for ( InitAlternative & alt : ret ) {
    368                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    369                                         alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );
    370                                 }
    371                         }
    372                         if ( atbegin ) {
    373                                 // xxx - what about case of empty struct??
    374                                 // only add self if at the very beginning of the structure
    375                                 PRINT( std::cerr << "adding self" << std::endl; )
    376                                 ret.push_front( { inst->clone(), new Designation( {} ) } );
    377                         }
    378                         return ret;
    379                 }
    380 
    381                 virtual void print( std::ostream & out, Indenter indent ) const {
    382                         out << kind << "(" << name << ")";
    383                         if ( memberIter ) {
    384                                 Indenter childIndent = indent+1;
    385                                 out << std::endl << childIndent;
    386                                 memberIter->print( out, childIndent );
    387                         }
    388                 }
    389         };
    390 
    391         class UnionIterator : public AggregateIterator {
    392         public:
    393                 UnionIterator( UnionInstType * inst ) : AggregateIterator( "UnionIterator", inst->get_name(), inst, inst->get_baseUnion()->get_members() ) {}
    394 
    395                 virtual operator bool() const { return (memberIter && *memberIter); }
    396                 virtual MemberIterator & bigStep() {
    397                         // unions only initialize one member
    398                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    399                         atbegin = false;
    400                         delete memberIter;
    401                         memberIter = nullptr;
    402                         curType = nullptr;
    403                         curMember = members.end();
    404                         return *this;
    405                 }
    406         };
    407 
    408         class StructIterator : public AggregateIterator {
    409         public:
    410                 StructIterator( StructInstType * inst ) : AggregateIterator( "StructIterator", inst->get_name(), inst, inst->get_baseStruct()->get_members() ) {}
    411 
    412                 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }
    413 
    414                 virtual MemberIterator & bigStep() {
    415                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    416                         atbegin = false;
    417                         delete memberIter;
    418                         memberIter = nullptr;
    419                         curType = nullptr;
    420                         for ( ; curMember != members.end(); ) {
    421                                 ++curMember;
    422                                 if ( init() ) {
    423                                         return *this;
    424                                 }
    425                         }
    426                         return *this;
    427                 }
    428         };
    429 
    430         class TupleIterator : public AggregateIterator {
    431         public:
    432                 TupleIterator( TupleType * inst ) : AggregateIterator( "TupleIterator", toString("Tuple", inst->size()), inst, inst->get_members() ) {}
    433 
    434                 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }
    435 
    436                 virtual MemberIterator & bigStep() {
    437                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    438                         atbegin = false;
    439                         delete memberIter;
    440                         memberIter = nullptr;
    441                         curType = nullptr;
    442                         for ( ; curMember != members.end(); ) {
    443                                 ++curMember;
    444                                 if ( init() ) {
    445                                         return *this;
    446                                 }
    447                         }
    448                         return *this;
    449                 }
    450         };
    451 
    452         MemberIterator * createMemberIterator( Type * type ) {
    453                 if ( ReferenceToType * aggr = dynamic_cast< ReferenceToType * >( type ) ) {
    454                         if ( StructInstType * sit = dynamic_cast< StructInstType * >( aggr ) ) {
    455                                 return new StructIterator( sit );
    456                         } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( aggr ) ) {
    457                                 return new UnionIterator( uit );
    458                         } else {
    459                                 assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );
    460                                 return new SimpleIterator( type );
    461                         }
    462                 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    463                         return new ArrayIterator( at );
    464                 } else if ( TupleType * tt = dynamic_cast< TupleType * >( type ) ) {
    465                         return new TupleIterator( tt );
    466                 } else {
    467                         return new SimpleIterator( type );
    468                 }
    469         }
    470 
    471         CurrentObject::CurrentObject() {}
    472         CurrentObject::CurrentObject( Type * type ) {
    473                 objStack.push( new SimpleIterator( type ) );
    474         }
    475 
    476 
    477         void CurrentObject::setNext( Designation * designation ) {
    478                 assertf( ! objStack.empty(), "obj stack empty in setNext" );
    479                 PRINT( std::cerr << "____setNext" << designation << std::endl; )
    480                 objStack.top()->setPosition( designation->get_designators() );
    481         }
    482 
    483         Designation * CurrentObject::findNext( Designation * designation ) {
    484                 typedef std::list< Expression * > DesignatorChain;
    485                 PRINT( std::cerr << "___findNext" << std::endl; )
    486                 // find all the d's
    487                 std::list<DesignatorChain> desigAlts{ { } }, newDesigAlts;
    488                 std::list<Type *> curTypes { (objStack.top())->getType() }, newTypes;
    489                 for ( Expression * expr : designation->get_designators() ) {
    490                         PRINT( std::cerr << "____untyped: " << expr << std::endl; )
    491                         std::list<DesignatorChain>::iterator dit = desigAlts.begin();
    492                         if ( NameExpr * nexpr = dynamic_cast<NameExpr *>(expr) ) {
    493                                 for ( Type * t : curTypes ) {
    494                                         assert( dit != desigAlts.end() );
    495                                         DesignatorChain & d = *dit;
    496                                         PRINT( std::cerr << "____actual: " << t << std::endl; )
    497                                         ReferenceToType * refType = dynamic_cast<ReferenceToType *>(t);
    498                                         std::list<Declaration *> members;
    499                                         if ( refType ) {
    500                                                 refType->lookup( nexpr->get_name(), members ); // concatenate identical field name
    501                                                 // xxx - need to also include anonymous members in this somehow...
    502                                                 for ( Declaration * mem: members ) {
    503                                                         if ( ObjectDecl * field = dynamic_cast<ObjectDecl *>(mem) ) {
    504                                                                 PRINT( std::cerr << "____alt: " << field->get_type() << std::endl; )
    505                                                                 DesignatorChain newD = d;
    506                                                                 newD.push_back( new VariableExpr( field ) );
    507                                                                 newDesigAlts.push_back( newD );
    508                                                                 newTypes.push_back( field->get_type() );
    509                                                         } // if
    510                                                 } // for
    511                                         } // if
    512                                         ++dit;
    513                                 } // for
    514                         } else {
    515                                 for ( Type * t : curTypes ) {
    516                                         assert( dit != desigAlts.end() );
    517                                         DesignatorChain & d = *dit;
    518                                         if ( ArrayType * at = dynamic_cast< ArrayType * > ( t ) ) {
    519                                                 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
    520                                                 d.push_back( expr );
    521                                                 newDesigAlts.push_back( d );
    522                                                 newTypes.push_back( at->get_base() );
    523                                         }
    524                                         ++dit;
    525                                 } // for
    526                         } // if
    527                         desigAlts = newDesigAlts;
    528                         newDesigAlts.clear();
    529                         curTypes = newTypes;
    530                         newTypes.clear();
    531                         assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
    532                 } // for
    533                 if ( desigAlts.size() > 1 ) {
    534                         SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
    535                 } else if ( desigAlts.size() == 0 ) {
    536                         SemanticError( designation, "No reasonable alternatives for designation: " );
    537                 }
    538                 DesignatorChain & d = desigAlts.back();
    539                 PRINT( for ( Expression * expr : d ) {
    540                         std::cerr << "____desig: " << expr << std::endl;
    541                 } ) // for
    542                 assertf( ! curTypes.empty(), "empty designator chosen");
    543 
    544                 // set new designators
    545                 assertf( ! objStack.empty(), "empty object stack when setting designation" );
    546                 Designation * actualDesignation = new Designation( d );
    547                 objStack.top()->setPosition( d ); // destroys d
    548                 return actualDesignation;
    549         }
    550 
    551         void CurrentObject::increment() {
    552                 PRINT( std::cerr << "____increment" << std::endl; )
    553                 if ( ! objStack.empty() ) {
    554                         PRINT( std::cerr << *objStack.top() << std::endl; )
    555                         objStack.top()->smallStep();
    556                 }
    557         }
    558 
    559         void CurrentObject::enterListInit() {
    560                 PRINT( std::cerr << "____entering list init" << std::endl; )
    561                 assertf( ! objStack.empty(), "empty obj stack entering list init" );
    562                 Type * type = objStack.top()->getNext();
    563                 if ( type ) {
    564                         objStack.push( createMemberIterator( type ) );
    565                 } else {
    566                         assertf( false, "not sure about this case..." );
    567                 }
    568         }
    569 
    570         void CurrentObject::exitListInit() {
    571                 PRINT( std::cerr << "____exiting list init" << std::endl; )
    572                 assertf( ! objStack.empty(), "objstack empty" );
    573                 delete objStack.top();
    574                 objStack.pop();
    575                 if ( ! objStack.empty() ) {
    576                         PRINT( std::cerr << *objStack.top() << std::endl; )
    577                         objStack.top()->bigStep();
    578                 }
    579         }
    580 
    581         std::list< InitAlternative > CurrentObject::getOptions() {
    582                 PRINT( std::cerr << "____getting current options" << std::endl; )
    583                 assertf( ! objStack.empty(), "objstack empty in getOptions" );
    584                 return **objStack.top();
    585         }
    586 
    587         Type * CurrentObject::getCurrentType() {
    588                 PRINT( std::cerr << "____getting current type" << std::endl; )
    589                 assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
    590                 return objStack.top()->getNext();
    591         }
    592 } // namespace ResolvExpr
    59341
    59442namespace ast {
     
    1064512                                        } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
    1065513                                                auto nexpr = dynamic_cast< const NameExpr *>( expr );
    1066                                                 auto res = eval( nexpr );
    1067514                                                for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
    1068515                                                        if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
     
    1070517                                                                d2.emplace_back( new VariableExpr{ expr->location, field } );
    1071518                                                                newDesigAlts.emplace_back( std::move( d2 ) );
    1072                                                                 // newTypes.emplace_back( field->type );
    1073519                                                                newTypes.emplace_back( at->base );
    1074520                                                        }
    1075521                                                }
    1076 
    1077                                                 // d.emplace_back( expr );
    1078                                                 // newDesigAlts.emplace_back( d );
    1079                                                 // newTypes.emplace_back( at->base );
    1080522                                        }
    1081523
  • src/ResolvExpr/FindOpenVars.cc

    r0030b508 rfc12f05  
    1616#include "FindOpenVars.h"
    1717
    18 #include <list>                   // for _List_const_iterator, list<>::const...
    19 #include <map>                    // for map<>::mapped_type
    20 
    2118#include "AST/Pass.hpp"
    2219#include "AST/Type.hpp"
    2320#include "AST/TypeEnvironment.hpp"
    24 #include "Common/PassVisitor.h"
    25 #include "SynTree/Declaration.h"  // for TypeDecl, DeclarationWithType (ptr ...
    26 #include "SynTree/Type.h"         // for Type, Type::ForallList, ArrayType
    2721
    2822#include <iostream>
    2923
    3024namespace ResolvExpr {
    31         struct FindOpenVars_old : public WithGuards {
    32                 FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
    33 
    34                 void previsit( const PointerType * pointerType );
    35                 void previsit( const ArrayType * arrayType );
    36                 void previsit( const FunctionType * functionType );
    37                 void previsit( const TupleType * tupleType );
    38 
    39                 void common_action( const Type *type );
    40 
    41                 OpenVarSet &openVars, &closedVars;
    42                 AssertionSet &needAssertions, &haveAssertions;
    43                 bool nextIsOpen;
    44         };
    45 
    46         void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {
    47                 PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );
    48                 type->accept( finder );
    49         }
    50 
    51         FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )
    52                 : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) {
    53         }
    54 
    55         void FindOpenVars_old::common_action( const Type * type ) {
    56                 if ( nextIsOpen ) {
    57                         for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    58                                 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    59                                 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
    60                                         needAssertions[ *assert ].isUsed = false;
    61                                 }
    62 ///       cloneAll( (*i)->get_assertions(), needAssertions );
    63 ///       needAssertions.insert( needAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );
    64                         }
    65                 } else {
    66                         for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    67                                 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    68                                 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
    69                                         haveAssertions[ *assert ].isUsed = false;
    70                                 }
    71 ///       cloneAll( (*i)->get_assertions(), haveAssertions );
    72 ///       haveAssertions.insert( haveAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );
    73                         } // for
    74                 } // if
    75 ///   std::cerr << "type is ";
    76 ///   type->print( std::cerr );
    77 ///   std::cerr << std::endl << "need is" << std::endl;
    78 ///   printAssertionSet( needAssertions, std::cerr );
    79 ///   std::cerr << std::endl << "have is" << std::endl;
    80 ///   printAssertionSet( haveAssertions, std::cerr );
    81         }
    82 
    83         void FindOpenVars_old::previsit(const PointerType * pointerType) {
    84                 common_action( pointerType );
    85         }
    86 
    87         void FindOpenVars_old::previsit(const ArrayType * arrayType) {
    88                 common_action( arrayType );
    89         }
    90 
    91         void FindOpenVars_old::previsit(const FunctionType * functionType) {
    92                 common_action( functionType );
    93                 nextIsOpen = ! nextIsOpen;
    94                 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
    95         }
    96 
    97         void FindOpenVars_old::previsit(const TupleType * tupleType) {
    98                 common_action( tupleType );
    99         }
    10025
    10126        namespace {
  • src/ResolvExpr/FindOpenVars.h

    r0030b508 rfc12f05  
    1717
    1818#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
    19 #include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
    2019
    21 class Type;
    2220namespace ast {
    2321        class Type;
     
    2523
    2624namespace ResolvExpr {
    27         // Updates open and closed variables and their associated assertions
    28         void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
    29 
    3025        enum FirstMode { FirstClosed, FirstOpen };
    3126
  • src/ResolvExpr/PolyCost.cc

    r0030b508 rfc12f05  
    1818#include "AST/Type.hpp"
    1919#include "AST/TypeEnvironment.hpp"
    20 #include "Common/PassVisitor.h"
    21 #include "SymTab/Indexer.h"   // for Indexer
    22 #include "SynTree/Type.h"     // for TypeInstType, Type
    23 #include "TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2420
    2521namespace ResolvExpr {
    26         struct PolyCost {
    27                 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );
    28 
    29                 void previsit( TypeInstType * aggregateUseType );
    30                 int result;
    31                 const TypeEnvironment &tenv;
    32                 const SymTab::Indexer &indexer;
    33         };
    34 
    35         int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) {
    36                 PassVisitor<PolyCost> coster( env, indexer );
    37                 type->accept( coster );
    38                 return (coster.pass.result > 0) ? 1 : 0;
    39         }
    40 
    41         PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) {
    42         }
    43 
    44         void PolyCost::previsit(TypeInstType * typeInst) {
    45                 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) {
    46                         if ( eqvClass->type ) {
    47                                 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) {
    48                                         if ( indexer.lookupType( otherTypeInst->name ) ) {
    49                                                 // bound to opaque type
    50                                                 result += 1;
    51                                         } // if
    52                                 } else {
    53                                         // bound to concrete type
    54                                         result += 1;
    55                                 } // if
    56                         } // if
    57                 } // if
    58         }
    5922
    6023// TODO: When the old PolyCost is torn out get rid of the _new suffix.
  • src/ResolvExpr/PtrsAssignable.cc

    r0030b508 rfc12f05  
    1919#include "AST/Type.hpp"
    2020#include "AST/TypeEnvironment.hpp"
    21 #include "Common/PassVisitor.h"
    22 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    23 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    24 #include "SynTree/Visitor.h"             // for Visitor
    25 
    2621
    2722namespace ResolvExpr {
    28         struct PtrsAssignable : public WithShortCircuiting {
    29                 PtrsAssignable( const Type * dest, const TypeEnvironment &env );
    30 
    31                 int get_result() const { return result; }
    32 
    33                 void previsit( const Type * ) { visit_children = false; }
    34 
    35                 void postvisit( const VoidType * voidType );
    36                 void postvisit( const BasicType * basicType );
    37                 void postvisit( const PointerType * pointerType );
    38                 void postvisit( const ArrayType * arrayType );
    39                 void postvisit( const FunctionType * functionType );
    40                 void postvisit( const StructInstType * inst );
    41                 void postvisit( const UnionInstType * inst );
    42                 void postvisit( const EnumInstType * inst );
    43                 void postvisit( const TraitInstType * inst );
    44                 void postvisit( const TypeInstType * inst );
    45                 void postvisit( const TupleType * tupleType );
    46                 void postvisit( const VarArgsType * varArgsType );
    47                 void postvisit( const ZeroType * zeroType );
    48                 void postvisit( const OneType * oneType );
    49           private:
    50                 const Type * dest;
    51                 int result;
    52                 const TypeEnvironment &env;
    53         };
    54 
    55         int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) {
    56                 // std::cerr << "assignable: " << src << " | " << dest << std::endl;
    57                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
    58                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    59                                 return ptrsAssignable( src, eqvClass->type, env );
    60                         } // if
    61                 } // if
    62                 if ( dynamic_cast< const VoidType* >( dest ) ) {
    63                         // void * = T * for any T is unsafe
    64                         // xxx - this should be safe, but that currently breaks the build
    65                         return -1;
    66                 } else {
    67                         PassVisitor<PtrsAssignable> ptrs( dest, env );
    68                         src->accept( ptrs );
    69                         return ptrs.pass.get_result();
    70                 } // if
    71         }
    72 
    73         PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
    74 
    75         void PtrsAssignable::postvisit( const VoidType * ) {
    76                 // T * = void * is disallowed - this is a change from C, where any
    77                 // void * can be assigned or passed to a non-void pointer without a cast.
    78         }
    79 
    80         void PtrsAssignable::postvisit( const BasicType * ) {}
    81         void PtrsAssignable::postvisit( const PointerType * ) {}
    82         void PtrsAssignable::postvisit( const ArrayType * ) {}
    83         void PtrsAssignable::postvisit( const FunctionType * ) {}
    84 
    85         void PtrsAssignable::postvisit( const StructInstType * ) {}
    86         void PtrsAssignable::postvisit( const UnionInstType * ) {}
    87 
    88         void PtrsAssignable::postvisit( const EnumInstType * ) {
    89                 if ( dynamic_cast< const BasicType* >( dest ) ) {
    90                         // int * = E *, etc. is safe. This isn't technically correct, as each
    91                         // enum has one basic type that it is compatible with, an that type can
    92                         // differ from enum to enum. Without replicating GCC's internal logic,
    93                         // there is no way to know which type this particular enum is compatible
    94                         // with, so punt on this for now.
    95                         result = 1;
    96                 }
    97         }
    98 
    99         void PtrsAssignable::postvisit(  const TraitInstType * ) {}
    100         void PtrsAssignable::postvisit( const TypeInstType * inst ) {
    101                 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
    102                         if ( eqvClass->type ) {
    103                                 // T * = S * for any S depends on the type bound to T
    104                                 result = ptrsAssignable( eqvClass->type, dest, env );
    105                         }
    106                 } // if
    107         }
    108 
    109         void PtrsAssignable::postvisit( const TupleType * ) {}
    110         void PtrsAssignable::postvisit( const VarArgsType * ) {}
    111         void PtrsAssignable::postvisit( const ZeroType * ) {}
    112         void PtrsAssignable::postvisit( const OneType * ) {}
    11323
    11424// TODO: Get rid of the `_new` suffix when the old version is removed.
  • src/ResolvExpr/PtrsCastable.cc

    r0030b508 rfc12f05  
    2020#include "AST/Type.hpp"
    2121#include "AST/TypeEnvironment.hpp"
    22 #include "Common/PassVisitor.h"
    2322#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    24 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    25 #include "SymTab/Indexer.h"              // for Indexer
    26 #include "SynTree/Declaration.h"         // for TypeDecl, TypeDecl::Kind::Ftype
    27 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    28 #include "SynTree/Visitor.h"             // for Visitor
    2923
    3024namespace ResolvExpr {
    31         struct PtrsCastable_old : public WithShortCircuiting  {
    32           public:
    33                 PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
    34 
    35                 int get_result() const { return result; }
    36 
    37                 void previsit( const Type * ) { visit_children = false; }
    38 
    39                 void postvisit( const VoidType * voidType );
    40                 void postvisit( const BasicType * basicType );
    41                 void postvisit( const PointerType * pointerType );
    42                 void postvisit( const ArrayType * arrayType );
    43                 void postvisit( const FunctionType * functionType );
    44                 void postvisit( const StructInstType * inst );
    45                 void postvisit( const UnionInstType * inst );
    46                 void postvisit( const EnumInstType * inst );
    47                 void postvisit( const TraitInstType * inst );
    48                 void postvisit( const TypeInstType * inst );
    49                 void postvisit( const TupleType * tupleType );
    50                 void postvisit( const VarArgsType * varArgsType );
    51                 void postvisit( const ZeroType * zeroType );
    52                 void postvisit( const OneType * oneType );
    53           private:
    54                 const Type * dest;
    55                 int result;
    56                 const TypeEnvironment &env;
    57                 const SymTab::Indexer &indexer;
    58         };
    59 
    60         namespace {
    61                 int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    62                         if ( dynamic_cast< const FunctionType* >( src ) ) {
    63                                 return -1;
    64                         } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) {
    65                                 if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) {
    66                                         if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) {
    67                                                 if ( tyDecl->kind == TypeDecl::Ftype ) {
    68                                                         return -1;
    69                                                 } // if
    70                                         } //if
    71                                 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    72                                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    73                                                 return -1;
    74                                         } // if
    75                                 } // if
    76                         } //if
    77                         return 1;
    78                 }
    79                 int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    80                         return -1 * objectCast( src, env, indexer );  // reverse the sense of objectCast
    81                 }
    82         }
    83 
    84         int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    85                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
    86                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    87                                 // xxx - should this be ptrsCastable?
    88                                 return ptrsAssignable( src, eqvClass->type, env );
    89                         } // if
    90                 } // if
    91                 if ( dynamic_cast< const VoidType* >( dest ) ) {
    92                         return objectCast( src, env, indexer );
    93                 } else {
    94                         PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer );
    95                         src->accept( ptrs );
    96                         return ptrs.pass.get_result();
    97                 } // if
    98         }
    99 
    100         PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )
    101                 : dest( dest ), result( 0 ), env( env ), indexer( indexer )     {
    102         }
    103 
    104         void PtrsCastable_old::postvisit( const VoidType * ) {
    105                 result = objectCast( dest, env, indexer );
    106         }
    107 
    108         void PtrsCastable_old::postvisit( const BasicType * ) {
    109                 result = objectCast( dest, env, indexer );
    110         }
    111 
    112         void PtrsCastable_old::postvisit( const PointerType * ) {
    113                 result = objectCast( dest, env, indexer );
    114         }
    115 
    116         void PtrsCastable_old::postvisit( const ArrayType * ) {
    117                 result = objectCast( dest, env, indexer );
    118         }
    119 
    120         void PtrsCastable_old::postvisit( const FunctionType * ) {
    121                 // result = -1;
    122                 result = functionCast( dest, env, indexer );
    123         }
    124 
    125         void PtrsCastable_old::postvisit( const StructInstType * ) {
    126                 result = objectCast( dest, env, indexer );
    127         }
    128 
    129         void PtrsCastable_old::postvisit( const UnionInstType * ) {
    130                 result = objectCast( dest, env, indexer );
    131         }
    132 
    133         void PtrsCastable_old::postvisit( const EnumInstType * ) {
    134                 if ( dynamic_cast< const EnumInstType * >( dest ) ) {
    135                         result = 1;
    136                 } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) {
    137                         if ( bt->kind == BasicType::SignedInt ) {
    138                                 result = 0;
    139                         } else {
    140                                 result = 1;
    141                         }
    142                 } else {
    143                         result = objectCast( dest, env, indexer );
    144                 }
    145         }
    146 
    147         void PtrsCastable_old::postvisit( const TraitInstType * ) {}
    148 
    149         void PtrsCastable_old::postvisit( const TypeInstType *inst ) {
    150                 //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;
    151                 result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;
    152         }
    153 
    154         void PtrsCastable_old::postvisit( const TupleType * ) {
    155                 result = objectCast( dest, env, indexer );
    156         }
    157 
    158         void PtrsCastable_old::postvisit( const VarArgsType * ) {
    159                 result = objectCast( dest, env, indexer );
    160         }
    161 
    162         void PtrsCastable_old::postvisit( const ZeroType * ) {
    163                 result = objectCast( dest, env, indexer );
    164         }
    165 
    166         void PtrsCastable_old::postvisit( const OneType * ) {
    167                 result = objectCast( dest, env, indexer );
    168         }
    16925
    17026namespace {
  • src/ResolvExpr/RenameVars.cc

    r0030b508 rfc12f05  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
    23 #include "Common/PassVisitor.h"
    2423#include "Common/ScopedMap.h"
    2524#include "Common/SemanticError.h"  // for SemanticError
    2625#include "RenameVars.h"
    27 #include "SynTree/Declaration.h"   // for DeclarationWithType, TypeDecl, Dec...
    28 #include "SynTree/Expression.h"    // for Expression
    29 #include "SynTree/Type.h"          // for Type, TypeInstType, TraitInstType
    30 #include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    3126
    3227#include "AST/Copy.hpp"
     
    4944                }
    5045
    51                 void rename( TypeInstType * type ) {
    52                         auto it = nameMap.find( type->name );
    53                         if ( it != nameMap.end() ) {
    54                                 type->name = it->second;
    55                         }
    56                 }
    57 
    5846                void nextUsage() {
    5947                        ++next_usage_id;
    60                 }
    61 
    62                 void openLevel( Type * type ) {
    63                         if ( ! type->forall.empty() ) {
    64                                 nameMap.beginScope();
    65                                 // renames all "forall" type names to `_${level}_${name}'
    66                                 for ( auto td : type->forall ) {
    67                                         std::ostringstream output;
    68                                         output << "_" << resetCount << "_" << level << "_" << td->name;
    69                                         std::string newname( output.str() );
    70                                         nameMap[ td->get_name() ] = newname;
    71                                         td->name = newname;
    72                                         // ditto for assertion names, the next level in
    73                                         level++;
    74                                 }
    75                         }
    76                 }
    77 
    78                 void closeLevel( Type * type ) {
    79                         if ( !type->forall.empty() ) {
    80                                 nameMap.endScope();
    81                         }
    8248                }
    8349
     
    135101        RenamingData renaming;
    136102
    137         struct RenameVars_old {
    138                 void previsit( TypeInstType * instType ) {
    139                         renaming.openLevel( (Type*)instType );
    140                         renaming.rename( instType );
    141                 }
    142                 void previsit( Type * type ) {
    143                         renaming.openLevel( type );
    144                 }
    145                 void postvisit( Type * type ) {
    146                         renaming.closeLevel( type );
    147                 }
    148         };
    149 
    150103        struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
    151104                RenameMode mode;
     
    178131} // namespace
    179132
    180 void renameTyVars( Type * t ) {
    181         PassVisitor<RenameVars_old> renamer;
    182         t->accept( renamer );
    183 }
    184 
    185133const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
    186134        ast::Pass<RenameVars_new> renamer;
  • src/ResolvExpr/RenameVars.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>               // for list
    19 #include <map>                // for map
    20 #include <string>             // for string
    21 
    22 #include "SynTree/SynTree.h"  // for Visitor Nodes
    23 #include "SynTree/Visitor.h"  // for Visitor
    24 
    2518namespace ast {
    2619        class Type;
     
    2821
    2922namespace ResolvExpr {
    30         /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
    31         void renameTyVars( Type * );
    32 
    3323        enum RenameMode {
    3424                GEN_USAGE, // for type in VariableExpr
  • src/ResolvExpr/ResolveTypeof.cc

    r0030b508 rfc12f05  
    2424#include "AST/Type.hpp"
    2525#include "AST/TypeEnvironment.hpp"
    26 #include "Common/PassVisitor.h"   // for PassVisitor
    2726#include "Common/utility.h"       // for copy
    2827#include "InitTweak/InitTweak.h"  // for isConstExpr
     
    3029#include "Resolver.h"  // for resolveInVoidContext
    3130#include "SymTab/Mangler.h"
    32 #include "SynTree/Expression.h"  // for Expression
    33 #include "SynTree/Mutator.h"     // for Mutator
    34 #include "SynTree/Type.h"        // for TypeofType, Type
    35 
    36 namespace SymTab {
    37 class Indexer;
    38 }  // namespace SymTab
    3931
    4032namespace ResolvExpr {
    41 namespace {
    42 #if 0
    43                 void
    44                 printAlts( const AltList &list, std::ostream &os, int indent = 0 )
    45                 {
    46                         for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
    47                                 i->print( os, indent );
    48                                 os << std::endl;
    49                         }
    50                 }
    51 #endif
    52         }
    53 
    54 class ResolveTypeof_old : public WithShortCircuiting {
    55    public:
    56                 ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {}
    57                 void premutate( TypeofType *typeofType );
    58                 Type * postmutate( TypeofType *typeofType );
    59 
    60    private:
    61     const SymTab::Indexer &indexer;
    62 };
    63 
    64         Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {
    65                 PassVisitor<ResolveTypeof_old> mutator( indexer );
    66                 return type->acceptMutator( mutator );
    67         }
    68 
    69         void ResolveTypeof_old::premutate( TypeofType * ) {
    70                 visit_children = false;
    71         }
    72 
    73     Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) {
    74 #if 0
    75                 std::cerr << "resolving typeof: ";
    76                 typeofType->print( std::cerr );
    77                 std::cerr << std::endl;
    78 #endif
    79     // pass on null expression
    80                 if ( ! typeofType->expr ) return typeofType;
    81 
    82     bool isBasetypeof = typeofType->is_basetypeof;
    83     auto oldQuals = typeofType->get_qualifiers().val;
    84 
    85     Type* newType;
    86                 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) {
    87         // typeof wrapping type
    88         newType = tyExpr->type;
    89         tyExpr->type = nullptr;
    90         delete tyExpr;
    91     } else {
    92         // typeof wrapping expression
    93                         Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );
    94                         assert( newExpr->result && ! newExpr->result->isVoid() );
    95         newType = newExpr->result;
    96         newExpr->result = nullptr;
    97         delete typeofType;
    98         delete newExpr;
    99     }
    100 
    101     // clear qualifiers for base, combine with typeoftype quals in any case
    102     if ( isBasetypeof ) {
    103                         // replace basetypeof(<enum>) by int
    104                         if ( dynamic_cast<EnumInstType*>(newType) ) {
    105                                 Type* newerType =
    106                                         new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
    107                                         newType->attributes };
    108                                 delete newType;
    109                                 newType = newerType;
    110                         }
    111                         newType->get_qualifiers().val
    112                                 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
    113                 } else {
    114         newType->get_qualifiers().val |= oldQuals;
    115     }
    116 
    117     return newType;
    118 }
    11933
    12034namespace {
  • src/ResolvExpr/Resolver.cc

    r0030b508 rfc12f05  
    1919#include <vector>                        // for vector
    2020
    21 #include "Alternative.h"                 // for Alternative, AltList
    22 #include "AlternativeFinder.h"           // for AlternativeFinder, resolveIn...
    2321#include "Candidate.hpp"
    2422#include "CandidateFinder.hpp"
     
    4038#include "Common/Eval.h"                 // for eval
    4139#include "Common/Iterate.hpp"            // for group_iterate
    42 #include "Common/PassVisitor.h"          // for PassVisitor
    4340#include "Common/SemanticError.h"        // for SemanticError
    4441#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    4542#include "Common/ToString.hpp"           // for toCString
     43#include "Common/UniqueName.h"           // for UniqueName
    4644#include "InitTweak/GenInit.h"
    4745#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
    48 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    49 #include "SymTab/Autogen.h"              // for SizeType
    50 #include "SymTab/Indexer.h"              // for Indexer
    5146#include "SymTab/Mangler.h"              // for Mangler
    52 #include "SynTree/Declaration.h"         // for ObjectDecl, TypeDecl, Declar...
    53 #include "SynTree/Expression.h"          // for Expression, CastExpr, InitExpr
    54 #include "SynTree/Initializer.h"         // for ConstructorInit, SingleInit
    55 #include "SynTree/Statement.h"           // for ForStmt, Statement, BranchStmt
    56 #include "SynTree/Type.h"                // for Type, BasicType, PointerType
    57 #include "SynTree/TypeSubstitution.h"    // for TypeSubstitution
    58 #include "SynTree/Visitor.h"             // for acceptAll, maybeAccept
    5947#include "Tuples/Tuples.h"
    6048#include "Validate/FindSpecialDecls.h"   // for SizeType
     
    6351
    6452namespace ResolvExpr {
    65         struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {
    66                 Resolver_old() {}
    67                 Resolver_old( const SymTab::Indexer & other ) {
    68                         indexer = other;
    69                 }
    70 
    71                 void previsit( FunctionDecl * functionDecl );
    72                 void postvisit( FunctionDecl * functionDecl );
    73                 void previsit( ObjectDecl * objectDecll );
    74                 void previsit( EnumDecl * enumDecl );
    75                 void previsit( StaticAssertDecl * assertDecl );
    76 
    77                 void previsit( ArrayType * at );
    78                 void previsit( PointerType * at );
    79 
    80                 void previsit( ExprStmt * exprStmt );
    81                 void previsit( AsmExpr * asmExpr );
    82                 void previsit( AsmStmt * asmStmt );
    83                 void previsit( IfStmt * ifStmt );
    84                 void previsit( WhileDoStmt * whileDoStmt );
    85                 void previsit( ForStmt * forStmt );
    86                 void previsit( SwitchStmt * switchStmt );
    87                 void previsit( CaseStmt * caseStmt );
    88                 void previsit( BranchStmt * branchStmt );
    89                 void previsit( ReturnStmt * returnStmt );
    90                 void previsit( ThrowStmt * throwStmt );
    91                 void previsit( CatchStmt * catchStmt );
    92                 void postvisit( CatchStmt * catchStmt );
    93                 void previsit( WaitForStmt * stmt );
    94 
    95                 void previsit( SingleInit * singleInit );
    96                 void previsit( ListInit * listInit );
    97                 void previsit( ConstructorInit * ctorInit );
    98           private:
    99                 typedef std::list< Initializer * >::iterator InitIterator;
    100 
    101                 template< typename PtrType >
    102                 void handlePtrType( PtrType * type );
    103 
    104                 void fallbackInit( ConstructorInit * ctorInit );
    105 
    106                 Type * functionReturn = nullptr;
    107                 CurrentObject currentObject = nullptr;
    108                 bool inEnumDecl = false;
    109         };
    110 
    111         struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {
    112                 void previsit( FunctionDecl * );
    113                 void previsit( WithStmt * );
    114 
    115                 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );
    116         };
    117 
    118         void resolve( std::list< Declaration * > translationUnit ) {
    119                 PassVisitor<Resolver_old> resolver;
    120                 acceptAll( translationUnit, resolver );
    121         }
    122 
    123         void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {
    124                 PassVisitor<Resolver_old> resolver( indexer );
    125                 maybeAccept( decl, resolver );
    126         }
    127 
    128         namespace {
    129                 struct DeleteFinder_old : public WithShortCircuiting    {
    130                         DeletedExpr * delExpr = nullptr;
    131                         void previsit( DeletedExpr * expr ) {
    132                                 if ( delExpr ) visit_children = false;
    133                                 else delExpr = expr;
    134                         }
    135 
    136                         void previsit( Expression * ) {
    137                                 if ( delExpr ) visit_children = false;
    138                         }
    139                 };
    140         }
    141 
    142         DeletedExpr * findDeletedExpr( Expression * expr ) {
    143                 PassVisitor<DeleteFinder_old> finder;
    144                 expr->accept( finder );
    145                 return finder.pass.delExpr;
    146         }
    147 
    148         namespace {
    149                 struct StripCasts_old {
    150                         Expression * postmutate( CastExpr * castExpr ) {
    151                                 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {
    152                                         // generated cast is to the same type as its argument, so it's unnecessary -- remove it
    153                                         Expression * expr = castExpr->arg;
    154                                         castExpr->arg = nullptr;
    155                                         std::swap( expr->env, castExpr->env );
    156                                         return expr;
    157                                 }
    158                                 return castExpr;
    159                         }
    160 
    161                         static void strip( Expression *& expr ) {
    162                                 PassVisitor<StripCasts_old> stripper;
    163                                 expr = expr->acceptMutator( stripper );
    164                         }
    165                 };
    166 
    167                 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {
    168                         expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
    169                         env.makeSubstitution( *expr->env );
    170                         StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression
    171                 }
    172 
    173                 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {
    174                         if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    175                                 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {
    176                                         // cast is to the same type as its argument, so it's unnecessary -- remove it
    177                                         expr = castExpr->arg;
    178                                         castExpr->arg = nullptr;
    179                                         std::swap( expr->env, castExpr->env );
    180                                         delete castExpr;
    181                                 }
    182                         }
    183                 }
    184         } // namespace
    185 
    186         namespace {
    187                 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {
    188                         assertf( untyped, "expected a non-null expression." );
    189 
    190                         // xxx - this isn't thread-safe, but should work until we parallelize the resolver
    191                         static unsigned recursion_level = 0;
    192 
    193                         ++recursion_level;
    194                         TypeEnvironment env;
    195                         AlternativeFinder finder( indexer, env );
    196                         finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
    197                         --recursion_level;
    198 
    199                         #if 0
    200                         if ( finder.get_alternatives().size() != 1 ) {
    201                                 std::cerr << "untyped expr is ";
    202                                 untyped->print( std::cerr );
    203                                 std::cerr << std::endl << "alternatives are:";
    204                                 for ( const Alternative & alt : finder.get_alternatives() ) {
    205                                         alt.print( std::cerr );
    206                                 } // for
    207                         } // if
    208                         #endif
    209 
    210                         // produce filtered list of alternatives
    211                         AltList candidates;
    212                         for ( Alternative & alt : finder.get_alternatives() ) {
    213                                 if ( pred( alt ) ) {
    214                                         candidates.push_back( std::move( alt ) );
    215                                 }
    216                         }
    217 
    218                         // produce invalid error if no candidates
    219                         if ( candidates.empty() ) {
    220                                 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
    221                         }
    222 
    223                         // search for cheapest candidate
    224                         AltList winners;
    225                         bool seen_undeleted = false;
    226                         for ( unsigned i = 0; i < candidates.size(); ++i ) {
    227                                 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );
    228 
    229                                 if ( c > 0 ) continue; // skip more expensive than winner
    230 
    231                                 if ( c < 0 ) {
    232                                         // reset on new cheapest
    233                                         seen_undeleted = ! findDeletedExpr( candidates[i].expr );
    234                                         winners.clear();
    235                                 } else /* if ( c == 0 ) */ {
    236                                         if ( findDeletedExpr( candidates[i].expr ) ) {
    237                                                 // skip deleted expression if already seen one equivalent-cost not
    238                                                 if ( seen_undeleted ) continue;
    239                                         } else if ( ! seen_undeleted ) {
    240                                                 // replace list of equivalent-cost deleted expressions with one non-deleted
    241                                                 winners.clear();
    242                                                 seen_undeleted = true;
    243                                         }
    244                                 }
    245 
    246                                 winners.emplace_back( std::move( candidates[i] ) );
    247                         }
    248 
    249                         // promote alternative.cvtCost to .cost
    250                         // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost
    251                         for ( Alternative& winner : winners ) {
    252                                 winner.cost = winner.cvtCost;
    253                         }
    254 
    255                         // produce ambiguous errors, if applicable
    256                         if ( winners.size() != 1 ) {
    257                                 std::ostringstream stream;
    258                                 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
    259                                 untyped->print( stream );
    260                                 stream << " Alternatives are:\n";
    261                                 printAlts( winners, stream, 1 );
    262                                 SemanticError( untyped->location, stream.str() );
    263                         }
    264 
    265                         // single selected choice
    266                         Alternative& choice = winners.front();
    267 
    268                         // fail on only expression deleted
    269                         if ( ! seen_undeleted ) {
    270                                 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );
    271                         }
    272 
    273                         // xxx - check for ambiguous expressions
    274 
    275                         // output selected choice
    276                         alt = std::move( choice );
    277                 }
    278 
    279                 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
    280                 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {
    281                         if ( ! untyped ) return;
    282                         Alternative choice;
    283                         findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );
    284                         finishExpr( choice.expr, choice.env, untyped->env );
    285                         delete untyped;
    286                         untyped = choice.expr;
    287                         choice.expr = nullptr;
    288                 }
    289 
    290                 bool standardAlternativeFilter( const Alternative & ) {
    291                         // currently don't need to filter, under normal circumstances.
    292                         // in the future, this may be useful for removing deleted expressions
    293                         return true;
    294                 }
    295         } // namespace
    296 
    297         // used in resolveTypeof
    298         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {
    299                 TypeEnvironment env;
    300                 return resolveInVoidContext( expr, indexer, env );
    301         }
    302 
    303         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {
    304                 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
    305                 // interpretations, an exception has already been thrown.
    306                 assertf( expr, "expected a non-null expression." );
    307 
    308                 CastExpr * untyped = new CastExpr( expr ); // cast to void
    309                 untyped->location = expr->location;
    310 
    311                 // set up and resolve expression cast to void
    312                 Alternative choice;
    313                 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
    314                 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
    315                 assert( castExpr );
    316                 env = std::move( choice.env );
    317 
    318                 // clean up resolved expression
    319                 Expression * ret = castExpr->arg;
    320                 castExpr->arg = nullptr;
    321 
    322                 // unlink the arg so that it isn't deleted twice at the end of the program
    323                 untyped->arg = nullptr;
    324                 return ret;
    325         }
    326 
    327         void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    328                 resetTyVarRenaming();
    329                 TypeEnvironment env;
    330                 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );
    331                 finishExpr( newExpr, env, untyped->env );
    332                 delete untyped;
    333                 untyped = newExpr;
    334         }
    335 
    336         void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    337                 findKindExpression( untyped, indexer, "", standardAlternativeFilter );
    338         }
    339 
    340         void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {
    341                 assert( untyped && type );
    342                 // transfer location to generated cast for error purposes
    343                 CodeLocation location = untyped->location;
    344                 untyped = new CastExpr( untyped, type );
    345                 untyped->location = location;
    346                 findSingleExpression( untyped, indexer );
    347                 removeExtraneousCast( untyped, indexer );
    348         }
    349 
    350         namespace {
    351                 bool isIntegralType( const Alternative & alt ) {
    352                         Type * type = alt.expr->result;
    353                         if ( dynamic_cast< EnumInstType * >( type ) ) {
    354                                 return true;
    355                         } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {
    356                                 return bt->isInteger();
    357                         } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {
    358                                 return true;
    359                         } else {
    360                                 return false;
    361                         } // if
    362                 }
    363 
    364                 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    365                         findKindExpression( untyped, indexer, "condition", isIntegralType );
    366                 }
    367         }
    368 
    369 
    370         bool isStructOrUnion( const Alternative & alt ) {
    371                 Type * t = alt.expr->result->stripReferences();
    372                 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
    373         }
    374 
    375         void resolveWithExprs( std::list< Declaration * > & translationUnit ) {
    376                 PassVisitor<ResolveWithExprs> resolver;
    377                 acceptAll( translationUnit, resolver );
    378         }
    379 
    380         void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {
    381                 for ( Expression *& expr : withExprs )  {
    382                         // only struct- and union-typed expressions are viable candidates
    383                         findKindExpression( expr, indexer, "with statement", isStructOrUnion );
    384 
    385                         // if with expression might be impure, create a temporary so that it is evaluated once
    386                         if ( Tuples::maybeImpure( expr ) ) {
    387                                 static UniqueName tmpNamer( "_with_tmp_" );
    388                                 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );
    389                                 expr = new VariableExpr( tmp );
    390                                 newStmts.push_back( new DeclStmt( tmp ) );
    391                                 if ( InitTweak::isConstructable( tmp->type ) ) {
    392                                         // generate ctor/dtor and resolve them
    393                                         tmp->init = InitTweak::genCtorInit( tmp );
    394                                         tmp->accept( *visitor );
    395                                 }
    396                         }
    397                 }
    398         }
    399 
    400         void ResolveWithExprs::previsit( WithStmt * withStmt ) {
    401                 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );
    402         }
    403 
    404         void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {
    405                 {
    406                         // resolve with-exprs with parameters in scope and add any newly generated declarations to the
    407                         // front of the function body.
    408                         auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );
    409                         indexer.addFunctionType( functionDecl->type );
    410                         std::list< Statement * > newStmts;
    411                         resolveWithExprs( functionDecl->withExprs, newStmts );
    412                         if ( functionDecl->statements ) {
    413                                 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );
    414                         } else {
    415                                 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );
    416                         }
    417                 }
    418         }
    419 
    420         void Resolver_old::previsit( ObjectDecl * objectDecl ) {
    421                 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
    422                 // class-variable initContext is changed multiple time because the LHS is analysed twice.
    423                 // The second analysis changes initContext because of a function type can contain object
    424                 // declarations in the return and parameter types. So each value of initContext is
    425                 // retained, so the type on the first analysis is preserved and used for selecting the RHS.
    426                 GuardValue( currentObject );
    427                 currentObject = CurrentObject( objectDecl->get_type() );
    428                 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {
    429                         // enumerator initializers should not use the enum type to initialize, since
    430                         // the enum type is still incomplete at this point. Use signed int instead.
    431                         // TODO: BasicType::SignedInt may not longer be true
    432                         currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    433                 }
    434         }
    435 
    436         template< typename PtrType >
    437         void Resolver_old::handlePtrType( PtrType * type ) {
    438                 if ( type->get_dimension() ) {
    439                         findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
    440                 }
    441         }
    442 
    443         void Resolver_old::previsit( ArrayType * at ) {
    444                 handlePtrType( at );
    445         }
    446 
    447         void Resolver_old::previsit( PointerType * pt ) {
    448                 handlePtrType( pt );
    449         }
    450 
    451         void Resolver_old::previsit( FunctionDecl * functionDecl ) {
    452 #if 0
    453                 std::cerr << "resolver visiting functiondecl ";
    454                 functionDecl->print( std::cerr );
    455                 std::cerr << std::endl;
    456 #endif
    457                 GuardValue( functionReturn );
    458                 functionReturn = ResolvExpr::extractResultType( functionDecl->type );
    459         }
    460 
    461         void Resolver_old::postvisit( FunctionDecl * functionDecl ) {
    462                 // default value expressions have an environment which shouldn't be there and trips up
    463                 // later passes.
    464                 // xxx - it might be necessary to somehow keep the information from this environment, but I
    465                 // can't currently see how it's useful.
    466                 for ( Declaration * d : functionDecl->type->parameters ) {
    467                         if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {
    468                                 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {
    469                                         delete init->value->env;
    470                                         init->value->env = nullptr;
    471                                 }
    472                         }
    473                 }
    474         }
    475 
    476         void Resolver_old::previsit( EnumDecl * ) {
    477                 // in case we decide to allow nested enums
    478                 GuardValue( inEnumDecl );
    479                 inEnumDecl = true;
    480         }
    481 
    482         void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {
    483                 findIntegralExpression( assertDecl->condition, indexer );
    484         }
    485 
    486         void Resolver_old::previsit( ExprStmt * exprStmt ) {
    487                 visit_children = false;
    488                 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );
    489                 findVoidExpression( exprStmt->expr, indexer );
    490         }
    491 
    492         void Resolver_old::previsit( AsmExpr * asmExpr ) {
    493                 visit_children = false;
    494                 findVoidExpression( asmExpr->operand, indexer );
    495         }
    496 
    497         void Resolver_old::previsit( AsmStmt * asmStmt ) {
    498                 visit_children = false;
    499                 acceptAll( asmStmt->get_input(), *visitor );
    500                 acceptAll( asmStmt->get_output(), *visitor );
    501         }
    502 
    503         void Resolver_old::previsit( IfStmt * ifStmt ) {
    504                 findIntegralExpression( ifStmt->condition, indexer );
    505         }
    506 
    507         void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {
    508                 findIntegralExpression( whileDoStmt->condition, indexer );
    509         }
    510 
    511         void Resolver_old::previsit( ForStmt * forStmt ) {
    512                 if ( forStmt->condition ) {
    513                         findIntegralExpression( forStmt->condition, indexer );
    514                 } // if
    515 
    516                 if ( forStmt->increment ) {
    517                         findVoidExpression( forStmt->increment, indexer );
    518                 } // if
    519         }
    520 
    521         void Resolver_old::previsit( SwitchStmt * switchStmt ) {
    522                 GuardValue( currentObject );
    523                 findIntegralExpression( switchStmt->condition, indexer );
    524 
    525                 currentObject = CurrentObject( switchStmt->condition->result );
    526         }
    527 
    528         void Resolver_old::previsit( CaseStmt * caseStmt ) {
    529                 if ( caseStmt->condition ) {
    530                         std::list< InitAlternative > initAlts = currentObject.getOptions();
    531                         assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );
    532                         // must remove cast from case statement because RangeExpr cannot be cast.
    533                         Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );
    534                         findSingleExpression( newExpr, indexer );
    535                         // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.
    536                         // Ideally we would perform the conversion internally here.
    537                         if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {
    538                                 newExpr = castExpr->arg;
    539                                 castExpr->arg = nullptr;
    540                                 std::swap( newExpr->env, castExpr->env );
    541                                 delete castExpr;
    542                         }
    543                         caseStmt->condition = newExpr;
    544                 }
    545         }
    546 
    547         void Resolver_old::previsit( BranchStmt * branchStmt ) {
    548                 visit_children = false;
    549                 // must resolve the argument for a computed goto
    550                 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement
    551                         if ( branchStmt->computedTarget ) {
    552                                 // computed goto argument is void *
    553                                 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );
    554                         } // if
    555                 } // if
    556         }
    557 
    558         void Resolver_old::previsit( ReturnStmt * returnStmt ) {
    559                 visit_children = false;
    560                 if ( returnStmt->expr ) {
    561                         findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );
    562                 } // if
    563         }
    564 
    565         void Resolver_old::previsit( ThrowStmt * throwStmt ) {
    566                 visit_children = false;
    567                 // TODO: Replace *exception type with &exception type.
    568                 if ( throwStmt->get_expr() ) {
    569                         const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
    570                         assert( exception_decl );
    571                         Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
    572                         findSingleExpression( throwStmt->expr, exceptType, indexer );
    573                 }
    574         }
    575 
    576         void Resolver_old::previsit( CatchStmt * catchStmt ) {
    577                 // Until we are very sure this invarent (ifs that move between passes have then)
    578                 // holds, check it. This allows a check for when to decode the mangling.
    579                 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
    580                         assert( ifStmt->then );
    581                 }
    582                 // Encode the catchStmt so the condition can see the declaration.
    583                 if ( catchStmt->cond ) {
    584                         IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );
    585                         catchStmt->cond = nullptr;
    586                         catchStmt->body = ifStmt;
    587                 }
    588         }
    589 
    590         void Resolver_old::postvisit( CatchStmt * catchStmt ) {
    591                 // Decode the catchStmt so everything is stored properly.
    592                 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
    593                 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
    594                         assert( ifStmt->condition );
    595                         assert( ifStmt->else_ );
    596                         catchStmt->cond = ifStmt->condition;
    597                         catchStmt->body = ifStmt->else_;
    598                         ifStmt->condition = nullptr;
    599                         ifStmt->else_ = nullptr;
    600                         delete ifStmt;
    601                 }
    602         }
    603 
    60453        template< typename iterator_t >
    60554        inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) {
     
    61059                return it != end;
    61160        }
    612 
    613         void Resolver_old::previsit( WaitForStmt * stmt ) {
    614                 visit_children = false;
    615 
    616                 // Resolve all clauses first
    617                 for( auto& clause : stmt->clauses ) {
    618 
    619                         TypeEnvironment env;
    620                         AlternativeFinder funcFinder( indexer, env );
    621 
    622                         // Find all alternatives for a function in canonical form
    623                         funcFinder.findWithAdjustment( clause.target.function );
    624 
    625                         if ( funcFinder.get_alternatives().empty() ) {
    626                                 stringstream ss;
    627                                 ss << "Use of undeclared indentifier '";
    628                                 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;
    629                                 ss << "' in call to waitfor";
    630                                 SemanticError( stmt->location, ss.str() );
    631                         }
    632 
    633                         if(clause.target.arguments.empty()) {
    634                                 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");
    635                         }
    636 
    637                         // Find all alternatives for all arguments in canonical form
    638                         std::vector< AlternativeFinder > argAlternatives;
    639                         funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );
    640 
    641                         // List all combinations of arguments
    642                         std::vector< AltList > possibilities;
    643                         combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
    644 
    645                         AltList                func_candidates;
    646                         std::vector< AltList > args_candidates;
    647 
    648                         // For every possible function :
    649                         //      try matching the arguments to the parameters
    650                         //      not the other way around because we have more arguments than parameters
    651                         SemanticErrorException errors;
    652                         for ( Alternative & func : funcFinder.get_alternatives() ) {
    653                                 try {
    654                                         PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );
    655                                         if( !pointer ) {
    656                                                 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );
    657                                         }
    658 
    659                                         FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );
    660                                         if( !function ) {
    661                                                 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );
    662                                         }
    663 
    664 
    665                                         {
    666                                                 auto param     = function->parameters.begin();
    667                                                 auto param_end = function->parameters.end();
    668 
    669                                                 if( !advance_to_mutex( param, param_end ) ) {
    670                                                         SemanticError(function, "candidate function not viable: no mutex parameters\n");
    671                                                 }
    672                                         }
    673 
    674                                         Alternative newFunc( func );
    675                                         // Strip reference from function
    676                                         referenceToRvalueConversion( newFunc.expr, newFunc.cost );
    677 
    678                                         // For all the set of arguments we have try to match it with the parameter of the current function alternative
    679                                         for ( auto & argsList : possibilities ) {
    680 
    681                                                 try {
    682                                                         // Declare data structures need for resolution
    683                                                         OpenVarSet openVars;
    684                                                         AssertionSet resultNeed, resultHave;
    685                                                         TypeEnvironment resultEnv( func.env );
    686                                                         makeUnifiableVars( function, openVars, resultNeed );
    687                                                         // add all type variables as open variables now so that those not used in the parameter
    688                                                         // list are still considered open.
    689                                                         resultEnv.add( function->forall );
    690 
    691                                                         // Load type variables from arguemnts into one shared space
    692                                                         simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );
    693 
    694                                                         // Make sure we don't widen any existing bindings
    695                                                         resultEnv.forbidWidening();
    696 
    697                                                         // Find any unbound type variables
    698                                                         resultEnv.extractOpenVars( openVars );
    699 
    700                                                         auto param     = function->parameters.begin();
    701                                                         auto param_end = function->parameters.end();
    702 
    703                                                         int n_mutex_param = 0;
    704 
    705                                                         // For every arguments of its set, check if it matches one of the parameter
    706                                                         // The order is important
    707                                                         for( auto & arg : argsList ) {
    708 
    709                                                                 // Ignore non-mutex arguments
    710                                                                 if( !advance_to_mutex( param, param_end ) ) {
    711                                                                         // We ran out of parameters but still have arguments
    712                                                                         // this function doesn't match
    713                                                                         SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));
    714                                                                 }
    715 
    716                                                                 n_mutex_param++;
    717 
    718                                                                 // Check if the argument matches the parameter type in the current scope
    719                                                                 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {
    720                                                                         // Type doesn't match
    721                                                                         stringstream ss;
    722                                                                         ss << "candidate function not viable: no known convertion from '";
    723                                                                         (*param)->get_type()->print( ss );
    724                                                                         ss << "' to '";
    725                                                                         arg.expr->get_result()->print( ss );
    726                                                                         ss << "' with env '";
    727                                                                         resultEnv.print(ss);
    728                                                                         ss << "'\n";
    729                                                                         SemanticError( function, ss.str() );
    730                                                                 }
    731 
    732                                                                 param++;
    733                                                         }
    734 
    735                                                         // All arguments match !
    736 
    737                                                         // Check if parameters are missing
    738                                                         if( advance_to_mutex( param, param_end ) ) {
    739                                                                 do {
    740                                                                         n_mutex_param++;
    741                                                                         param++;
    742                                                                 } while( advance_to_mutex( param, param_end ) );
    743 
    744                                                                 // We ran out of arguments but still have parameters left
    745                                                                 // this function doesn't match
    746                                                                 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));
    747                                                         }
    748 
    749                                                         // All parameters match !
    750 
    751                                                         // Finish the expressions to tie in the proper environments
    752                                                         finishExpr( newFunc.expr, resultEnv );
    753                                                         for( Alternative & alt : argsList ) {
    754                                                                 finishExpr( alt.expr, resultEnv );
    755                                                         }
    756 
    757                                                         // This is a match store it and save it for later
    758                                                         func_candidates.push_back( newFunc );
    759                                                         args_candidates.push_back( argsList );
    760 
    761                                                 }
    762                                                 catch( SemanticErrorException & e ) {
    763                                                         errors.append( e );
    764                                                 }
    765                                         }
    766                                 }
    767                                 catch( SemanticErrorException & e ) {
    768                                         errors.append( e );
    769                                 }
    770                         }
    771 
    772                         // Make sure we got the right number of arguments
    773                         if( func_candidates.empty() )    { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor"  ); top.append( errors ); throw top; }
    774                         if( args_candidates.empty() )    { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }
    775                         if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor"            ); top.append( errors ); throw top; }
    776                         if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor"           ); top.append( errors ); throw top; }
    777                         // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
    778 
    779                         // Swap the results from the alternative with the unresolved values.
    780                         // Alternatives will handle deletion on destruction
    781                         std::swap( clause.target.function, func_candidates.front().expr );
    782                         for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {
    783                                 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );
    784                         }
    785 
    786                         // Resolve the conditions as if it were an IfStmt
    787                         // Resolve the statments normally
    788                         findSingleExpression( clause.condition, this->indexer );
    789                         clause.statement->accept( *visitor );
    790                 }
    791 
    792 
    793                 if( stmt->timeout.statement ) {
    794                         // Resolve the timeout as an size_t for now
    795                         // Resolve the conditions as if it were an IfStmt
    796                         // Resolve the statments normally
    797                         findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );
    798                         findSingleExpression( stmt->timeout.condition, this->indexer );
    799                         stmt->timeout.statement->accept( *visitor );
    800                 }
    801 
    802                 if( stmt->orelse.statement ) {
    803                         // Resolve the conditions as if it were an IfStmt
    804                         // Resolve the statments normally
    805                         findSingleExpression( stmt->orelse.condition, this->indexer );
    806                         stmt->orelse.statement->accept( *visitor );
    807                 }
    808         }
    809 
    810         bool isCharType( Type * t ) {
    811                 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {
    812                         return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||
    813                                 bt->get_kind() == BasicType::UnsignedChar;
    814                 }
    815                 return false;
    816         }
    817 
    818         void Resolver_old::previsit( SingleInit * singleInit ) {
    819                 visit_children = false;
    820                 // resolve initialization using the possibilities as determined by the currentObject cursor
    821                 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );
    822                 findSingleExpression( newExpr, indexer );
    823                 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );
    824 
    825                 // move cursor to the object that is actually initialized
    826                 currentObject.setNext( initExpr->get_designation() );
    827 
    828                 // discard InitExpr wrapper and retain relevant pieces
    829                 newExpr = initExpr->expr;
    830                 initExpr->expr = nullptr;
    831                 std::swap( initExpr->env, newExpr->env );
    832                 // InitExpr may have inferParams in the case where the expression specializes a function
    833                 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not
    834                 // sufficient.
    835                 newExpr->spliceInferParams( initExpr );
    836                 delete initExpr;
    837 
    838                 // get the actual object's type (may not exactly match what comes back from the resolver
    839                 // due to conversions)
    840                 Type * initContext = currentObject.getCurrentType();
    841 
    842                 removeExtraneousCast( newExpr, indexer );
    843 
    844                 // check if actual object's type is char[]
    845                 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {
    846                         if ( isCharType( at->get_base() ) ) {
    847                                 // check if the resolved type is char *
    848                                 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {
    849                                         if ( isCharType( pt->get_base() ) ) {
    850                                                 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
    851                                                         // strip cast if we're initializing a char[] with a char *,
    852                                                         // e.g.  char x[] = "hello";
    853                                                         newExpr = ce->get_arg();
    854                                                         ce->set_arg( nullptr );
    855                                                         std::swap( ce->env, newExpr->env );
    856                                                         delete ce;
    857                                                 }
    858                                         }
    859                                 }
    860                         }
    861                 }
    862 
    863                 // set initializer expr to resolved express
    864                 singleInit->value = newExpr;
    865 
    866                 // move cursor to next object in preparation for next initializer
    867                 currentObject.increment();
    868         }
    869 
    870         void Resolver_old::previsit( ListInit * listInit ) {
    871                 visit_children = false;
    872                 // move cursor into brace-enclosed initializer-list
    873                 currentObject.enterListInit();
    874                 // xxx - fix this so that the list isn't copied, iterator should be used to change current
    875                 // element
    876                 std::list<Designation *> newDesignations;
    877                 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
    878                         // iterate designations and initializers in pairs, moving the cursor to the current
    879                         // designated object and resolving the initializer against that object.
    880                         Designation * des = std::get<0>(p);
    881                         Initializer * init = std::get<1>(p);
    882                         newDesignations.push_back( currentObject.findNext( des ) );
    883                         init->accept( *visitor );
    884                 }
    885                 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list
    886                 listInit->get_designations() = newDesignations; // xxx - memory management
    887                 currentObject.exitListInit();
    888 
    889                 // xxx - this part has not be folded into CurrentObject yet
    890                 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {
    891                 //      Type * base = tt->get_baseType()->get_base();
    892                 //      if ( base ) {
    893                 //              // know the implementation type, so try using that as the initContext
    894                 //              ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );
    895                 //              currentObject = &tmpObj;
    896                 //              visit( listInit );
    897                 //      } else {
    898                 //              // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context
    899                 //              Parent::visit( listInit );
    900                 //      }
    901                 // } else {
    902         }
    903 
    904         // ConstructorInit - fall back on C-style initializer
    905         void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {
    906                 // could not find valid constructor, or found an intrinsic constructor
    907                 // fall back on C-style initializer
    908                 delete ctorInit->get_ctor();
    909                 ctorInit->set_ctor( nullptr );
    910                 delete ctorInit->get_dtor();
    911                 ctorInit->set_dtor( nullptr );
    912                 maybeAccept( ctorInit->get_init(), *visitor );
    913         }
    914 
    915         // needs to be callable from outside the resolver, so this is a standalone function
    916         void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {
    917                 assert( ctorInit );
    918                 PassVisitor<Resolver_old> resolver( indexer );
    919                 ctorInit->accept( resolver );
    920         }
    921 
    922         void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {
    923                 assert( stmtExpr );
    924                 PassVisitor<Resolver_old> resolver( indexer );
    925                 stmtExpr->accept( resolver );
    926                 stmtExpr->computeResult();
    927                 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?
    928         }
    929 
    930         void Resolver_old::previsit( ConstructorInit * ctorInit ) {
    931                 visit_children = false;
    932                 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit
    933                 maybeAccept( ctorInit->ctor, *visitor );
    934                 maybeAccept( ctorInit->dtor, *visitor );
    935 
    936                 // found a constructor - can get rid of C-style initializer
    937                 delete ctorInit->init;
    938                 ctorInit->init = nullptr;
    939 
    940                 // intrinsic single parameter constructors and destructors do nothing. Since this was
    941                 // implicitly generated, there's no way for it to have side effects, so get rid of it
    942                 // to clean up generated code.
    943                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
    944                         delete ctorInit->ctor;
    945                         ctorInit->ctor = nullptr;
    946                 }
    947 
    948                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
    949                         delete ctorInit->dtor;
    950                         ctorInit->dtor = nullptr;
    951                 }
    952 
    953                 // xxx - todo -- what about arrays?
    954                 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
    955                 //      // can reduce the constructor down to a SingleInit using the
    956                 //      // second argument from the ctor call, since
    957                 //      delete ctorInit->get_ctor();
    958                 //      ctorInit->set_ctor( nullptr );
    959 
    960                 //      Expression * arg =
    961                 //      ctorInit->set_init( new SingleInit( arg ) );
    962                 // }
    963         }
    964 
    965         ///////////////////////////////////////////////////////////////////////////
    966         //
    967         // *** NEW RESOLVER ***
    968         //
    969         ///////////////////////////////////////////////////////////////////////////
    97061
    97162        namespace {
  • src/ResolvExpr/SatisfyAssertions.cpp

    r0030b508 rfc12f05  
    4646#include "SymTab/Mangler.h"
    4747
    48 
    49 
    5048namespace ResolvExpr {
    5149
    5250// in CandidateFinder.cpp; unique ID for assertion satisfaction
    53 extern UniqueId globalResnSlot;
     51extern ast::UniqueId globalResnSlot;
    5452
    5553namespace {
     
    298296                        if ( !expr->inferred.hasSlots() ) return expr;
    299297                        // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
    300                         std::vector<UniqueId> missingSlots;
     298                        std::vector<ast::UniqueId> missingSlots;
    301299                        // find inferred parameters for resolution slots
    302300                        ast::InferredParams * newInferred = new ast::InferredParams();
    303                         for ( UniqueId slot : expr->inferred.resnSlots() ) {
     301                        for ( ast::UniqueId slot : expr->inferred.resnSlots() ) {
    304302                                // fail if no matching assertions found
    305303                                auto it = inferred.find( slot );
  • src/ResolvExpr/SpecCost.cc

    r0030b508 rfc12f05  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
    23 #include "Common/PassVisitor.h"
    24 #include "SynTree/Declaration.h"
    25 #include "SynTree/Expression.h"
    26 #include "SynTree/Type.h"
    2723
    2824namespace ResolvExpr {
    29 
    30         /// Counts specializations in a type
    31         class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> {
    32                 int count = -1;  ///< specialization count (-1 for none)
    33 
    34         public:
    35                 int get_count() const { return count >= 0 ? count : 0; }
    36 
    37                 // mark specialization of base type
    38                 void postvisit(PointerType*) { if ( count >= 0 ) ++count; }
    39 
    40                 // mark specialization of base type
    41                 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }
    42 
    43                 // mark specialization of base type
    44                 void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }
    45 
    46                 void postvisit(StructInstType*) { if ( count >= 0 ) ++count; }
    47                 void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; }
    48 
    49         private:
    50                 // takes minimum non-negative count over parameter/return list
    51                 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {
    52                         for ( DeclarationWithType* dwt : dwts ) {
    53                                 count = -1;
    54                                 maybeAccept( dwt->get_type(), *visitor );
    55                                 if ( count != -1 && count < mincount ) mincount = count;
    56                         }
    57                 }
    58 
    59         public:
    60                 // take minimal specialization value over ->returnVals and ->parameters
    61                 void previsit(FunctionType* fty) {
    62                         int mincount = std::numeric_limits<int>::max();
    63                         takeminover( mincount, fty->parameters );
    64                         takeminover( mincount, fty->returnVals );
    65                         // add another level to mincount if set
    66                         count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    67                         // already visited children
    68                         visit_children = false;
    69                 }
    70 
    71         private:
    72                 // returns minimum non-negative count + 1 over type parameters (-1 if none such)
    73                 int minover( std::list<Expression*>& parms ) {
    74                         int mincount = std::numeric_limits<int>::max();
    75                         for ( Expression* parm : parms ) {
    76                                 count = -1;
    77                                 maybeAccept( parm->result, *visitor );
    78                                 if ( count != -1 && count < mincount ) mincount = count;
    79                         }
    80                         return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    81                 }
    82 
    83         public:
    84                 // look for polymorphic parameters
    85                 void previsit(StructInstType* sty) {
    86                         count = minover( sty->parameters );
    87                 }
    88 
    89                 // look for polymorphic parameters
    90                 void previsit(UnionInstType* uty) {
    91                         count = minover( uty->parameters );
    92                 }
    93 
    94                 // note polymorphic type (which may be specialized)
    95                 // xxx - maybe account for open/closed type variables
    96                 void postvisit(TypeInstType*) { count = 0; }
    97 
    98                 // take minimal specialization over elements
    99                 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
    100                 void previsit(TupleType* tty) {
    101                         int mincount = std::numeric_limits<int>::max();
    102                         for ( Type* ty : tty->types ) {
    103                                 count = -1;
    104                                 maybeAccept( ty, *visitor );
    105                                 if ( count != -1 && count < mincount ) mincount = count;
    106                         }
    107                         count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    108                         visit_children = false;
    109                 }
    110         };
    111 
    112         /// Returns the (negated) specialization cost for a given type
    113         int specCost( Type* ty ) {
    114                 PassVisitor<CountSpecs> counter;
    115                 maybeAccept( ty, *counter.pass.visitor );
    116                 return counter.pass.get_count();
    117         }
    11825
    11926namespace {
  • src/ResolvExpr/Unify.cc

    r0030b508 rfc12f05  
    3333#include "AST/TypeEnvironment.hpp"
    3434#include "Common/Eval.h"            // for eval
    35 #include "Common/PassVisitor.h"     // for PassVisitor
    3635#include "CommonType.hpp"           // for commonType
    3736#include "FindOpenVars.h"           // for findOpenVars
    3837#include "SpecCost.hpp"             // for SpecCost
    39 #include "SynTree/LinkageSpec.h"    // for C
    40 #include "SynTree/Constant.h"       // for Constant
    41 #include "SynTree/Declaration.h"    // for TypeDecl, TypeDecl::Data, Declarati...
    42 #include "SynTree/Expression.h"     // for TypeExpr, Expression, ConstantExpr
    43 #include "SynTree/Mutator.h"        // for Mutator
    44 #include "SynTree/Type.h"           // for Type, TypeInstType, FunctionType
    45 #include "SynTree/Visitor.h"        // for Visitor
    4638#include "Tuples/Tuples.h"          // for isTtype
    47 #include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
    4839#include "typeops.h"                // for flatten, occurs
    4940
     
    5243}
    5344
    54 namespace SymTab {
    55         class Indexer;
    56 }  // namespace SymTab
    57 
    5845// #define DEBUG
    5946
    6047namespace ResolvExpr {
    61 
    62 // Template Helpers:
    63 template< typename Iterator1, typename Iterator2 >
    64 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {
    65         for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    66                 Type *commonType = 0;
    67                 if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    68                         return false;
    69                 } // if
    70                 commonTypes.push_back( commonType );
    71         } // for
    72         return ( list1Begin == list1End && list2Begin == list2End );
    73 }
    74 
    75 template< typename Iterator1, typename Iterator2 >
    76 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    77         std::list< Type* > commonTypes;
    78         if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions,  openVars, indexer, commonTypes ) ) {
    79                 deleteAll( commonTypes );
    80                 return true;
    81         } else {
    82                 return false;
    83         } // if
    84 }
    85 
    86         struct Unify_old : public WithShortCircuiting {
    87                 Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
    88 
    89                 bool get_result() const { return result; }
    90 
    91                 void previsit( BaseSyntaxNode * ) { visit_children = false; }
    92 
    93                 void postvisit( VoidType * voidType );
    94                 void postvisit( BasicType * basicType );
    95                 void postvisit( PointerType * pointerType );
    96                 void postvisit( ArrayType * arrayType );
    97                 void postvisit( ReferenceType * refType );
    98                 void postvisit( FunctionType * functionType );
    99                 void postvisit( StructInstType * aggregateUseType );
    100                 void postvisit( UnionInstType * aggregateUseType );
    101                 void postvisit( EnumInstType * aggregateUseType );
    102                 void postvisit( TraitInstType * aggregateUseType );
    103                 void postvisit( TypeInstType * aggregateUseType );
    104                 void postvisit( TupleType * tupleType );
    105                 void postvisit( VarArgsType * varArgsType );
    106                 void postvisit( ZeroType * zeroType );
    107                 void postvisit( OneType * oneType );
    108 
    109           private:
    110                 template< typename RefType > void handleRefType( RefType *inst, Type *other );
    111                 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
    112 
    113                 bool result;
    114                 Type *type2;                            // inherited
    115                 TypeEnvironment &env;
    116                 AssertionSet &needAssertions;
    117                 AssertionSet &haveAssertions;
    118                 const OpenVarSet &openVars;
    119                 WidenMode widen;
    120                 const SymTab::Indexer &indexer;
    121         };
    122 
    123         /// Attempts an inexact unification of type1 and type2.
    124         /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)
    125         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    126         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
    127 
    128         bool unifyExact(
    129                 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    130                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    131                 WidenMode widen );
    132 
    133         bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    134                 TypeEnvironment newEnv;
    135                 OpenVarSet openVars, closedVars; // added closedVars
    136                 AssertionSet needAssertions, haveAssertions;
    137                 Type * newFirst = first->clone(), * newSecond = second->clone();
    138                 env.apply( newFirst );
    139                 env.apply( newSecond );
    140 
    141                 // do we need to do this? Seems like we do, types should be able to be compatible if they
    142                 // have free variables that can unify
    143                 findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );
    144                 findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );
    145 
    146                 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    147                 delete newFirst;
    148                 delete newSecond;
    149                 return result;
    150         }
    15148
    15249        bool typesCompatible(
     
    16562
    16663                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
    167         }
    168 
    169         bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    170                 TypeEnvironment newEnv;
    171                 OpenVarSet openVars;
    172                 AssertionSet needAssertions, haveAssertions;
    173                 Type *newFirst = first->clone(), *newSecond = second->clone();
    174                 env.apply( newFirst );
    175                 env.apply( newSecond );
    176                 newFirst->get_qualifiers() = Type::Qualifiers();
    177                 newSecond->get_qualifiers() = Type::Qualifiers();
    178 
    179                 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    180                 delete newFirst;
    181                 delete newSecond;
    182                 return result;
    18364        }
    18465
     
    21899                        subSecond,
    219100                        newEnv, need, have, open, noWiden() );
    220         }
    221 
    222         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    223                 OpenVarSet closedVars;
    224                 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
    225                 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
    226                 Type *commonType = 0;
    227                 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {
    228                         if ( commonType ) {
    229                                 delete commonType;
    230                         } // if
    231                         return true;
    232                 } else {
    233                         return false;
    234                 } // if
    235         }
    236 
    237         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {
    238                 OpenVarSet closedVars;
    239                 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
    240                 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
    241                 return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );
    242         }
    243 
    244         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
    245 #ifdef DEBUG
    246                 TypeEnvironment debugEnv( env );
    247 #endif
    248                 if ( type1->get_qualifiers() != type2->get_qualifiers() ) {
    249                         return false;
    250                 }
    251 
    252                 bool result;
    253                 TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );
    254                 TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );
    255                 OpenVarSet::const_iterator entry1, entry2;
    256                 if ( var1 ) {
    257                         entry1 = openVars.find( var1->get_name() );
    258                 } // if
    259                 if ( var2 ) {
    260                         entry2 = openVars.find( var2->get_name() );
    261                 } // if
    262                 bool isopen1 = var1 && ( entry1 != openVars.end() );
    263                 bool isopen2 = var2 && ( entry2 != openVars.end() );
    264 
    265                 if ( isopen1 && isopen2 ) {
    266                         if ( entry1->second.kind != entry2->second.kind ) {
    267                                 result = false;
    268                         } else {
    269                                 result = env.bindVarToVar(
    270                                         var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
    271                                         haveAssertions, openVars, widen, indexer );
    272                         }
    273                 } else if ( isopen1 ) {
    274                         result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );
    275                 } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?
    276                         result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );
    277                 } else {
    278                         PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );
    279                         type1->accept( comparator );
    280                         result = comparator.pass.get_result();
    281                 } // if
    282 #ifdef DEBUG
    283                 std::cerr << "============ unifyExact" << std::endl;
    284                 std::cerr << "type1 is ";
    285                 type1->print( std::cerr );
    286                 std::cerr << std::endl << "type2 is ";
    287                 type2->print( std::cerr );
    288                 std::cerr << std::endl << "openVars are ";
    289                 printOpenVarSet( openVars, std::cerr, 8 );
    290                 std::cerr << std::endl << "input env is " << std::endl;
    291                 debugEnv.print( std::cerr, 8 );
    292                 std::cerr << std::endl << "result env is " << std::endl;
    293                 env.print( std::cerr, 8 );
    294                 std::cerr << "result is " << result << std::endl;
    295 #endif
    296                 return result;
    297         }
    298 
    299         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    300                 return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    301         }
    302 
    303         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {
    304                 Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();
    305                 type1->get_qualifiers() = Type::Qualifiers();
    306                 type2->get_qualifiers() = Type::Qualifiers();
    307                 bool result;
    308 #ifdef DEBUG
    309                 std::cerr << "unifyInexact type 1 is ";
    310                 type1->print( std::cerr );
    311                 std::cerr << " type 2 is ";
    312                 type2->print( std::cerr );
    313                 std::cerr << std::endl;
    314 #endif
    315                 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {
    316 #ifdef DEBUG
    317                         std::cerr << "unifyInexact: no exact unification found" << std::endl;
    318 #endif
    319                         if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {
    320                                 common->tq = tq1.unify( tq2 );
    321 #ifdef DEBUG
    322                                 std::cerr << "unifyInexact: common type is ";
    323                                 common->print( std::cerr );
    324                                 std::cerr << std::endl;
    325 #endif
    326                                 result = true;
    327                         } else {
    328 #ifdef DEBUG
    329                                 std::cerr << "unifyInexact: no common type found" << std::endl;
    330 #endif
    331                                 result = false;
    332                         } // if
    333                 } else {
    334                         if ( tq1 != tq2 ) {
    335                                 if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {
    336                                         common = type1->clone();
    337                                         common->tq = tq1.unify( tq2 );
    338                                         result = true;
    339                                 } else {
    340                                         result = false;
    341                                 } // if
    342                         } else {
    343                                 common = type1->clone();
    344                                 common->tq = tq1.unify( tq2 );
    345                                 result = true;
    346                         } // if
    347                 } // if
    348                 type1->get_qualifiers() = tq1;
    349                 type2->get_qualifiers() = tq2;
    350                 return result;
    351         }
    352 
    353         Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )
    354                 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {
    355         }
    356 
    357         void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {
    358                 result = dynamic_cast< VoidType* >( type2 );
    359         }
    360 
    361         void Unify_old::postvisit(BasicType *basicType) {
    362                 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
    363                         result = basicType->get_kind() == otherBasic->get_kind();
    364                 } // if
    365         }
    366 
    367         void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
    368                 AssertionSet::iterator i = assertions.find( assert );
    369                 if ( i != assertions.end() ) {
    370                         i->second.isUsed = true;
    371                 } // if
    372         }
    373 
    374         void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {
    375                 for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
    376                         for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
    377                                 markAssertionSet( assertion1, *assert );
    378                                 markAssertionSet( assertion2, *assert );
    379                         } // for
    380                 } // for
    381         }
    382 
    383         void Unify_old::postvisit(PointerType *pointerType) {
    384                 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
    385                         result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    386                         markAssertions( haveAssertions, needAssertions, pointerType );
    387                         markAssertions( haveAssertions, needAssertions, otherPointer );
    388                 } // if
    389         }
    390 
    391         void Unify_old::postvisit(ReferenceType *refType) {
    392                 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
    393                         result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    394                         markAssertions( haveAssertions, needAssertions, refType );
    395                         markAssertions( haveAssertions, needAssertions, otherRef );
    396                 } // if
    397         }
    398 
    399         void Unify_old::postvisit(ArrayType *arrayType) {
    400                 ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
    401                 // to unify, array types must both be VLA or both not VLA
    402                 // and must both have a dimension expression or not have a dimension
    403                 if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {
    404 
    405                         if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&
    406                                 arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {
    407                                 ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );
    408                                 ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );
    409                                 // see C11 Reference Manual 6.7.6.2.6
    410                                 // two array types with size specifiers that are integer constant expressions are
    411                                 // compatible if both size specifiers have the same constant value
    412                                 if ( ce1 && ce2 ) {
    413                                         Constant * c1 = ce1->get_constant();
    414                                         Constant * c2 = ce2->get_constant();
    415 
    416                                         if ( c1->get_value() != c2->get_value() ) {
    417                                                 // does not unify if the dimension is different
    418                                                 return;
    419                                         }
    420                                 }
    421                         }
    422 
    423                         result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    424                 } // if
    425         }
    426 
    427         template< typename Iterator, typename Func >
    428         std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {
    429                 std::list< Type * > types;
    430                 for ( ; begin != end; ++begin ) {
    431                         // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple
    432                         flatten( toType( *begin ), back_inserter( types ) );
    433                 }
    434                 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
    435         }
    436 
    437         template< typename Iterator1, typename Iterator2 >
    438         bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    439                 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
    440                 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    441                         Type * t1 = (*list1Begin)->get_type();
    442                         Type * t2 = (*list2Begin)->get_type();
    443                         bool isTtype1 = Tuples::isTtype( t1 );
    444                         bool isTtype2 = Tuples::isTtype( t2 );
    445                         // xxx - assumes ttype must be last parameter
    446                         // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
    447                         if ( isTtype1 && ! isTtype2 ) {
    448                                 // combine all of the things in list2, then unify
    449                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    450                         } else if ( isTtype2 && ! isTtype1 ) {
    451                                 // combine all of the things in list1, then unify
    452                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    453                         } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    454                                 return false;
    455                         } // if
    456                 } // for
    457                 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype
    458                 if ( list1Begin != list1End ) {
    459                         // try unifying empty tuple type with ttype
    460                         Type * t1 = (*list1Begin)->get_type();
    461                         if ( Tuples::isTtype( t1 ) ) {
    462                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    463                         } else return false;
    464                 } else if ( list2Begin != list2End ) {
    465                         // try unifying empty tuple type with ttype
    466                         Type * t2 = (*list2Begin)->get_type();
    467                         if ( Tuples::isTtype( t2 ) ) {
    468                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    469                         } else return false;
    470                 } else {
    471                         return true;
    472                 } // if
    473         }
    474 
    475         /// Finds ttypes and replaces them with their expansion, if known.
    476         /// This needs to be done so that satisfying ttype assertions is easier.
    477         /// If this isn't done then argument lists can have wildly different
    478         /// size and structure, when they should be compatible.
    479         struct TtypeExpander_old : public WithShortCircuiting {
    480                 TypeEnvironment & tenv;
    481                 TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}
    482                 void premutate( TypeInstType * ) { visit_children = false; }
    483                 Type * postmutate( TypeInstType * typeInst ) {
    484                         if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {
    485                                 // expand ttype parameter into its actual type
    486                                 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {
    487                                         delete typeInst;
    488                                         return eqvClass->type->clone();
    489                                 }
    490                         }
    491                         return typeInst;
    492                 }
    493         };
    494 
    495         /// flattens a list of declarations, so that each tuple type has a single declaration.
    496         /// makes use of TtypeExpander to ensure ttypes are flat as well.
    497         void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {
    498                 dst.clear();
    499                 for ( DeclarationWithType * dcl : src ) {
    500                         PassVisitor<TtypeExpander_old> expander( env );
    501                         dcl->acceptMutator( expander );
    502                         std::list< Type * > types;
    503                         flatten( dcl->get_type(), back_inserter( types ) );
    504                         for ( Type * t : types ) {
    505                                 // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.
    506                                 // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.
    507                                 t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);
    508 
    509                                 dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );
    510                         }
    511                         delete dcl;
    512                 }
    513         }
    514 
    515         void Unify_old::postvisit(FunctionType *functionType) {
    516                 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
    517                 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
    518                         // flatten the parameter lists for both functions so that tuple structure
    519                         // doesn't affect unification. Must be a clone so that the types don't change.
    520                         std::unique_ptr<FunctionType> flatFunc( functionType->clone() );
    521                         std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );
    522                         flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );
    523                         flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );
    524 
    525                         // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
    526                         if (
    527                                         (flatFunc->parameters.size() == flatOther->parameters.size() &&
    528                                                 flatFunc->returnVals.size() == flatOther->returnVals.size())
    529                                         || flatFunc->isTtype()
    530                                         || flatOther->isTtype()
    531                         ) {
    532                                 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    533                                         if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    534 
    535                                                 // the original types must be used in mark assertions, since pointer comparisons are used
    536                                                 markAssertions( haveAssertions, needAssertions, functionType );
    537                                                 markAssertions( haveAssertions, needAssertions, otherFunction );
    538 
    539                                                 result = true;
    540                                         } // if
    541                                 } // if
    542                         } // if
    543                 } // if
    544         }
    545 
    546         template< typename RefType >
    547         void Unify_old::handleRefType( RefType *inst, Type *other ) {
    548                 // check that other type is compatible and named the same
    549                 RefType *otherStruct = dynamic_cast< RefType* >( other );
    550                 result = otherStruct && inst->name == otherStruct->name;
    551         }
    552 
    553         template< typename RefType >
    554         void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {
    555                 // Check that other type is compatible and named the same
    556                 handleRefType( inst, other );
    557                 if ( ! result ) return;
    558                 // Check that parameters of types unify, if any
    559                 std::list< Expression* > params = inst->parameters;
    560                 std::list< Expression* > otherParams = ((RefType*)other)->parameters;
    561 
    562                 std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();
    563                 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {
    564                         TypeExpr *param = dynamic_cast< TypeExpr* >(*it);
    565                         assertf(param, "Aggregate parameters should be type expressions");
    566                         TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);
    567                         assertf(otherParam, "Aggregate parameters should be type expressions");
    568 
    569                         Type* paramTy = param->get_type();
    570                         Type* otherParamTy = otherParam->get_type();
    571 
    572                         bool tupleParam = Tuples::isTtype( paramTy );
    573                         bool otherTupleParam = Tuples::isTtype( otherParamTy );
    574 
    575                         if ( tupleParam && otherTupleParam ) {
    576                                 ++it; ++jt;  // skip ttype parameters for break
    577                         } else if ( tupleParam ) {
    578                                 // bundle other parameters into tuple to match
    579                                 std::list< Type * > binderTypes;
    580 
    581                                 do {
    582                                         binderTypes.push_back( otherParam->get_type()->clone() );
    583                                         ++jt;
    584 
    585                                         if ( jt == otherParams.end() ) break;
    586 
    587                                         otherParam = dynamic_cast< TypeExpr* >(*jt);
    588                                         assertf(otherParam, "Aggregate parameters should be type expressions");
    589                                 } while (true);
    590 
    591                                 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };
    592                                 ++it;  // skip ttype parameter for break
    593                         } else if ( otherTupleParam ) {
    594                                 // bundle parameters into tuple to match other
    595                                 std::list< Type * > binderTypes;
    596 
    597                                 do {
    598                                         binderTypes.push_back( param->get_type()->clone() );
    599                                         ++it;
    600 
    601                                         if ( it == params.end() ) break;
    602 
    603                                         param = dynamic_cast< TypeExpr* >(*it);
    604                                         assertf(param, "Aggregate parameters should be type expressions");
    605                                 } while (true);
    606 
    607                                 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };
    608                                 ++jt;  // skip ttype parameter for break
    609                         }
    610 
    611                         if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {
    612                                 result = false;
    613                                 return;
    614                         }
    615 
    616                         // ttype parameter should be last
    617                         if ( tupleParam || otherTupleParam ) break;
    618                 }
    619                 result = ( it == params.end() && jt == otherParams.end() );
    620         }
    621 
    622         void Unify_old::postvisit(StructInstType *structInst) {
    623                 handleGenericRefType( structInst, type2 );
    624         }
    625 
    626         void Unify_old::postvisit(UnionInstType *unionInst) {
    627                 handleGenericRefType( unionInst, type2 );
    628         }
    629 
    630         void Unify_old::postvisit(EnumInstType *enumInst) {
    631                 handleRefType( enumInst, type2 );
    632         }
    633 
    634         void Unify_old::postvisit(TraitInstType *contextInst) {
    635                 handleRefType( contextInst, type2 );
    636         }
    637 
    638         void Unify_old::postvisit(TypeInstType *typeInst) {
    639                 assert( openVars.find( typeInst->get_name() ) == openVars.end() );
    640                 TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
    641                 if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {
    642                         result = true;
    643 ///   } else {
    644 ///     NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );
    645 ///     if ( nt ) {
    646 ///       TypeDecl *type = dynamic_cast< TypeDecl* >( nt );
    647 ///       assert( type );
    648 ///       if ( type->get_base() ) {
    649 ///         result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    650 ///       }
    651 ///     }
    652                 } // if
    653         }
    654 
    655         template< typename Iterator1, typename Iterator2 >
    656         bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    657                 auto get_type = [](Type * t) { return t; };
    658                 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    659                         Type * t1 = *list1Begin;
    660                         Type * t2 = *list2Begin;
    661                         bool isTtype1 = Tuples::isTtype( t1 );
    662                         bool isTtype2 = Tuples::isTtype( t2 );
    663                         // xxx - assumes ttype must be last parameter
    664                         // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
    665                         if ( isTtype1 && ! isTtype2 ) {
    666                                 // combine all of the things in list2, then unify
    667                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    668                         } else if ( isTtype2 && ! isTtype1 ) {
    669                                 // combine all of the things in list1, then unify
    670                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    671                         } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    672                                 return false;
    673                         } // if
    674 
    675                 } // for
    676                 if ( list1Begin != list1End ) {
    677                         // try unifying empty tuple type with ttype
    678                         Type * t1 = *list1Begin;
    679                         if ( Tuples::isTtype( t1 ) ) {
    680                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    681                         } else return false;
    682                 } else if ( list2Begin != list2End ) {
    683                         // try unifying empty tuple type with ttype
    684                         Type * t2 = *list2Begin;
    685                         if ( Tuples::isTtype( t2 ) ) {
    686                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    687                         } else return false;
    688                 } else {
    689                         return true;
    690                 } // if
    691         }
    692 
    693         void Unify_old::postvisit(TupleType *tupleType) {
    694                 if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
    695                         std::unique_ptr<TupleType> flat1( tupleType->clone() );
    696                         std::unique_ptr<TupleType> flat2( otherTuple->clone() );
    697                         std::list<Type *> types1, types2;
    698 
    699                         PassVisitor<TtypeExpander_old> expander( env );
    700                         flat1->acceptMutator( expander );
    701                         flat2->acceptMutator( expander );
    702 
    703                         flatten( flat1.get(), back_inserter( types1 ) );
    704                         flatten( flat2.get(), back_inserter( types2 ) );
    705 
    706                         result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );
    707                 } // if
    708         }
    709 
    710         void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
    711                 result = dynamic_cast< VarArgsType* >( type2 );
    712         }
    713 
    714         void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
    715                 result = dynamic_cast< ZeroType* >( type2 );
    716         }
    717 
    718         void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {
    719                 result = dynamic_cast< OneType* >( type2 );
    720         }
    721 
    722         Type * extractResultType( FunctionType * function ) {
    723                 if ( function->get_returnVals().size() == 0 ) {
    724                         return new VoidType( Type::Qualifiers() );
    725                 } else if ( function->get_returnVals().size() == 1 ) {
    726                         return function->get_returnVals().front()->get_type()->clone();
    727                 } else {
    728                         std::list< Type * > types;
    729                         for ( DeclarationWithType * decl : function->get_returnVals() ) {
    730                                 types.push_back( decl->get_type()->clone() );
    731                         } // for
    732                         return new TupleType( Type::Qualifiers(), types );
    733                 }
    734101        }
    735102
  • src/ResolvExpr/Unify.h

    r0030b508 rfc12f05  
    2020#include "AST/Node.hpp"             // for ptr
    2121#include "AST/TypeEnvironment.hpp"  // for TypeEnvironment, AssertionSet, OpenVarSet
    22 #include "Common/utility.h"       // for deleteAll
    23 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Data
    24 #include "TypeEnvironment.h"      // for AssertionSet, OpenVarSet
    2522#include "WidenMode.h"              // for WidenMode
    26 
    27 class Type;
    28 class TypeInstType;
    29 namespace SymTab {
    30         class Indexer;
    31 }
    3223
    3324namespace ast {
     
    3728
    3829namespace ResolvExpr {
    39 
    40 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    41 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
    42 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    43 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    44 
    45 bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    46 bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    47 
    48 inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    49         TypeEnvironment env;
    50         return typesCompatible( t1, t2, indexer, env );
    51 }
    52 
    53 inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    54         TypeEnvironment env;
    55         return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
    56 }
    5730
    5831bool unify(
     
    8558        const ast::TypeEnvironment & env = {} );
    8659
    87 /// Creates the type represented by the list of returnVals in a FunctionType.
    88 /// The caller owns the return value.
    89 Type * extractResultType( FunctionType * functionType );
    9060/// Creates or extracts the type represented by returns in a `FunctionType`.
    9161ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
  • src/ResolvExpr/module.mk

    r0030b508 rfc12f05  
    1818      ResolvExpr/AdjustExprType.cc \
    1919      ResolvExpr/AdjustExprType.hpp \
    20       ResolvExpr/Alternative.cc \
    21       ResolvExpr/AlternativeFinder.cc \
    22       ResolvExpr/AlternativeFinder.h \
    23       ResolvExpr/Alternative.h \
    2420      ResolvExpr/Candidate.cpp \
    2521      ResolvExpr/CandidateFinder.cpp \
     
    3531      ResolvExpr/CurrentObject.cc \
    3632      ResolvExpr/CurrentObject.h \
    37       ResolvExpr/ExplodedActual.cc \
    38       ResolvExpr/ExplodedActual.h \
    3933      ResolvExpr/ExplodedArg.cpp \
    4034      ResolvExpr/ExplodedArg.hpp \
    4135      ResolvExpr/FindOpenVars.cc \
    4236      ResolvExpr/FindOpenVars.h \
    43       ResolvExpr/Occurs.cc \
    4437      ResolvExpr/PolyCost.cc \
    4538      ResolvExpr/PolyCost.hpp \
     
    5043      ResolvExpr/RenameVars.cc \
    5144      ResolvExpr/RenameVars.h \
    52       ResolvExpr/ResolveAssertions.cc \
    53       ResolvExpr/ResolveAssertions.h \
    5445      ResolvExpr/Resolver.cc \
    5546      ResolvExpr/Resolver.h \
     
    6152      ResolvExpr/SpecCost.cc \
    6253      ResolvExpr/SpecCost.hpp \
    63       ResolvExpr/TypeEnvironment.cc \
    64       ResolvExpr/TypeEnvironment.h \
    6554      ResolvExpr/typeops.h \
    6655      ResolvExpr/Unify.cc \
     
    6958
    7059SRC += $(SRC_RESOLVEXPR) \
    71         ResolvExpr/AlternativePrinter.cc \
    72         ResolvExpr/AlternativePrinter.h \
    7360        ResolvExpr/CandidatePrinter.cpp \
    7461        ResolvExpr/CandidatePrinter.hpp \
  • src/ResolvExpr/typeops.h

    r0030b508 rfc12f05  
    1919
    2020#include "AST/Type.hpp"
    21 #include "SynTree/Type.h"
    2221
    2322namespace SymTab {
     
    5251                        std::copy( i.begin(), i.end(), inserter );
    5352                        *out++ = result;
    54                 }
    55         }
    56 
    57         // in Occurs.cc
    58         bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );
    59         // new AST version in TypeEnvironment.cpp (only place it was used in old AST)
    60 
    61         template<typename Iter>
    62         bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) {
    63                 while ( begin != end ) {
    64                         if ( occurs( ty, *begin, env ) ) return true;
    65                         ++begin;
    66                 }
    67                 return false;
    68         }
    69 
    70         /// flatten tuple type into list of types
    71         template< typename OutputIterator >
    72         void flatten( Type * type, OutputIterator out ) {
    73                 if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {
    74                         for ( Type * t : tupleType->get_types() ) {
    75                                 flatten( t, out );
    76                         }
    77                 } else {
    78                         *out++ = type->clone();
    7953                }
    8054        }
     
    12094                return tupleFromTypes( tys.begin(), tys.end() );
    12195        }
    122 
    123         // in TypeEnvironment.cc
    124         bool isFtype( const Type * type );
    12596} // namespace ResolvExpr
    12697
  • src/SymTab/Demangle.cc

    r0030b508 rfc12f05  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jul 19 12:52:41 2018
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 11 21:28:27 2021
    13 // Update Count     : 11
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  6 15:59:00 2023
     13// Update Count     : 12
    1414//
    1515
     
    1717#include <sstream>
    1818
     19#include "AST/Pass.hpp"
     20#include "AST/Type.hpp"
    1921#include "CodeGen/GenType.h"
    20 #include "Common/PassVisitor.h"
     22#include "CodeGen/OperatorTable.h"
    2123#include "Common/utility.h"                                                             // isPrefix
    2224#include "Mangler.h"
    23 #include "SynTree/Type.h"
    24 #include "SynTree/Declaration.h"
    2525
    2626#define DEBUG
     
    3131#endif
    3232
     33namespace Mangle {
     34
    3335namespace {
    34         struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    35                 std::string typeString;
    36                 GenType( const std::string &typeString );
    37 
    38                 void previsit( BaseSyntaxNode * );
    39                 void postvisit( BaseSyntaxNode * );
    40 
    41                 void postvisit( FunctionType * funcType );
    42                 void postvisit( VoidType * voidType );
    43                 void postvisit( BasicType * basicType );
    44                 void postvisit( PointerType * pointerType );
    45                 void postvisit( ArrayType * arrayType );
    46                 void postvisit( ReferenceType * refType );
    47                 void postvisit( StructInstType * structInst );
    48                 void postvisit( UnionInstType * unionInst );
    49                 void postvisit( EnumInstType * enumInst );
    50                 void postvisit( TypeInstType * typeInst );
    51                 void postvisit( TupleType  * tupleType );
    52                 void postvisit( VarArgsType * varArgsType );
    53                 void postvisit( ZeroType * zeroType );
    54                 void postvisit( OneType * oneType );
    55                 void postvisit( GlobalScopeType * globalType );
    56                 void postvisit( QualifiedType * qualType );
    57 
    58           private:
    59                 void handleQualifiers( Type *type );
    60                 std::string handleGeneric( ReferenceToType * refType );
    61                 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    62         };
    63 
    64   std::string genDemangleType( Type * type, const std::string & baseString ) {
    65                 PassVisitor<GenType> gt( baseString );
    66                 assert( type );
    67                 type->accept( gt );
    68                 return gt.pass.typeString;
    69   }
    70 
    71         GenType::GenType( const std::string &typeString ) : typeString( typeString ) {}
    72 
    73         // *** BaseSyntaxNode
    74         void GenType::previsit( BaseSyntaxNode * ) {
    75                 // turn off automatic recursion for all nodes, to allow each visitor to
    76                 // precisely control the order in which its children are visited.
    77                 visit_children = false;
    78         }
    79 
    80         void GenType::postvisit( BaseSyntaxNode * node ) {
    81                 std::stringstream ss;
    82                 node->print( ss );
    83                 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
    84         }
    85 
    86         void GenType::postvisit( VoidType * voidType ) {
    87                 typeString = "void " + typeString;
    88                 handleQualifiers( voidType );
    89         }
    90 
    91         void GenType::postvisit( BasicType * basicType ) {
    92                 BasicType::Kind kind = basicType->kind;
    93                 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
    94                 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
    95                 handleQualifiers( basicType );
    96         }
    97 
    98         void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool ) {
    99                 std::ostringstream os;
    100                 if ( typeString != "" ) {
    101                         if ( typeString[ 0 ] == '*' ) {
    102                                 os << "(" << typeString << ")";
    103                         } else {
    104                                 os << typeString;
    105                         } // if
    106                 } // if
    107                 os << "[";
    108 
    109                 if ( qualifiers.is_const ) {
    110                         os << "const ";
    111                 } // if
    112                 if ( qualifiers.is_volatile ) {
    113                         os << "volatile ";
    114                 } // if
    115                 if ( qualifiers.is_restrict ) {
    116                         os << "__restrict ";
    117                 } // if
    118                 if ( qualifiers.is_atomic ) {
    119                         os << "_Atomic ";
    120                 } // if
    121                 if ( dimension != 0 ) {
    122                         // TODO: ???
    123                         // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    124                         // dimension->accept( cg );
    125                 } else if ( isVarLen ) {
    126                         // no dimension expression on a VLA means it came in with the * token
    127                         os << "*";
    128                 } // if
    129                 os << "]";
    130 
    131                 typeString = os.str();
    132 
    133                 base->accept( *visitor );
    134         }
    135 
    136         void GenType::postvisit( PointerType * pointerType ) {
    137                 assert( pointerType->base != 0);
    138                 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
    139                         assert(false);
    140                         genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
    141                 } else {
    142                         handleQualifiers( pointerType );
    143                         if ( typeString[ 0 ] == '?' ) {
    144                                 typeString = "* " + typeString;
    145                         } else {
    146                                 typeString = "*" + typeString;
    147                         } // if
    148                         pointerType->base->accept( *visitor );
    149                 } // if
    150         }
    151 
    152         void GenType::postvisit( ArrayType * arrayType ) {
    153                 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
    154         }
    155 
    156         void GenType::postvisit( ReferenceType * refType ) {
    157                 assert( false );
    158                 assert( refType->base != 0);
    159                 handleQualifiers( refType );
    160                 typeString = "&" + typeString;
    161                 refType->base->accept( *visitor );
    162         }
    163 
    164         void GenType::postvisit( FunctionType * funcType ) {
    165                 std::ostringstream os;
    166 
    167                 if ( typeString != "" ) {
    168                         if ( typeString[0] == '*' ) {
    169                                 os << "(" << typeString << ")";
    170                         } else {
    171                                 os << typeString;
    172                         } // if
    173                 } // if
    174 
    175                 /************* parameters ***************/
    176                 const std::list<DeclarationWithType *> &pars = funcType->parameters;
    177 
    178                 if ( pars.empty() ) {
    179                         if ( funcType->get_isVarArgs() ) {
    180                                 os << "()";
    181                         } else {
    182                                 os << "(void)";
    183                         } // if
    184                 } else {
    185                         os << "(" ;
    186 
    187                         unsigned int i = 0;
    188                         for (DeclarationWithType * p : pars) {
    189                                 os << genDemangleType( p->get_type(), "" );
    190                                 if (++i != pars.size()) os << ", ";
    191                         }
    192 
    193                         if ( funcType->get_isVarArgs() ) {
    194                                 os << ", ...";
    195                         } // if
    196                         os << ")";
    197                 } // if
    198 
    199                 typeString = os.str();
    200 
    201                 if ( funcType->returnVals.size() == 0 ) {
    202                         typeString += ": void";
    203                 } else {
    204                         typeString += ": " + genDemangleType(funcType->returnVals.front()->get_type(), "");
    205                 } // if
    206 
    207                 // add forall
    208                 if( ! funcType->forall.empty() ) {
    209                         std::ostringstream os;
    210                         os << "forall(";
    211                         unsigned int i = 0;
    212                         for ( auto td : funcType->forall ) {
    213                                 os << td->typeString() << " " << td->name;
    214                                 if (! td->assertions.empty()) {
    215                                         os << " | { ";
    216                                         unsigned int j = 0;
    217                                         for (DeclarationWithType * assert : td->assertions) {
    218                                                 os << genDemangleType(assert->get_type(), assert->name);
    219                                                 if (++j != td->assertions.size()) os << ", ";
    220                                         }
    221                                         os << "}";
    222                                 }
    223                                 if (++i != funcType->forall.size()) os << ", ";
    224                         }
    225                         os << ")";
    226                         typeString = typeString + " -> " + os.str();
     36
     37struct Demangler {
     38private:
     39        std::string str;
     40        size_t index = 0;
     41        using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>;
     42        std::vector<std::pair<std::string, Parser>> parsers;
     43public:
     44        Demangler( const std::string & str );
     45
     46        bool done() const { return str.size() <= index; }
     47        char cur() const { assert( !done() ); return str[index]; }
     48        bool expect( char ch ) { return str[index++] == ch; }
     49
     50        bool isPrefix( const std::string & pref );
     51        bool extractNumber( size_t & out );
     52        bool extractName( std::string & out );
     53        bool stripMangleName( std::string & name );
     54
     55        ast::Type * parseFunction( ast::CV::Qualifiers tq );
     56        ast::Type * parseTuple( ast::CV::Qualifiers tq );
     57        ast::Type * parsePointer( ast::CV::Qualifiers tq );
     58        ast::Type * parseArray( ast::CV::Qualifiers tq );
     59        ast::Type * parseStruct( ast::CV::Qualifiers tq );
     60        ast::Type * parseUnion( ast::CV::Qualifiers tq );
     61        ast::Type * parseEnum( ast::CV::Qualifiers tq );
     62        ast::Type * parseType( ast::CV::Qualifiers tq );
     63        ast::Type * parseZero( ast::CV::Qualifiers tq );
     64        ast::Type * parseOne( ast::CV::Qualifiers tq );
     65
     66        ast::Type * parseType();
     67        bool parse( std::string & name, ast::Type *& type );
     68};
     69
     70Demangler::Demangler(const std::string & str) : str(str) {
     71        for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
     72                parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) {
     73                        PRINT( std::cerr << "basic type: " << k << std::endl; )
     74                        return new ast::BasicType( (ast::BasicType::Kind)k, tq );
     75                });
     76        }
     77
     78        for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) {
     79                static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
     80                static_assert(
     81                        sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
     82                        "Each type variable kind should have a demangle name prefix"
     83                );
     84                parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * {
     85                        PRINT( std::cerr << "type variable type: " << k << std::endl; )
     86                        size_t N;
     87                        if (!extractNumber(N)) return nullptr;
     88                        return new ast::TypeInstType(
     89                                toString(typeVariableNames[k], N),
     90                                (ast::TypeDecl::Kind)k,
     91                                tq );
     92                });
     93        }
     94
     95        parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); });
     96        parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); });
     97        parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); });
     98        parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); });
     99        parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); });
     100        parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); });
     101        parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); });
     102        parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); });
     103        parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); });
     104        parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); });
     105        parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); });
     106}
     107
     108bool Demangler::extractNumber( size_t & out ) {
     109        std::stringstream numss;
     110        if ( str.size() <= index ) return false;
     111        while ( isdigit( str[index] ) ) {
     112                numss << str[index];
     113                ++index;
     114                if ( str.size() == index ) break;
     115        }
     116        if ( !(numss >> out) ) return false;
     117        PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
     118        return true;
     119}
     120
     121bool Demangler::extractName( std::string & out ) {
     122        size_t len;
     123        if ( !extractNumber(len) ) return false;
     124        if ( str.size() < index + len ) return false;
     125        out = str.substr( index, len );
     126        index += len;
     127        PRINT( std::cerr << "extractName success: " << out << std::endl; )
     128        return true;
     129}
     130
     131bool Demangler::isPrefix( const std::string & pref ) {
     132        // Wraps the utility isPrefix function.
     133        if ( ::isPrefix( str, pref, index ) ) {
     134                index += pref.size();
     135                return true;
     136        }
     137        return false;
     138}
     139
     140// strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
     141bool Demangler::stripMangleName( std::string & name ) {
     142        PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
     143        if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
     144        if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false;
     145
     146        if (!extractName(name)) return false;
     147
     148        // Find bounds for type.
     149        PRINT( std::cerr << index << " " << str.size() << std::endl; )
     150        PRINT( std::cerr << "[");
     151        while (isdigit(str.back())) {
     152                PRINT(std::cerr << ".");
     153                str.pop_back();
     154                if (str.size() <= index) return false;
     155        }
     156        PRINT( std::cerr << "]" << std::endl );
     157        if (str.back() != '_') return false;
     158        str.pop_back();
     159        PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; )
     160        return index < str.size();
     161}
     162
     163ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) {
     164        PRINT( std::cerr << "function..." << std::endl; )
     165        if ( done() ) return nullptr;
     166        ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq );
     167        std::unique_ptr<ast::Type> manager( ftype );
     168        ast::Type * retVal = parseType();
     169        if ( !retVal ) return nullptr;
     170        PRINT( std::cerr << "with return type: " << retVal << std::endl; )
     171        ftype->returns.emplace_back( retVal );
     172        if ( done() || !expect('_') ) return nullptr;
     173        while ( !done() ) {
     174                PRINT( std::cerr << "got ch: " << cur() << std::endl; )
     175                if ( cur() == '_' ) return manager.release();
     176                ast::Type * param = parseType();
     177                if ( !param ) return nullptr;
     178                PRINT( std::cerr << "with parameter : " << param << std::endl; )
     179                ftype->params.emplace_back( param );
     180        }
     181        return nullptr;
     182}
     183
     184ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) {
     185        PRINT( std::cerr << "tuple..." << std::endl; )
     186        std::vector<ast::ptr<ast::Type>> types;
     187        size_t ncomponents;
     188        if ( !extractNumber(ncomponents) ) return nullptr;
     189        for ( size_t i = 0; i < ncomponents; ++i ) {
     190                if ( done() ) return nullptr;
     191                PRINT( std::cerr << "got ch: " << cur() << std::endl; )
     192                ast::Type * t = parseType();
     193                if ( !t ) return nullptr;
     194                PRINT( std::cerr << "with type : " << t << std::endl; )
     195                types.push_back( t );
     196        }
     197        return new ast::TupleType( std::move( types ), tq );
     198}
     199
     200ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) {
     201        PRINT( std::cerr << "pointer..." << std::endl; )
     202        ast::Type * t = parseType();
     203        if ( !t ) return nullptr;
     204        return new ast::PointerType( t, tq );
     205}
     206
     207ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) {
     208        PRINT( std::cerr << "array..." << std::endl; )
     209        size_t length;
     210        if ( !extractNumber(length) ) return nullptr;
     211        ast::Type * t = parseType();
     212        if ( !t ) return nullptr;
     213        return new ast::ArrayType(
     214                t,
     215                ast::ConstantExpr::from_ulong( CodeLocation(), length ),
     216                ast::FixedLen,
     217                ast::DynamicDim,
     218                tq );
     219}
     220
     221ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) {
     222        PRINT( std::cerr << "struct..." << std::endl; )
     223        std::string name;
     224        if ( !extractName(name) ) return nullptr;
     225        return new ast::StructInstType( name, tq );
     226}
     227
     228ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) {
     229        PRINT( std::cerr << "union..." << std::endl; )
     230        std::string name;
     231        if ( !extractName(name) ) return nullptr;
     232        return new ast::UnionInstType( name, tq );
     233}
     234
     235ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) {
     236        PRINT( std::cerr << "enum..." << std::endl; )
     237        std::string name;
     238        if ( !extractName(name) ) return nullptr;
     239        return new ast::EnumInstType( name, tq );
     240}
     241
     242ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) {
     243        PRINT( std::cerr << "type..." << std::endl; )
     244        std::string name;
     245        if ( !extractName(name) ) return nullptr;
     246        PRINT( std::cerr << "typename..." << name << std::endl; )
     247        return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq );
     248}
     249
     250ast::Type * Demangler::parseType() {
     251        if (done()) return nullptr;
     252
     253        if (isPrefix(Encoding::forall)) {
     254                PRINT( std::cerr << "polymorphic with..." << std::endl; )
     255                size_t dcount, fcount, vcount, acount;
     256                if ( !extractNumber(dcount) ) return nullptr;
     257                PRINT( std::cerr << dcount << " dtypes" << std::endl; )
     258                if ( !expect('_') ) return nullptr;
     259                if ( !extractNumber(fcount) ) return nullptr;
     260                PRINT( std::cerr << fcount << " ftypes" << std::endl; )
     261                if ( !expect('_')) return nullptr;
     262                if ( !extractNumber(vcount)) return nullptr;
     263                PRINT( std::cerr << vcount << " ttypes" << std::endl; )
     264                if ( !expect('_') ) return nullptr;
     265                if ( !extractNumber(acount) ) return nullptr;
     266                PRINT( std::cerr << acount << " assertions" << std::endl; )
     267                if ( !expect('_') ) return nullptr;
     268                for ( size_t i = 0 ; i < acount ; ++i ) {
     269                        // TODO: need to recursively parse assertions, but for now just return nullptr so that
     270                        // demangler does not crash if there are assertions
     271                        return nullptr;
    227272                }
    228         }
    229 
    230         std::string GenType::handleGeneric( ReferenceToType * refType ) {
    231                 if ( ! refType->parameters.empty() ) {
    232                         std::ostringstream os;
    233                         // TODO: ???
    234                         // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    235                         os << "(";
    236                         // cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
    237                         os << ") ";
    238                         return os.str();
    239                 }
    240                 return "";
    241         }
    242 
    243         void GenType::postvisit( StructInstType * structInst )  {
    244                 typeString = "struct " + structInst->name + handleGeneric( structInst ) + " " + typeString;
    245                 handleQualifiers( structInst );
    246         }
    247 
    248         void GenType::postvisit( UnionInstType * unionInst ) {
    249                 typeString = "union " + unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    250                 handleQualifiers( unionInst );
    251         }
    252 
    253         void GenType::postvisit( EnumInstType * enumInst ) {
    254                 typeString = "enum " + enumInst->name + " " + typeString;
    255                 handleQualifiers( enumInst );
    256         }
    257 
    258         void GenType::postvisit( TypeInstType * typeInst ) {
    259                 typeString = typeInst->name + " " + typeString;
    260                 handleQualifiers( typeInst );
    261         }
    262 
    263         void GenType::postvisit( TupleType * tupleType ) {
    264                 unsigned int i = 0;
    265                 std::ostringstream os;
    266                 os << "[";
    267                 for ( Type * t : *tupleType ) {
    268                         i++;
    269                         os << genDemangleType( t, "" ) << (i == tupleType->size() ? "" : ", ");
    270                 }
    271                 os << "] ";
    272                 typeString = os.str() + typeString;
    273         }
    274 
    275         void GenType::postvisit( VarArgsType * varArgsType ) {
    276                 typeString = "__builtin_va_list " + typeString;
    277                 handleQualifiers( varArgsType );
    278         }
    279 
    280         void GenType::postvisit( ZeroType * zeroType ) {
    281                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    282                 typeString = "zero_t " + typeString;
    283                 handleQualifiers( zeroType );
    284         }
    285 
    286         void GenType::postvisit( OneType * oneType ) {
    287                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    288                 typeString = "one_t " + typeString;
    289                 handleQualifiers( oneType );
    290         }
    291 
    292         void GenType::postvisit( GlobalScopeType * globalType ) {
    293                 handleQualifiers( globalType );
    294         }
    295 
    296         void GenType::postvisit( QualifiedType * qualType ) {
    297                 std::ostringstream os;
    298                 os << genDemangleType( qualType->parent, "" ) << "." << genDemangleType( qualType->child, "" ) << typeString;
    299                 typeString = os.str();
    300                 handleQualifiers( qualType );
    301         }
    302 
    303         void GenType::handleQualifiers( Type * type ) {
    304                 if ( type->get_const() ) {
    305                         typeString = "const " + typeString;
    306                 } // if
    307                 if ( type->get_volatile() ) {
    308                         typeString = "volatile " + typeString;
    309                 } // if
    310                 if ( type->get_restrict() ) {
    311                         typeString = "__restrict " + typeString;
    312                 } // if
    313                 if ( type->get_atomic() ) {
    314                         typeString = "_Atomic " + typeString;
    315                 } // if
    316         }
    317 }
    318 
    319 
    320 namespace SymTab {
    321         namespace Mangler {
    322                 namespace {
    323                         struct StringView {
    324                         private:
    325                                 std::string str;
    326                                 size_t idx = 0;
    327                                 // typedef Type * (StringView::*parser)(Type::Qualifiers);
    328                                 typedef std::function<Type * (Type::Qualifiers)> parser;
    329                                 std::vector<std::pair<std::string, parser>> parsers;
    330                         public:
    331                                 StringView(const std::string & str);
    332 
    333                                 bool done() const { return idx >= str.size(); }
    334                                 char cur() const { assert(! done()); return str[idx]; }
    335 
    336                                 bool expect(char ch) { return str[idx++] == ch; }
    337                                 void next(size_t inc = 1) { idx += inc; }
    338 
    339                                 /// determines if `pref` is a prefix of `str`
    340                                 bool isPrefix(const std::string & pref);
    341                                 bool extractNumber(size_t & out);
    342                                 bool extractName(std::string & out);
    343                                 bool stripMangleName(std::string & name);
    344 
    345                                 Type * parseFunction(Type::Qualifiers tq);
    346                                 Type * parseTuple(Type::Qualifiers tq);
    347                                 Type * parseVoid(Type::Qualifiers tq);
    348                                 Type * parsePointer(Type::Qualifiers tq);
    349                                 Type * parseArray(Type::Qualifiers tq);
    350                                 Type * parseStruct(Type::Qualifiers tq);
    351                                 Type * parseUnion(Type::Qualifiers tq);
    352                                 Type * parseEnum(Type::Qualifiers tq);
    353                                 Type * parseType(Type::Qualifiers tq);
    354 
    355                                 Type * parseType();
    356                                 bool parse(std::string & name, Type *& type);
    357                         };
    358 
    359                         StringView::StringView(const std::string & str) : str(str) {
    360                                 // basic types
    361                                 for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
    362                                         parsers.emplace_back(Encoding::basicTypes[k], [k](Type::Qualifiers tq) {
    363                                                 PRINT( std::cerr << "basic type: " << k << std::endl; )
    364                                                 return new BasicType(tq, (BasicType::Kind)k);
    365                                         });
    366                                 }
    367                                 // type variable types
    368                                 for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) {
    369                                         static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
    370                                         static_assert(
    371                                                 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS,
    372                                                 "Each type variable kind should have a demangle name prefix"
    373                                         );
    374                                         parsers.emplace_back(Encoding::typeVariables[k], [k, this](Type::Qualifiers tq) -> TypeInstType * {
    375                                                 PRINT( std::cerr << "type variable type: " << k << std::endl; )
    376                                                 size_t N;
    377                                                 if (! extractNumber(N)) return nullptr;
    378                                                 return new TypeInstType(tq, toString(typeVariableNames[k], N), (TypeDecl::Kind)k != TypeDecl::Ftype);
    379                                         });
    380                                 }
    381                                 // everything else
    382                                 parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); });
    383                                 parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); });
    384                                 parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); });
    385                                 parsers.emplace_back(Encoding::array, [this](Type::Qualifiers tq) { return parseArray(tq); });
    386                                 parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); });
    387                                 parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); });
    388                                 parsers.emplace_back(Encoding::union_t, [this](Type::Qualifiers tq) { return parseUnion(tq); });
    389                                 parsers.emplace_back(Encoding::enum_t, [this](Type::Qualifiers tq) { return parseEnum(tq); });
    390                                 parsers.emplace_back(Encoding::type, [this](Type::Qualifiers tq) { return parseType(tq); });
    391                                 parsers.emplace_back(Encoding::zero, [](Type::Qualifiers tq) { return new ZeroType(tq); });
    392                                 parsers.emplace_back(Encoding::one, [](Type::Qualifiers tq) { return new OneType(tq); });
    393                         }
    394 
    395                         bool StringView::extractNumber(size_t & out) {
    396                                 std::stringstream numss;
    397                                 if (idx >= str.size()) return false;
    398                                 while (isdigit(str[idx])) {
    399                                         numss << str[idx];
    400                                         ++idx;
    401                                         if (idx == str.size()) break;
    402                                 }
    403                                 if (! (numss >> out)) return false;
    404                                 PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
    405                                 return true;
    406                         }
    407 
    408                         bool StringView::extractName(std::string & out) {
    409                                 size_t len;
    410                                 if (! extractNumber(len)) return false;
    411                                 if (idx+len > str.size()) return false;
    412                                 out = str.substr(idx, len);
    413                                 idx += len;
    414                                 PRINT( std::cerr << "extractName success: " << out << std::endl; )
    415                                 return true;
    416                         }
    417 
    418                         bool StringView::isPrefix(const std::string & pref) {
    419                                 // if ( pref.size() > str.size()-idx ) return false;
    420                                 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
    421                                 // if (its.first == pref.end()) {
    422                                 //      idx += pref.size();
    423                                 //      return true;
    424                                 // }
    425 
    426                                 // This update is untested because there are no tests for this code.
    427                                 if ( ::isPrefix( str, pref, idx ) ) {
    428                                         idx += pref.size();
    429                                         return true;
    430                                 }
    431                                 return false;
    432                         }
    433 
    434                         // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
    435                         bool StringView::stripMangleName(std::string & name) {
    436                                 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
    437                                 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
    438                                 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;
    439 
    440                                 // get name
    441                                 if (! extractName(name)) return false;
    442 
    443                                 // find bounds for type
    444                                 PRINT( std::cerr << idx << " " << str.size() << std::endl; )
    445                                 PRINT( std::cerr << "[");
    446                                 while (isdigit(str.back())) {
    447                                         PRINT(std::cerr << ".");
    448                                         str.pop_back();
    449                                         if (str.size() <= idx) return false;
    450                                 }
    451                                 PRINT( std::cerr << "]" << std::endl );
    452                                 if (str.back() != '_') return false;
    453                                 str.pop_back();
    454                                 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; )
    455                                 return str.size() > idx;
    456                         }
    457 
    458                         Type * StringView::parseFunction(Type::Qualifiers tq) {
    459                                 PRINT( std::cerr << "function..." << std::endl; )
    460                                 if (done()) return nullptr;
    461                                 FunctionType * ftype = new FunctionType( tq, false );
    462                                 std::unique_ptr<Type> manager(ftype);
    463                                 Type * retVal = parseType();
    464                                 if (! retVal) return nullptr;
    465                                 PRINT( std::cerr << "with return type: " << retVal << std::endl; )
    466                                 ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr));
    467                                 if (done() || ! expect('_')) return nullptr;
    468                                 while (! done()) {
    469                                         PRINT( std::cerr << "got ch: " << cur() << std::endl; )
    470                                         if (cur() == '_') return manager.release();
    471                                         Type * param = parseType();
    472                                         if (! param) return nullptr;
    473                                         PRINT( std::cerr << "with parameter : " << param << std::endl; )
    474                                         ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr));
    475                                 }
    476                                 return nullptr;
    477                         }
    478 
    479                         Type * StringView::parseTuple(Type::Qualifiers tq) {
    480                                 PRINT( std::cerr << "tuple..." << std::endl; )
    481                                 std::list< Type * > types;
    482                                 size_t ncomponents;
    483                                 if (! extractNumber(ncomponents)) return nullptr;
    484                                 for (size_t i = 0; i < ncomponents; ++i) {
    485                                         // TODO: delete all on return
    486                                         if (done()) return nullptr;
    487                                         PRINT( std::cerr << "got ch: " << cur() << std::endl; )
    488                                         Type * t = parseType();
    489                                         if (! t) return nullptr;
    490                                         PRINT( std::cerr << "with type : " << t << std::endl; )
    491                                         types.push_back(t);
    492                                 }
    493                                 return new TupleType( tq, types );
    494                         }
    495 
    496                         Type * StringView::parseVoid(Type::Qualifiers tq) {
    497                                 return new VoidType( tq );
    498                         }
    499 
    500                         Type * StringView::parsePointer(Type::Qualifiers tq) {
    501                                 PRINT( std::cerr << "pointer..." << std::endl; )
    502                                 Type * t = parseType();
    503                                 if (! t) return nullptr;
    504                                 return new PointerType( tq, t );
    505                         }
    506 
    507                         Type * StringView::parseArray(Type::Qualifiers tq) {
    508                                 PRINT( std::cerr << "array..." << std::endl; )
    509                                 size_t length;
    510                                 if (! extractNumber(length)) return nullptr;
    511                                 Type * t = parseType();
    512                                 if (! t) return nullptr;
    513                                 return new ArrayType( tq, t, new ConstantExpr( Constant::from_ulong(length) ), false, false );
    514                         }
    515 
    516                         Type * StringView::parseStruct(Type::Qualifiers tq) {
    517                                 PRINT( std::cerr << "struct..." << std::endl; )
    518                                 std::string name;
    519                                 if (! extractName(name)) return nullptr;
    520                                 return new StructInstType(tq, name);
    521                         }
    522 
    523                         Type * StringView::parseUnion(Type::Qualifiers tq) {
    524                                 PRINT( std::cerr << "union..." << std::endl; )
    525                                 std::string name;
    526                                 if (! extractName(name)) return nullptr;
    527                                 return new UnionInstType(tq, name);
    528                         }
    529 
    530                         Type * StringView::parseEnum(Type::Qualifiers tq) {
    531                                 PRINT( std::cerr << "enum..." << std::endl; )
    532                                 std::string name;
    533                                 if (! extractName(name)) return nullptr;
    534                                 return new EnumInstType(tq, name);
    535                         }
    536 
    537                         Type * StringView::parseType(Type::Qualifiers tq) {
    538                                 PRINT( std::cerr << "type..." << std::endl; )
    539                                 std::string name;
    540                                 if (! extractName(name)) return nullptr;
    541                                 PRINT( std::cerr << "typename..." << name << std::endl; )
    542                                 return new TypeInstType(tq, name, false);
    543                         }
    544 
    545                         Type * StringView::parseType() {
    546                                 if (done()) return nullptr;
    547 
    548                                 std::list<TypeDecl *> forall;
    549                                 if (isPrefix(Encoding::forall)) {
    550                                         PRINT( std::cerr << "polymorphic with..." << std::endl; )
    551                                         size_t dcount, fcount, vcount, acount;
    552                                         if (! extractNumber(dcount)) return nullptr;
    553                                         PRINT( std::cerr << dcount << " dtypes" << std::endl; )
    554                                         if (! expect('_')) return nullptr;
    555                                         if (! extractNumber(fcount)) return nullptr;
    556                                         PRINT( std::cerr << fcount << " ftypes" << std::endl; )
    557                                         if (! expect('_')) return nullptr;
    558                                         if (! extractNumber(vcount)) return nullptr;
    559                                         PRINT( std::cerr << vcount << " ttypes" << std::endl; )
    560                                         if (! expect('_')) return nullptr;
    561                                         if (! extractNumber(acount)) return nullptr;
    562                                         PRINT( std::cerr << acount << " assertions" << std::endl; )
    563                                         if (! expect('_')) return nullptr;
    564                                         for (size_t i = 0; i < acount; ++i) {
    565                                                 // TODO: need to recursively parse assertions, but for now just return nullptr so that
    566                                                 // demangler does not crash if there are assertions
    567                                                 return nullptr;
    568                                         }
    569                                         if (! expect('_')) return nullptr;
    570                                 }
    571 
    572                                 // qualifiers
    573                                 Type::Qualifiers tq;
    574                                 while (true) {
    575                                         auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
    576                                                 return isPrefix(val.second);
    577                                         });
    578                                         if (qual == Encoding::qualifiers.end()) break;
    579                                         tq |= qual->first;
    580                                 }
    581 
    582                                 // find the correct type parser and use it
    583                                 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) {
    584                                         return isPrefix(p.first);
    585                                 });
    586                                 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx);
    587                                 Type * ret = iter->second(tq);
    588                                 if (! ret) return nullptr;
    589                                 ret->forall = std::move(forall);
    590                                 return ret;
    591                         }
    592 
    593                         bool StringView::parse(std::string & name, Type *& type) {
    594                                 if (! stripMangleName(name)) return false;
    595                                 PRINT( std::cerr << "stripped name: " << name << std::endl; )
    596                                 Type * t = parseType();
    597                                 if (! t) return false;
    598                                 type = t;
    599                                 return true;
    600                         }
    601 
    602                         std::string demangle(const std::string & mangleName) {
    603                                 SymTab::Mangler::StringView view(mangleName);
    604                                 std::string name;
    605                                 Type * type = nullptr;
    606                                 if (! view.parse(name, type)) return mangleName;
    607                                 std::unique_ptr<Type> manager(type);
    608                                 return genDemangleType(type, name);
    609                         }
    610                 } // namespace
    611         } // namespace Mangler
    612 } // namespace SymTab
     273                if ( !expect('_') ) return nullptr;
     274        }
     275
     276        ast::CV::Qualifiers tq;
     277        while (true) {
     278                auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
     279                        return isPrefix(val.second);
     280                });
     281                if (qual == Encoding::qualifiers.end()) break;
     282                tq |= qual->first;
     283        }
     284
     285        // Find the correct type parser and then apply it.
     286        auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) {
     287                return isPrefix(p.first);
     288        });
     289        assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index);
     290        ast::Type * ret = iter->second(tq);
     291        if ( !ret ) return nullptr;
     292        return ret;
     293}
     294
     295bool Demangler::parse( std::string & name, ast::Type *& type) {
     296        if ( !stripMangleName(name) ) return false;
     297        PRINT( std::cerr << "stripped name: " << name << std::endl; )
     298        ast::Type * t = parseType();
     299        if ( !t ) return false;
     300        type = t;
     301        return true;
     302}
     303
     304std::string demangle( const std::string & mangleName ) {
     305        using namespace CodeGen;
     306        Demangler demangler( mangleName );
     307        std::string name;
     308        ast::Type * type = nullptr;
     309        if ( !demangler.parse( name, type ) ) return mangleName;
     310        ast::readonly<ast::Type> roType = type;
     311        if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName;
     312        return genType( type, name, Options( false, false, false, false ) );
     313}
     314
     315} // namespace
     316
     317} // namespace Mangle
    613318
    614319extern "C" {
    615320        char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) {
    616                 const std::string & demangleName = SymTab::Mangler::demangle(mangleName);
     321                const std::string & demangleName = Mangle::demangle(mangleName);
    617322                return strdup(demangleName.c_str());
    618323        }
  • src/SymTab/Demangle.h

    r0030b508 rfc12f05  
    1010// Created On       : Fri May 13 10:11:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri May 13 10:30:00 2022
    13 // Update Count     : 0
     12// Last Modified On : Mon Nov  6 15:48:00 2023
     13// Update Count     : 1
    1414//
    1515
     
    1717
    1818extern "C" {
     19        /// Main interface to the demangler as a utility.
     20        /// Caller must free the returned string.
    1921        char * cforall_demangle(const char *, int);
    2022}
  • src/SymTab/FixFunction.cc

    r0030b508 rfc12f05  
    2222#include "AST/Type.hpp"
    2323#include "Common/utility.h"       // for copy
    24 #include "SynTree/Declaration.h"  // for FunctionDecl, ObjectDecl, Declarati...
    25 #include "SynTree/Expression.h"   // for Expression
    26 #include "SynTree/Type.h"         // for ArrayType, PointerType, Type, Basic...
    2724
    2825namespace SymTab {
    29         class FixFunction_old : public WithShortCircuiting {
    30                 typedef Mutator Parent;
    31           public:
    32                 FixFunction_old() : isVoid( false ) {}
    33 
    34                 void premutate(FunctionDecl *functionDecl);
    35                 DeclarationWithType* postmutate(FunctionDecl *functionDecl);
    36 
    37                 Type * postmutate(ArrayType * arrayType);
    38 
    39                 void premutate(ArrayType * arrayType);
    40                 void premutate(VoidType * voidType);
    41                 void premutate(BasicType * basicType);
    42                 void premutate(PointerType * pointerType);
    43                 void premutate(StructInstType * aggregateUseType);
    44                 void premutate(UnionInstType * aggregateUseType);
    45                 void premutate(EnumInstType * aggregateUseType);
    46                 void premutate(TraitInstType * aggregateUseType);
    47                 void premutate(TypeInstType * aggregateUseType);
    48                 void premutate(TupleType * tupleType);
    49                 void premutate(VarArgsType * varArgsType);
    50                 void premutate(ZeroType * zeroType);
    51                 void premutate(OneType * oneType);
    52 
    53                 bool isVoid;
    54         };
    55 
    56         DeclarationWithType * FixFunction_old::postmutate(FunctionDecl *functionDecl) {
    57                 // can't delete function type because it may contain assertions, so transfer ownership to new object
    58                 ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes );
    59                 pointer->location = functionDecl->location;
    60                 functionDecl->attributes.clear();
    61                 functionDecl->type = nullptr;
    62                 delete functionDecl;
    63                 return pointer;
    64         }
    65 
    66         // xxx - this passes on void[], e.g.
    67         //   void foo(void [10]);
    68         // does not cause an error
    69 
    70         Type * FixFunction_old::postmutate(ArrayType *arrayType) {
    71                 // need to recursively mutate the base type in order for multi-dimensional arrays to work.
    72                 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic );
    73                 pointerType->location = arrayType->location;
    74                 arrayType->base = nullptr;
    75                 arrayType->dimension = nullptr;
    76                 delete arrayType;
    77                 return pointerType;
    78         }
    79 
    80         void FixFunction_old::premutate(VoidType *) {
    81                 isVoid = true;
    82         }
    83 
    84         void FixFunction_old::premutate(FunctionDecl *) { visit_children = false; }
    85         void FixFunction_old::premutate(ArrayType *) { visit_children = false; }
    86         void FixFunction_old::premutate(BasicType *) { visit_children = false; }
    87         void FixFunction_old::premutate(PointerType *) { visit_children = false; }
    88         void FixFunction_old::premutate(StructInstType *) { visit_children = false; }
    89         void FixFunction_old::premutate(UnionInstType *) { visit_children = false; }
    90         void FixFunction_old::premutate(EnumInstType *) { visit_children = false; }
    91         void FixFunction_old::premutate(TraitInstType *) { visit_children = false; }
    92         void FixFunction_old::premutate(TypeInstType *) { visit_children = false; }
    93         void FixFunction_old::premutate(TupleType *) { visit_children = false; }
    94         void FixFunction_old::premutate(VarArgsType *) { visit_children = false; }
    95         void FixFunction_old::premutate(ZeroType *) { visit_children = false; }
    96         void FixFunction_old::premutate(OneType *) { visit_children = false; }
    97 
    98         bool fixFunction( DeclarationWithType *& dwt ) {
    99                 PassVisitor<FixFunction_old> fixer;
    100                 dwt = dwt->acceptMutator( fixer );
    101                 return fixer.pass.isVoid;
    102         }
    10326
    10427namespace {
  • src/SymTab/FixFunction.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include "Common/PassVisitor.h" // for PassVisitor
    19 #include "SynTree/SynTree.h"    // for Types
    20 
    2118namespace ast {
    2219        class DeclWithType;
     
    2522
    2623namespace SymTab {
    27         /// Replaces function and array types by equivalent pointer types. Returns true if type is
    28         /// void
    29         bool fixFunction( DeclarationWithType *& );
    30 
    3124        /// Returns declaration with function and array types replaced by equivalent pointer types.
    3225        /// Sets isVoid to true if type is void
  • src/SymTab/Mangler.cc

    r0030b508 rfc12f05  
    2222#include <string>                        // for string, char_traits, operator<<
    2323
     24#include "AST/Pass.hpp"
    2425#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
    25 #include "Common/PassVisitor.h"
    2626#include "Common/ToString.hpp"           // for toCString
    2727#include "Common/SemanticError.h"        // for SemanticError
    28 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    29 #include "SynTree/LinkageSpec.h"         // for Spec, isOverridable, AutoGen, Int...
    30 #include "SynTree/Declaration.h"         // for TypeDecl, DeclarationWithType
    31 #include "SynTree/Expression.h"          // for TypeExpr, Expression, operator<<
    32 #include "SynTree/Type.h"                // for Type, ReferenceToType, Type::Fora...
    33 
    34 #include "AST/Pass.hpp"
    35 
    36 namespace SymTab {
    37         namespace Mangler {
    38                 namespace {
    39                         /// Mangles names to a unique C identifier
    40                         struct Mangler_old : public WithShortCircuiting, public WithVisitorRef<Mangler_old>, public WithGuards {
    41                                 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
    42                                 Mangler_old( const Mangler_old & ) = delete;
    43 
    44                                 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    45 
    46                                 void postvisit( const ObjectDecl * declaration );
    47                                 void postvisit( const FunctionDecl * declaration );
    48                                 void postvisit( const TypeDecl * declaration );
    49 
    50                                 void postvisit( const VoidType * voidType );
    51                                 void postvisit( const BasicType * basicType );
    52                                 void postvisit( const PointerType * pointerType );
    53                                 void postvisit( const ArrayType * arrayType );
    54                                 void postvisit( const ReferenceType * refType );
    55                                 void postvisit( const FunctionType * functionType );
    56                                 void postvisit( const StructInstType * aggregateUseType );
    57                                 void postvisit( const UnionInstType * aggregateUseType );
    58                                 void postvisit( const EnumInstType * aggregateUseType );
    59                                 void postvisit( const TypeInstType * aggregateUseType );
    60                                 void postvisit( const TraitInstType * inst );
    61                                 void postvisit( const TupleType * tupleType );
    62                                 void postvisit( const VarArgsType * varArgsType );
    63                                 void postvisit( const ZeroType * zeroType );
    64                                 void postvisit( const OneType * oneType );
    65                                 void postvisit( const QualifiedType * qualType );
    66 
    67                                 std::string get_mangleName() { return mangleName; }
    68                           private:
    69                                 std::string mangleName;         ///< Mangled name being constructed
    70                                 typedef std::map< std::string, std::pair< int, int > > VarMapType;
    71                                 VarMapType varNums;             ///< Map of type variables to indices
    72                                 int nextVarNum;                 ///< Next type variable index
    73                                 bool isTopLevel;                ///< Is the Mangler at the top level
    74                                 bool mangleOverridable;         ///< Specially mangle overridable built-in methods
    75                                 bool typeMode;                  ///< Produce a unique mangled name for a type
    76                                 bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
    77                                 bool inFunctionType = false;    ///< Include type qualifiers if false.
    78                                 bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
    79 
    80                           public:
    81                                 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    82                                         int nextVarNum, const VarMapType& varNums );
    83 
    84                           private:
    85                                 void mangleDecl( const DeclarationWithType * declaration );
    86                                 void mangleRef( const ReferenceToType * refType, std::string prefix );
    87 
    88                                 void printQualifiers( const Type *type );
    89                         }; // Mangler_old
    90                 } // namespace
    91 
    92                 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
    93                         PassVisitor<Mangler_old> mangler( mangleOverridable, typeMode, mangleGenericParams );
    94                         maybeAccept( decl, mangler );
    95                         return mangler.pass.get_mangleName();
    96                 }
    97 
    98                 std::string mangleType( const Type * ty ) {
    99                         PassVisitor<Mangler_old> mangler( false, true, true );
    100                         maybeAccept( ty, mangler );
    101                         return mangler.pass.get_mangleName();
    102                 }
    103 
    104                 std::string mangleConcrete( const Type * ty ) {
    105                         PassVisitor<Mangler_old> mangler( false, false, false );
    106                         maybeAccept( ty, mangler );
    107                         return mangler.pass.get_mangleName();
    108                 }
    109 
    110                 namespace {
    111                         Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
    112                                 : nextVarNum( 0 ), isTopLevel( true ),
    113                                 mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    114                                 mangleGenericParams( mangleGenericParams ) {}
    115 
    116                         Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    117                                 int nextVarNum, const VarMapType& varNums )
    118                                 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
    119                                 mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    120                                 mangleGenericParams( mangleGenericParams ) {}
    121 
    122                         void Mangler_old::mangleDecl( const DeclarationWithType * declaration ) {
    123                                 bool wasTopLevel = isTopLevel;
    124                                 if ( isTopLevel ) {
    125                                         varNums.clear();
    126                                         nextVarNum = 0;
    127                                         isTopLevel = false;
    128                                 } // if
    129                                 mangleName += Encoding::manglePrefix;
    130                                 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
    131                                 if ( opInfo ) {
    132                                         mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
    133                                 } else {
    134                                         mangleName += std::to_string( declaration->name.size() ) + declaration->name;
    135                                 } // if
    136                                 maybeAccept( declaration->get_type(), *visitor );
    137                                 if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
    138                                         // want to be able to override autogenerated and intrinsic routines,
    139                                         // so they need a different name mangling
    140                                         if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
    141                                                 mangleName += Encoding::autogen;
    142                                         } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
    143                                                 mangleName += Encoding::intrinsic;
    144                                         } else {
    145                                                 // if we add another kind of overridable function, this has to change
    146                                                 assert( false && "unknown overrideable linkage" );
    147                                         } // if
    148                                 }
    149                                 isTopLevel = wasTopLevel;
    150                         }
    151 
    152                         void Mangler_old::postvisit( const ObjectDecl * declaration ) {
    153                                 mangleDecl( declaration );
    154                         }
    155 
    156                         void Mangler_old::postvisit( const FunctionDecl * declaration ) {
    157                                 mangleDecl( declaration );
    158                         }
    159 
    160                         void Mangler_old::postvisit( const VoidType * voidType ) {
    161                                 printQualifiers( voidType );
    162                                 mangleName += Encoding::void_t;
    163                         }
    164 
    165                         void Mangler_old::postvisit( const BasicType * basicType ) {
    166                                 printQualifiers( basicType );
    167                                 assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    168                                 mangleName += Encoding::basicTypes[ basicType->kind ];
    169                         }
    170 
    171                         void Mangler_old::postvisit( const PointerType * pointerType ) {
    172                                 printQualifiers( pointerType );
    173                                 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
    174                                 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer;
    175                                 maybeAccept( pointerType->base, *visitor );
    176                         }
    177 
    178                         void Mangler_old::postvisit( const ArrayType * arrayType ) {
    179                                 // TODO: encode dimension
    180                                 printQualifiers( arrayType );
    181                                 mangleName += Encoding::array + "0";
    182                                 maybeAccept( arrayType->base, *visitor );
    183                         }
    184 
    185                         void Mangler_old::postvisit( const ReferenceType * refType ) {
    186                                 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
    187                                 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
    188                                 // by pretending every reference type is a function parameter.
    189                                 GuardValue( inFunctionType );
    190                                 inFunctionType = true;
    191                                 printQualifiers( refType );
    192                                 maybeAccept( refType->base, *visitor );
    193                         }
    194 
    195                         namespace {
    196                                 inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {
    197                                         std::list< Type* > ret;
    198                                         std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
    199                                                                         std::mem_fun( &DeclarationWithType::get_type ) );
    200                                         return ret;
    201                                 }
    202                         }
    203 
    204                         void Mangler_old::postvisit( const FunctionType * functionType ) {
    205                                 printQualifiers( functionType );
    206                                 mangleName += Encoding::function;
    207                                 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    208                                 // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
    209                                 // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different
    210                                 GuardValue( inFunctionType );
    211                                 inFunctionType = true;
    212                                 std::list< Type* > returnTypes = getTypes( functionType->returnVals );
    213                                 if (returnTypes.empty()) mangleName += Encoding::void_t;
    214                                 else acceptAll( returnTypes, *visitor );
    215                                 mangleName += "_";
    216                                 std::list< Type* > paramTypes = getTypes( functionType->parameters );
    217                                 acceptAll( paramTypes, *visitor );
    218                                 mangleName += "_";
    219                         }
    220 
    221                         void Mangler_old::mangleRef( const ReferenceToType * refType, std::string prefix ) {
    222                                 printQualifiers( refType );
    223 
    224                                 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
    225 
    226                                 if ( mangleGenericParams ) {
    227                                         const std::list< Expression* > & params = refType->parameters;
    228                                         if ( ! params.empty() ) {
    229                                                 mangleName += "_";
    230                                                 for ( const Expression * param : params ) {
    231                                                         const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param );
    232                                                         assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    233                                                         maybeAccept( paramType->type, *visitor );
    234                                                 }
    235                                                 mangleName += "_";
    236                                         }
    237                                 }
    238                         }
    239 
    240                         void Mangler_old::postvisit( const StructInstType * aggregateUseType ) {
    241                                 mangleRef( aggregateUseType, Encoding::struct_t );
    242                         }
    243 
    244                         void Mangler_old::postvisit( const UnionInstType * aggregateUseType ) {
    245                                 mangleRef( aggregateUseType, Encoding::union_t );
    246                         }
    247 
    248                         void Mangler_old::postvisit( const EnumInstType * aggregateUseType ) {
    249                                 mangleRef( aggregateUseType, Encoding::enum_t );
    250                         }
    251 
    252                         void Mangler_old::postvisit( const TypeInstType * typeInst ) {
    253                                 VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
    254                                 if ( varNum == varNums.end() ) {
    255                                         mangleRef( typeInst, Encoding::type );
    256                                 } else {
    257                                         printQualifiers( typeInst );
    258                                         // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
    259                                         //   forall(dtype T) void f(T);
    260                                         //   forall(dtype S) void f(S);
    261                                         // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
    262                                         // are first found and prefixing with the appropriate encoding for the type class.
    263                                         assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    264                                         mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    265                                 } // if
    266                         }
    267 
    268                         void Mangler_old::postvisit( const TraitInstType * inst ) {
    269                                 printQualifiers( inst );
    270                                 mangleName += std::to_string( inst->name.size() ) + inst->name;
    271                         }
    272 
    273                         void Mangler_old::postvisit( const TupleType * tupleType ) {
    274                                 printQualifiers( tupleType );
    275                                 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
    276                                 acceptAll( tupleType->types, *visitor );
    277                         }
    278 
    279                         void Mangler_old::postvisit( const VarArgsType * varArgsType ) {
    280                                 printQualifiers( varArgsType );
    281                                 static const std::string vargs = "__builtin_va_list";
    282                                 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
    283                         }
    284 
    285                         void Mangler_old::postvisit( const ZeroType * ) {
    286                                 mangleName += Encoding::zero;
    287                         }
    288 
    289                         void Mangler_old::postvisit( const OneType * ) {
    290                                 mangleName += Encoding::one;
    291                         }
    292 
    293                         void Mangler_old::postvisit( const QualifiedType * qualType ) {
    294                                 bool inqual = inQualifiedType;
    295                                 if (! inqual ) {
    296                                         // N marks the start of a qualified type
    297                                         inQualifiedType = true;
    298                                         mangleName += Encoding::qualifiedTypeStart;
    299                                 }
    300                                 maybeAccept( qualType->parent, *visitor );
    301                                 maybeAccept( qualType->child, *visitor );
    302                                 if ( ! inqual ) {
    303                                         // E marks the end of a qualified type
    304                                         inQualifiedType = false;
    305                                         mangleName += Encoding::qualifiedTypeEnd;
    306                                 }
    307                         }
    308 
    309                         void Mangler_old::postvisit( const TypeDecl * decl ) {
    310                                 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
    311                                 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
    312                                 // Note: The current scheme may already work correctly for this case, I have not thought about this deeply
    313                                 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed
    314                                 // aside from the assert false.
    315                                 assertf( false, "Mangler_old should not visit typedecl: %s", toCString(decl));
    316                                 assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    317                                 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
    318                         }
    319 
    320                         __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
    321                                 for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
    322                                         os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
    323                                 } // for
    324                         }
    325 
    326                         void Mangler_old::printQualifiers( const Type * type ) {
    327                                 // skip if not including qualifiers
    328                                 if ( typeMode ) return;
    329                                 if ( ! type->forall.empty() ) {
    330                                         std::list< std::string > assertionNames;
    331                                         int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    332                                         mangleName += Encoding::forall;
    333                                         for ( const TypeDecl * i : type->forall ) {
    334                                                 switch ( i->kind ) {
    335                                                   case TypeDecl::Dtype:
    336                                                         dcount++;
    337                                                         break;
    338                                                   case TypeDecl::Ftype:
    339                                                         fcount++;
    340                                                         break;
    341                                                   case TypeDecl::Ttype:
    342                                                         vcount++;
    343                                                         break;
    344                                                   default:
    345                                                         assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[i->kind].c_str() );
    346                                                 } // switch
    347                                                 varNums[ i->name ] = std::make_pair( nextVarNum, (int)i->kind );
    348                                                 for ( const DeclarationWithType * assert : i->assertions ) {
    349                                                         PassVisitor<Mangler_old> sub_mangler(
    350                                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    351                                                         assert->accept( sub_mangler );
    352                                                         assertionNames.push_back( sub_mangler.pass.get_mangleName() );
    353                                                         acount++;
    354                                                 } // for
    355                                         } // for
    356                                         mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
    357                                         for(const auto & a : assertionNames) mangleName += a;
    358 //                                      std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    359                                         mangleName += "_";
    360                                 } // if
    361                                 if ( ! inFunctionType ) {
    362                                         // these qualifiers do not distinguish the outermost type of a function parameter
    363                                         if ( type->get_const() ) {
    364                                                 mangleName += Encoding::qualifiers.at(Type::Const);
    365                                         } // if
    366                                         if ( type->get_volatile() ) {
    367                                                 mangleName += Encoding::qualifiers.at(Type::Volatile);
    368                                         } // if
    369                                         // Removed due to restrict not affecting function compatibility in GCC
    370                                         // if ( type->get_isRestrict() ) {
    371                                         //      mangleName += "E";
    372                                         // } // if
    373                                         if ( type->get_atomic() ) {
    374                                                 mangleName += Encoding::qualifiers.at(Type::Atomic);
    375                                         } // if
    376                                 }
    377                                 if ( type->get_mutex() ) {
    378                                         mangleName += Encoding::qualifiers.at(Type::Mutex);
    379                                 } // if
    380                                 if ( inFunctionType ) {
    381                                         // turn off inFunctionType so that types can be differentiated for nested qualifiers
    382                                         GuardValue( inFunctionType );
    383                                         inFunctionType = false;
    384                                 }
    385                         }
    386                 } // namespace
    387         } // namespace Mangler
    388 } // namespace SymTab
    38928
    39029namespace Mangle {
     
    476115                                mangleName += std::to_string( decl->name.size() ) + decl->name;
    477116                        } // if
    478                         maybeAccept( decl->get_type(), *visitor );
     117                        decl->get_type()->accept( *visitor );
    479118                        if ( mangleOverridable && decl->linkage.is_overrideable ) {
    480119                                // want to be able to override autogenerated and intrinsic routines,
     
    522161                        printQualifiers( arrayType );
    523162                        mangleName += Encoding::array + "0";
    524                         maybeAccept( arrayType->base.get(), *visitor );
     163                        arrayType->base->accept( *visitor );
    525164                }
    526165
     
    532171                        inFunctionType = true;
    533172                        printQualifiers( refType );
    534                         maybeAccept( refType->base.get(), *visitor );
     173                        refType->base->accept( *visitor );
    535174                }
    536175
     
    561200                                        auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
    562201                                        assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    563                                         maybeAccept( paramType->type.get(), *visitor );
     202                                        paramType->type->accept( *visitor );
    564203                                }
    565204                                mangleName += "_";
     
    590229                                // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
    591230                                // are first found and prefixing with the appropriate encoding for the type class.
    592                                 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
     231                                assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    593232                                mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    594233                        } // if
     
    622261                void Mangler_new::postvisit( const ast::QualifiedType * qualType ) {
    623262                        bool inqual = inQualifiedType;
    624                         if (! inqual ) {
     263                        if ( !inqual ) {
    625264                                // N marks the start of a qualified type
    626265                                inQualifiedType = true;
    627266                                mangleName += Encoding::qualifiedTypeStart;
    628267                        }
    629                         maybeAccept( qualType->parent.get(), *visitor );
    630                         maybeAccept( qualType->child.get(), *visitor );
    631                         if ( ! inqual ) {
     268                        qualType->parent->accept( *visitor );
     269                        qualType->child->accept( *visitor );
     270                        if ( !inqual ) {
    632271                                // E marks the end of a qualified type
    633272                                inQualifiedType = false;
     
    691330                                // these qualifiers do not distinguish the outermost type of a function parameter
    692331                                if ( type->is_const() ) {
    693                                         mangleName += Encoding::qualifiers.at(Type::Const);
     332                                        mangleName += Encoding::qualifiers.at( ast::CV::Const );
    694333                                } // if
    695334                                if ( type->is_volatile() ) {
    696                                         mangleName += Encoding::qualifiers.at(Type::Volatile);
     335                                        mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
    697336                                } // if
    698337                                // Removed due to restrict not affecting function compatibility in GCC
     
    701340                                // } // if
    702341                                if ( type->is_atomic() ) {
    703                                         mangleName += Encoding::qualifiers.at(Type::Atomic);
     342                                        mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
    704343                                } // if
    705344                        }
    706345                        if ( type->is_mutex() ) {
    707                                 mangleName += Encoding::qualifiers.at(Type::Mutex);
     346                                mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
    708347                        } // if
    709348                        if ( inFunctionType ) {
  • src/SymTab/Mangler.h

    r0030b508 rfc12f05  
    2222
    2323#include "AST/Bitfield.hpp"
    24 #include "SynTree/SynTree.h"  // for Types
    25 #include "SynTree/Visitor.h"  // for Visitor, maybeAccept
    2624
    2725// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
     
    3533        class Node;
    3634}
    37 namespace ResolvExpr {
    38         class TypeEnvironment;
    39 }
    4035
    4136namespace SymTab {
    4237        namespace Mangler {
    43                 /// Mangle syntax tree object; primary interface to clients
    44                 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );
    45 
    46                 /// Mangle a type name; secondary interface
    47                 std::string mangleType( const Type * ty );
    48                 /// Mangle ignoring generic type parameters
    49                 std::string mangleConcrete( const Type * ty );
    50 
    5138                namespace Encoding {
    5239                        extern const std::string manglePrefix;
  • src/SymTab/ManglerCommon.cc

    r0030b508 rfc12f05  
    1515
    1616#include "Mangler.h"
    17 #include "SynTree/Type.h"
    18 #include "SynTree/Declaration.h"
     17
     18#include "AST/Decl.hpp"
     19#include "AST/Type.hpp"
    1920
    2021namespace SymTab {
     
    3940                        //   - "Di" char32_t
    4041                        //   - "Ds" char16_t
    41                         const std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {
     42                        const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {
    4243                                "b",        // _Bool
    4344                                "c",        // char
     
    7980                        // GENERATED END
    8081                        static_assert(
    81                                 sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
     82                                sizeof(basicTypes)/sizeof(basicTypes[0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES,
    8283                                "Each basic type kind should have a corresponding mangler letter"
    8384                        );
    8485
    8586                        const std::map<int, std::string> qualifiers = {
    86                                 { Type::Const, "K" },
    87                                 { Type::Volatile, "V" },
    88                                 { Type::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
    89                                 { Type::Mutex, "X" },
     87                                { ast::CV::Const, "K" },
     88                                { ast::CV::Volatile, "V" },
     89                                { ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
     90                                { ast::CV::Mutex, "X" },
    9091                        };
    9192
     
    111112                        };
    112113                        static_assert(
    113                                 sizeof(typeVariables) / sizeof(typeVariables[0]) == TypeDecl::NUMBER_OF_KINDS,
     114                                sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
    114115                                "Each type variable kind should have a corresponding mangler prefix"
    115116                        );
  • src/SymTab/demangler.cc

    r0030b508 rfc12f05  
    22#include <iostream>
    33#include <fstream>
    4 using namespace std;
    54
    6 void f(const std::string & mangleName) {
     5void demangleAndPrint(const std::string & mangleName) {
    76        char * demangleName = cforall_demangle(mangleName.c_str(), 0);
    8         cout << mangleName << " => " << std::flush << demangleName << endl;
     7        std::cout << mangleName << " => " << demangleName << std::endl;
    98        free(demangleName);
    109}
    1110
    12 int main() {
    13         ifstream in("in-demangle.txt");
     11int main(int argc, char * argv[]) {
     12        char const * fileName = (1 < argc) ? argv[1] : "in-demangle.txt";
     13        std::ifstream in(fileName);
     14
    1415        std::string line;
    15         while (getline(in, line)) {
    16                 if (line.empty()) { cout << "=================================" << endl; continue; }
    17                 else if (line[0] == '#') continue;
    18                 f(line);
     16        while (std::getline(in, line)) {
     17                if (line.empty()) {
     18                        std::cout << "=================================" << std::endl;
     19                } else if (line[0] == '#') {
     20                        continue;
     21                } else {
     22                        demangleAndPrint(line);
     23                }
    1924        }
    2025}
  • src/SymTab/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC_SYMTAB = \
    18         SymTab/Autogen.cc \
    19         SymTab/Autogen.h \
    2018        SymTab/FixFunction.cc \
    2119        SymTab/FixFunction.h \
    2220        SymTab/GenImplicitCall.cpp \
    2321        SymTab/GenImplicitCall.hpp \
    24         SymTab/Indexer.cc \
    25         SymTab/Indexer.h \
    2622        SymTab/Mangler.cc \
    2723        SymTab/ManglerCommon.cc \
    28         SymTab/Mangler.h \
    29         SymTab/ValidateType.cc \
    30         SymTab/ValidateType.h
     24        SymTab/Mangler.h
    3125
    32 SRC += $(SRC_SYMTAB) \
    33         SymTab/Validate.cc \
    34         SymTab/Validate.h
     26SRC += $(SRC_SYMTAB)
    3527
    3628SRCDEMANGLE += $(SRC_SYMTAB) \
  • src/Tuples/Explode.cc

    r0030b508 rfc12f05  
    1515
    1616#include "Explode.h"
    17 #include <list>                  // for list
    1817
    1918#include "AST/Pass.hpp"          // for Pass
    20 #include "SynTree/Mutator.h"     // for Mutator
    21 #include "Common/PassVisitor.h"  // for PassVisitor
    2219
    2320namespace Tuples {
    24         namespace {
    25                 // remove one level of reference from a reference type -- may be useful elsewhere.
    26                 Type * getReferenceBase( Type * t ) {
    27                         if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) {
    28                                 return refType->get_base();
    29                         } else {
    30                                 // for the moment, I want to know immediately if a non-reference type is ever passed in here.
    31                                 assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() );
    32                                 return nullptr;
    33                         }
    34                 }
    35 
    36                 struct CastExploder {
    37                         bool castAdded = false;
    38                         bool foundUniqueExpr = false;
    39                         Expression * applyCast( Expression * expr, bool first = true ) {
    40                                 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){
    41                                         foundUniqueExpr = true;
    42                                         std::list< Expression * > exprs;
    43                                         for ( Expression *& expr : tupleExpr->get_exprs() ) {
    44                                                 // move cast into tuple exprs
    45                                                 exprs.push_back( applyCast( expr, false ) );
    46                                         }
    47                                         // want the top-level expression to be cast to reference type, but not nested
    48                                         // tuple expressions
    49                                         if ( first ) {
    50                                                 castAdded = true;
    51                                                 Expression * tupleExpr = new TupleExpr( exprs );
    52                                                 return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );
    53                                         } else {
    54                                                 return new TupleExpr( exprs );
    55                                         }
    56                                 }
    57                                 if ( dynamic_cast<ReferenceType*>( expr->result ) ) {
    58                                         // don't need to cast reference type to another reference type
    59                                         return expr->clone();
    60                                 } else {
    61                                         // anything else should be cast to reference as normal
    62                                         castAdded = true;
    63                                         return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
    64                                 }
    65                         }
    66 
    67                         Expression * postmutate( UniqueExpr * uniqueExpr ) {
    68                                 // move cast into unique expr so that the unique expr has type T& rather than
    69                                 // type T. In particular, this transformation helps with generating the
    70                                 // correct code for reference-cast member tuple expressions, since the result
    71                                 // should now be a tuple of references rather than a reference to a tuple.
    72                                 // Still, this code is a bit awkward, and could use some improvement.
    73                                 UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() );
    74                                 delete uniqueExpr;
    75                                 if ( castAdded ) {
    76                                         // if a cast was added by applyCast, then unique expr now has one more layer of reference
    77                                         // than it had coming into this function. To ensure types still match correctly, need to cast
    78                                         //  to reference base so that outer expressions are still correct.
    79                                         castAdded = false;
    80                                         Type * toType = getReferenceBase( newUniqueExpr->result );
    81                                         return new CastExpr( newUniqueExpr, toType->clone() );
    82                                 }
    83                                 return newUniqueExpr;
    84                         }
    85 
    86 
    87                         Expression * postmutate( TupleIndexExpr * tupleExpr ) {
    88                                 // tuple index expr needs to be rebuilt to ensure that the type of the
    89                                 // field is consistent with the type of the tuple expr, since the field
    90                                 // may have changed from type T to T&.
    91                                 Expression * expr = tupleExpr->get_tuple();
    92                                 tupleExpr->set_tuple( nullptr );
    93                                 TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );
    94                                 delete tupleExpr;
    95                                 return ret;
    96                         }
    97                 };
    98         } // namespace
    99 
    100         Expression * distributeReference( Expression * expr ) {
    101                 PassVisitor<CastExploder> exploder;
    102                 expr = expr->acceptMutator( exploder );
    103                 if ( ! exploder.pass.foundUniqueExpr ) {
    104                         // if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate
    105                         expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
    106                 }
    107                 return expr;
    108         }
    10921
    11022namespace {
  • src/Tuples/Explode.h

    r0030b508 rfc12f05  
    2020
    2121#include "AST/Expr.hpp"
    22 #include "ResolvExpr/Alternative.h"     // for Alternative, AltList
    2322#include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
    24 #include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
    2523#include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
    26 #include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
    27 #include "SynTree/Type.h"               // for TupleType, Type
    2824#include "Tuples.h"                     // for maybeImpure
    2925
     
    3228}
    3329
    34 namespace SymTab {
    35 class Indexer;
    36 }  // namespace SymTab
    37 
    3830namespace Tuples {
    39         Expression * distributeReference( Expression * );
    40 
    41         static inline CastExpr * isReferenceCast( Expression * expr ) {
    42                 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    43                         if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) {
    44                                 return castExpr;
    45                         }
    46                 }
    47                 return nullptr;
    48         }
    49 
    50         /// Append alternative to an OutputIterator of Alternatives
    51         template<typename OutputIterator>
    52         void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,
    53                         const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,
    54                         const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {
    55                 *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };
    56         }
    57 
    58         /// Append alternative to an ExplodedActual
    59         static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,
    60                         const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,
    61                         const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
    62                 ea.exprs.emplace_back( expr );
    63                 /// xxx -- merge environment, openVars, need, cost?
    64         }
    65 
    66         /// helper function used by explode
    67         template< typename Output >
    68         void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt,
    69                         const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {
    70                 if ( isTupleAssign ) {
    71                         // tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components
    72                         if ( CastExpr * castExpr = isReferenceCast( expr ) ) {
    73                                 ResolvExpr::AltList alts;
    74                                 explodeUnique(
    75                                         castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
    76                                 for ( ResolvExpr::Alternative & alt : alts ) {
    77                                         // distribute reference cast over all components
    78                                         append( std::forward<Output>(out), distributeReference( alt.release_expr() ),
    79                                                 alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );
    80                                 }
    81                                 // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)
    82                                 return;
    83                         }
    84                 }
    85                 Type * res = expr->get_result()->stripReferences();
    86                 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
    87                         if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
    88                                 // can open tuple expr and dump its exploded components
    89                                 for ( Expression * expr : tupleExpr->get_exprs() ) {
    90                                         explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
    91                                 }
    92                         } else {
    93                                 // tuple type, but not tuple expr - recursively index into its components.
    94                                 // if expr type is reference, convert to value type
    95                                 Expression * arg = expr->clone();
    96                                 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    97                                         // expressions which may contain side effects require a single unique instance of the expression.
    98                                         arg = new UniqueExpr( arg );
    99                                 }
    100                                 // cast reference to value type to facilitate further explosion
    101                                 if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {
    102                                         arg = new CastExpr( arg, tupleType->clone() );
    103                                 }
    104                                 for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
    105                                         TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
    106                                         explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );
    107                                         delete idx;
    108                                 }
    109                                 delete arg;
    110                         }
    111                 } else {
    112                         // atomic (non-tuple) type - output a clone of the expression in a new alternative
    113                         append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,
    114                                 alt.cost, alt.cvtCost );
    115                 }
    116         }
    117 
    118         /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
    119         template< typename Output >
    120         void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer,
    121                         Output&& out, bool isTupleAssign = false ) {
    122                 explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
    123         }
    124 
    125         // explode list of alternatives
    126         template< typename AltIterator, typename Output >
    127         void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer,
    128                         Output&& out, bool isTupleAssign = false ) {
    129                 for ( ; altBegin != altEnd; ++altBegin ) {
    130                         explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );
    131                 }
    132         }
    133 
    134         template< typename Output >
    135         void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out,
    136                         bool isTupleAssign = false ) {
    137                 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
    138         }
    13931
    14032const ast::Expr * distributeReference( const ast::Expr * );
  • src/Tuples/TupleAssignment.cc

    r0030b508 rfc12f05  
    2828#include "AST/TypeEnvironment.hpp"
    2929#include "CodeGen/OperatorTable.h"
    30 #include "Common/PassVisitor.h"
    3130#include "Common/UniqueName.h"             // for UniqueName
    3231#include "Common/utility.h"                // for splice, zipWith
     
    3433#include "InitTweak/GenInit.h"             // for genCtorInit
    3534#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
    36 #include "ResolvExpr/Alternative.h"        // for AltList, Alternative
    37 #include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
    3835#include "ResolvExpr/Cost.h"               // for Cost
    3936#include "ResolvExpr/Resolver.h"           // for resolveCtorInit
    40 #include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
    4137#include "ResolvExpr/typeops.h"            // for combos
    42 #include "SynTree/LinkageSpec.h"           // for Cforall
    43 #include "SynTree/Declaration.h"           // for ObjectDecl
    44 #include "SynTree/Expression.h"            // for Expression, CastExpr, Name...
    45 #include "SynTree/Initializer.h"           // for ConstructorInit, SingleInit
    46 #include "SynTree/Statement.h"             // for ExprStmt
    47 #include "SynTree/Type.h"                  // for Type, Type::Qualifiers
    48 #include "SynTree/TypeSubstitution.h"      // for TypeSubstitution
    49 #include "SynTree/Visitor.h"               // for Visitor
    5038
    5139#if 0
     
    5644
    5745namespace Tuples {
    58         class TupleAssignSpotter_old {
    59           public:
    60                 // dispatcher for Tuple (multiple and mass) assignment operations
    61                 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
    62                 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
    63 
    64           private:
    65                 void match();
    66 
    67                 struct Matcher {
    68                   public:
    69                         Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    70                                 const ResolvExpr::AltList& rhs );
    71                         virtual ~Matcher() {}
    72 
    73                         virtual void match( std::list< Expression * > &out ) = 0;
    74                         ObjectDecl * newObject( UniqueName & namer, Expression * expr );
    75 
    76                         void combineState( const ResolvExpr::Alternative& alt ) {
    77                                 compositeEnv.simpleCombine( alt.env );
    78                                 ResolvExpr::mergeOpenVars( openVars, alt.openVars );
    79                                 cloneAll( alt.need, need );
    80                         }
    81 
    82                         void combineState( const ResolvExpr::AltList& alts ) {
    83                                 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }
    84                         }
    85 
    86                         ResolvExpr::AltList lhs, rhs;
    87                         TupleAssignSpotter_old &spotter;
    88                         ResolvExpr::Cost baseCost;
    89                         std::list< ObjectDecl * > tmpDecls;
    90                         ResolvExpr::TypeEnvironment compositeEnv;
    91                         ResolvExpr::OpenVarSet openVars;
    92                         ResolvExpr::AssertionSet need;
    93                 };
    94 
    95                 struct MassAssignMatcher : public Matcher {
    96                   public:
    97                         MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    98                                 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    99                         virtual void match( std::list< Expression * > &out );
    100                 };
    101 
    102                 struct MultipleAssignMatcher : public Matcher {
    103                   public:
    104                         MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    105                                 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    106                         virtual void match( std::list< Expression * > &out );
    107                 };
    108 
    109                 ResolvExpr::AlternativeFinder &currentFinder;
    110                 std::string fname;
    111                 std::unique_ptr< Matcher > matcher;
    112         };
    113 
    114         /// true if expr is an expression of tuple type
    115         bool isTuple( Expression *expr ) {
    116                 if ( ! expr ) return false;
    117                 assert( expr->result );
    118                 return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
    119         }
    120 
    121         template< typename AltIter >
    122         bool isMultAssign( AltIter begin, AltIter end ) {
    123                 // multiple assignment if more than one alternative in the range or if
    124                 // the alternative is a tuple
    125                 if ( begin == end ) return false;
    126                 if ( isTuple( begin->expr ) ) return true;
    127                 return ++begin != end;
    128         }
    129 
    130         bool refToTuple( Expression *expr ) {
    131                 assert( expr->get_result() );
    132                 // also check for function returning tuple of reference types
    133                 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    134                         return refToTuple( castExpr->get_arg() );
    135                 } else {
    136                         return isTuple( expr );
    137                 }
    138                 return false;
    139         }
    140 
    141         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
    142                                 std::vector<ResolvExpr::AlternativeFinder> &args ) {
    143                 TupleAssignSpotter_old spotter( currentFinder );
    144                 spotter.spot( expr, args );
    145         }
    146 
    147         TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
    148                 : currentFinder(f) {}
    149 
    150         void TupleAssignSpotter_old::spot( UntypedExpr * expr,
    151                         std::vector<ResolvExpr::AlternativeFinder> &args ) {
    152                 if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
    153                         if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
    154                                 fname = op->get_name();
    155 
    156                                 // AlternativeFinder will naturally handle this case case, if it's legal
    157                                 if ( args.size() == 0 ) return;
    158 
    159                                 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote
    160                                 // the function, in which case AlternativeFinder will handle it normally
    161                                 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;
    162 
    163                                 // look over all possible left-hand-sides
    164                                 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {
    165                                         // skip non-tuple LHS
    166                                         if ( ! refToTuple(lhsAlt.expr) ) continue;
    167 
    168                                         // explode is aware of casts - ensure every LHS expression is sent into explode
    169                                         // with a reference cast
    170                                         // xxx - this seems to change the alternatives before the normal
    171                                         //  AlternativeFinder flow; maybe this is desired?
    172                                         if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {
    173                                                 lhsAlt.expr = new CastExpr( lhsAlt.expr,
    174                                                                 new ReferenceType( Type::Qualifiers(),
    175                                                                         lhsAlt.expr->result->clone() ) );
    176                                         }
    177 
    178                                         // explode the LHS so that each field of a tuple-valued-expr is assigned
    179                                         ResolvExpr::AltList lhs;
    180                                         explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );
    181                                         for ( ResolvExpr::Alternative& alt : lhs ) {
    182                                                 // each LHS value must be a reference - some come in with a cast expression,
    183                                                 // if not just cast to reference here
    184                                                 if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {
    185                                                         alt.expr = new CastExpr( alt.expr,
    186                                                                 new ReferenceType( Type::Qualifiers(),
    187                                                                         alt.expr->get_result()->clone() ) );
    188                                                 }
    189                                         }
    190 
    191                                         if ( args.size() == 1 ) {
    192                                                 // mass default-initialization/destruction
    193                                                 ResolvExpr::AltList rhs{};
    194                                                 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
    195                                                 match();
    196                                         } else if ( args.size() > 2 ) {
    197                                                 // expand all possible RHS possibilities
    198                                                 // TODO build iterative version of this instead of using combos
    199                                                 std::vector< ResolvExpr::AltList > rhsAlts;
    200                                                 combos( std::next(args.begin(), 1), args.end(),
    201                                                         std::back_inserter( rhsAlts ) );
    202                                                 for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {
    203                                                         // multiple assignment
    204                                                         ResolvExpr::AltList rhs;
    205                                                         explode( rhsAlt, currentFinder.get_indexer(),
    206                                                                 std::back_inserter(rhs), true );
    207                                                         matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
    208                                                         match();
    209                                                 }
    210                                         } else {
    211                                                 for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {
    212                                                         ResolvExpr::AltList rhs;
    213                                                         if ( isTuple(rhsAlt.expr) ) {
    214                                                                 // multiple assignment
    215                                                                 explode( rhsAlt, currentFinder.get_indexer(),
    216                                                                         std::back_inserter(rhs), true );
    217                                                                 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
    218                                                         } else {
    219                                                                 // mass assignment
    220                                                                 rhs.push_back( rhsAlt );
    221                                                                 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
    222                                                         }
    223                                                         match();
    224                                                 }
    225                                         }
    226                                 }
    227                         }
    228                 }
    229         }
    230 
    231         void TupleAssignSpotter_old::match() {
    232                 assert ( matcher != 0 );
    233 
    234                 std::list< Expression * > new_assigns;
    235                 matcher->match( new_assigns );
    236 
    237                 if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
    238                         // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
    239                         // if not the empty tuple case, return early so that no new alternatives are generated.
    240                         if ( new_assigns.empty() ) return;
    241                 }
    242                 ResolvExpr::AltList current;
    243                 // now resolve new assignments
    244                 for ( std::list< Expression * >::iterator i = new_assigns.begin();
    245                                 i != new_assigns.end(); ++i ) {
    246                         PRINT(
    247                                 std::cerr << "== resolving tuple assign ==" << std::endl;
    248                                 std::cerr << *i << std::endl;
    249                         )
    250 
    251                         ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),
    252                                 matcher->compositeEnv };
    253 
    254                         try {
    255                                 finder.findWithAdjustment(*i);
    256                         } catch (...) {
    257                                 return; // no match should not mean failure, it just means this particular tuple assignment isn't valid
    258                         }
    259                         // prune expressions that don't coincide with
    260                         ResolvExpr::AltList alts = finder.get_alternatives();
    261                         assert( alts.size() == 1 );
    262                         assert( alts.front().expr != 0 );
    263                         current.push_back( alts.front() );
    264                 }
    265 
    266                 // extract expressions from the assignment alternatives to produce a list of assignments
    267                 // that together form a single alternative
    268                 std::list< Expression *> solved_assigns;
    269                 for ( ResolvExpr::Alternative & alt : current ) {
    270                         solved_assigns.push_back( alt.expr->clone() );
    271                         matcher->combineState( alt );
    272                 }
    273 
    274                 // xxx -- was push_front
    275                 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{
    276                         new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,
    277                         matcher->openVars,
    278                         ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),
    279                         ResolvExpr::sumCost( current ) + matcher->baseCost } );
    280         }
    281 
    282         TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
    283                 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
    284         : lhs(lhs), rhs(rhs), spotter(spotter),
    285           baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
    286                 combineState( lhs );
    287                 combineState( rhs );
    288         }
    289 
    290         UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
    291                 assert( left );
    292                 std::list< Expression * > args;
    293                 args.push_back( new VariableExpr( left ) );
    294                 // args.push_back( new AddressExpr( new VariableExpr( left ) ) );
    295                 if ( right ) args.push_back( new VariableExpr( right ) );
    296                 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
    297                         args.front() = new AddressExpr( args.front() );
    298                         if ( right ) args.back() = new AddressExpr( args.back() );
    299                         return new UntypedExpr( new NameExpr( "?=?" ), args );
    300                 } else {
    301                         return new UntypedExpr( new NameExpr( fname ), args );
    302                 }
    303         }
    304 
    305         // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv
    306         // xxx - maybe this should happen in alternative finder for every StmtExpr?
    307         struct EnvRemover {
    308                 void previsit( ExprStmt * stmt ) {
    309                         assert( compositeEnv );
    310                         if ( stmt->expr->env ) {
    311                                 compositeEnv->add( *stmt->expr->env );
    312                                 delete stmt->expr->env;
    313                                 stmt->expr->env = nullptr;
    314                         }
    315                 }
    316 
    317                 ResolvExpr::TypeEnvironment * compositeEnv = nullptr;
    318         };
    319 
    320         ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    321                 assert( expr->result && ! expr->get_result()->isVoid() );
    322                 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
    323                 // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
    324                 if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {
    325                         ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
    326                         ret->init = ctorInit;
    327                         ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
    328                         PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs
    329                         rm.pass.compositeEnv = &compositeEnv;
    330                         ctorInit->accept( rm );
    331                 }
    332                 PRINT( std::cerr << "new object: " << ret << std::endl; )
    333                 return ret;
    334         }
    335 
    336         void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
    337                 static UniqueName lhsNamer( "__massassign_L" );
    338                 static UniqueName rhsNamer( "__massassign_R" );
    339                 // empty tuple case falls into this matcher, hence the second part of the assert
    340                 assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
    341 
    342                 // xxx - may need to split this up into multiple declarations, because potential conversion to references
    343                 //  probably should not reference local variable - see MultipleAssignMatcher::match
    344                 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    345                 for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
    346                         // create a temporary object for each value in the lhs and create a call involving the rhs
    347                         ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
    348                         out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
    349                         tmpDecls.push_back( ltmp );
    350                 }
    351                 if ( rtmp ) tmpDecls.push_back( rtmp );
    352         }
    353 
    354         void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
    355                 static UniqueName lhsNamer( "__multassign_L" );
    356                 static UniqueName rhsNamer( "__multassign_R" );
    357 
    358                 if ( lhs.size() == rhs.size() ) {
    359                         // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
    360                         std::list< ObjectDecl * > ltmp;
    361                         std::list< ObjectDecl * > rtmp;
    362                         for ( auto p : group_iterate( lhs, rhs ) ) {
    363                                 ResolvExpr::Alternative & lhsAlt = std::get<0>(p);
    364                                 ResolvExpr::Alternative & rhsAlt = std::get<1>(p);
    365                                 // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.
    366                                 ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );
    367                                 rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );
    368                                 ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );
    369                                 ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );
    370                                 out.push_back( createFunc(spotter.fname, lobj, robj) );
    371                                 ltmp.push_back( lobj );
    372                                 rtmp.push_back( robj );
    373 
    374                                 // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment
    375                                 ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };
    376                                 finder.findWithAdjustment( rhsAlt.expr );
    377                                 assert( finder.get_alternatives().size() == 1 );
    378                                 compositeEnv = std::move( finder.get_alternatives().front().env );
    379                         }
    380                         tmpDecls.splice( tmpDecls.end(), ltmp );
    381                         tmpDecls.splice( tmpDecls.end(), rtmp );
    382                 }
    383         }
    38446
    38547namespace {
  • src/Tuples/TupleExpansion.cc

    r0030b508 rfc12f05  
    2323#include "AST/Node.hpp"
    2424#include "AST/Type.hpp"
    25 #include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
    2625#include "Common/ScopedMap.h"     // for ScopedMap
    2726#include "Common/utility.h"       // for CodeLocation
    2827#include "InitTweak/InitTweak.h"  // for getFunction
    29 #include "SynTree/LinkageSpec.h"  // for Spec, C, Intrinsic
    30 #include "SynTree/Constant.h"     // for Constant
    31 #include "SynTree/Declaration.h"  // for StructDecl, DeclarationWithType
    32 #include "SynTree/Expression.h"   // for UntypedMemberExpr, Expression, Uniq...
    33 #include "SynTree/Label.h"        // for operator==, Label
    34 #include "SynTree/Mutator.h"      // for Mutator
    35 #include "SynTree/Type.h"         // for Type, Type::Qualifiers, TupleType
    36 #include "SynTree/Visitor.h"      // for Visitor
    3728#include "Tuples.h"
    3829
    39 class CompoundStmt;
    40 class TypeSubstitution;
     30namespace Tuples {
    4131
    42 namespace Tuples {
    43         namespace {
    44                 struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> {
    45                         void premutate( UntypedMemberExpr * ) { visit_children = false; }
    46                         Expression * postmutate( UntypedMemberExpr * memberExpr );
    47                 };
    48 
    49                 struct UniqueExprExpander final : public WithDeclsToAdd {
    50                         Expression * postmutate( UniqueExpr * unqExpr );
    51 
    52                         std::map< int, Expression * > decls; // not vector, because order added may not be increasing order
    53 
    54                         ~UniqueExprExpander() {
    55                                 for ( std::pair<const int, Expression *> & p : decls ) {
    56                                         delete p.second;
    57                                 }
    58                         }
    59                 };
    60 
    61                 struct TupleAssignExpander {
    62                         Expression * postmutate( TupleAssignExpr * tupleExpr );
    63                 };
    64 
    65                 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
    66                         Type * postmutate( TupleType * tupleType );
    67 
    68                         void premutate( CompoundStmt * ) {
    69                                 GuardScope( typeMap );
    70                         }
    71                   private:
    72                         ScopedMap< int, StructDecl * > typeMap;
    73                 };
    74 
    75                 struct TupleIndexExpander {
    76                         Expression * postmutate( TupleIndexExpr * tupleExpr );
    77                 };
    78 
    79                 struct TupleExprExpander final {
    80                         Expression * postmutate( TupleExpr * tupleExpr );
    81                 };
    82         }
    83 
    84         void expandMemberTuples( std::list< Declaration * > & translationUnit ) {
    85                 PassVisitor<MemberTupleExpander> expander;
    86                 mutateAll( translationUnit, expander );
    87         }
    88 
    89         void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {
    90                 PassVisitor<UniqueExprExpander> unqExpander;
    91                 mutateAll( translationUnit, unqExpander );
    92         }
    93 
    94         void expandTuples( std::list< Declaration * > & translationUnit ) {
    95                 PassVisitor<TupleAssignExpander> assnExpander;
    96                 mutateAll( translationUnit, assnExpander );
    97 
    98                 PassVisitor<TupleTypeReplacer> replacer;
    99                 mutateAll( translationUnit, replacer );
    100 
    101                 PassVisitor<TupleIndexExpander> idxExpander;
    102                 mutateAll( translationUnit, idxExpander );
    103 
    104                 PassVisitor<TupleExprExpander> exprExpander;
    105                 mutateAll( translationUnit, exprExpander );
    106         }
    107 
    108         namespace {
    109                 /// given a expression representing the member and an expression representing the aggregate,
    110                 /// reconstructs a flattened UntypedMemberExpr with the right precedence
    111                 Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {
    112                         if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {
    113                                 // construct a new UntypedMemberExpr with the correct structure , and recursively
    114                                 // expand that member expression.
    115                                 PassVisitor<MemberTupleExpander> expander;
    116                                 UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() );
    117                                 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner );
    118                                 inner->location = newMemberExpr->location = loc;
    119                                 memberExpr->member = nullptr;
    120                                 memberExpr->aggregate = nullptr;
    121                                 delete memberExpr;
    122                                 return newMemberExpr->acceptMutator( expander );
    123                         } else {
    124                                 // not a member expression, so there is nothing to do but attach and return
    125                                 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );
    126                                 newMemberExpr->location = loc;
    127                                 return newMemberExpr;
    128                         }
    129                 }
    130         }
    131 
    132         Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) {
    133                 if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) {
    134                         Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );
    135                         // aggregate expressions which might be impure must be wrapped in unique expressions
    136                         if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );
    137                         for ( Expression *& expr : tupleExpr->exprs ) {
    138                                 expr = reconstructMemberExpr( expr, aggr, memberExpr->location );
    139                                 expr->location = memberExpr->location;
    140                         }
    141                         delete aggr;
    142                         tupleExpr->location = memberExpr->location;
    143                         return tupleExpr;
    144                 } else {
    145                         // there may be a tuple expr buried in the aggregate
    146                         // xxx - this is a memory leak
    147                         UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) );
    148                         newMemberExpr->location = memberExpr->location;
    149                         return newMemberExpr;
    150                 }
    151         }
    152 
    153         Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {
    154                 const int id = unqExpr->get_id();
    155 
    156                 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
    157                 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
    158                 if ( ! decls.count( id ) ) {
    159                         Expression * assignUnq;
    160                         Expression * var = unqExpr->get_var();
    161                         if ( unqExpr->get_object() ) {
    162                                 // an object was generated to represent this unique expression -- it should be added to the list of declarations now
    163                                 declsToAddBefore.push_back( unqExpr->get_object() );
    164                                 unqExpr->set_object( nullptr );
    165                                 // steal the expr from the unqExpr
    166                                 assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );
    167                                 unqExpr->set_expr( nullptr );
    168                         } else {
    169                                 // steal the already generated assignment to var from the unqExpr - this has been generated by FixInit
    170                                 Expression * expr = unqExpr->get_expr();
    171                                 CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr );
    172                                 assignUnq = commaExpr->get_arg1();
    173                                 commaExpr->set_arg1( nullptr );
    174                         }
    175                         ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),
    176                                                                                                         new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );
    177                         declsToAddBefore.push_back( finished );
    178                         // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
    179                         // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
    180                         Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) );
    181                         ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),
    182                                 new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );
    183                         condExpr->set_result( var->get_result()->clone() );
    184                         condExpr->set_env( maybeClone( unqExpr->get_env() ) );
    185                         decls[id] = condExpr;
    186                 }
    187                 delete unqExpr;
    188                 return decls[id]->clone();
    189         }
    190 
    191         Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {
    192                 StmtExpr * ret = assnExpr->get_stmtExpr();
    193                 assnExpr->set_stmtExpr( nullptr );
    194                 // move env to StmtExpr
    195                 ret->set_env( assnExpr->get_env() );
    196                 assnExpr->set_env( nullptr );
    197                 delete assnExpr;
    198                 return ret;
    199         }
    200 
    201         Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) {
    202                 unsigned tupleSize = tupleType->size();
    203                 if ( ! typeMap.count( tupleSize ) ) {
    204                         // generate struct type to replace tuple type based on the number of components in the tuple
    205                         StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );
    206                         decl->location = tupleType->location;
    207                         decl->set_body( true );
    208                         for ( size_t i = 0; i < tupleSize; ++i ) {
    209                                 TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );
    210                                 decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );
    211                                 decl->get_parameters().push_back( tyParam );
    212                         }
    213                         if ( tupleSize == 0 ) {
    214                                 // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.
    215                                 decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
    216                         }
    217                         typeMap[tupleSize] = decl;
    218                         declsToAddBefore.push_back( decl );
    219                 }
    220                 Type::Qualifiers qualifiers = tupleType->get_qualifiers();
    221 
    222                 StructDecl * decl = typeMap[tupleSize];
    223                 StructInstType * newType = new StructInstType( qualifiers, decl );
    224                 for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) {
    225                         Type * t = std::get<0>(p);
    226                         newType->get_parameters().push_back( new TypeExpr( t->clone() ) );
    227                 }
    228                 delete tupleType;
    229                 return newType;
    230         }
    231 
    232         Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {
    233                 Expression * tuple = tupleExpr->tuple;
    234                 assert( tuple );
    235                 tupleExpr->tuple = nullptr;
    236                 unsigned int idx = tupleExpr->index;
    237                 TypeSubstitution * env = tupleExpr->env;
    238                 tupleExpr->env = nullptr;
    239                 delete tupleExpr;
    240 
    241                 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {
    242                         if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {
    243                                 // optimization: definitely pure tuple expr => can reduce to the only relevant component.
    244                                 assert( tupleExpr->exprs.size() > idx );
    245                                 Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);
    246                                 Expression * ret = expr;
    247                                 ret->env = env;
    248                                 expr = nullptr; // remove from list so it can safely be deleted
    249                                 delete tupleExpr;
    250                                 return ret;
    251                         }
    252                 }
    253 
    254                 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );
    255                 StructDecl * structDecl = type->baseStruct;
    256                 assert( structDecl->members.size() > idx );
    257                 Declaration * member = *std::next(structDecl->members.begin(), idx);
    258                 MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );
    259                 memExpr->env = env;
    260                 return memExpr;
    261         }
    262 
    263         Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {
    264                 if ( result->isVoid() ) {
    265                         // void result - don't need to produce a value for cascading - just output a chain of comma exprs
    266                         assert( ! exprs.empty() );
    267                         std::list< Expression * >::const_iterator iter = exprs.begin();
    268                         Expression * expr = new CastExpr( *iter++ );
    269                         for ( ; iter != exprs.end(); ++iter ) {
    270                                 expr = new CommaExpr( expr, new CastExpr( *iter ) );
    271                         }
    272                         expr->set_env( env );
    273                         return expr;
    274                 } else {
    275                         // typed tuple expression - produce a compound literal which performs each of the expressions
    276                         // as a distinct part of its initializer - the produced compound literal may be used as part of
    277                         // another expression
    278                         std::list< Initializer * > inits;
    279                         for ( Expression * expr : exprs ) {
    280                                 inits.push_back( new SingleInit( expr ) );
    281                         }
    282                         Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );
    283                         expr->set_env( env );
    284                         return expr;
    285                 }
    286         }
    287 
    288         Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {
    289                 Type * result = tupleExpr->get_result();
    290                 std::list< Expression * > exprs = tupleExpr->get_exprs();
    291                 assert( result );
    292                 TypeSubstitution * env = tupleExpr->get_env();
    293 
    294                 // remove data from shell and delete it
    295                 tupleExpr->set_result( nullptr );
    296                 tupleExpr->get_exprs().clear();
    297                 tupleExpr->set_env( nullptr );
    298                 delete tupleExpr;
    299 
    300                 return replaceTupleExpr( result, exprs, env );
    301         }
    302 
    303         Type * makeTupleType( const std::list< Expression * > & exprs ) {
    304                 // produce the TupleType which aggregates the types of the exprs
    305                 std::list< Type * > types;
    306                 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );
    307                 for ( Expression * expr : exprs ) {
    308                         assert( expr->get_result() );
    309                         if ( expr->get_result()->isVoid() ) {
    310                                 // if the type of any expr is void, the type of the entire tuple is void
    311                                 return new VoidType( Type::Qualifiers() );
    312                         }
    313                         Type * type = expr->get_result()->clone();
    314                         types.push_back( type );
    315                         // the qualifiers on the tuple type are the qualifiers that exist on all component types
    316                         qualifiers &= type->get_qualifiers();
    317                 } // for
    318                 if ( exprs.empty() ) qualifiers = Type::Qualifiers();
    319                 return new TupleType( qualifiers, types );
    320         }
    32132        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
    32233                // produce the TupleType which aggregates the types of the exprs
     
    34152        }
    34253
    343         TypeInstType * isTtype( Type * type ) {
    344                 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {
    345                         if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {
    346                                 return inst;
    347                         }
    348                 }
    349                 return nullptr;
    350         }
    351 
    352         const TypeInstType * isTtype( const Type * type ) {
    353                 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {
    354                         if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {
    355                                 return inst;
    356                         }
    357                 }
    358                 return nullptr;
    359         }
    360 
    36154        const ast::TypeInstType * isTtype( const ast::Type * type ) {
    36255                if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
  • src/Tuples/Tuples.cc

    r0030b508 rfc12f05  
    1919#include "AST/Inspect.hpp"
    2020#include "AST/LinkageSpec.hpp"
    21 #include "Common/PassVisitor.h"
    2221#include "InitTweak/InitTweak.h"
    2322
     
    2524
    2625namespace {
    27         /// Checks if impurity (read: side-effects) may exist in a piece of code.
    28         /// Currently gives a very crude approximation, wherein any function
    29         /// call expression means the code may be impure.
    30         struct ImpurityDetector_old : public WithShortCircuiting {
    31                 bool const ignoreUnique;
    32                 bool maybeImpure;
    33 
    34                 ImpurityDetector_old( bool ignoreUnique ) :
    35                         ignoreUnique( ignoreUnique ), maybeImpure( false )
    36                 {}
    37 
    38                 void previsit( const ApplicationExpr * appExpr ) {
    39                         visit_children = false;
    40                         if ( const DeclarationWithType * function =
    41                                         InitTweak::getFunction( appExpr ) ) {
    42                                 if ( function->linkage == LinkageSpec::Intrinsic ) {
    43                                         if ( function->name == "*?" || function->name == "?[?]" ) {
    44                                                 // intrinsic dereference, subscript are pure,
    45                                                 // but need to recursively look for impurity
    46                                                 visit_children = true;
    47                                                 return;
    48                                         }
    49                                 }
    50                         }
    51                         maybeImpure = true;
    52                 }
    53 
    54                 void previsit( const UntypedExpr * ) {
    55                         maybeImpure = true;
    56                         visit_children = false;
    57                 }
    58 
    59                 void previsit( const UniqueExpr * ) {
    60                         if ( ignoreUnique ) {
    61                                 // bottom out at unique expression.
    62                                 // The existence of a unique expression doesn't change the purity of an expression.
    63                                 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
    64                                 visit_children = false;
    65                                 return;
    66                         }
    67                 }
    68         };
    69 
    70         bool detectImpurity( const Expression * expr, bool ignoreUnique ) {
    71                 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );
    72                 expr->accept( detector );
    73                 return detector.pass.maybeImpure;
    74         }
    7526
    7627        /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
     
    11061}
    11162
    112 bool maybeImpure( const Expression * expr ) {
    113         return detectImpurity( expr, false );
    114 }
    115 
    116 bool maybeImpureIgnoreUnique( const Expression * expr ) {
    117         return detectImpurity( expr, true );
    118 }
    119 
    12063} // namespace Tuples
    12164
  • src/Tuples/Tuples.h

    r0030b508 rfc12f05  
    2121#include "AST/Fwd.hpp"
    2222#include "AST/Node.hpp"
    23 #include "SynTree/Expression.h"
    24 #include "SynTree/Declaration.h"
    25 #include "SynTree/Type.h"
    26 
    27 #include "ResolvExpr/AlternativeFinder.h"
    2823#include "ResolvExpr/CandidateFinder.hpp"
    2924
    3025namespace Tuples {
    3126        // TupleAssignment.cc
    32         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
    33                 std::vector< ResolvExpr::AlternativeFinder >& args );
    3427        void handleTupleAssignment(
    3528                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     
    3831        // TupleExpansion.cc
    3932        /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
    40         void expandMemberTuples( std::list< Declaration * > & translationUnit );
    4133        void expandMemberTuples( ast::TranslationUnit & translationUnit );
    4234
    4335        /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
    44         void expandTuples( std::list< Declaration * > & translationUnit );
    4536        void expandTuples( ast::TranslationUnit & translaionUnit );
    4637
    4738        /// replaces UniqueExprs with a temporary variable and one call
    48         void expandUniqueExpr( std::list< Declaration * > & translationUnit );
    4939        void expandUniqueExpr( ast::TranslationUnit & translationUnit );
    5040
    5141        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
    52         Type * makeTupleType( const std::list< Expression * > & exprs );
    5342        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    5443
    5544        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
    56         TypeInstType * isTtype( Type * type );
    57         const TypeInstType * isTtype( const Type * type );
    5845        const ast::TypeInstType * isTtype( const ast::Type * type );
    5946
    6047        /// returns true if the expression may contain side-effects.
    61         bool maybeImpure( const Expression * expr );
    6248        bool maybeImpure( const ast::Expr * expr );
    6349
    6450        /// Returns true if the expression may contain side-effect,
    6551        /// ignoring the presence of unique expressions.
    66         bool maybeImpureIgnoreUnique( const Expression * expr );
    6752        bool maybeImpureIgnoreUnique( const ast::Expr * expr );
    6853} // namespace Tuples
  • src/Validate/FindSpecialDecls.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>  // for list
    19 
    20 class Declaration;
    21 class FunctionDecl;
    22 class StructDecl;
    23 class Type;
    24 
    2518namespace ast {
    2619        class TranslationUnit;
     
    2821
    2922namespace Validate {
    30         /// size_t type - set when size_t typedef is seen. Useful in a few places,
    31         /// such as in determining array dimension type
    32         extern Type * SizeType;
    33 
    34         /// intrinsic dereference operator for unqualified types - set when *? function is seen in FindSpecialDeclarations.
    35         /// Useful for creating dereference ApplicationExprs without a full resolver pass.
    36         extern FunctionDecl * dereferenceOperator;
    37 
    38         /// special built-in functions and data structures necessary for destructor generation
    39         extern StructDecl * dtorStruct;
    40         extern FunctionDecl * dtorStructDestroy;
    41 
    42         /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times.
    43         void findSpecialDecls( std::list< Declaration * > & translationUnit );
    4423
    4524/// Find and remember some of the special declarations that are useful for
  • src/Validate/FixReturnTypes.cpp

    r0030b508 rfc12f05  
    1919#include "AST/Pass.hpp"
    2020#include "AST/Type.hpp"
    21 #include "CodeGen/CodeGenerator.h"
     21#include "CodeGen/CodeGeneratorNew.hpp"
    2222#include "ResolvExpr/Unify.h"
    2323
  • src/Validate/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC_VALIDATE = \
    18         Validate/FindSpecialDecls.cc \
    1918        Validate/FindSpecialDecls.h
    2019
     
    3736        Validate/GenericParameter.cpp \
    3837        Validate/GenericParameter.hpp \
    39         Validate/HandleAttributes.cc \
    40         Validate/HandleAttributes.h \
    4138        Validate/HoistStruct.cpp \
    4239        Validate/HoistStruct.hpp \
  • src/Virtual/ExpandCasts.cc

    r0030b508 rfc12f05  
    2424#include "AST/Expr.hpp"
    2525#include "AST/Pass.hpp"
    26 #include "Common/PassVisitor.h"    // for PassVisitor
    2726#include "Common/ScopedMap.h"      // for ScopedMap
    2827#include "Common/SemanticError.h"  // for SemanticError
    2928#include "SymTab/Mangler.h"        // for mangleType
    30 #include "SynTree/Declaration.h"   // for ObjectDecl, StructDecl, FunctionDecl
    31 #include "SynTree/Expression.h"    // for VirtualCastExpr, CastExpr, Address...
    32 #include "SynTree/Mutator.h"       // for mutateAll
    33 #include "SynTree/Type.h"          // for Type, PointerType, StructInstType
    34 #include "SynTree/Visitor.h"       // for acceptAll
    3529
    3630namespace Virtual {
     
    4337}
    4438
    45 bool is_type_id_object( const ObjectDecl * objectDecl ) {
    46         const std::string & objectName = objectDecl->name;
    47         return is_prefix( "__cfatid_", objectName );
    48 }
    49 
    5039bool is_type_id_object( const ast::ObjectDecl * decl ) {
    5140        return is_prefix( "__cfatid_", decl->name );
     
    5544
    5645        /// Maps virtual table types the instance for that type.
    57         class VirtualTableMap final {
    58                 ScopedMap<std::string, ObjectDecl *> vtable_instances;
    59         public:
    60                 void enterScope() {
    61                         vtable_instances.beginScope();
    62                 }
    63                 void leaveScope() {
    64                         vtable_instances.endScope();
    65                 }
    66 
    67                 ObjectDecl * insert( ObjectDecl * vtableDecl ) {
    68                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
    69                         ObjectDecl *& value = vtable_instances[ mangledName ];
    70                         if ( value ) {
    71                                 if ( vtableDecl->storageClasses.is_extern ) {
    72                                         return nullptr;
    73                                 } else if ( ! value->storageClasses.is_extern ) {
    74                                         return value;
    75                                 }
    76                         }
    77                         value = vtableDecl;
    78                         return nullptr;
    79                 }
    80 
    81                 ObjectDecl * lookup( const Type * vtableType ) {
    82                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
    83                         const auto it = vtable_instances.find( mangledName );
    84                         return ( vtable_instances.end() == it ) ? nullptr : it->second;
    85                 }
    86         };
    87 
    88         class VirtualCastCore {
    89                 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
    90                         Type * type = new StructInstType(
    91                                 Type::Qualifiers( Type::Const ), pvt_decl );
    92                         for (int i = 0 ; i < level_of_indirection ; ++i) {
    93                                 type = new PointerType( noQualifiers, type );
    94                         }
    95                         return new CastExpr( expr, type );
    96                 }
    97 
    98         public:
    99                 VirtualCastCore() :
    100                         indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
    101                 {}
    102 
    103                 void premutate( FunctionDecl * functionDecl );
    104                 void premutate( StructDecl * structDecl );
    105                 void premutate( ObjectDecl * objectDecl );
    106 
    107                 Expression * postmutate( VirtualCastExpr * castExpr );
    108 
    109                 VirtualTableMap indexer;
    110         private:
    111                 FunctionDecl *vcast_decl;
    112                 StructDecl *pvt_decl;
    113         };
    114 
    115         void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
    116                 if ( (! vcast_decl) &&
    117                      functionDecl->get_name() == "__cfavir_virtual_cast" ) {
    118                         vcast_decl = functionDecl;
    119                 }
    120         }
    121 
    122         void VirtualCastCore::premutate( StructDecl * structDecl ) {
    123                 if ( pvt_decl || ! structDecl->has_body() ) {
    124                         return;
    125                 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {
    126                         pvt_decl = structDecl;
    127                 }
    128         }
    129 
    130         void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    131                 if ( is_type_id_object( objectDecl ) ) {
    132                         // Multiple definitions should be fine because of linkonce.
    133                         indexer.insert( objectDecl );
    134                 }
    135         }
    136 
    137         /// Better error locations for generated casts.
    138         CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
    139                 if ( castExpr->location.isSet() ) {
    140                         return castExpr->location;
    141                 } else if ( castExpr->arg->location.isSet() ) {
    142                         return castExpr->arg->location;
    143                 } else if ( castExpr->result->location.isSet() ) {
    144                         return castExpr->result->location;
    145                 } else {
    146                         return CodeLocation();
    147                 }
    148         }
    149 
    150         [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
    151                 SemanticError( castLocation( castExpr ), message );
    152         }
    153 
    154         /// Get the base type from a pointer or reference.
    155         const Type * getBaseType( const Type * type ) {
    156                 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
    157                         return target->base;
    158                 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
    159                         return target->base;
    160                 } else {
    161                         return nullptr;
    162                 }
    163         }
    164 
    165         /* Attempt to follow the "head" field of the structure to get the...
    166          * Returns nullptr on error, otherwise owner must free returned node.
    167          */
    168         StructInstType * followHeadPointerType(
    169                         const StructInstType * oldType,
    170                         const std::string& fieldName,
    171                         const CodeLocation& errorLocation ) {
    172 
    173                 // First section of the function is all about trying to fill this variable in.
    174                 StructInstType * newType = nullptr;
    175                 {
    176                         const StructDecl * oldDecl = oldType->baseStruct;
    177                         assert( oldDecl );
    178 
    179                         // Helper function for throwing semantic errors.
    180                         auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
    181                                 const std::string& context = "While following head pointer of " +
    182                                         oldDecl->name + " named '" + fieldName + "': ";
    183                                 SemanticError( errorLocation, context + message );
    184                         };
    185 
    186                         if ( oldDecl->members.empty() ) {
    187                                 throwError( "Type has no fields." );
    188                         }
    189                         const Declaration * memberDecl = oldDecl->members.front();
    190                         assert( memberDecl );
    191                         const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
    192                         assert( fieldDecl );
    193                         if ( fieldName != fieldDecl->name ) {
    194                                 throwError( "Head field did not have expected name." );
    195                         }
    196 
    197                         const Type * fieldType = fieldDecl->type;
    198                         if ( nullptr == fieldType ) {
    199                                 throwError( "Could not get head field." );
    200                         }
    201                         const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
    202                         if ( nullptr == ptrType ) {
    203                                 throwError( "First field is not a pointer type." );
    204                         }
    205                         assert( ptrType->base );
    206                         newType = dynamic_cast<StructInstType *>( ptrType->base );
    207                         if ( nullptr == newType ) {
    208                                 throwError( "First field does not point to a structure type." );
    209                         }
    210                 }
    211 
    212                 // Now we can look into copying it.
    213                 newType = newType->clone();
    214                 if ( ! oldType->parameters.empty() ) {
    215                         deleteAll( newType->parameters );
    216                         newType->parameters.clear();
    217                         cloneAll( oldType->parameters, newType->parameters );
    218                 }
    219                 return newType;
    220         }
    221 
    222         /// Get the type-id type from a virtual type.
    223         StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
    224                 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
    225                 if ( nullptr == typeInst ) {
    226                         return nullptr;
    227                 }
    228                 StructInstType * tableInst =
    229                         followHeadPointerType( typeInst, "virtual_table", errorLocation );
    230                 if ( nullptr == tableInst ) {
    231                         return nullptr;
    232                 }
    233                 StructInstType * typeIdInst =
    234                         followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
    235                 delete tableInst;
    236                 return typeIdInst;
    237         }
    238 
    239         Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
    240                 assertf( castExpr->result, "Virtual Cast target not found before expansion." );
    241 
    242                 assert( vcast_decl );
    243                 assert( pvt_decl );
    244 
    245                 const Type * base_type = getBaseType( castExpr->result );
    246                 if ( nullptr == base_type ) {
    247                         castError( castExpr, "Virtual cast target must be a pointer or reference type." );
    248                 }
    249                 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
    250                 if ( nullptr == type_id_type ) {
    251                         castError( castExpr, "Ill formed virtual cast target type." );
    252                 }
    253                 ObjectDecl * type_id = indexer.lookup( type_id_type );
    254                 delete type_id_type;
    255                 if ( nullptr == type_id ) {
    256                         castError( castExpr, "Virtual cast does not target a virtual type." );
    257                 }
    258 
    259                 Expression * result = new CastExpr(
    260                         new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    261                                 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
    262                                 cast_to_type_id( castExpr->get_arg(), 2 ),
    263                         } ),
    264                         castExpr->get_result()->clone()
    265                 );
    266 
    267                 castExpr->set_arg( nullptr );
    268                 castExpr->set_result( nullptr );
    269                 delete castExpr;
    270                 return result;
    271         }
    27246
    27347/// Better error locations for generated casts.
     
    494268} // namespace
    495269
    496 void expandCasts( std::list< Declaration * > & translationUnit ) {
    497         PassVisitor<VirtualCastCore> translator;
    498         mutateAll( translationUnit, translator );
    499 }
    500 
    501270void expandCasts( ast::TranslationUnit & translationUnit ) {
    502271        ast::Pass<ExpandCastsCore>::run( translationUnit );
  • src/Virtual/Tables.cc

    r0030b508 rfc12f05  
    2121#include "AST/Stmt.hpp"
    2222#include "AST/Type.hpp"
    23 #include <SynTree/Attribute.h>
    24 #include <SynTree/Declaration.h>
    25 #include <SynTree/Expression.h>
    26 #include <SynTree/Statement.h>
    27 #include <SynTree/Type.h>
    2823
    2924namespace Virtual {
     
    6560        return 17 < name.size() && '_' == name[0] &&
    6661                std::string("_vtable_instance") == name.substr(1, name.size() - 17);
    67 }
    68 
    69 static ObjectDecl * makeVtableDeclaration(
    70                 std::string const & name,
    71                 StructInstType * type, Initializer * init ) {
    72         Type::StorageClasses storage = noStorageClasses;
    73         if ( nullptr == init ) {
    74                 storage.is_extern = true;
    75         }
    76         return new ObjectDecl(
    77                 name,
    78                 storage,
    79                 LinkageSpec::Cforall,
    80                 nullptr,
    81                 type,
    82                 init
    83         );
    8462}
    8563
     
    10179}
    10280
    103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
    104         assert( type );
    105         return makeVtableDeclaration( name, type, nullptr );
    106 }
    107 
    10881ast::ObjectDecl * makeVtableForward(
    10982                CodeLocation const & location, std::string const & name,
     
    11184        assert( vtableType );
    11285        return makeVtableDeclaration( location, name, vtableType, nullptr );
    113 }
    114 
    115 ObjectDecl * makeVtableInstance(
    116                 std::string const & name, StructInstType * vtableType,
    117                 Type * objectType, Initializer * init ) {
    118         assert( vtableType );
    119         assert( objectType );
    120         StructDecl * vtableStruct = vtableType->baseStruct;
    121         // Build the initialization
    122         if ( nullptr == init ) {
    123                 std::list< Initializer * > inits;
    124 
    125                 // This is going to have to be run before the resolver to connect expressions.
    126                 for ( auto field : vtableStruct->members ) {
    127                         if ( std::string( "parent" ) == field->name ) {
    128                                 // This will not work with polymorphic state.
    129                                 auto oField = strict_dynamic_cast< ObjectDecl * >( field );
    130                                 auto fieldType = strict_dynamic_cast< PointerType * >( oField->type );
    131                                 auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base );
    132                                 std::string const & parentInstance = instanceName( parentType->name );
    133                                 inits.push_back(
    134                                                 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
    135                         } else if ( std::string( "__cfavir_typeid" ) == field->name ) {
    136                                 std::string const & baseType = baseTypeName( vtableType->name );
    137                                 std::string const & typeId = typeIdName( baseType );
    138                                 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
    139                         } else if ( std::string( "size" ) == field->name ) {
    140                                 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
    141                         } else if ( std::string( "align" ) == field->name ) {
    142                                 inits.push_back( new SingleInit( new AlignofExpr( objectType->clone() ) ) );
    143                         } else {
    144                                 inits.push_back( new SingleInit( new NameExpr( field->name ) ) );
    145                         }
    146                 }
    147                 init = new ListInit( inits );
    148         // This should initialize everything except the parent pointer, the
    149         // size-of and align-of fields. These should be inserted.
    150         } else {
    151                 assert(false);
    152         }
    153         return makeVtableDeclaration( name, vtableType, init );
    15486}
    15587
     
    224156}
    225157
    226 FunctionDecl * makeGetExceptionForward(
    227                 Type * vtableType, Type * exceptType ) {
    228         assert( vtableType );
    229         assert( exceptType );
    230         FunctionType * type = new FunctionType( noQualifiers, false );
    231         vtableType->tq.is_const = true;
    232         type->returnVals.push_back( new ObjectDecl(
    233                 "_retvalue",
    234                 noStorageClasses,
    235                 LinkageSpec::Cforall,
    236                 nullptr,
    237                 new ReferenceType( noQualifiers, vtableType ),
    238                 nullptr,
    239                 { new Attribute("unused") }
    240         ) );
    241         type->parameters.push_back( new ObjectDecl(
    242                 "__unused",
    243                 noStorageClasses,
    244                 LinkageSpec::Cforall,
    245                 nullptr,
    246                 new PointerType( noQualifiers, exceptType ),
    247                 nullptr,
    248                 { new Attribute("unused") }
    249         ) );
    250         return new FunctionDecl(
    251                 functionName,
    252                 noStorageClasses,
    253                 LinkageSpec::Cforall,
    254                 type,
    255                 nullptr
    256         );
    257 }
    258 
    259158ast::FunctionDecl * makeGetExceptionForward(
    260159                CodeLocation const & location,
     
    284183}
    285184
    286 FunctionDecl * makeGetExceptionFunction(
    287                 ObjectDecl * vtableInstance, Type * exceptType ) {
    288         assert( vtableInstance );
    289         assert( exceptType );
    290         FunctionDecl * func = makeGetExceptionForward(
    291                 vtableInstance->type->clone(), exceptType );
    292         func->statements = new CompoundStmt( {
    293                 new ReturnStmt( new VariableExpr( vtableInstance ) ),
    294         } );
    295         return func;
    296 }
    297 
    298185ast::FunctionDecl * makeGetExceptionFunction(
    299186                CodeLocation const & location,
     
    307194        } );
    308195        return func;
    309 }
    310 
    311 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
    312         assert( typeIdType );
    313         StructInstType * type = typeIdType->clone();
    314         type->tq.is_const = true;
    315         std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
    316         return new ObjectDecl(
    317                 typeid_name,
    318                 noStorageClasses,
    319                 LinkageSpec::Cforall,
    320                 /* bitfieldWidth */ nullptr,
    321                 type,
    322                 new ListInit( { new SingleInit(
    323                         new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
    324                         ) } ),
    325                 { new Attribute( "cfa_linkonce", {} ) },
    326                 noFuncSpecifiers
    327         );
    328196}
    329197
  • src/Virtual/Tables.h

    r0030b508 rfc12f05  
    1818#include <string>
    1919#include "AST/Fwd.hpp"
    20 class Declaration;
    21 class Expression;
    22 class FunctionDecl;
    23 class Initializer;
    24 class ObjectDecl;
    25 class StructDecl;
    26 class StructInstType;
    27 class Type;
    2820
    2921namespace Virtual {
     
    3729bool isVTableInstanceName( std::string const & name );
    3830
    39 ObjectDecl * makeVtableForward(
    40         std::string const & name, StructInstType * vtableType );
    4131/* Create a forward declaration of a vtable of the given type.
    4232 * vtableType node is consumed.
     
    4636        ast::StructInstType const * vtableType );
    4737
    48 ObjectDecl * makeVtableInstance(
    49         std::string const & name,
    50         StructInstType * vtableType, Type * objectType,
    51         Initializer * init = nullptr );
    5238/* Create an initialized definition of a vtable.
    5339 * vtableType and init (if provided) nodes are consumed.
     
    6147
    6248// Some special code for how exceptions interact with virtual tables.
    63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType );
     49
    6450/* Create a forward declaration of the exception virtual function
    6551 * linking the vtableType to the exceptType. Both nodes are consumed.
     
    7056        ast::Type const * exceptType );
    7157
    72 FunctionDecl * makeGetExceptionFunction(
    73         ObjectDecl * vtableInstance, Type * exceptType );
    7458/* Create the definition of the exception virtual function.
    7559 * exceptType node is consumed.
     
    7963        ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType );
    8064
    81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
    8265/* Build an instance of the type-id from the type of the type-id.
    8366 * TODO: Should take the parent type. Currently locked to the exception_t.
  • src/main.cc

    r0030b508 rfc12f05  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Sep 28 22:28:45 2023
    13 // Update Count     : 687
     12// Last Modified On : Wed Nov  1 21:12:58 2023
     13// Update Count     : 690
    1414//
    1515
     
    2929#include <string>                           // for char_traits, operator<<
    3030
    31 #include "AST/Convert.hpp"
    3231#include "AST/Pass.hpp"                     // for pass_visitor_stats
     32#include "AST/Print.hpp"                    // for printAll
    3333#include "AST/TranslationUnit.hpp"          // for TranslationUnit
    3434#include "AST/Util.hpp"                     // for checkInvariants
     
    3939#include "CodeGen/Generate.h"               // for generate
    4040#include "CodeGen/LinkOnce.h"               // for translateLinkOnce
    41 #include "CodeTools/TrackLoc.h"             // for fillLocations
    4241#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4342#include "Common/DeclStats.hpp"             // for printDeclStats
     
    6564#include "ResolvExpr/EraseWith.hpp"         // for eraseWith
    6665#include "ResolvExpr/Resolver.h"            // for resolve
    67 #include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
    68 #include "SynTree/Declaration.h"            // for Declaration
    6966#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
    7067#include "Validate/Autogen.hpp"             // for autogenerateRoutines
     
    9491        using namespace Stats::Counters;
    9592        {
    96                 static auto group = build<CounterGroup>( "Pass Visitor" );
     93                static auto group = build<CounterGroup>( "Pass Visitor Template" );
    9794                auto pass = build<CounterGroup>( name, group );
    98                 pass_visitor_stats.depth = 0;
    99                 pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass );
    100                 pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass );
    101         }
    102         {
    103                 static auto group = build<CounterGroup>( "Syntax Node" );
    104                 auto pass = build<CounterGroup>( name, group );
    105                 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass );
     95                ast::pass_visitor_stats.depth = 0;
     96                ast::pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass );
     97                ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass );
    10698        }
    10799}
     
    132124
    133125static void parse_cmdline( int argc, char * argv[] );
    134 static void dump( list< Declaration * > & translationUnit, ostream & out = cout );
    135126static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
    136127
     
    246237        FILE * input;                                                                           // use FILE rather than istream because yyin is FILE
    247238        ostream * output = & cout;
    248         list< Declaration * > translationUnit;
    249239        ast::TranslationUnit transUnit;
    250240
     
    260250
    261251        parse_cmdline( argc, argv );                                            // process command-line arguments
    262         CodeGen::FixMain::setReplaceMain( !nomainp );
    263252
    264253        if ( waiting_for_gdb ) {
     
    290279
    291280                        // Read to gcc builtins, if not generating the cfa library
    292                         FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" );
     281                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cfa").c_str(), "r" );
    293282                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
    294283                        parse( gcc_builtins, ast::Linkage::Compiler );
    295284
    296285                        // read the extra prelude in, if not generating the cfa library
    297                         FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" );
     286                        FILE * extras = fopen( (PreludeDirector + "/extras.cfa").c_str(), "r" );
    298287                        assertf( extras, "cannot open extras.cf\n" );
    299288                        parse( extras, ast::Linkage::BuiltinC );
     
    306295
    307296                                // Read to cfa builtins, if not generating the cfa library
    308                                 FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" );
     297                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cfa").c_str(), "r" );
    309298                                assertf( builtins, "cannot open builtins.cf\n" );
    310299                                parse( builtins, ast::Linkage::BuiltinCFA );
     
    319308
    320309                Stats::Time::StopBlock();
    321 
    322                 if (Stats::Counters::enabled) {
    323                         ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
    324                         ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");
    325                 }
    326310
    327311                PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
     
    409393                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
    410394                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
     395                PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp );
    411396
    412397                // Needs to happen before tuple types are expanded.
     
    427412                PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit );
    428413
    429                 translationUnit = convert( std::move( transUnit ) );
    430 
    431414                // Code has been lowered to C, now we can start generation.
    432415
    433                 DUMP( bcodegenp, translationUnit );
     416                DUMP( bcodegenp, std::move( transUnit ) );
    434417
    435418                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    437420                } // if
    438421
    439                 CodeTools::fillLocations( translationUnit );
    440                 PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
    441 
    442                 CodeGen::FixMain::fix( translationUnit, *output,
    443                                 (PreludeDirector + "/bootloader.c").c_str() );
     422                PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false );
     423                CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() );
     424
    444425                if ( output != &cout ) {
    445426                        delete output;
     
    448429                if ( errorp ) {
    449430                        cerr << "---AST at error:---" << endl;
    450                         // We check which section the errors came from without looking at
    451                         // transUnit because std::move means it could look like anything.
    452                         if ( !translationUnit.empty() ) {
    453                                 dump( translationUnit, cerr );
    454                         } else {
    455                                 dump( std::move( transUnit ), cerr );
    456                         }
     431                        dump( std::move( transUnit ), cerr );
    457432                        cerr << endl << "---End of AST, begin error message:---\n" << endl;
    458433                } // if
     
    480455        } // try
    481456
    482         deleteAll( translationUnit );
    483457        Stats::print();
    484458        return EXIT_SUCCESS;
     
    710684} // parse_cmdline
    711685
    712 static bool notPrelude( Declaration * decl ) {
    713         return ! LinkageSpec::isBuiltin( decl->get_linkage() );
    714 } // notPrelude
    715 
    716 static void dump( list< Declaration * > & translationUnit, ostream & out ) {
    717         list< Declaration * > decls;
    718 
     686static bool notPrelude( ast::ptr<ast::Decl> & decl ) {
     687        return !decl->linkage.is_builtin;
     688}
     689
     690static void dump( ast::TranslationUnit && unit, std::ostream & out ) {
     691        // May filter out all prelude declarations.
    719692        if ( genproto ) {
    720                 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude );
     693                std::list<ast::ptr<ast::Decl>> decls;
     694                std::copy_if( unit.decls.begin(), unit.decls.end(),
     695                        std::back_inserter( decls ), notPrelude );
     696                decls.swap( unit.decls );
     697        }
     698
     699        // May print as full dump or as code generation.
     700        if ( codegenp ) {
     701                CodeGen::generate( unit, out, !genproto, prettycodegenp, false, false, false );
    721702        } else {
    722                 decls = translationUnit;
    723         } // if
    724 
    725         // depending on commandline options, either generate code or dump the AST
    726         if ( codegenp ) {
    727                 CodeGen::generate( decls, out, ! genproto, prettycodegenp );
    728         } else {
    729                 printAll( decls, out );
    730         } // if
    731         deleteAll( translationUnit );
    732 } // dump
    733 
    734 static void dump( ast::TranslationUnit && transUnit, ostream & out ) {
    735         std::list< Declaration * > translationUnit = convert( std::move( transUnit ) );
    736         dump( translationUnit, out );
     703                ast::printAll( out, unit.decls );
     704        }
    737705}
    738706
  • tests/collections/.expect/string-istream-manip.txt

    r0030b508 rfc12f05  
    696913 wwwwwwww
    707014 cccc
    71 15
     7115 q
    72721 yyyyyyyyyyyyyyyyyyyy
    73732 abcxxx
     
    848413 wwwwwwww
    858514 cccc
    86 15
     8615 q
  • tests/collections/string-istream-manip.cfa

    r0030b508 rfc12f05  
    3838        void echoTillX(const char * casename) {
    3939            string s;
    40             do {
     40            // loop assumes behaviour not tested until main-case #15:
     41            // on reading nothing, the prior string value is left alone
     42            do {
     43                s = "";
    4144                forceStringHeapFreeSpaceTo(9);
    4245                sin | s;
     
    5457            string s;
    5558            do {
     59                s = "";
    5660                sin | plainjane( s );
    5761                sout | casename | s;
     
    6872            string_res s;
    6973            do {
     74                s = "";
    7075                sin | plainjane( s );
    7176                sout | casename | s;
     
    8287            string s;
    8388            do {
     89                s = "";
    8490                sin | skip("-\n");
    8591                sin | incl( ".:|# x", s );
     
    97103            string s;
    98104            do {
     105                s = "";
    99106                sin | skip("-\n");
    100107                sin | excl( "-\n", s );
     
    113120            string s;
    114121            do {
     122                s = "";
    115123                sin | getline( s );
    116124                sout | casename | s;
     
    127135            string s;
    128136            do {
     137                s = "";
    129138                sin | getline( s, '@' );
    130139                sout | casename | s;
  • tests/concurrency/actors/.expect/dynamic.txt

    r0030b508 rfc12f05  
    11starting
    22started
    3 stopping
    43Done
    54stopped
  • tests/concurrency/actors/.expect/static.txt

    r0030b508 rfc12f05  
    11starting
    22started
    3 stopping
    43Done
    54stopped
  • tests/concurrency/actors/dynamic.cfa

    r0030b508 rfc12f05  
    5858        *d_actor | *d_msg;
    5959
    60         sout | "stopping";
    61 
    6260        stop_actor_system();
    6361
  • tests/concurrency/actors/static.cfa

    r0030b508 rfc12f05  
    5555        actor | msg;
    5656
    57         sout | "stopping";
    58 
    5957        stop_actor_system();
    6058
  • tests/concurrency/cofor.cfa

    r0030b508 rfc12f05  
    11#include <cofor.hfa>
    2 
    32
    43void add_num( long * total, long val ) { __atomic_fetch_add( total, (long)val, __ATOMIC_SEQ_CST ); }
     
    87    processor p[4];
    98    long total = 0;
    10     COFOR( i, 0, 10, __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST ); );
     9    cofor( i; 10 ) {
     10        __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST );
     11    }
    1112    {
    1213        corun;      // does nothing
  • tests/concurrency/waitfor/parse.cfa

    r0030b508 rfc12f05  
    1010// Created On       : Wed Aug 30 17:53:29 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 22:52:18 2023
    13 // Update Count     : 64
     12// Last Modified On : Wed Nov  1 07:28:19 2023
     13// Update Count     : 65
    1414//
    1515
     
    258258// Local Variables: //
    259259// tab-width: 4 //
    260 // compile-command: "cfa waitfor.cfa" //
     260// compile-command: "cfa parse.cfa" //
    261261// End: //
  • tests/concurrency/waituntil/channel_close.cfa

    r0030b508 rfc12f05  
    2626        for( ;; ) {
    2727            if ( useAnd ) {
    28                 waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }
    29                 and waituntil( (in2 << B) ) { assert( B_removes == in2 ); B_removes++; removes++; }
     28                waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( A_removes == in ); A_removes++; removes++; }
     29                and waituntil( (in2 << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( B_removes == in2 ); B_removes++; removes++; }
    3030                continue;
    3131            }
    32             waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }
    33             or waituntil( (in << B) ) { assert( B_removes == in ); B_removes++; removes++; }
     32            waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( A_removes == in ); A_removes++; removes++; }
     33            or waituntil( (in << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); ( B_removes == in ); B_removes++; removes++; }
    3434        }
    3535    } catchResume ( channel_closed * e ) {} // continue to remove until would block
     
    3737    try {
    3838        for( ;; )
    39             waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }
     39            waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( A_removes == in ); A_removes++; removes++; }
    4040    } catchResume ( channel_closed * e ) {} // continue to remove until would block
    4141    catch ( channel_closed * e ) {}
    4242    try {
    4343        for( ;; )
    44             waituntil( (in << B) ) { assert( B_removes == in ); B_removes++; removes++; }
     44            waituntil( (in << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( B_removes == in ); B_removes++; removes++; }
    4545    } catchResume ( channel_closed * e ) {} // continue to remove until would block
    4646    catch ( channel_closed * e ) {}
  • tests/genericUnion.cfa

    r0030b508 rfc12f05  
    1010// Created On       : Tue Dec 25 14:42:46 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 25 14:46:33 2018
    13 // Update Count     : 2
     12// Last Modified On : Fri Oct 20 09:13:26 2023
     13// Update Count     : 15
    1414//
    1515
     16#include <fstream.hfa>
    1617#include <limits.hfa>
    1718
    18 forall(T)
     19forall( T )
    1920union ByteView {
    2021        T val;
     
    2324
    2425forall(T)
    25 void print(ByteView(T) x) {
    26         for (int i = 0; i < sizeof(int); i++) {                         // want to change to sizeof(T)
    27                 printf("%02x", x.bytes[i] & 0xff);
     26void print( ByteView(T) x ) {
     27        for ( i; sizeof(int) ) {                                                        // want to change to sizeof(T)
     28                sout | nobase( pad0( wd( 2, hex( x.bytes[i] & 0xff ) ) ) ) | nosep;
    2829        }
    2930}
    3031
    3132forall(T)
    32 void f(ByteView(T) x, T val) {
    33         print(x);
    34         printf(" ");
     33void f( ByteView(T) x, T val ) {
     34        print( x );
     35        sout | " ";
    3536        x.val = val;
    36         print(x);
    37         printf("\n");
     37        print( x );
     38        sout | nl;
    3839}
    3940
    4041int main() {
     42        sout | nlOff;
    4143        ByteView(unsigned) u = { 0 };
    4244        ByteView(int) i = { 0 };
    43         f(u, MAX);
    44         f(i, -1);
     45        f( u, MAX );
     46        f( i, -1 );
    4547}
    4648
  • tests/io/.expect/manipulatorsInput.arm64.txt

    r0030b508 rfc12f05  
    24243 abcxxx
    25254 aaaaaaaa
    26 5 aaaaaaaa
     265
    27276 aabbccbb
    28287 dddwww
    29 8 dddwww
    30 9 dddwww
     298
     309
    313110 aaaaaaaa
    323211 wwwwwwww
    33 12 wwwwwwww
    34 13 wwwwwwww
     3312
     3413
    353514 cccc
    363615
  • tests/io/.expect/manipulatorsInput.x64.txt

    r0030b508 rfc12f05  
    24243 abcxxx
    25254 aaaaaaaa
    26 5 aaaaaaaa
     265
    27276 aabbccbb
    28287 dddwww
    29 8 dddwww
    30 9 dddwww
     298
     309
    313110 aaaaaaaa
    323211 wwwwwwww
    33 12 wwwwwwww
    34 13 wwwwwwww
     3312
     3413
    353514 cccc
    363615
  • tests/io/.expect/manipulatorsInput.x86.txt

    r0030b508 rfc12f05  
    24243 abcxxx
    25254 aaaaaaaa
    26 5 aaaaaaaa
     265
    27276 aabbccbb
    28287 dddwww
    29 8 dddwww
    30 9 dddwww
     298
     309
    313110 aaaaaaaa
    323211 wwwwwwww
    33 12 wwwwwwww
    34 13 wwwwwwww
     3312
     3413
    353514 cccc
    363615
  • tests/io/.expect/manipulatorsOutput4.txt

    r0030b508 rfc12f05  
    225225-1.55051464826854e+28 -15.5051e27 -15.5051e27   -15.505e27   -15.505e27 -15.50515e27 -15.50515e27 -0015.505e27 -0015.505e27 -15.50515e27 -15.50515e27 -15.505e27   -15.505e27   -15.50515e27 -15.50515e27 -15.505e27   -15.505e27   -15.50515e27 -15.50515e27
    226226-6.51216152272788e+29 -651.216e27 -651.216e27   -651.22e27   -651.22e27 -651.21615e27 -651.21615e27 -00651.22e27 -00651.22e27 -651.21615e27 -651.21615e27 -651.22e27   -651.22e27   -651.21615e27 -651.21615e27 -651.22e27   -651.22e27   -651.21615e27 -651.21615e27
     2270 1 1 1.0 1
     2281 2 2 2.0 2
     2292 4 4 4.0 4
     2303 8 8 8.0 8
     2314 16 16 16.0 16
     2325 32 32 32.0 32
     2336 64 64 64.0 64
     2347 128 128 128.0 128
     2358 256 256 256.0 256
     2369 512 512 512.0 512
     23710 1024 1.024K 1.0K 1K
     23811 2048 2.048K 2.0K 2K
     23912 4096 4.096K 4.1K 4K
     24013 8192 8.192K 8.2K 8K
     24114 16384 16.384K 16.4K 16K
     24215 32768 32.768K 32.8K 33K
     24316 65536 65.536K 65.5K 66K
     24417 131072 131.072K 131.1K 131K
     24518 262144 262.144K 262.1K 262K
     24619 524288 524.288K 524.3K 524K
     24720 1048576 1.04858M 1.0M 1M
     24821 2097152 2.09715M 2.1M 2M
     24922 4194304 4.1943M 4.2M 4M
     25023 8388608 8.38861M 8.4M 8M
     25124 16777216 16.7772M 16.8M 17M
     25225 33554432 33.5544M 33.6M 34M
     25326 67108864 67.1089M 67.1M 67M
     25427 134217728 134.218M 134.2M 134M
     25528 268435456 268.435M 268.4M 268M
     25629 536870912 536.871M 536.9M 537M
     25730 1073741824 1.07374G 1.1G 1G
     25831 2147483648 2.14748G 2.1G 2G
  • tests/io/manipulatorsOutput4.cfa

    r0030b508 rfc12f05  
    77// Created On       : Tue Apr 13 17:55:02 2021
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Tue Apr 13 18:00:33 2021
    10 // Update Count     : 4
     9// Last Modified On : Tue Oct 17 08:37:42 2023
     10// Update Count     : 5
    1111//
    1212
     
    4242                         | left(ws(12,5, eng(w) )) | left(sign(ws(12,5, eng(w) ))) | left(wd(12,5, eng(w) )) | left(sign(wd(12,5, eng(w) ))) | left(pad0(ws(12,5, eng(w) ))) | left(pad0(sign(ws(12,5, eng(w) )))) | left(pad0(wd(12,5, eng(w) ))) | left(pad0(sign(wd(12,5, eng(w) ))));
    4343        } // for
     44
     45        for ( exp; sizeof(int) * 8 ) {
     46                size_t pow2 = 1z << exp;
     47                sout | exp | pow2 | unit(eng(pow2)) | wd(0,1, unit(eng( pow2 ))) | wd(0,0, unit(eng(pow2)));
     48        } // for
    4449} // main
    4550
Note: See TracChangeset for help on using the changeset viewer.