Changes in / [fc12f05:0030b508]


Ignore:
Files:
117 added
8 deleted
134 edited

Legend:

Unmodified
Added
Removed
  • doc/bibliography/pl.bib

    rfc12f05 r0030b508  
    41084108}
    41094109
    4110 @article{Buhr23,
     4110@article{Buhr22,
    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       = dec,
    4117     volume      = 53,
    4118     number      = 12,
    4119     pages       = {2463-2500},
    4120     note        = {\url{https://onlinelibrary.wiley.com/doi/10.1002/spe.3262},
     4116    month       = sep,
     4117    note        = {\url{https://onlinelibrary.wiley.com/doi/pdf/10.1002/spe.3262}}
    41214118}
    41224119
     
    41364133    journal     = spe,
    41374134    year        = 1983,
    4138     month       = jul,
    41394135    volume      = 13,
    41404136    number      = 7,
    41414137    pages       = {577-596},
     4138    month       = jul
    41424139}
    41434140
  • driver/as.cc

    rfc12f05 r0030b508  
    1111// Created On       : Wed Aug  1 10:49:42 2018
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Tue Oct 24 20:45:06 2023
    14 // Update Count     : 159
     13// Last Modified On : Wed Dec  8 07:56:12 2021
     14// Update Count     : 136
    1515//
    1616
     
    4545                char * dcursor;
    4646                if ( (dcursor = strstr( start, ".Ldebug_info0:" ) ) ) { // debug information ?
    47                         // fprintf( stderr, "found .Ldebug_info0:\n" );
    48 #if defined( __i386 ) || defined( __x86_64 )
     47
    4948                        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
    5749                                for ( int i = 0; i < 2; i += 1 ) {              // move N (magic) lines forward
    5850                                        cursor = strstr( cursor, "\n" ) + 1;
     
    6355                                if ( *(cursor - 2) == '0' && *(cursor - 1) == 'x' &&
    6456                                         (*cursor == 'c' || *cursor == '1' || *cursor == '2') ) { // C99/C89/C
    65                                         // fprintf( stderr, "language code C99/C89/C %c\n", *cursor );
    6657                                        // Expand file by one byte to hold 2 character Cforall language code.
    6758                                        if ( ftruncate( fd, size + 1 ) ) { perror( "ftruncate" ); exit( EXIT_FAILURE ); };
    6859                                        memmove( cursor + 2, cursor + 1, start + size - cursor - 1 ); // move remaining text 1 character right
    6960                                } else if ( *(cursor - 3) == '0' && *(cursor - 2) == 'x' && *(cursor - 1) == '1' && *cursor == 'd' ) { // C11
    70                                         // fprintf( stderr, "language code C11 %c\n", *cursor );
    7161                                } else {
    7262                                        for ( int i = 0; i < 6; i += 1 ) {      // move N (magic) lines forward
  • libcfa/prelude/Makefile.am

    rfc12f05 r0030b508  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Wed Nov  1 21:09:25 2023
    14 ## Update Count     : 221
     13## Last Modified On : Thu Jan 13 17:06:27 2022
     14## Update Count     : 215
    1515###############################################################################
    1616
     
    2121# put into lib for now
    2222cfalibdir = ${CFA_LIBDIR}
    23 cfalib_DATA = gcc-builtins.cfa builtins.cfa extras.cfa prelude.cfa bootloader.c defines.hfa
     23cfalib_DATA = gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c defines.hfa
    2424
    25 EXTRA_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
     25EXTRA_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
    2626
    2727CC = @LOCAL_CFACC@
     
    3636
    3737# create extra forward types/declarations to reduce inclusion of library files
    38 extras.cfa : ${srcdir}/extras.regx ${srcdir}/extras.c
     38extras.cf : ${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.cfa : gcc-builtins.c ${srcdir}/prototypes.sed
     44gcc-builtins.cf : 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.cfa ${srcdir}/prototypes.c
     48gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cf ${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.cfa : builtins.c @LOCAL_CFACC@
     61builtins.cf : 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.cfa/g' $(DEPDIR)/builtins.Po
     63        ${AM_V_at}sed -i 's/builtins.o/builtins.cf/g' $(DEPDIR)/builtins.Po
    6464
    6565include $(DEPDIR)/builtins.Po
    6666
    67 bootloader.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
     67bootloader.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
    6969
    7070maintainer-clean-local :
    7171        rm -rf $(DEPDIR)
    7272
    73 MOSTLYCLEANFILES = bootloader.c builtins.cfa extras.cfa gcc-builtins.c gcc-builtins.cfa prelude.cfa
     73MOSTLYCLEANFILES = bootloader.c builtins.cf extras.cf gcc-builtins.c gcc-builtins.cf 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.cfa builtins.cfa extras.cfa prelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh
     78distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ defines.hfa gcc-builtins.cf builtins.cf extras.cf 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

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

    rfc12f05 r0030b508  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Wed Nov  1 19:03:42 2023
    14 ## Update Count     : 266
     13## Last Modified On : Mon Sep 18 17:06:56 2023
     14## Update Count     : 264
    1515###############################################################################
    1616
     
    195195if ENABLE_DISTCC
    196196
    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
     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
    198198        @+make -C ../prelude distribution
    199199
     
    202202endif ENABLE_DISTCC
    203203
    204 prelude.o : prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @LOCAL_CFACC@ @CFACPP@
     204prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
    205205        ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@}
    206206
    207 prelude.lo: prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @LOCAL_CFACC@ @CFACPP@
     207prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @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

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

    rfc12f05 r0030b508  
    1010// Created On       : Fri Sep 03 11:00:00 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Oct 18 21:54:54 2023
    13 // Update Count     : 15
     12// Last Modified On : Mon Aug 14 18:06:01 2023
     13// Update Count     : 12
    1414//
    1515
     
    236236        // get bytes
    237237        try {
    238                         *(temp.Handle.ulink->EndVbyte) = '\0';   // pre-assign empty cstring
    239238            in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
    240239        } catch (cstring_length*) {
     
    248247    }
    249248
    250         if ( temp.Handle.lnth > 0 ) s = temp;
     249    s = temp;
    251250    return in;
    252251}
    253252
    254253void ?|?( ifstream & in, string_res & this ) {
    255     (ifstream &)(in | this);
     254    (ifstream &)(in | this); ends( in );
    256255}
    257256
     
    269268        cstr[wd] = '\0';                                                                        // guard null terminate string
    270269        try {
    271                 cstr[0] = '\0';                                                                 // pre-assign as empty cstring
    272270                is | cf;
    273271        } catch( cstring_length * ) {
    274272                cont = true;
    275273        } finally {
    276                 if ( ! cf.flags.ignore &&                                               // ok to initialize string
    277                                 cstr[0] != '\0' ) {                                             // something was read
    278                         *(f.s) = cstr;
    279                 }
     274        if ( ! cf.flags.ignore ) *(f.s) = cstr;                 // ok to initialize string
    280275        } // try
    281276        for ( ; cont; )  {                                                                      // overflow read ?
    282277                cont = false;
    283278                try {
    284                         cstr[0] = '\0';                                                         // pre-assign as empty cstring
    285279                        is | cf;
    286280                } catch( cstring_length * ) {
    287281                        cont = true;                                                            // continue not allowed
    288282                } finally {
    289                         if ( ! cf.flags.ignore &&
    290                                         cstr[0] != '\0' ) {                                     // something was read
    291                                 *(f.s) += cstr;                                                 // build string chunk at a time
    292                         }
     283                        if ( ! cf.flags.ignore ) *(f.s) += cstr;        // build string chunk at a time
    293284                } // try
    294285        } // for
     
    297288
    298289void ?|?( ifstream & in, _Istream_Rstr f ) {
    299     (ifstream &)(in | f);
     290    (ifstream &)(in | f); ends( in );
    300291}
    301292
  • libcfa/src/concurrency/channel.hfa

    rfc12f05 r0030b508  
    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 );
    132133    wake_one( cons );
    133134}
     
    136137static inline void __prods_handoff( channel(T) & chan, T & retval ) with(chan) {
    137138    memcpy( (void *)&retval, prods`first.extra, sizeof(T) );
     139    __atomic_thread_fence( __ATOMIC_SEQ_CST );
    138140    wake_one( prods );
    139141}
  • libcfa/src/concurrency/cofor.cfa

    rfc12f05 r0030b508  
    44// cofor ( uC++ COFOR )
    55
    6 thread cofor_task {
     6thread cofor_runner {
    77        ssize_t low, high;
    88        __cofor_body_t loop_body;
    99};
    1010
    11 static void ?{}( cofor_task & this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) {
     11static void ?{}( cofor_runner & 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_task & this ) with( this ) {
     17void main( cofor_runner & 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_task * runners[ threads ];
     31        cofor_runner * runners[ threads ];
    3232        for ( i; threads ) {
    3333                runners[i] = alloc();
  • libcfa/src/concurrency/cofor.hfa

    rfc12f05 r0030b508  
    11#include <thread.hfa>
    2 #include <locks.hfa>
    3 #include <list.hfa>
    42
    53//////////////////////////////////////////////////////////////////////////////////////////
     
    1614                __Cofor__( low, high, __CFA_loopLambda__ ); \
    1715        }
    18 
    19 struct runner_node {
    20     void * value;
    21     inline dlink(runner_node);
    22 };
    23 P9_EMBEDDED( runner_node, dlink(runner_node) )
    24 
    25 thread cofor_runner {
    26         go_mutex mutex_lock;              // MX lock
    27     dlist( runner_node ) items;
    28     void (*func)(void *);
    29     volatile bool done;
    30 };
    31 
    32 void ?{}( cofor_runner & this ) { this.done = false; }
    33 
    34 void 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 
    45 void start_runners( cofor_runner * thds, unsigned nprocs, void (*func)(void *) ) {
    46         for ( i; nprocs ) {
    47                 thds[i].func = func;
    48         }
    49 }
    50 
    51 void end_runners( cofor_runner * thds, unsigned nprocs ) {
    52         for ( i; nprocs ) {
    53                 thds[i].done = true;
    54         }
    55 }
    56 
    57 void 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 }
    6616
    6717//////////////////////////////////////////////////////////////////////////////////////////
     
    9242    delete( this.runner );
    9343}
     44
  • libcfa/src/concurrency/kernel.hfa

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

    rfc12f05 r0030b508  
    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 
    189184        mcs_spin_node * prev = __atomic_exchange_n(&l.queue.tail, &n, __ATOMIC_SEQ_CST);
    190185        if( prev == 0p ) return;
    191186        prev->next = &n;
    192        
    193         #if defined(__ARM_ARCH)
    194         __asm__ __volatile__ ( "DMB ISH" ::: );
    195         #endif
    196 
    197187        while( __atomic_load_n(&n.locked, __ATOMIC_RELAXED) ) Pause();
    198 
    199         #if defined(__ARM_ARCH)
    200         __asm__ __volatile__ ( "DMB ISH" ::: );
    201         #endif
    202188}
    203189
    204190static inline void unlock(mcs_spin_lock & l, mcs_spin_node & n) {
    205         #if defined(__ARM_ARCH)
    206         __asm__ __volatile__ ( "DMB ISH" ::: );
    207         #endif
    208 
    209191        mcs_spin_node * n_ptr = &n;
    210192        if (__atomic_compare_exchange_n(&l.queue.tail, &n_ptr, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return;
    211193        while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) Pause();
    212 
    213         #if defined(__ARM_ARCH)
    214         __asm__ __volatile__ ( "DMB ISH" ::: );
    215         #endif
    216 
    217194        n.next->locked = false;
    218195}
  • libcfa/src/fstream.cfa

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

    rfc12f05 r0030b508  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Oct 18 20:30:12 2023
    13 // Update Count     : 261
     12// Last Modified On : Fri Aug 18 10:41:15 2023
     13// Update Count     : 258
    1414//
    1515
     
    117117void nlOn( ifstream & );
    118118void nlOff( ifstream & );
     119void ends( ifstream & );
    119120int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    120 ifstream & ungetc( ifstream & is, char c );
    121 bool eof( ifstream & is );
    122121
    123122bool fail( ifstream & is );
    124123void clear( ifstream & );
     124bool 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
    128129ifstream & read( ifstream & is, char data[], size_t size );
     130ifstream & ungetc( ifstream & is, char c );
    129131
    130132void ?{}( ifstream & is );
  • libcfa/src/iostream.cfa

    rfc12f05 r0030b508  
     1
    12//
    23// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
     
    1011// Created On       : Wed May 27 17:56:53 2015
    1112// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Nov 11 07:06:27 2023
    13 // Update Count     : 1803
     13// Last Modified On : Sun Oct  8 12:10:21 2023
     14// Update Count     : 1564
    1415//
    1516
     
    784785                return is;
    785786        } // ?|?
     787        ISTYPE_VOID_IMPL( bool & )
    786788
    787789        istype & ?|?( istype & is, char & c ) {
     
    795797                return is;
    796798        } // ?|?
     799        ISTYPE_VOID_IMPL( char & )
    797800
    798801        istype & ?|?( istype & is, signed char & sc ) {
     
    800803                return is;
    801804        } // ?|?
     805        ISTYPE_VOID_IMPL( signed char & )
    802806
    803807        istype & ?|?( istype & is, unsigned char & usc ) {
     
    805809                return is;
    806810        } // ?|?
     811        ISTYPE_VOID_IMPL( unsigned char & )
    807812
    808813        istype & ?|?( istype & is, short int & si ) {
     
    810815                return is;
    811816        } // ?|?
     817        ISTYPE_VOID_IMPL( short int & )
    812818
    813819        istype & ?|?( istype & is, unsigned short int & usi ) {
     
    815821                return is;
    816822        } // ?|?
     823        ISTYPE_VOID_IMPL( unsigned short int & )
    817824
    818825        istype & ?|?( istype & is, int & i ) {
     
    820827                return is;
    821828        } // ?|?
     829        ISTYPE_VOID_IMPL( int & )
    822830
    823831        istype & ?|?( istype & is, unsigned int & ui ) {
     
    825833                return is;
    826834        } // ?|?
     835        ISTYPE_VOID_IMPL( unsigned int & )
    827836
    828837        istype & ?|?( istype & is, long int & li ) {
     
    830839                return is;
    831840        } // ?|?
     841        ISTYPE_VOID_IMPL( long int & )
    832842
    833843        istype & ?|?( istype & is, unsigned long int & ulli ) {
     
    835845                return is;
    836846        } // ?|?
     847        ISTYPE_VOID_IMPL( unsigned long int & )
    837848
    838849        istype & ?|?( istype & is, long long int & lli ) {
     
    840851                return is;
    841852        } // ?|?
     853        ISTYPE_VOID_IMPL( long long int & )
    842854
    843855        istype & ?|?( istype & is, unsigned long long int & ulli ) {
     
    845857                return is;
    846858        } // ?|?
     859        ISTYPE_VOID_IMPL( unsigned long long int & )
    847860
    848861        #if defined( __SIZEOF_INT128__ )
     
    850863                return (istype &)(is | (unsigned int128 &)llli);
    851864        } // ?|?
     865        ISTYPE_VOID_IMPL( int128 & )
    852866
    853867        istype & ?|?( istype & is, unsigned int128 & ullli ) {
     
    866880                return is;
    867881        } // ?|?
     882        ISTYPE_VOID_IMPL( unsigned int128 & )
    868883        #endif // __SIZEOF_INT128__
    869884
     
    872887                return is;
    873888        } // ?|?
     889        ISTYPE_VOID_IMPL( float & )
    874890
    875891        istype & ?|?( istype & is, double & d ) {
     
    877893                return is;
    878894        } // ?|?
     895        ISTYPE_VOID_IMPL( double & )
    879896
    880897        istype & ?|?( istype & is, long double & ld ) {
     
    882899                return is;
    883900        } // ?|?
     901        ISTYPE_VOID_IMPL( long double & )
    884902
    885903        istype & ?|?( istype & is, float _Complex & fc ) {
     
    889907                return is;
    890908        } // ?|?
     909        ISTYPE_VOID_IMPL( float _Complex & )
    891910
    892911        istype & ?|?( istype & is, double _Complex & dc ) {
     
    896915                return is;
    897916        } // ?|?
     917        ISTYPE_VOID_IMPL( double _Complex & )
    898918
    899919        istype & ?|?( istype & is, long double _Complex & ldc ) {
     
    903923                return is;
    904924        } // ?|?
     925        ISTYPE_VOID_IMPL( long double _Complex & )
    905926
    906927        istype & ?|?( istype & is, const char fmt[] ) {
     
    908929                return is;
    909930        } // ?|?
     931        ISTYPE_VOID_IMPL( const char * )
    910932
    911933        // manipulators
     
    915937
    916938        void ?|?( istype & is, istype & (* manip)( istype & ) ) {
    917                 manip( is );
     939                manip( is ); ends( is );
    918940        } // ?|?
    919941
     
    944966                        char fmtstr[ sizeof("%*[]") + nscanset ];
    945967                        int pos = 0;
    946                         strcpy( &fmtstr[pos], "%*[" );  pos += 3;
     968                        fmtstr[pos] = '%';                  pos += 1;
     969                        fmtstr[pos] = '*';                  pos += 1;
     970                        fmtstr[pos] = '[';                  pos += 1;
    947971                        strcpy( &fmtstr[pos], f.scanset );  pos += nscanset;
    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
     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" );
    959977                return is;
    960978        }
     979        ISTYPE_VOID_IMPL( _Istream_Cskip )
    961980
    962981        istype & ?|?( istype & is, _Istream_Cstr f ) {
    963                 const char * scanset;
    964                 size_t nscanset = 0;
     982                const char * scanset = f.scanset;
    965983                if ( f.flags.delimiter ) scanset = f.delimiter; // getline ?
    966                 else scanset = f.scanset;
    967                 if ( scanset ) nscanset = strlen( scanset );
    968 
    969                 char fmtstr[nscanset + 32];                                             // storage for scanset and format codes
     984
     985                size_t len = 0;
     986                if ( scanset ) len = strlen( scanset );
     987                char fmtstr[len + 16];
     988                int start = 1;
    970989                fmtstr[0] = '%';
    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
     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 ) {
    979993                        // wd is buffer bytes available (for input chars + null terminator)
    980994                        // rwd is count of input chars
    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 );
     995                        int rwd;
     996                        if (f.flags.rwd) {
     997                                verify (f.wd >= 0);
     998                                rwd = f.wd;
     999                        } else {
     1000                                verify (f.wd >= 1);
     1001                                rwd = f.wd - 1;
     1002                        } // 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 );
    9851019                } // if
    9861020
    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
     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 ) ) {
    9951032                                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
     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 };
    10021045                        } // 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
    1025                         } else {
    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
     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 );
    10441054                        } // if
    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         } // ?|?
     1055                } //if
     1056                return is;
     1057        } // ?|?
     1058        ISTYPE_VOID_IMPL( _Istream_Cstr )
    10531059
    10541060        istype & ?|?( istype & is, _Istream_Char f ) {
     
    10561062                return is;
    10571063        } // ?|?
     1064        ISTYPE_VOID_IMPL( _Istream_Char )
    10581065} // distribution
    10591066
     
    10721079                return is; \
    10731080        } /* ?|? */ \
     1081        ISTYPE_VOID_IMPL( _Istream_Manip(T) ) \
    10741082} // distribution
    10751083
     
    10991107                return is;
    11001108        } // ?|?
     1109        ISTYPE_VOID_IMPL( _Istream_Manip(float _Complex) )
    11011110
    11021111        istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
     
    11091118                return is;
    11101119        } // ?|?
     1120        ISTYPE_VOID_IMPL( _Istream_Manip(double _Complex) )
    11111121
    11121122        istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
     
    11191129                return is;
    11201130        } // ?|?
     1131        ISTYPE_VOID_IMPL( _Istream_Manip(long double _Complex) )
    11211132} // distribution
    11221133
  • libcfa/src/iostream.hfa

    rfc12f05 r0030b508  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Oct 18 21:21:20 2023
    13 // Update Count     : 583
     12// Last Modified On : Sun Oct  8 12:02:55 2023
     13// Update Count     : 568
    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
    308314forall( istype & )
    309315trait basic_istream {
     
    314320        void nlOn( istype & );                                                          // read newline
    315321        void nlOff( istype & );                                                         // scan newline
     322        void ends( istype & os );                                                       // end of output statement
    316323        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    317324        istype & ungetc( istype &, char );
    318325        bool eof( istype & );
    319         void clear( istype & );
    320326}; // basic_istream
    321327
     
    323329trait istream {
    324330        bool fail( istype & );
    325         void open( istype & is, const char name[], const char mode[] );
     331        void clear( istype & );
    326332        void open( istype & is, const char name[] );
    327333        void close( istype & is );
     
    336342forall( istype & | basic_istream( istype ) ) {
    337343        istype & ?|?( istype &, bool & );
     344        ISTYPE_VOID( bool & );
    338345
    339346        istype & ?|?( istype &, char & );
     347        ISTYPE_VOID( char & );
    340348        istype & ?|?( istype &, signed char & );
     349        ISTYPE_VOID( signed char & );
    341350        istype & ?|?( istype &, unsigned char & );
     351        ISTYPE_VOID( unsigned char & );
    342352
    343353        istype & ?|?( istype &, short int & );
     354        ISTYPE_VOID( short int & );
    344355        istype & ?|?( istype &, unsigned short int & );
     356        ISTYPE_VOID( unsigned short int & );
    345357        istype & ?|?( istype &, int & );
     358        ISTYPE_VOID( int & );
    346359        istype & ?|?( istype &, unsigned int & );
     360        ISTYPE_VOID( unsigned int & );
    347361        istype & ?|?( istype &, long int & );
     362        ISTYPE_VOID( long int & );
    348363        istype & ?|?( istype &, unsigned long int & );
     364        ISTYPE_VOID( unsigned long int & );
    349365        istype & ?|?( istype &, long long int & );
     366        ISTYPE_VOID( long long int & );
    350367        istype & ?|?( istype &, unsigned long long int & );
     368        ISTYPE_VOID( unsigned long long int & );
    351369        #if defined( __SIZEOF_INT128__ )
    352370        istype & ?|?( istype &, int128 & );
     371        ISTYPE_VOID( int128 & );
    353372        istype & ?|?( istype &, unsigned int128 & );
     373        ISTYPE_VOID( unsigned int128 & );
    354374        #endif // __SIZEOF_INT128__
    355375
    356376        istype & ?|?( istype &, float & );
     377        ISTYPE_VOID( float & );
    357378        istype & ?|?( istype &, double & );
     379        ISTYPE_VOID( double & );
    358380        istype & ?|?( istype &, long double & );
     381        ISTYPE_VOID( long double & );
    359382
    360383        istype & ?|?( istype &, float _Complex & );
     384        ISTYPE_VOID( float _Complex & );
    361385        istype & ?|?( istype &, double _Complex & );
     386        ISTYPE_VOID( double _Complex & );
    362387        istype & ?|?( istype &, long double _Complex & );
     388        ISTYPE_VOID( long double _Complex & );
    363389
    364390        istype & ?|?( istype &, const char [] );
     391        ISTYPE_VOID( const char [] );
    365392
    366393        // manipulators
    367394        istype & ?|?( istype &, istype & (*)( istype & ) );
     395        ISTYPE_VOID( istype & (*)( istype & ) );
    368396        istype & nl( istype & is );
    369397        istype & nlOn( istype & );
     
    374402
    375403ExceptionDecl( cstring_length );
    376 ExceptionDecl( missing_data );
    377404
    378405// *********************************** manipulators ***********************************
    379406
    380 // skip does not compose with other C string manipulators.
    381407struct _Istream_Cskip {
    382408        const char * scanset;
     
    390416forall( istype & | basic_istream( istype ) ) {
    391417        istype & ?|?( istype & is, _Istream_Cskip f );
     418        ISTYPE_VOID( _Istream_Cskip );
    392419}
    393420
     
    431458forall( istype & | basic_istream( istype ) ) {
    432459        istype & ?|?( istype & is, _Istream_Cstr f );
     460        ISTYPE_VOID( _Istream_Cstr );
    433461}
    434462
     
    443471forall( istype & | basic_istream( istype ) ) {
    444472        istype & ?|?( istype & is, _Istream_Char f );
     473        ISTYPE_VOID( _Istream_Char );
    445474}
    446475
     
    461490forall( istype & | basic_istream( istype ) ) { \
    462491        istype & ?|?( istype & is, _Istream_Manip(T) f ); \
     492        ISTYPE_VOID( _Istream_Manip(T) ); \
    463493} // ?|?
    464494
  • src/AST/Decl.hpp

    rfc12f05 r0030b508  
    125125
    126126/// Object declaration `int foo()`
    127 class FunctionDecl final : public DeclWithType {
     127class FunctionDecl : public DeclWithType {
    128128public:
    129129        std::vector<ptr<TypeDecl>> type_params;
     
    314314class EnumDecl final : public AggregateDecl {
    315315public:
    316         // isTyped indicated if the enum has a declaration like:
     316        bool isTyped; // isTyped indicated if the enum has a declaration like:
    317317        // enum (type_optional) Name {...}
    318         bool isTyped;
    319         // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    320         ptr<Type> base;
     318        ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    321319        enum class EnumHiding { Visible, Hide } hide;
    322320
     
    376374
    377375/// Assembly declaration: `asm ... ( "..." : ... )`
    378 class AsmDecl final : public Decl {
     376class AsmDecl : public Decl {
    379377public:
    380378        ptr<AsmStmt> stmt;
    381379
    382380        AsmDecl( const CodeLocation & loc, AsmStmt * stmt )
    383         : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {}
     381        : Decl( loc, "", {}, {} ), stmt(stmt) {}
    384382
    385383        const AsmDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    390388
    391389/// C-preprocessor directive `#...`
    392 class DirectiveDecl final : public Decl {
     390class DirectiveDecl : public Decl {
    393391public:
    394392        ptr<DirectiveStmt> stmt;
    395393
    396394        DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt )
    397         : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {}
     395        : Decl( loc, "", {}, {} ), stmt(stmt) {}
    398396
    399397        const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    404402
    405403/// Static Assertion `_Static_assert( ... , ... );`
    406 class StaticAssertDecl final : public Decl {
     404class StaticAssertDecl : public Decl {
    407405public:
    408406        ptr<Expr> cond;
     
    410408
    411409        StaticAssertDecl( const CodeLocation & loc, const Expr * condition, const ConstantExpr * msg )
    412         : Decl( loc, "", {}, Linkage::C ), cond( condition ), msg( msg ) {}
     410        : Decl( loc, "", {}, {} ), cond( condition ), msg( msg ) {}
    413411
    414412        const StaticAssertDecl * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

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

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

    rfc12f05 r0030b508  
    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.
    2321// Stats::Counters::SimpleCounter * BaseSyntaxNode::new_nodes = nullptr;
    2422
  • src/AST/Pass.hpp

    rfc12f05 r0030b508  
    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;
    175174        const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
    176175        const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
  • src/AST/Pass.impl.hpp

    rfc12f05 r0030b508  
    11341134
    11351135//--------------------------------------------------------------------------
    1136 // CoforStmt
    1137 template< typename core_t >
    1138 const 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 //--------------------------------------------------------------------------
    11541136// ApplicationExpr
    11551137template< typename core_t >
  • src/AST/Print.cpp

    rfc12f05 r0030b508  
    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 
    978936        virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) override final {
    979937                ++indent;
  • src/AST/Stmt.hpp

    rfc12f05 r0030b508  
    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
    549 class 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 }; }
    563545        MUTATE_FRIEND
    564546};
  • src/AST/Type.hpp

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

    rfc12f05 r0030b508  
    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;
    6362    virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) = 0;
    6463    virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) = 0;
  • src/AST/module.mk

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

    rfc12f05 r0030b508  
    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         #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 );
     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 );
    278279        start += sizeof( STARTMK );                                                     // includes newline
    279280        code << str.substr( 0, start );
     
    283284        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    284285                code << "\t\t" << graph[r].name << "," << endl;
    285         } // for
     286        } // for       
    286287        code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;
    287288        code << "\t} kind;" << endl;
    288289        code << "\t";                                                                           // indentation for end marker
    289290
    290         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST );
    291         code << str.substr( start );
    292 
    293         output( file, TypeH_AST, code );
    294         // cout << code.str();
    295 
    296 
    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 );
     291        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );
     292        code << str.substr( start );
     293
     294        output( file, TypeH, code );
     295        // cout << code.str();
     296
     297
     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 );
    301302        start += sizeof( STARTMK );                                                     // includes newline
    302303        code << str.substr( 0, start );
     
    306307        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    307308                code << "\t\"" << graph[r].type << "\"," << endl;
    308         } // for
     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       
    309355        code << "};" << endl;
    310356
     
    345391        end += sizeof( STARTMK );
    346392        code << str.substr( start, end - start );
    347 
     393       
    348394        code << "\t" << BYMK << 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
     395        code << "\tstatic const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl
    350396                 << "\t\t/*           ";
    351397        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    365411        code << "\tstatic const int maxIntCost = " << *max_element(costMatrix[SignedInt], costMatrix[SignedInt] + NUMBER_OF_BASIC_TYPES) << ";" << endl;
    366412        code << "\t";                                                                           // indentation for end marker
    367 
     413       
    368414        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ConversionCost );
    369415        if ( (end = str.find( STARTMK, start + 1 )) == string::npos ) Abort( "start", ConversionCost );
     
    372418
    373419        code << "\t" << BYMK << 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
     420        code << "\tstatic const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl
    375421                 << "\t\t/*           ";
    376422        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    404450        enum { PER_ROW = 6 };
    405451        code << "\t" << BYMK << 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
     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
    408454             << "\t\t/*\t\t ";
    409455        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    459505                "\t\t\t//   - \"Di\" char32_t\n"
    460506                "\t\t\t//   - \"Ds\" char16_t\n";
    461 
    462         code << "\t\t\tconst std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
     507               
     508        code << "\t\t\tconst std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
    463509        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    464510                code << "\t\t\t\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl;
    465         } // for
     511        } // for       
    466512        code << "\t\t\t}; // basicTypes" << endl;
    467513        code << "\t\t\t";                                                                       // indentation for end marker
  • src/CodeGen/FixMain.cc

    rfc12f05 r0030b508  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.cc -- Tools to change a Cforall main into a C main.
     7// FixMain.cc --
    88//
    99// Author           : Thierry Delisle
     
    1313// Update Count     : 0
    1414//
     15
    1516
    1617#include "FixMain.h"
     
    2223
    2324#include "AST/Decl.hpp"
    24 #include "AST/Pass.hpp"
    2525#include "AST/Type.hpp"
    26 #include "AST/Vector.hpp"
     26#include "Common/PassVisitor.h"
    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
    2931#include "SymTab/Mangler.h"
    3032
     
    3335namespace {
    3436
    35 struct FindMainCore final {
    36         ast::FunctionDecl const * main_declaration = nullptr;
     37struct FindMainCore {
     38        FunctionDecl * main_signature = nullptr;
    3739
    38         void previsit( ast::FunctionDecl const * decl ) {
    39                 if ( isMain( decl ) ) {
    40                         if ( main_declaration ) {
     40        void previsit( FunctionDecl * decl ) {
     41                if ( FixMain::isMain( decl ) ) {
     42                        if ( main_signature ) {
    4143                                SemanticError( decl, "Multiple definition of main routine\n" );
    4244                        }
    43                         main_declaration = decl;
     45                        main_signature = decl;
    4446                }
    4547        }
    4648};
    4749
    48 std::string genTypeAt( const ast::vector<ast::Type> & types, size_t at ) {
    49         return genType( types[at], "", Options( false, false, false, false ) );
    5050}
    5151
    52 ast::ObjectDecl * makeIntObj(){
    53         return new ast::ObjectDecl( CodeLocation(), "",
    54                 new ast::BasicType( ast::BasicType::SignedInt ) );
     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
     83namespace {
     84
     85ObjectDecl * signedIntObj() {
     86        return new ObjectDecl(
     87                "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
     88                new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr );
    5589}
    5690
    57 ast::ObjectDecl * makeCharStarStarObj() {
    58         return new ast::ObjectDecl( CodeLocation(), "",
    59                 new ast::PointerType(
    60                         new ast::PointerType(
    61                                 new ast::BasicType( ast::BasicType::Char ) ) ) );
     91ObjectDecl * 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 );
    6298}
    6399
    64 std::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() );
     100std::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() );
    81105}
    82106
    83 std::string getMangledNameOf0ParameterMain() {
    84         return getMangledNameOfMain( {}, ast::VariableArgs );
     107std::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 );
    85111}
    86112
    87 std::string getMangledNameOf2ParameterMain() {
    88         return getMangledNameOfMain( {
    89                 makeIntObj(),
    90                 makeCharStarStarObj(),
    91         }, ast::FixedArgs );
     113std::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 );
    92119}
    93120
     
    95122        // This breaks if you move it out of the function.
    96123        static const std::string mangled_mains[] = {
    97                 getMangledNameOf0ParameterMain(),
    98                 getMangledNameOf2ParameterMain(),
    99                 //getMangledNameOf3ParameterMain(),
     124                mangled_0_argument_main(),
     125                mangled_2_argument_main(),
     126                //mangled_3_argument_main(),
    100127        };
    101128
     
    106133}
    107134
    108 struct 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 
    118135} // namespace
    119136
    120 bool isMain( const ast::FunctionDecl * decl ) {
     137bool 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
     144bool FixMain::isMain( const ast::FunctionDecl * decl ) {
    121145        if ( std::string("main") != decl->name ) {
    122146                return false;
     
    125149}
    126150
    127 void 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 
    134 void 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
     151};
  • src/CodeGen/FixMain.h

    rfc12f05 r0030b508  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.h -- Tools to change a Cforall main into a C main.
     7// FixMain.h --
    88//
    99// Author           : Thierry Delisle
     
    1717
    1818#include <iosfwd>
     19#include <memory>
     20#include <list>
    1921
     22#include "SynTree/LinkageSpec.h"
     23
     24class Declaration;
     25class FunctionDecl;
    2026namespace ast {
    2127        class FunctionDecl;
    22         class TranslationUnit;
    2328}
    2429
    2530namespace CodeGen {
    2631
    27 /// Is this function a program main function?
    28 bool isMain( const ast::FunctionDecl * decl );
     32class FixMain {
     33public :
     34        static inline LinkageSpec::Spec mainLinkage() {
     35                return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;
     36        }
    2937
    30 /// Adjust the linkage of main functions.
    31 void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain );
     38        static inline void setReplaceMain(bool val) {
     39                replace_main = val;
     40        }
    3241
    33 /// Add a wrapper around to run the Cforall main.
    34 void fixMainInvoke( ast::TranslationUnit & transUnit,
    35                 std::ostream & os, const char * bootloaderFilename );
     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
     48private:
     49        static bool replace_main;
     50};
    3651
    3752} // namespace CodeGen
  • src/CodeGen/FixNames.cc

    rfc12f05 r0030b508  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
     24#include "Common/PassVisitor.h"
    2425#include "Common/SemanticError.h"  // for SemanticError
    2526#include "FixMain.h"               // for FixMain
    2627#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
    2736#include "CompilationState.h"
    2837
    2938namespace CodeGen {
     39        class FixNames : public WithGuards {
     40          public:
     41                void postvisit( ObjectDecl *objectDecl );
     42                void postvisit( FunctionDecl *functionDecl );
    3043
    31 namespace {
     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        }
    3287
    3388/// Does work with the main function and scopeLevels.
    34 class FixNames final {
     89class FixNames_new final {
    3590        int scopeLevel = 1;
    3691
     
    48103
    49104        const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) {
    50                 if ( isMain( functionDecl ) ) {
     105                if ( FixMain::isMain( functionDecl ) ) {
    51106                        auto mutDecl = ast::mutate( functionDecl );
    52107
     
    83138};
    84139
    85 } // namespace
    86 
    87140void fixNames( ast::TranslationUnit & translationUnit ) {
    88         ast::Pass<FixNames>::run( translationUnit );
     141        ast::Pass<FixNames_new>::run( translationUnit );
    89142}
    90143
  • src/CodeGen/FixNames.h

    rfc12f05 r0030b508  
    1616#pragma once
    1717
     18#include <list>  // for list
     19
     20class Declaration;
    1821namespace ast {
    1922        class TranslationUnit;
     
    2124
    2225namespace CodeGen {
    23 
     26        /// mangles object and function names
     27        void fixNames( std::list< Declaration* > & translationUnit );
    2428/// Sets scope levels and fills in main's default return.
    2529void fixNames( ast::TranslationUnit & translationUnit );
    26 
    2730} // namespace CodeGen
    2831
  • src/CodeGen/GenType.cc

    rfc12f05 r0030b508  
    1919#include <sstream>                // for operator<<, ostringstream, basic_os...
    2020
    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
     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
    2526
    2627namespace CodeGen {
    27 
    28 namespace {
    29 
    30 #warning Remove the _new when old version is removed.
    31 struct 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 
    60 private:
    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 
    69 GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}
    70 
    71 void 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 
    77 void 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 
    83 void GenType_new::postvisit( ast::VoidType const * type ) {
    84         result = "void " + result;
    85         handleQualifiers( type );
    86 }
    87 
    88 void 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 
    95 void 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 << ")";
     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 );
     65                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 ) {
     112                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() );
    100155                } else {
    101                         os << result;
     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;
    102228                }
    103229        }
    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 
    133 void 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;
     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);
    140258                } else {
    141                         result = "*" + result;
     259                        typeString = enumInst->name + " " + typeString;
     260                        if ( options.genC ) {
     261                                typeString = "enum " + typeString;
     262                        }
    142263                }
    143                 type->base->accept( *visitor );
    144         }
    145 }
    146 
    147 void GenType_new::postvisit( ast::ArrayType const * type ) {
    148         genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
    149 }
    150 
    151 void 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 
    158 void 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;
     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() ? "" : ", ");
    166281                }
    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." );
    197                 std::ostringstream os;
    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 
    206 std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) {
    207         if ( !type->params.empty() ) {
    208                 std::ostringstream os;
    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 
    218 void 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 
    224 void 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 
    230 void 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 
    242 void 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 
    248 void 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 
    261 void GenType_new::postvisit( ast::VarArgsType const * type ) {
    262         result = "__builtin_va_list " + result;
    263         handleQualifiers( type );
    264 }
    265 
    266 void 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 
    272 void 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 
    278 void GenType_new::postvisit( ast::GlobalScopeType const * type ) {
    279         assertf( !options.genC, "GlobalScopeType should not reach code generation." );
    280         handleQualifiers( type );
    281 }
    282 
    283 void 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 
    289 void 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 
    298 void 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 
    306 void 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 
    314 void 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 
    329 std::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 
    345 std::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 
    355 std::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 
     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        }
    359354} // namespace CodeGen
    360355
  • src/CodeGen/GenType.h

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

    rfc12f05 r0030b508  
    1919#include <string>                    // for operator<<
    2020
    21 #include "CodeGeneratorNew.hpp"      // for CodeGenerator_new, doSemicolon, ...
     21#include "CodeGenerator.h"           // for CodeGenerator, doSemicolon, oper...
    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
    2328
    2429using namespace std;
    2530
    2631namespace 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 );
    2737
    28 namespace {
    29         bool shouldClean( ast::Decl const * decl ) {
    30                 return dynamic_cast<ast::TraitDecl const *>( decl );
     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
    3162        }
    3263
    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;
     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 );
    4282                }
    4383
    44                 ast::Stmt const * postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
    45                         return stmt->callStmt;
     84                Statement * TreeCleaner::postmutate( ImplicitCtorDtorStmt * stmt ) {
     85                        Statement * callStmt = nullptr;
     86                        std::swap( stmt->callStmt, callStmt );
     87                        delete stmt;
     88                        return callStmt;
    4689                }
    47         };
    48 } // namespace
    4990
    50 void 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;
     91                bool TreeCleaner::shouldClean( Declaration * decl ) {
     92                        return dynamic_cast< TraitDecl * >( decl );
    6593                }
    66         }
    67 }
    68 
     94        } // namespace
    6995} // namespace CodeGen
    7096
  • src/CodeGen/Generate.h

    rfc12f05 r0030b508  
    2222class Declaration;
    2323
    24 namespace ast {
    25         class TranslationUnit;
    26 }
     24namespace 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 );
    2727
    28 namespace CodeGen {
    29 
    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.
    36 void generate( ast::TranslationUnit & transUnit, std::ostream &os, bool doIntrinsics,
    37                 bool pretty, bool generateC, bool lineMarks, bool printExprTypes );
    38 
     28        /// Generate code for a single node -- helpful for debugging in gdb
     29        void generate( BaseSyntaxNode * node, std::ostream & os );
    3930} // namespace CodeGen
    4031
  • src/CodeGen/LinkOnce.cc

    rfc12f05 r0030b508  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
     24#include "Common/PassVisitor.h"       // for PassVisitor, WithShortCircuiting
    2425
    2526namespace CodeGen {
    2627
    2728namespace {
     29
     30bool is_cfa_linkonce_old( Attribute const * attr ) {
     31        return std::string("cfa_linkonce") == attr->name;
     32}
     33
     34bool is_section_attribute_old( Attribute const * attr ) {
     35        return std::string("section") == attr->name;
     36}
     37
     38class LinkOnceVisitorCore : public WithShortCircuiting {
     39public:
     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};
    2870
    2971bool is_cfa_linkonce( ast::Attribute const * attr ) {
     
    80122} // namespace
    81123
     124void translateLinkOnce( std::list< Declaration *> & translationUnit ) {
     125        PassVisitor<LinkOnceVisitorCore> translator;
     126        acceptAll( translationUnit, translator );
     127}
     128
    82129void translateLinkOnce( ast::TranslationUnit & translationUnit ) {
    83130        ast::Pass<LinkOnceCore>::run( translationUnit );
  • src/CodeGen/LinkOnce.h

    rfc12f05 r0030b508  
    2020// for now its almost the only attribute we handle.
    2121
     22#include <list>  // for list
    2223
     24class Declaration;
    2325namespace ast {
    2426        class TranslationUnit;
     
    2729namespace CodeGen {
    2830
     31void translateLinkOnce( std::list< Declaration *> & translationUnit );
    2932void translateLinkOnce( ast::TranslationUnit & translationUnit );
    3033/* Convert the cfa_linkonce attribute on top level declaration into
  • src/CodeGen/OperatorTable.cc

    rfc12f05 r0030b508  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Nov  3 16:00:00 2023
    13 // Update Count     : 56
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Tue Feb 18 15:55:01 2020
     13// Update Count     : 55
    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
     19using namespace std;
     20
    1621#include "OperatorTable.h"
    17 
    18 #include <cassert>         // for assert
    19 #include <unordered_map>   // for unordered_map
     22#include "Common/utility.h"
    2023
    2124namespace 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
    2270
    23 static 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
     71        std::map< std::string, OperatorInfo > CodeGen::table;
    6872
    69 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
    70 
    71 const 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;
     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
    7678        }
    7779
    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 }
     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;
     85        }
    8486
    85 bool isOperator( const std::string & inputName ) {
    86         return operatorLookup( inputName ) != nullptr;
    87 }
     87        bool isOperator( const string & funcName ) {
     88                return operatorLookup( funcName ) != nullptr;
     89        }
    8890
    89 std::string operatorFriendlyName( const std::string & inputName ) {
    90         const OperatorInfo * info = operatorLookup( inputName );
    91         if ( info ) return info->friendlyName;
    92         return "";
    93 }
     91        string operatorFriendlyName( const string & funcName ) {
     92                const OperatorInfo * info = operatorLookup( funcName );
     93                if ( info ) return info->friendlyName;
     94                return "";
     95        }
    9496
    95 // This is only used in the demangler, so it is smaller (and only maybe slow).
    96 const 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                 }
     97        bool isConstructor( const string & funcName ) {
     98                const OperatorInfo * info = operatorLookup( funcName );
     99                if ( info ) return info->type == OT_CTOR;
     100                return false;
    102101        }
    103         return nullptr;
    104 }
    105102
    106 bool isConstructor( const std::string & inputName ) {
    107         const OperatorInfo * info = operatorLookup( inputName );
    108         if ( info ) return info->type == OT_CTOR;
    109         return false;
    110 }
     103        bool isDestructor( const string & funcName ) {
     104                const OperatorInfo * info = operatorLookup( funcName );
     105                if ( info ) return info->type == OT_DTOR;
     106                return false;
     107        }
    111108
    112 bool isDestructor( const std::string & inputName ) {
    113         const OperatorInfo * info = operatorLookup( inputName );
    114         if ( info ) return info->type == OT_DTOR;
    115         return false;
    116 }
     109        bool isCtorDtor( const string & funcName ) {
     110                const OperatorInfo * info = operatorLookup( funcName );
     111                if ( info ) return info->type <= OT_CONSTRUCTOR;
     112                return false;
     113        }
    117114
    118 bool isCtorDtor( const std::string & inputName ) {
    119         const OperatorInfo * info = operatorLookup( inputName );
    120         if ( info ) return info->type <= OT_CONSTRUCTOR;
    121         return false;
    122 }
     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        }
    123120
    124 bool 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 }
     121        bool isCtorDtorAssign( const string & funcName ) {
     122                const OperatorInfo * info = operatorLookup( funcName );
     123                if ( info ) return info->type <= OT_ASSIGNMENT;
     124                return false;
     125        }
    129126
    130 bool isCtorDtorAssign( const std::string & inputName ) {
    131         const OperatorInfo * info = operatorLookup( inputName );
    132         if ( info ) return info->type <= OT_ASSIGNMENT;
    133         return false;
    134 }
    135 
     127        CodeGen codegen;                                                                        // initialize singleton package
    136128} // namespace CodeGen
    137129
  • src/CodeGen/OperatorTable.h

    rfc12f05 r0030b508  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Nov  3 14:53:00 2023
    13 // Update Count     : 27
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Feb 16 08:13:34 2020
     13// Update Count     : 26
    1414//
    1515
     
    1717
    1818#include <string>
     19#include <map>
    1920
    2021namespace 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        };
    2138
    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 };
     39        struct OperatorInfo {
     40                std::string inputName;
     41                std::string symbol;
     42                std::string outputName;
     43                std::string friendlyName;
     44                OperatorType type;
     45        };
    3846
    39 struct 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 };
     47        class CodeGen {
     48                friend const OperatorInfo * operatorLookup( const std::string & funcName );
    5149
    52 // Look up the operator (by inputName), return nullptr if no such operator.
    53 const OperatorInfo * operatorLookup( const std::string & inputName );
    54 // Is there an operator with this name?
    55 bool isOperator( const std::string & inputName );
    56 // Get the friendlyName of the operator with the inputName
    57 std::string operatorFriendlyName( const std::string & inputName );
    58 // Get the OperatorInfo with the given outputName, if one exists.
    59 const OperatorInfo * operatorLookupByOutput( const std::string & outputName );
     50                static const OperatorInfo tableValues[];
     51                static std::map< std::string, OperatorInfo > table;
     52          public:
     53                CodeGen();
     54        }; // CodeGen
    6055
    61 // Is the operator a constructor, destructor or any form of assignment.
    62 // (Last two are "or" combinations of the first three.)
    63 bool isConstructor( const std::string & );
    64 bool isDestructor( const std::string & );
    65 bool isAssignment( const std::string & );
    66 bool isCtorDtor( const std::string & );
    67 bool isCtorDtorAssign( const std::string & );
     56        bool isOperator( const std::string & funcName );
     57        const OperatorInfo * operatorLookup( const std::string & funcName );
     58        std::string operatorFriendlyName( const std::string & funcName );
    6859
     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 & );
    6965} // namespace CodeGen
    7066
  • src/CodeGen/module.mk

    rfc12f05 r0030b508  
    1616
    1717SRC_CODEGEN = \
    18         CodeGen/CodeGeneratorNew.cpp \
    19         CodeGen/CodeGeneratorNew.hpp \
    20         CodeGen/GenType.cc \
    21         CodeGen/GenType.h \
     18        CodeGen/FixMain2.cc \
     19        CodeGen/FixMain.h \
    2220        CodeGen/OperatorTable.cc \
    2321        CodeGen/OperatorTable.h
    2422
    2523SRC += $(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 \
    3029        CodeGen/FixNames.cc \
    3130        CodeGen/FixNames.h \
     31        CodeGen/GenType.cc \
     32        CodeGen/GenType.h \
    3233        CodeGen/LinkOnce.cc \
    3334        CodeGen/LinkOnce.h \
  • src/Common/CodeLocationTools.cpp

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

    rfc12f05 r0030b508  
    1919
    2020#include "AST/Inspect.hpp"
     21#include "Common/PassVisitor.h"
    2122#include "CodeGen/OperatorTable.h"                                              // access: OperatorInfo
    2223#include "AST/Pass.hpp"
    2324#include "InitTweak/InitTweak.h"
    24 
     25#include "SynTree/Expression.h"
     26
     27//-------------------------------------------------------------
     28// Old AST
     29struct 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
    2597struct EvalNew : public ast::WithShortCircuiting {
    2698        Evaluation result = { 0, true, true };
     
    198270};
    199271
     272std::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
    200282Evaluation eval( const ast::Expr * expr ) {
    201283        if ( expr ) {
  • src/Common/Eval.h

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

    rfc12f05 r0030b508  
    1919#include "CodeGen/OperatorTable.h"
    2020#include "InitTweak/InitTweak.h"
     21
     22DeclarationWithType * 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}
    2138
    2239namespace {
     
    5269
    5370namespace {
     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        }
    5483
    5584const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
     
    5988}
    6089
     90}
     91
     92bool 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;
    6198}
    6299
  • src/Common/Examine.h

    rfc12f05 r0030b508  
    1515
    1616#include "AST/Decl.hpp"
     17#include "SynTree/Declaration.h"
    1718
    1819/// Check if this is a main function for a type of an aggregate kind.
     20DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );
    1921const ast::DeclWithType * isMainFor(
    2022        const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind );
     
    2224
    2325/// Check if this function is a destructor for the given structure.
     26bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );
    2427bool isDestructorFor(
    2528        const ast::FunctionDecl * func, const ast::StructDecl * type );
  • src/Common/UniqueName.cc

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

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

    rfc12f05 r0030b508  
    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 \
    3337        Common/PersistentMap.h \
    3438        Common/ResolvProtoDump.hpp \
  • src/Concurrency/Corun.cpp

    rfc12f05 r0030b508  
    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;
    3129    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    
    3930
    4031    const StructDecl * runnerBlockDecl = nullptr;
    41     const StructDecl * coforRunnerDecl = nullptr;
    4232
    43     // Finds runner_block (corun task) and cofor_runner (cofor task) decls
     33    // Finds select_node decl
    4434    void previsit( const StructDecl * decl ) {
    4535        if ( !decl->body ) {
     
    4838            assert( !runnerBlockDecl );
    4939            runnerBlockDecl = decl;
    50         } else if ( "cofor_runner" == decl->name ) {
    51             assert( !coforRunnerDecl );
    52             coforRunnerDecl = decl;
    5340        }
    5441    }
    5542
    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
    24743    Stmt * postvisit( const CorunStmt * stmt ) {
    248         if ( !runnerBlockDecl || !coforRunnerDecl )
     44        if ( !runnerBlockDecl )
    24945            SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>\n" );
    25046
  • src/Concurrency/module.mk

    rfc12f05 r0030b508  
    2121        Concurrency/Corun.hpp \
    2222        Concurrency/KeywordsNew.cpp \
     23        Concurrency/Keywords.cc \
    2324        Concurrency/Keywords.h \
    2425        Concurrency/WaitforNew.cpp \
     26        Concurrency/Waitfor.cc \
    2527        Concurrency/Waitfor.h \
    2628        Concurrency/Waituntil.cpp \
  • src/ControlStruct/module.mk

    rfc12f05 r0030b508  
    1616
    1717SRC += \
     18        ControlStruct/ExceptDecl.cc \
    1819        ControlStruct/ExceptDeclNew.cpp \
    1920        ControlStruct/ExceptDecl.h \
    2021        ControlStruct/ExceptTranslateNew.cpp \
     22        ControlStruct/ExceptTranslate.cc \
    2123        ControlStruct/ExceptTranslate.h \
    2224        ControlStruct/FixLabels.cpp \
    2325        ControlStruct/FixLabels.hpp \
     26        ControlStruct/ForExprMutator.cc \
     27        ControlStruct/ForExprMutator.h \
    2428        ControlStruct/HoistControlDecls.cpp \
    2529        ControlStruct/HoistControlDecls.hpp \
     30        ControlStruct/LabelFixer.cc \
     31        ControlStruct/LabelFixer.h \
     32        ControlStruct/LabelGenerator.cc \
     33        ControlStruct/LabelGenerator.h \
    2634        ControlStruct/LabelGeneratorNew.cpp \
    2735        ControlStruct/LabelGeneratorNew.hpp \
     36        ControlStruct/MLEMutator.cc \
     37        ControlStruct/MLEMutator.h \
    2838        ControlStruct/MultiLevelExit.cpp \
    29         ControlStruct/MultiLevelExit.hpp
     39        ControlStruct/MultiLevelExit.hpp \
     40        ControlStruct/Mutate.cc \
     41        ControlStruct/Mutate.h
    3042
  • src/GenPoly/BoxNew.cpp

    rfc12f05 r0030b508  
    3939
    4040namespace {
     41
     42/// Common field of several sub-passes of box.
     43struct BoxPass {
     44        TypeVarMap scopeTypeVars;
     45        BoxPass() : scopeTypeVars( ast::TypeData() ) {}
     46};
     47
     48// TODO: Could this be a common helper somewhere?
     49ast::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}
    4168
    4269// --------------------------------------------------------------------------
     
    332359/// * Adds appropriate type variables to the function calls.
    333360struct CallAdapter final :
     361                public BoxPass,
    334362                public ast::WithConstTypeSubstitution,
    335363                public ast::WithGuards,
     
    348376        ast::Expr const * postvisit( ast::AddressExpr const * expr );
    349377        ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
     378        void previsit( ast::PointerType const * type );
     379        void previsit( ast::FunctionType const * type );
    350380
    351381        void beginScope();
     
    410440                CodeLocation const & location, ast::Type const * type );
    411441
    412         TypeVarMap scopeTypeVars;
     442        /// Set of adapter functions in the current scope.
    413443        ScopedMap< std::string, ast::DeclWithType const * > adapters;
    414444        std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
     
    523553
    524554ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
    525         // Prevent type declaration information from leaking out.
     555        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 );
     559                return decl;
     560        }
     561
    526562        GuardScope( scopeTypeVars );
    527 
    528         if ( nullptr == decl->stmts ) {
    529                 return decl;
    530         }
    531 
    532563        GuardValue( retval );
    533564
     
    631662        ptrdiff_t initArgCount = mutExpr->args.size();
    632663
    633         TypeVarMap exprTypeVars;
     664        TypeVarMap exprTypeVars = { ast::TypeData() };
    634665        // TODO: Should this take into account the variables already bound in
    635666        // scopeTypeVars ([ex] remove them from exprTypeVars)?
     
    656687
    657688        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).
    658693        ast::vector<ast::Expr>::iterator argIt =
    659694                passTypeVars( mutExpr, function );
     
    733768        }
    734769        return stmt;
     770}
     771
     772void CallAdapter::previsit( ast::PointerType const * type ) {
     773        GuardScope( scopeTypeVars );
     774        makeTypeVarMap( type, scopeTypeVars );
     775}
     776
     777void CallAdapter::previsit( ast::FunctionType const * type ) {
     778        GuardScope( scopeTypeVars );
     779        makeTypeVarMap( type, scopeTypeVars );
    735780}
    736781
     
    13821427
    13831428ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
    1384         TypeVarMap localTypeVars;
     1429        TypeVarMap localTypeVars = { ast::TypeData() };
    13851430        makeTypeVarMap( decl, localTypeVars );
    13861431
     
    14131458                        layoutParams.emplace_back( alignParam );
    14141459                }
    1415                 // Assertions should be stored in the main list.
    1416                 assert( mutParam->assertions.empty() );
     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();
    14171470                typeParam = mutParam;
    14181471        }
     1472        // TODO: New version of inner loop.
    14191473        for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
    14201474                // Assertion parameters may not be used in body,
     
    14311485        spliceBegin( mutDecl->params, layoutParams );
    14321486        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;
    14471487
    14481488        return mutDecl;
     
    14781518                }
    14791519        }
     1520        // TODO: Can this be updated as we go along?
     1521        mutDecl->type = makeFunctionType( mutDecl );
    14801522        return mutDecl;
    14811523}
     
    15331575        assertf( it != adapters.end(), "Could not correct floating node." );
    15341576        return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
     1577
    15351578}
    15361579
     
    15441587/// * Inserts dynamic calculation of polymorphic type layouts where needed.
    15451588struct PolyGenericCalculator final :
     1589                public BoxPass,
    15461590                public ast::WithConstTypeSubstitution,
    15471591                public ast::WithDeclsToAdd<>,
     
    15511595        PolyGenericCalculator();
    15521596
     1597        void previsit( ast::ObjectDecl const * decl );
    15531598        void previsit( ast::FunctionDecl const * decl );
    15541599        void previsit( ast::TypedefDecl const * decl );
     
    15571602        ast::StructDecl const * previsit( ast::StructDecl const * decl );
    15581603        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
     1604        void previsit( ast::PointerType const * type );
     1605        void previsit( ast::FunctionType const * type );
    15591606        ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
    15601607        ast::Expr const * postvisit( ast::MemberExpr const * expr );
     
    15881635        /// C sizeof().
    15891636        ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
     1637
    15901638        /// Enters a new scope for type-variables,
    15911639        /// adding the type variables from the provided type.
    15921640        void beginTypeScope( ast::Type const * );
    1593 
    1594         /// The type variables and polymorphic parameters currently in scope.
    1595         TypeVarMap scopeTypeVars;
     1641        /// Enters a new scope for known layouts and offsets, and queues exit calls.
     1642        void beginGenericScope();
     1643
    15961644        /// Set of generic type layouts known in the current scope,
    15971645        /// indexed by sizeofName.
     
    16041652        /// If the argument of an AddressExpr is MemberExpr, it is stored here.
    16051653        ast::MemberExpr const * addrMember = nullptr;
     1654        /// Used to avoid recursing too deep in type declarations.
     1655        bool expect_func_type = false;
    16061656};
    16071657
     
    16251675}
    16261676
     1677void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
     1678        beginTypeScope( decl->type );
     1679}
     1680
    16271681void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
    1628         GuardScope( *this );
     1682        beginGenericScope();
    16291683        beginTypeScope( decl->type );
    16301684}
     
    16421696                ast::TypeDecl const * decl ) {
    16431697        ast::Type const * base = decl->base;
    1644         if ( nullptr == base ) return decl;
     1698        if ( nullptr == base) return decl;
    16451699
    16461700        // Add size/align variables for opaque type declarations.
     
    16671721        alignDecl->accept( *visitor );
    16681722
    1669         // A little trick to replace this with two declarations.
    1670         // Adding after makes sure that there is no conflict with adding stmts.
     1723        // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
     1724        // can occur at global scope.
    16711725        declsToAddAfter.push_back( alignDecl );
     1726        // replace with sizeDecl.
    16721727        return sizeDecl;
    16731728}
     
    16871742}
    16881743
     1744void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
     1745        beginTypeScope( type );
     1746}
     1747
     1748void 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 ) {
    16891761ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
    16901762        ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
     
    16941766
    16951767        // Change initialization of a polymorphic value object to allocate via a
    1696         // variable-length-array (alloca cannot be safely used in loops).
     1768        // variable-length-array (alloca was previouly used, but it cannot be
     1769        // safely used in loops).
    16971770        ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
    16981771                bufNamer.newName(),
     
    21752248}
    21762249
     2250void 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
    21772258// --------------------------------------------------------------------------
    2178 /// Removes unneeded or incorrect type information.
     2259/// No common theme found.
    21792260/// * Replaces initialization of polymorphic values with alloca.
    21802261/// * Replaces declaration of dtype/ftype with appropriate void expression.
     
    21822263/// * Strips fields from generic structure declarations.
    21832264struct Eraser final :
     2265                public BoxPass,
    21842266                public ast::WithGuards {
    21852267        void guardTypeVarMap( ast::Type const * type ) {
     
    21962278        void previsit( ast::PointerType const * type );
    21972279        void previsit( ast::FunctionType const * type );
    2198 public:
    2199         TypeVarMap scopeTypeVars;
    22002280};
    22012281
  • src/GenPoly/FindFunction.cc

    rfc12f05 r0030b508  
    2020#include "AST/Pass.hpp"                 // for Pass
    2121#include "AST/Type.hpp"
     22#include "Common/PassVisitor.h"         // for PassVisitor
    2223#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::iterator
    2324#include "GenPoly/GenPoly.h"            // for TyVarMap
    2425#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...
    2529
    2630namespace 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        }
    2793
    2894namespace {
     
    88154void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) {
    89155        GuardScope( typeVars );
     156        //handleForall( type->forall );
    90157}
    91158
     
    97164        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false );
    98165        type->accept( pass );
     166        //(void)type;
     167        //(void)functions;
     168        //(void)typeVars;
     169        //(void)predicate;
    99170}
    100171
     
    104175        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true );
    105176        return type->accept( pass );
     177        //(void)functions;
     178        //(void)typeVars;
     179        //(void)predicate;
     180        //return type;
    106181}
    107182
  • src/GenPoly/FindFunction.h

    rfc12f05 r0030b508  
    1616#pragma once
    1717
     18#include <list>       // for list
     19
    1820#include "GenPoly.h"  // for TyVarMap
    1921
     22class FunctionType;
     23class Type;
     24
    2025namespace 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 );
    2132
    2233typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & );
  • src/GenPoly/GenPoly.cc

    rfc12f05 r0030b508  
    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
    3135
    3236using namespace std;
     
    3539        namespace {
    3640                /// 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
    3750                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) {
    3851                        for ( auto &param : params ) {
     
    4558
    4659                /// 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
    4769                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) {
    4870                        for ( auto & param : params ) {
     
    5577
    5678                /// 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
    5788                bool hasDynParams(
    5889                                const std::vector<ast::ptr<ast::Expr>> & params,
     
    6899                        return false;
    69100                }
     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;
    70139        }
    71140
     
    77146                }
    78147                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;
    79163        }
    80164
     
    94178        }
    95179
     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
    96197const ast::Type * isPolyType( const ast::Type * type,
    97198                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    110211}
    111212
     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
    112229const ast::BaseInstType * isDynType(
    113230                const ast::Type * type, const TypeVarMap & typeVars,
     
    132249}
    133250
     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
    134257const ast::BaseInstType *isDynRet(
    135258                const ast::FunctionType * type, const TypeVarMap & typeVars ) {
     
    139262}
    140263
     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
    141272const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) {
    142273        if ( func->returns.empty() ) return nullptr;
    143274
    144         TypeVarMap forallTypes;
     275        TypeVarMap forallTypes = { ast::TypeData() };
    145276        makeTypeVarMap( func, forallTypes );
    146277        return isDynType( func->returns.front(), forallTypes );
    147278}
     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        }
    148294
    149295bool needsAdapter(
     
    158304        return false;
    159305}
     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        }
    160324
    161325const ast::Type * isPolyPtr(
     
    169333        return nullptr;
    170334}
     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        }
    171369
    172370ast::Type const * hasPolyBase(
     
    190388}
    191389
     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
    192431        const ast::FunctionType * getFunctionType( const ast::Type * ty ) {
    193432                if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) {
     
    198437        }
    199438
     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
    200478        namespace {
    201479                /// Checks if is a pointer to D
     
    210488                inline D const * as( B const * p ) {
    211489                        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                        }
    212506                }
    213507
     
    221515                }
    222516
     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
    223537                bool paramListsPolyCompatible(
    224538                                std::vector<ast::ptr<ast::Expr>> const & lparams,
     
    245559                        return true;
    246560                }
     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
    247651        }
    248652
     
    359763}
    360764
     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
    361775bool needsBoxing( const ast::Type * param, const ast::Type * arg,
    362776                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    372786        return !isPolyType( newType );
    373787}
     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        }
    374796
    375797bool needsBoxing(
     
    379801        const ast::FunctionType * function = getFunctionType( expr->func->result );
    380802        assertf( function, "ApplicationExpr has non-function type: %s", toString( expr->func->result ).c_str() );
    381         TypeVarMap exprTyVars;
     803        TypeVarMap exprTyVars = { ast::TypeData() };
    382804        makeTypeVarMap( function, exprTyVars );
    383805        return needsBoxing( param, arg, exprTyVars, subst );
    384806}
    385807
     808        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
     809                tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
     810        }
     811
    386812void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) {
    387813        typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) );
     
    391817        typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) );
    392818}
     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        }
    393829
    394830void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) {
     
    410846}
    411847
     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
    412855} // namespace GenPoly
    413856
  • src/GenPoly/GenPoly.h

    rfc12f05 r0030b508  
    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
    2527
    2628namespace ast {
     
    3032namespace GenPoly {
    3133
    32         struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> {
    33                 TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {}
    34         };
     34        typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
     35        using TypeVarMap = ErasableScopedMap< ast::TypeEnvKey, ast::TypeData >;
    3536
    3637        /// 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 );
    3740        const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * );
    3841
    3942        /// 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 );
    4044        const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);
    4145
    4246        /// 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 );
    4348        const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr );
    4449
    4550        /// 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 );
    4652        const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 );
    4753
    4854        /// true iff function has dynamic-layout return type under the given type variable map
     55        ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );
    4956        const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars );
    5057
    5158        /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
     59        ReferenceToType *isDynRet( FunctionType *function );
    5260        const ast::BaseInstType *isDynRet( const ast::FunctionType * func );
    5361
    5462        /// 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 );
    5564        bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars );
    5665
     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
    5769        /// 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 );
    5871        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 );
    5976
    6077        /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise;
    6178        /// 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 );
    6280        const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 );
    6381
     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
    6490        /// 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 );
    6592        const ast::FunctionType * getFunctionType( const ast::Type * ty );
    6693
     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
    6798        /// true iff types are structurally identical, where TypeInstType's match any type.
     99        bool typesPolyCompatible( Type *aty, Type *bty );
    68100        bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs );
    69101
    70102        /// true if arg requires boxing given exprTyVars
     103        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
    71104        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst );
    72105
    73106        /// true if arg requires boxing in the call to appExpr
     107        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
    74108        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst );
    75109
    76110        /// Adds the type variable `tyVar` to `tyVarMap`
     111        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );
    77112        void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars );
    78113        void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars );
    79114
    80115        /// 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 );
    81117        void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
    82118        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 ); }
    83125
    84126        /// Gets the name of the sizeof parameter for the type, given its mangled name
     
    92134
    93135        /// 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(); }
    94137        inline std::string layoutofName( ast::AggregateDecl const * decl ) {
    95138                return std::string( "_layoutof_" ) + decl->name;
  • src/GenPoly/ScrubTyVars.cc

    rfc12f05 r0030b508  
    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
    2327
    2428namespace 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        }
    25116
    26117namespace {
  • src/GenPoly/ScrubTyVars.h

    rfc12f05 r0030b508  
    1919
    2020#include "AST/Fwd.hpp"        // for Node
     21#include "Common/PassVisitor.h"
    2122#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
     26class AlignofExpr;
     27class Expression;
     28class SizeofExpr;
    2229
    2330namespace 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        }
    24110
    25111// ScrubMode and scrubTypeVarsBase are internal.
  • src/GenPoly/SpecializeNew.cpp

    rfc12f05 r0030b508  
    2323#include "GenPoly/GenPoly.h"             // for getFunctionType
    2424#include "ResolvExpr/FindOpenVars.h"     // for findOpenVars
     25#include "ResolvExpr/TypeEnvironment.h"  // for FirstOpen, FirstClosed
    2526
    2627namespace GenPoly {
     
    8081}
    8182
    82 // The number of elements in a list, if all tuples had been flattened.
    83 size_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;
     83// The number of elements in a type if it is a flattened tuple.
     84size_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        }
    9394}
    9495
    9596// Find the total number of components in a parameter list.
    9697size_t functionParameterSize( const ast::FunctionType * type ) {
    97         return flatTypeListSize( type->params );
     98        size_t sum = 0;
     99        for ( auto param : type->params ) {
     100                sum += flatTupleSize( param );
     101        }
     102        return sum;
    98103}
    99104
  • src/GenPoly/module.mk

    rfc12f05 r0030b508  
    2323SRC += $(SRC_GENPOLY) \
    2424        GenPoly/BoxNew.cpp \
     25        GenPoly/Box.cc \
    2526        GenPoly/Box.h \
    2627        GenPoly/ErasableScopedMap.h \
     
    2829        GenPoly/FindFunction.h \
    2930        GenPoly/InstantiateGenericNew.cpp \
     31        GenPoly/InstantiateGeneric.cc \
    3032        GenPoly/InstantiateGeneric.h \
    3133        GenPoly/LvalueNew.cpp \
     34        GenPoly/Lvalue.cc \
    3235        GenPoly/ScopedSet.h \
    3336        GenPoly/ScrubTyVars.cc \
    3437        GenPoly/ScrubTyVars.h \
     38        GenPoly/Specialize.cc \
    3539        GenPoly/SpecializeNew.cpp \
    3640        GenPoly/Specialize.h
  • src/InitTweak/FixGlobalInit.cc

    rfc12f05 r0030b508  
    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
    2236#include "AST/Expr.hpp"
    2337#include "AST/Node.hpp"
    2438#include "AST/Pass.hpp"
    25 #include "Common/UniqueName.h"     // for UniqueName
    26 #include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    2739
    2840namespace 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
    2958        class GlobalFixer_new : public ast::WithShortCircuiting {
    3059        public:
     
    4170        };
    4271
     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        }
     110
    43111        void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
    44112                ast::Pass<GlobalFixer_new> fixer;
     
    70138
    71139                        translationUnit.decls.emplace_back(destroyFunction);
     140                } // if
     141        }
     142
     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;
    72176                } // if
    73177        }
     
    103207        }
    104208
     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
    105217} // namespace InitTweak
    106218
  • src/InitTweak/FixInitNew.cpp

    rfc12f05 r0030b508  
    3333#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3434
    35 bool ctordtorp = false; // print all debug
    36 bool ctorp = false; // print ctor debug
    37 bool cpctorp = false; // print copy ctor debug
    38 bool dtorp = false; // print dtor debug
     35extern bool ctordtorp; // print all debug
     36extern bool ctorp; // print ctor debug
     37extern bool cpctorp; // print copy ctor debug
     38extern bool dtorp; // 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
    180183        InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {}
    181184
     
    191194        ast::Pass<LabelFinder> & finder;
    192195        LabelFinder::LabelMap & labelVars;
     196        OrderedDeclsStack reverseDeclOrder;
    193197};
    194198
  • src/InitTweak/GenInit.cc

    rfc12f05 r0030b508  
    2929#include "CompilationState.h"
    3030#include "CodeGen/OperatorTable.h"
     31#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
    3132#include "Common/SemanticError.h"      // for SemanticError
    3233#include "Common/ToString.hpp"         // for toCString
     
    3738#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
    3839#include "ResolvExpr/Resolver.h"
     40#include "SymTab/Autogen.h"            // for genImplicitCall
    3941#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4042#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
    4152#include "Tuples/Tuples.h"             // for maybeImpure
    4253#include "Validate/FindSpecialDecls.h" // for SizeType
    4354
    4455namespace 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        }
    45298
    46299namespace {
     
    273526        }
    274527
     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
    275590        bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
    276591                // references are never constructed
     
    332647        void ManagedTypes_new::endScope() { managedTypes.endScope(); }
    333648
     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
    334660        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
    335661                assertf(objDecl, "genCtorDtor passed null objDecl");
    336662                InitExpander_new srcParam(arg);
    337663                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 );
    338738        }
    339739
  • src/InitTweak/GenInit.h

    rfc12f05 r0030b508  
    2222#include "Common/CodeLocation.h"
    2323#include "GenPoly/ScopedSet.h" // for ScopedSet
     24#include "SynTree/SynTree.h"   // for Visitor Nodes
    2425
    2526namespace InitTweak {
    2627        /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
     28        void genInit( std::list< Declaration * > & translationUnit );
    2729        void genInit( ast::TranslationUnit & translationUnit );
    2830
    2931        /// Converts return statements into copy constructor calls on the hidden return variable.
    3032        /// This pass must happen before auto-gen.
     33        void fixReturnStatements( std::list< Declaration * > & translationUnit );
    3134        void fixReturnStatements( ast::TranslationUnit & translationUnit );
    3235
    3336        /// 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 );
    3438        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3539
    3640        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
     41        ConstructorInit * genCtorInit( ObjectDecl * objDecl );
    3742        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        };
    3857
    3958        class ManagedTypes_new {
  • src/InitTweak/InitTweak.cc

    rfc12f05 r0030b508  
    2929#include "AST/Type.hpp"
    3030#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
     31#include "Common/PassVisitor.h"
    3132#include "Common/SemanticError.h"  // for SemanticError
    3233#include "Common/UniqueName.h"     // for UniqueName
     
    3536#include "InitTweak.h"
    3637#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
    3750#include "Tuples/Tuples.h"         // for Tuples::isTtype
    3851
    3952namespace InitTweak {
    4053        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
    4191                struct HasDesignations_new : public ast::WithShortCircuiting {
    4292                        bool result = false;
     
    57107                };
    58108
    59                 struct InitDepthChecker_new {
     109                struct InitDepthChecker_new : public ast::WithGuards {
    60110                        bool result = true;
    61111                        const ast::Type * type;
     
    69119                                maxDepth++;
    70120                        }
    71                         void previsit( ast::ListInit const * ) {
     121                        void previsit( ListInit * ) {
    72122                                curDepth++;
     123                                GuardAction( [this]() { curDepth--; } );
    73124                                if ( curDepth > maxDepth ) result = false;
    74125                        }
    75                         void postvisit( ast::ListInit const * ) {
    76                                 curDepth--;
    77                         }
     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;
    78134                };
    79135
     
    88144
    89145        } // 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        }
    90164
    91165        bool isDesignated( const ast::Init * init ) {
     
    106180        return std::move( flattener.core.argList );
    107181}
     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        }
    108366
    109367class InitExpander_new::ExpanderImpl {
     
    277535}
    278536
     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
    279544        const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
    280545                assertf( ftype, "getTypeofThis: nullptr ftype" );
     
    287552        }
    288553
     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
    289561        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
    290562                assertf( func, "getParamThis: nullptr ftype" );
     
    292564                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
    293565                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 );
    294579        }
    295580
     
    308593        }
    309594
     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
    310619        struct CallFinder_new final {
    311620                std::vector< const ast::Expr * > matches;
     
    325634        };
    326635
     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
    327642        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    328643                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
     
    331646        }
    332647
     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
    333655        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
    334723                template <typename Predicate>
    335724                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
     
    337726                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    338727                }
     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                });
    339739        }
    340740
     
    349749                        return false;
    350750                });
     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 } );
    351876        }
    352877
     
    380905                return app;
    381906        }
     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        };
    382947
    383948        struct ConstExprChecker_new : public ast::WithShortCircuiting {
     
    424989        };
    425990
     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
    4261010        bool isConstExpr( const ast::Expr * expr ) {
    4271011                if ( expr ) {
     
    4431027        }
    4441028
     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
    4451047bool isAssignment( const ast::FunctionDecl * decl ) {
    4461048        return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
     
    4691071        return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
    4701072}
     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        }
    4711097
    4721098        #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
     
    4771103        static const char * const data_section =  ".data" ASM_COMMENT;
    4781104        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        }
    4791112
    4801113        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
  • src/InitTweak/InitTweak.h

    rfc12f05 r0030b508  
    2222
    2323#include "AST/Fwd.hpp"        // for AST nodes
     24#include "SynTree/SynTree.h"  // for Visitor Nodes
    2425
    2526// helper functions for initialization
    2627namespace 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 );
    2733        bool isAssignment( const ast::FunctionDecl * decl );
    2834        bool isDestructor( const ast::FunctionDecl * decl );
     
    3238
    3339        /// returns the base type of the first parameter to a constructor/destructor/assignment function
     40        Type * getTypeofThis( FunctionType * ftype );
    3441        const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
    3542
    3643        /// returns the first parameter of a constructor/destructor/assignment function
     44        ObjectDecl * getParamThis( FunctionType * ftype );
    3745        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    3846
    3947        /// generate a bitwise assignment operation.
     48        ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
     49
    4050        ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    4151
    4252        /// transform Initializer into an argument list that can be passed to a call expression
     53        std::list< Expression * > makeInitList( Initializer * init );
    4354        std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
    4455
    4556        /// True if the resolver should try to construct dwt
     57        bool tryConstruct( DeclarationWithType * dwt );
    4658        bool tryConstruct( const ast::DeclWithType * dwt );
    4759
    4860        /// True if the type can have a user-defined constructor
     61        bool isConstructable( Type * t );
    4962        bool isConstructable( const ast::Type * t );
    5063
    5164        /// True if the Initializer contains designations
     65        bool isDesignated( Initializer * init );
    5266        bool isDesignated( const ast::Init * init );
    5367
    5468        /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
    5569        /// type, where the depth of its type is the number of nested ArrayTypes + 1
     70        bool checkInitDepth( ObjectDecl * objDecl );
    5671        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 );
    5779
    5880        /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
    5981        /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
    6082        /// Currently has assertions that make it less than fully general.
     83        bool isIntrinsicSingleArgCallStmt( Statement * stmt );
    6184        bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
    6285
     86        /// True if stmt is a call statement where the function called is intrinsic.
     87        bool isIntrinsicCallStmt( Statement * stmt );
     88
    6389        /// get all Ctor/Dtor call expressions from a Statement
     90        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    6491        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
    6592
     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
    66108        /// returns true if expr is trivially a compile-time constant
     109        bool isConstExpr( Expression * expr );
     110        bool isConstExpr( Initializer * init );
     111
    67112        bool isConstExpr( const ast::Expr * expr );
    68113        bool isConstExpr( const ast::Init * init );
     
    77122        ///    .section .data#,"a"
    78123        /// to avoid assembler warning "ignoring changed section attributes for .data"
     124        void addDataSectionAttribute( ObjectDecl * objDecl );
     125
    79126        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        };
    80157
    81158        class InitExpander_new {
  • src/InitTweak/module.mk

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

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

    rfc12f05 r0030b508  
    2222      CompilationState.cc \
    2323      CompilationState.h \
     24      MakeLibCfa.cc \
    2425          MakeLibCfaNew.cpp \
    2526        MakeLibCfa.h
     
    4142include AST/module.mk
    4243include CodeGen/module.mk
     44include CodeTools/module.mk
    4345include Concurrency/module.mk
    4446include Common/module.mk
     
    4951include ResolvExpr/module.mk
    5052include SymTab/module.mk
     53include SynTree/module.mk
    5154include Tuples/module.mk
    5255include Validate/module.mk
    5356include Virtual/module.mk
    5457
    55 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/AST/Type.hpp
     58$(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h
    5659
    5760$(srcdir)/AST/Type.hpp : BasicTypes-gen.cc
  • src/Parser/RunParser.cpp

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

    rfc12f05 r0030b508  
    503503} // build_corun
    504504
    505 ast::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 
    524505// Local Variables: //
    525506// tab-width: 4 //
  • src/Parser/StatementNode.h

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

    rfc12f05 r0030b508  
    4848using namespace std;
    4949
     50#include "SynTree/Type.h"                               // for Type
    5051#include "DeclarationNode.h"                            // for DeclarationNode, ...
    5152#include "ExpressionNode.h"                             // for ExpressionNode, ...
     
    5758#include "Common/SemanticError.h"                                               // error_str
    5859#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
     60
     61#include "SynTree/Attribute.h"                                                  // for Attribute
    5962
    6063// lex uses __null in a boolean context, it's fine.
     
    17231726cofor_statement:
    17241727        COFOR '(' for_control_expression_list ')' statement
    1725                 { $$ = new StatementNode( build_cofor( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
     1728                { SemanticError( yylloc, "cofor statement is currently unimplemented." ); $$ = nullptr; }
    17261729        ;
    17271730
     
    21662169type_qualifier_name:
    21672170        CONST
    2168                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Const ); }
     2171                { $$ = DeclarationNode::newTypeQualifier( Type::Const ); }
    21692172        | RESTRICT
    2170                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Restrict ); }
     2173                { $$ = DeclarationNode::newTypeQualifier( Type::Restrict ); }
    21712174        | VOLATILE
    2172                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Volatile ); }
     2175                { $$ = DeclarationNode::newTypeQualifier( Type::Volatile ); }
    21732176        | ATOMIC
    2174                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Atomic ); }
     2177                { $$ = DeclarationNode::newTypeQualifier( Type::Atomic ); }
    21752178        | forall
    21762179                { $$ = DeclarationNode::newForall( $1 ); }
     
    22032206storage_class:
    22042207        EXTERN
    2205                 { $$ = DeclarationNode::newStorageClass( ast::Storage::Extern ); }
     2208                { $$ = DeclarationNode::newStorageClass( Type::Extern ); }
    22062209        | STATIC
    2207                 { $$ = DeclarationNode::newStorageClass( ast::Storage::Static ); }
     2210                { $$ = DeclarationNode::newStorageClass( Type::Static ); }
    22082211        | AUTO
    2209                 { $$ = DeclarationNode::newStorageClass( ast::Storage::Auto ); }
     2212                { $$ = DeclarationNode::newStorageClass( Type::Auto ); }
    22102213        | REGISTER
    2211                 { $$ = DeclarationNode::newStorageClass( ast::Storage::Register ); }
     2214                { $$ = DeclarationNode::newStorageClass( Type::Register ); }
    22122215        | THREADLOCALGCC                                                                                // GCC
    2213                 { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalGcc ); }
     2216                { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalGcc ); }
    22142217        | THREADLOCALC11                                                                                // C11
    2215                 { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalC11 ); }
     2218                { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalC11 ); }
    22162219                // Put function specifiers here to simplify parsing rules, but separate them semantically.
    22172220        | INLINE                                                                                        // C99
    2218                 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Inline ); }
     2221                { $$ = DeclarationNode::newFuncSpecifier( Type::Inline ); }
    22192222        | FORTRAN                                                                                       // C99
    2220                 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Fortran ); }
     2223                { $$ = DeclarationNode::newFuncSpecifier( Type::Fortran ); }
    22212224        | NORETURN                                                                                      // C11
    2222                 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Noreturn ); }
     2225                { $$ = DeclarationNode::newFuncSpecifier( Type::Noreturn ); }
    22232226        ;
    22242227
     
    37143717                { $$ = $1->addQualifiers( $2 ); }
    37153718        | '&' MUTEX paren_identifier attribute_list_opt
    3716                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3719                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37173720        | identifier_parameter_ptr
    37183721        | identifier_parameter_array attribute_list_opt
     
    37643767                { $$ = $1->addQualifiers( $2 ); }
    37653768        | '&' MUTEX typedef_name attribute_list_opt
    3766                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3769                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37673770        | type_parameter_ptr
    37683771        | type_parameter_array attribute_list_opt
     
    39383941        abstract_parameter_ptr
    39393942        | '&' MUTEX attribute_list_opt
    3940                 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }
     3943                { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }
    39413944        | abstract_parameter_array attribute_list_opt
    39423945                { $$ = $1->addQualifiers( $2 ); }
  • src/ResolvExpr/AdjustExprType.cc

    rfc12f05 r0030b508  
    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
    2127
    2228namespace ResolvExpr {
     29
     30namespace {
     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
     89void 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
     95void adjustExprType( Type *& type ) {
     96        TypeEnvironment env;
     97        SymTab::Indexer indexer;
     98        adjustExprType( type, env, indexer );
     99}
    23100
    24101namespace {
  • src/ResolvExpr/CandidateFinder.cpp

    rfc12f05 r0030b508  
    5757
    5858/// Unique identifier for matching expression resolutions to their requesting expression
    59 ast::UniqueId globalResnSlot = 0;
     59UniqueId globalResnSlot = 0;
    6060
    6161namespace {
     
    686686        void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) {
    687687                // Set need bindings for any unbound assertions
    688                 ast::UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
     688                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

    rfc12f05 r0030b508  
    2626#include "ResolvExpr/ConversionCost.h"   // for conversionCost
    2727#include "ResolvExpr/PtrsCastable.hpp"   // for ptrsCastable
     28#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment, EqvClass
    2829#include "ResolvExpr/typeops.h"          // for ptrsCastable
    2930#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
    3034
    3135#if 0
     
    3640
    3741namespace 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        }
    38142
    39143namespace {
     
    96200} // anonymous namespace
    97201
     202
     203
    98204Cost castCost(
    99205        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
  • src/ResolvExpr/CommonType.cc

    rfc12f05 r0030b508  
    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
    2531#include "Unify.h"                       // for unifyExact, WidenMode
    2632#include "typeops.h"                     // for isFtype
     
    3541
    3642namespace 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        }
    37183
    38184        // GENERATED START, DO NOT EDIT
    39185        // GENERATED BY BasicTypes-gen.cc
    40         #define BT ast::BasicType::
    41         static const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
     186        #define BT BasicType::
     187        static const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
    42188                /*                                      B                       C                      SC                      UC                      SI                     SUI
    43189                                                        I                      UI                      LI                     LUI                     LLI                    LLUI
     
    339485        // GENERATED END
    340486        static_assert(
    341                 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
     487                sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
    342488                "Each basic type kind should have a corresponding row in the combined type matrix"
    343489        );
     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        }
    344674
    345675        class CommonType_new final : public ast::WithShortCircuiting {
     
    370700                                else if (!widen.first) kind = basic->kind; // widen.second
    371701                                else if (!widen.second) kind = basic2->kind;
    372                                 else kind = commonTypes[ basic->kind ][ basic2->kind ];
     702                                else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
    373703                                // xxx - what does qualifiers even do here??
    374704                                if ( (basic->qualifiers >= basic2->qualifiers || widen.first)
     
    389719                                } else {
    390720                                        #warning remove casts when `commonTypes` moved to new AST
    391                                         ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
     721                                        ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
    392722                                        if (
    393723                                                ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
  • src/ResolvExpr/CommonType.hpp

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

    rfc12f05 r0030b508  
    2121
    2222#include "ResolvExpr/Cost.h"             // for Cost
     23#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2324#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    2425#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
    2530
    2631namespace 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
    2743
    2844#if 0
     
    3147#define PRINT(x)
    3248#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        }
    33200
    34201        // GENERATED START, DO NOT EDIT
     
    59226        // GENERATED START, DO NOT EDIT
    60227        // GENERATED BY BasicTypes-gen.cc
    61         static const int costMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
     228        static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
    62229                /*               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 */
    63230                /*      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, },
     
    101268        // GENERATED END
    102269        static_assert(
    103                 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
     270                sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
    104271                "Missing row in the cost matrix"
    105272        );
     
    107274        // GENERATED START, DO NOT EDIT
    108275        // GENERATED BY BasicTypes-gen.cc
    109         static const int signMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
     276        static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
    110277                /*               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 */
    111278                /*      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, },
     
    148315        // GENERATED END
    149316        static_assert(
    150                 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
     317                sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
    151318                "Missing row in the sign matrix"
    152319        );
     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        }
    153502
    154503namespace {
  • src/ResolvExpr/ConversionCost.h

    rfc12f05 r0030b508  
    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
    2427
    2528namespace SymTab {
     
    2932namespace ResolvExpr {
    3033        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 );
    3179
    3280// Some function pointer types, differ in return type.
  • src/ResolvExpr/CurrentObject.cc

    rfc12f05 r0030b508  
    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
    3541
    3642#if 0
     
    3945#define PRINT(x)
    4046#endif
     47
     48namespace 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
    41593
    42594namespace ast {
     
    5121064                                        } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
    5131065                                                auto nexpr = dynamic_cast< const NameExpr *>( expr );
     1066                                                auto res = eval( nexpr );
    5141067                                                for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
    5151068                                                        if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
     
    5171070                                                                d2.emplace_back( new VariableExpr{ expr->location, field } );
    5181071                                                                newDesigAlts.emplace_back( std::move( d2 ) );
     1072                                                                // newTypes.emplace_back( field->type );
    5191073                                                                newTypes.emplace_back( at->base );
    5201074                                                        }
    5211075                                                }
     1076
     1077                                                // d.emplace_back( expr );
     1078                                                // newDesigAlts.emplace_back( d );
     1079                                                // newTypes.emplace_back( at->base );
    5221080                                        }
    5231081
  • src/ResolvExpr/FindOpenVars.cc

    rfc12f05 r0030b508  
    1616#include "FindOpenVars.h"
    1717
     18#include <list>                   // for _List_const_iterator, list<>::const...
     19#include <map>                    // for map<>::mapped_type
     20
    1821#include "AST/Pass.hpp"
    1922#include "AST/Type.hpp"
    2023#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
    2127
    2228#include <iostream>
    2329
    2430namespace 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        }
    25100
    26101        namespace {
  • src/ResolvExpr/FindOpenVars.h

    rfc12f05 r0030b508  
    1717
    1818#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
     19#include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
    1920
     21class Type;
    2022namespace ast {
    2123        class Type;
     
    2325
    2426namespace 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
    2530        enum FirstMode { FirstClosed, FirstOpen };
    2631
  • src/ResolvExpr/PolyCost.cc

    rfc12f05 r0030b508  
    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
    2024
    2125namespace 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        }
    2259
    2360// TODO: When the old PolyCost is torn out get rid of the _new suffix.
  • src/ResolvExpr/PtrsAssignable.cc

    rfc12f05 r0030b508  
    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
    2126
    2227namespace 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 * ) {}
    23113
    24114// TODO: Get rid of the `_new` suffix when the old version is removed.
  • src/ResolvExpr/PtrsCastable.cc

    rfc12f05 r0030b508  
    2020#include "AST/Type.hpp"
    2121#include "AST/TypeEnvironment.hpp"
     22#include "Common/PassVisitor.h"
    2223#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
    2329
    2430namespace 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        }
    25169
    26170namespace {
  • src/ResolvExpr/RenameVars.cc

    rfc12f05 r0030b508  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
     23#include "Common/PassVisitor.h"
    2324#include "Common/ScopedMap.h"
    2425#include "Common/SemanticError.h"  // for SemanticError
    2526#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
    2631
    2732#include "AST/Copy.hpp"
     
    4449                }
    4550
     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
    4658                void nextUsage() {
    4759                        ++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                        }
    4882                }
    4983
     
    101135        RenamingData renaming;
    102136
     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
    103150        struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
    104151                RenameMode mode;
     
    130177
    131178} // namespace
     179
     180void renameTyVars( Type * t ) {
     181        PassVisitor<RenameVars_old> renamer;
     182        t->accept( renamer );
     183}
    132184
    133185const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
  • src/ResolvExpr/RenameVars.h

    rfc12f05 r0030b508  
    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
    1825namespace ast {
    1926        class Type;
     
    2128
    2229namespace 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
    2333        enum RenameMode {
    2434                GEN_USAGE, // for type in VariableExpr
  • src/ResolvExpr/ResolveTypeof.cc

    rfc12f05 r0030b508  
    2424#include "AST/Type.hpp"
    2525#include "AST/TypeEnvironment.hpp"
     26#include "Common/PassVisitor.h"   // for PassVisitor
    2627#include "Common/utility.h"       // for copy
    2728#include "InitTweak/InitTweak.h"  // for isConstExpr
     
    2930#include "Resolver.h"  // for resolveInVoidContext
    3031#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
     36namespace SymTab {
     37class Indexer;
     38}  // namespace SymTab
    3139
    3240namespace ResolvExpr {
     41namespace {
     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
     54class 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}
    33119
    34120namespace {
  • src/ResolvExpr/Resolver.cc

    rfc12f05 r0030b508  
    1919#include <vector>                        // for vector
    2020
     21#include "Alternative.h"                 // for Alternative, AltList
     22#include "AlternativeFinder.h"           // for AlternativeFinder, resolveIn...
    2123#include "Candidate.hpp"
    2224#include "CandidateFinder.hpp"
     
    3840#include "Common/Eval.h"                 // for eval
    3941#include "Common/Iterate.hpp"            // for group_iterate
     42#include "Common/PassVisitor.h"          // for PassVisitor
    4043#include "Common/SemanticError.h"        // for SemanticError
    4144#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    4245#include "Common/ToString.hpp"           // for toCString
    43 #include "Common/UniqueName.h"           // for UniqueName
    4446#include "InitTweak/GenInit.h"
    4547#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
    4651#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
    4759#include "Tuples/Tuples.h"
    4860#include "Validate/FindSpecialDecls.h"   // for SizeType
     
    5163
    5264namespace 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
    53604        template< typename iterator_t >
    54605        inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) {
     
    59610                return it != end;
    60611        }
     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        ///////////////////////////////////////////////////////////////////////////
    61970
    62971        namespace {
  • src/ResolvExpr/SatisfyAssertions.cpp

    rfc12f05 r0030b508  
    4646#include "SymTab/Mangler.h"
    4747
     48
     49
    4850namespace ResolvExpr {
    4951
    5052// in CandidateFinder.cpp; unique ID for assertion satisfaction
    51 extern ast::UniqueId globalResnSlot;
     53extern UniqueId globalResnSlot;
    5254
    5355namespace {
     
    296298                        if ( !expr->inferred.hasSlots() ) return expr;
    297299                        // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
    298                         std::vector<ast::UniqueId> missingSlots;
     300                        std::vector<UniqueId> missingSlots;
    299301                        // find inferred parameters for resolution slots
    300302                        ast::InferredParams * newInferred = new ast::InferredParams();
    301                         for ( ast::UniqueId slot : expr->inferred.resnSlots() ) {
     303                        for ( UniqueId slot : expr->inferred.resnSlots() ) {
    302304                                // fail if no matching assertions found
    303305                                auto it = inferred.find( slot );
  • src/ResolvExpr/SpecCost.cc

    rfc12f05 r0030b508  
    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"
    2327
    2428namespace 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        }
    25118
    26119namespace {
  • src/ResolvExpr/Unify.cc

    rfc12f05 r0030b508  
    3333#include "AST/TypeEnvironment.hpp"
    3434#include "Common/Eval.h"            // for eval
     35#include "Common/PassVisitor.h"     // for PassVisitor
    3536#include "CommonType.hpp"           // for commonType
    3637#include "FindOpenVars.h"           // for findOpenVars
    3738#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
    3846#include "Tuples/Tuples.h"          // for isTtype
     47#include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
    3948#include "typeops.h"                // for flatten, occurs
    4049
     
    4352}
    4453
     54namespace SymTab {
     55        class Indexer;
     56}  // namespace SymTab
     57
    4558// #define DEBUG
    4659
    4760namespace ResolvExpr {
     61
     62// Template Helpers:
     63template< typename Iterator1, typename Iterator2 >
     64bool 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
     75template< typename Iterator1, typename Iterator2 >
     76bool 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        }
    48151
    49152        bool typesCompatible(
     
    62165
    63166                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;
    64183        }
    65184
     
    99218                        subSecond,
    100219                        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                }
    101734        }
    102735
  • src/ResolvExpr/Unify.h

    rfc12f05 r0030b508  
    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
    2225#include "WidenMode.h"              // for WidenMode
     26
     27class Type;
     28class TypeInstType;
     29namespace SymTab {
     30        class Indexer;
     31}
    2332
    2433namespace ast {
     
    2837
    2938namespace ResolvExpr {
     39
     40bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
     41bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
     42bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
     43bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
     44
     45bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
     46bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
     47
     48inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
     49        TypeEnvironment env;
     50        return typesCompatible( t1, t2, indexer, env );
     51}
     52
     53inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
     54        TypeEnvironment env;
     55        return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
     56}
    3057
    3158bool unify(
     
    5885        const ast::TypeEnvironment & env = {} );
    5986
     87/// Creates the type represented by the list of returnVals in a FunctionType.
     88/// The caller owns the return value.
     89Type * extractResultType( FunctionType * functionType );
    6090/// Creates or extracts the type represented by returns in a `FunctionType`.
    6191ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
  • src/ResolvExpr/module.mk

    rfc12f05 r0030b508  
    1818      ResolvExpr/AdjustExprType.cc \
    1919      ResolvExpr/AdjustExprType.hpp \
     20      ResolvExpr/Alternative.cc \
     21      ResolvExpr/AlternativeFinder.cc \
     22      ResolvExpr/AlternativeFinder.h \
     23      ResolvExpr/Alternative.h \
    2024      ResolvExpr/Candidate.cpp \
    2125      ResolvExpr/CandidateFinder.cpp \
     
    3135      ResolvExpr/CurrentObject.cc \
    3236      ResolvExpr/CurrentObject.h \
     37      ResolvExpr/ExplodedActual.cc \
     38      ResolvExpr/ExplodedActual.h \
    3339      ResolvExpr/ExplodedArg.cpp \
    3440      ResolvExpr/ExplodedArg.hpp \
    3541      ResolvExpr/FindOpenVars.cc \
    3642      ResolvExpr/FindOpenVars.h \
     43      ResolvExpr/Occurs.cc \
    3744      ResolvExpr/PolyCost.cc \
    3845      ResolvExpr/PolyCost.hpp \
     
    4350      ResolvExpr/RenameVars.cc \
    4451      ResolvExpr/RenameVars.h \
     52      ResolvExpr/ResolveAssertions.cc \
     53      ResolvExpr/ResolveAssertions.h \
    4554      ResolvExpr/Resolver.cc \
    4655      ResolvExpr/Resolver.h \
     
    5261      ResolvExpr/SpecCost.cc \
    5362      ResolvExpr/SpecCost.hpp \
     63      ResolvExpr/TypeEnvironment.cc \
     64      ResolvExpr/TypeEnvironment.h \
    5465      ResolvExpr/typeops.h \
    5566      ResolvExpr/Unify.cc \
     
    5869
    5970SRC += $(SRC_RESOLVEXPR) \
     71        ResolvExpr/AlternativePrinter.cc \
     72        ResolvExpr/AlternativePrinter.h \
    6073        ResolvExpr/CandidatePrinter.cpp \
    6174        ResolvExpr/CandidatePrinter.hpp \
  • src/ResolvExpr/typeops.h

    rfc12f05 r0030b508  
    1919
    2020#include "AST/Type.hpp"
     21#include "SynTree/Type.h"
    2122
    2223namespace SymTab {
     
    5152                        std::copy( i.begin(), i.end(), inserter );
    5253                        *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();
    5379                }
    5480        }
     
    94120                return tupleFromTypes( tys.begin(), tys.end() );
    95121        }
     122
     123        // in TypeEnvironment.cc
     124        bool isFtype( const Type * type );
    96125} // namespace ResolvExpr
    97126
  • src/SymTab/Demangle.cc

    rfc12f05 r0030b508  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jul 19 12:52:41 2018
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Nov  6 15:59:00 2023
    13 // Update Count     : 12
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Jan 11 21:28:27 2021
     13// Update Count     : 11
    1414//
    1515
     
    1717#include <sstream>
    1818
    19 #include "AST/Pass.hpp"
    20 #include "AST/Type.hpp"
    2119#include "CodeGen/GenType.h"
    22 #include "CodeGen/OperatorTable.h"
     20#include "Common/PassVisitor.h"
    2321#include "Common/utility.h"                                                             // isPrefix
    2422#include "Mangler.h"
     23#include "SynTree/Type.h"
     24#include "SynTree/Declaration.h"
    2525
    2626#define DEBUG
     
    3131#endif
    3232
    33 namespace Mangle {
    34 
    3533namespace {
    36 
    37 struct Demangler {
    38 private:
    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;
    43 public:
    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 
    70 Demangler::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); });
     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();
     227                }
     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        }
    106317}
    107318
    108 bool 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 
    121 bool 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 
    131 bool 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
    141 bool 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 
    163 ast::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 
    184 ast::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 
    200 ast::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 
    207 ast::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 
    221 ast::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 
    228 ast::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 
    235 ast::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 
    242 ast::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 
    250 ast::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;
    272                 }
    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 
    295 bool 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 
    304 std::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
     319
     320namespace 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
    318613
    319614extern "C" {
    320615        char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) {
    321                 const std::string & demangleName = Mangle::demangle(mangleName);
     616                const std::string & demangleName = SymTab::Mangler::demangle(mangleName);
    322617                return strdup(demangleName.c_str());
    323618        }
  • src/SymTab/Demangle.h

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

    rfc12f05 r0030b508  
    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...
    2427
    2528namespace 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        }
    26103
    27104namespace {
  • src/SymTab/FixFunction.h

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

    rfc12f05 r0030b508  
    2222#include <string>                        // for string, char_traits, operator<<
    2323
    24 #include "AST/Pass.hpp"
    2524#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
     36namespace 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
    28389
    29390namespace Mangle {
     
    115476                                mangleName += std::to_string( decl->name.size() ) + decl->name;
    116477                        } // if
    117                         decl->get_type()->accept( *visitor );
     478                        maybeAccept( decl->get_type(), *visitor );
    118479                        if ( mangleOverridable && decl->linkage.is_overrideable ) {
    119480                                // want to be able to override autogenerated and intrinsic routines,
     
    161522                        printQualifiers( arrayType );
    162523                        mangleName += Encoding::array + "0";
    163                         arrayType->base->accept( *visitor );
     524                        maybeAccept( arrayType->base.get(), *visitor );
    164525                }
    165526
     
    171532                        inFunctionType = true;
    172533                        printQualifiers( refType );
    173                         refType->base->accept( *visitor );
     534                        maybeAccept( refType->base.get(), *visitor );
    174535                }
    175536
     
    200561                                        auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
    201562                                        assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    202                                         paramType->type->accept( *visitor );
     563                                        maybeAccept( paramType->type.get(), *visitor );
    203564                                }
    204565                                mangleName += "_";
     
    229590                                // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
    230591                                // are first found and prefixing with the appropriate encoding for the type class.
    231                                 assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
     592                                assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    232593                                mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    233594                        } // if
     
    261622                void Mangler_new::postvisit( const ast::QualifiedType * qualType ) {
    262623                        bool inqual = inQualifiedType;
    263                         if ( !inqual ) {
     624                        if (! inqual ) {
    264625                                // N marks the start of a qualified type
    265626                                inQualifiedType = true;
    266627                                mangleName += Encoding::qualifiedTypeStart;
    267628                        }
    268                         qualType->parent->accept( *visitor );
    269                         qualType->child->accept( *visitor );
    270                         if ( !inqual ) {
     629                        maybeAccept( qualType->parent.get(), *visitor );
     630                        maybeAccept( qualType->child.get(), *visitor );
     631                        if ( ! inqual ) {
    271632                                // E marks the end of a qualified type
    272633                                inQualifiedType = false;
     
    330691                                // these qualifiers do not distinguish the outermost type of a function parameter
    331692                                if ( type->is_const() ) {
    332                                         mangleName += Encoding::qualifiers.at( ast::CV::Const );
     693                                        mangleName += Encoding::qualifiers.at(Type::Const);
    333694                                } // if
    334695                                if ( type->is_volatile() ) {
    335                                         mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
     696                                        mangleName += Encoding::qualifiers.at(Type::Volatile);
    336697                                } // if
    337698                                // Removed due to restrict not affecting function compatibility in GCC
     
    340701                                // } // if
    341702                                if ( type->is_atomic() ) {
    342                                         mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
     703                                        mangleName += Encoding::qualifiers.at(Type::Atomic);
    343704                                } // if
    344705                        }
    345706                        if ( type->is_mutex() ) {
    346                                 mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
     707                                mangleName += Encoding::qualifiers.at(Type::Mutex);
    347708                        } // if
    348709                        if ( inFunctionType ) {
  • src/SymTab/Mangler.h

    rfc12f05 r0030b508  
    2222
    2323#include "AST/Bitfield.hpp"
     24#include "SynTree/SynTree.h"  // for Types
     25#include "SynTree/Visitor.h"  // for Visitor, maybeAccept
    2426
    2527// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
     
    3335        class Node;
    3436}
     37namespace ResolvExpr {
     38        class TypeEnvironment;
     39}
    3540
    3641namespace SymTab {
    3742        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
    3851                namespace Encoding {
    3952                        extern const std::string manglePrefix;
  • src/SymTab/ManglerCommon.cc

    rfc12f05 r0030b508  
    1515
    1616#include "Mangler.h"
    17 
    18 #include "AST/Decl.hpp"
    19 #include "AST/Type.hpp"
     17#include "SynTree/Type.h"
     18#include "SynTree/Declaration.h"
    2019
    2120namespace SymTab {
     
    4039                        //   - "Di" char32_t
    4140                        //   - "Ds" char16_t
    42                         const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {
     41                        const std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {
    4342                                "b",        // _Bool
    4443                                "c",        // char
     
    8079                        // GENERATED END
    8180                        static_assert(
    82                                 sizeof(basicTypes)/sizeof(basicTypes[0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES,
     81                                sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
    8382                                "Each basic type kind should have a corresponding mangler letter"
    8483                        );
    8584
    8685                        const std::map<int, std::string> qualifiers = {
    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" },
     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" },
    9190                        };
    9291
     
    112111                        };
    113112                        static_assert(
    114                                 sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
     113                                sizeof(typeVariables) / sizeof(typeVariables[0]) == TypeDecl::NUMBER_OF_KINDS,
    115114                                "Each type variable kind should have a corresponding mangler prefix"
    116115                        );
  • src/SymTab/demangler.cc

    rfc12f05 r0030b508  
    22#include <iostream>
    33#include <fstream>
     4using namespace std;
    45
    5 void demangleAndPrint(const std::string & mangleName) {
     6void f(const std::string & mangleName) {
    67        char * demangleName = cforall_demangle(mangleName.c_str(), 0);
    7         std::cout << mangleName << " => " << demangleName << std::endl;
     8        cout << mangleName << " => " << std::flush << demangleName << endl;
    89        free(demangleName);
    910}
    1011
    11 int main(int argc, char * argv[]) {
    12         char const * fileName = (1 < argc) ? argv[1] : "in-demangle.txt";
    13         std::ifstream in(fileName);
    14 
     12int main() {
     13        ifstream in("in-demangle.txt");
    1514        std::string 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                 }
     15        while (getline(in, line)) {
     16                if (line.empty()) { cout << "=================================" << endl; continue; }
     17                else if (line[0] == '#') continue;
     18                f(line);
    2419        }
    2520}
  • src/SymTab/module.mk

    rfc12f05 r0030b508  
    1616
    1717SRC_SYMTAB = \
     18        SymTab/Autogen.cc \
     19        SymTab/Autogen.h \
    1820        SymTab/FixFunction.cc \
    1921        SymTab/FixFunction.h \
    2022        SymTab/GenImplicitCall.cpp \
    2123        SymTab/GenImplicitCall.hpp \
     24        SymTab/Indexer.cc \
     25        SymTab/Indexer.h \
    2226        SymTab/Mangler.cc \
    2327        SymTab/ManglerCommon.cc \
    24         SymTab/Mangler.h
     28        SymTab/Mangler.h \
     29        SymTab/ValidateType.cc \
     30        SymTab/ValidateType.h
    2531
    26 SRC += $(SRC_SYMTAB)
     32SRC += $(SRC_SYMTAB) \
     33        SymTab/Validate.cc \
     34        SymTab/Validate.h
    2735
    2836SRCDEMANGLE += $(SRC_SYMTAB) \
  • src/Tuples/Explode.cc

    rfc12f05 r0030b508  
    1515
    1616#include "Explode.h"
     17#include <list>                  // for list
    1718
    1819#include "AST/Pass.hpp"          // for Pass
     20#include "SynTree/Mutator.h"     // for Mutator
     21#include "Common/PassVisitor.h"  // for PassVisitor
    1922
    2023namespace 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        }
    21109
    22110namespace {
  • src/Tuples/Explode.h

    rfc12f05 r0030b508  
    2020
    2121#include "AST/Expr.hpp"
     22#include "ResolvExpr/Alternative.h"     // for Alternative, AltList
    2223#include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
     24#include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
    2325#include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
     26#include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
     27#include "SynTree/Type.h"               // for TupleType, Type
    2428#include "Tuples.h"                     // for maybeImpure
    2529
     
    2832}
    2933
     34namespace SymTab {
     35class Indexer;
     36}  // namespace SymTab
     37
    3038namespace 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        }
    31139
    32140const ast::Expr * distributeReference( const ast::Expr * );
  • src/Tuples/TupleAssignment.cc

    rfc12f05 r0030b508  
    2828#include "AST/TypeEnvironment.hpp"
    2929#include "CodeGen/OperatorTable.h"
     30#include "Common/PassVisitor.h"
    3031#include "Common/UniqueName.h"             // for UniqueName
    3132#include "Common/utility.h"                // for splice, zipWith
     
    3334#include "InitTweak/GenInit.h"             // for genCtorInit
    3435#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
     36#include "ResolvExpr/Alternative.h"        // for AltList, Alternative
     37#include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
    3538#include "ResolvExpr/Cost.h"               // for Cost
    3639#include "ResolvExpr/Resolver.h"           // for resolveCtorInit
     40#include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
    3741#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
    3850
    3951#if 0
     
    4456
    4557namespace 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        }
    46384
    47385namespace {
  • src/Tuples/TupleExpansion.cc

    rfc12f05 r0030b508  
    2323#include "AST/Node.hpp"
    2424#include "AST/Type.hpp"
     25#include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
    2526#include "Common/ScopedMap.h"     // for ScopedMap
    2627#include "Common/utility.h"       // for CodeLocation
    2728#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
    2837#include "Tuples.h"
    2938
     39class CompoundStmt;
     40class TypeSubstitution;
     41
    3042namespace Tuples {
    31 
     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        }
    32321        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
    33322                // produce the TupleType which aggregates the types of the exprs
     
    52341        }
    53342
     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
    54361        const ast::TypeInstType * isTtype( const ast::Type * type ) {
    55362                if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
  • src/Tuples/Tuples.cc

    rfc12f05 r0030b508  
    1919#include "AST/Inspect.hpp"
    2020#include "AST/LinkageSpec.hpp"
     21#include "Common/PassVisitor.h"
    2122#include "InitTweak/InitTweak.h"
    2223
     
    2425
    2526namespace {
     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        }
    2675
    2776        /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
     
    61110}
    62111
     112bool maybeImpure( const Expression * expr ) {
     113        return detectImpurity( expr, false );
     114}
     115
     116bool maybeImpureIgnoreUnique( const Expression * expr ) {
     117        return detectImpurity( expr, true );
     118}
     119
    63120} // namespace Tuples
    64121
  • src/Tuples/Tuples.h

    rfc12f05 r0030b508  
    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"
    2328#include "ResolvExpr/CandidateFinder.hpp"
    2429
    2530namespace Tuples {
    2631        // TupleAssignment.cc
     32        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
     33                std::vector< ResolvExpr::AlternativeFinder >& args );
    2734        void handleTupleAssignment(
    2835                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     
    3138        // TupleExpansion.cc
    3239        /// 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 );
    3341        void expandMemberTuples( ast::TranslationUnit & translationUnit );
    3442
    3543        /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
     44        void expandTuples( std::list< Declaration * > & translationUnit );
    3645        void expandTuples( ast::TranslationUnit & translaionUnit );
    3746
    3847        /// replaces UniqueExprs with a temporary variable and one call
     48        void expandUniqueExpr( std::list< Declaration * > & translationUnit );
    3949        void expandUniqueExpr( ast::TranslationUnit & translationUnit );
    4050
    4151        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
     52        Type * makeTupleType( const std::list< Expression * > & exprs );
    4253        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    4354
    4455        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
     56        TypeInstType * isTtype( Type * type );
     57        const TypeInstType * isTtype( const Type * type );
    4558        const ast::TypeInstType * isTtype( const ast::Type * type );
    4659
    4760        /// returns true if the expression may contain side-effects.
     61        bool maybeImpure( const Expression * expr );
    4862        bool maybeImpure( const ast::Expr * expr );
    4963
    5064        /// Returns true if the expression may contain side-effect,
    5165        /// ignoring the presence of unique expressions.
     66        bool maybeImpureIgnoreUnique( const Expression * expr );
    5267        bool maybeImpureIgnoreUnique( const ast::Expr * expr );
    5368} // namespace Tuples
  • src/Validate/FindSpecialDecls.h

    rfc12f05 r0030b508  
    1616#pragma once
    1717
     18#include <list>  // for list
     19
     20class Declaration;
     21class FunctionDecl;
     22class StructDecl;
     23class Type;
     24
    1825namespace ast {
    1926        class TranslationUnit;
     
    2128
    2229namespace 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 );
    2344
    2445/// Find and remember some of the special declarations that are useful for
  • src/Validate/FixReturnTypes.cpp

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

    rfc12f05 r0030b508  
    1616
    1717SRC_VALIDATE = \
     18        Validate/FindSpecialDecls.cc \
    1819        Validate/FindSpecialDecls.h
    1920
     
    3637        Validate/GenericParameter.cpp \
    3738        Validate/GenericParameter.hpp \
     39        Validate/HandleAttributes.cc \
     40        Validate/HandleAttributes.h \
    3841        Validate/HoistStruct.cpp \
    3942        Validate/HoistStruct.hpp \
  • src/Virtual/ExpandCasts.cc

    rfc12f05 r0030b508  
    2424#include "AST/Expr.hpp"
    2525#include "AST/Pass.hpp"
     26#include "Common/PassVisitor.h"    // for PassVisitor
    2627#include "Common/ScopedMap.h"      // for ScopedMap
    2728#include "Common/SemanticError.h"  // for SemanticError
    2829#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
    2935
    3036namespace Virtual {
     
    3743}
    3844
     45bool is_type_id_object( const ObjectDecl * objectDecl ) {
     46        const std::string & objectName = objectDecl->name;
     47        return is_prefix( "__cfatid_", objectName );
     48}
     49
    3950bool is_type_id_object( const ast::ObjectDecl * decl ) {
    4051        return is_prefix( "__cfatid_", decl->name );
     
    4455
    4556        /// 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        }
    46272
    47273/// Better error locations for generated casts.
     
    268494} // namespace
    269495
     496void expandCasts( std::list< Declaration * > & translationUnit ) {
     497        PassVisitor<VirtualCastCore> translator;
     498        mutateAll( translationUnit, translator );
     499}
     500
    270501void expandCasts( ast::TranslationUnit & translationUnit ) {
    271502        ast::Pass<ExpandCastsCore>::run( translationUnit );
  • src/Virtual/Tables.cc

    rfc12f05 r0030b508  
    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>
    2328
    2429namespace Virtual {
     
    6065        return 17 < name.size() && '_' == name[0] &&
    6166                std::string("_vtable_instance") == name.substr(1, name.size() - 17);
     67}
     68
     69static 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        );
    6284}
    6385
     
    79101}
    80102
     103ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
     104        assert( type );
     105        return makeVtableDeclaration( name, type, nullptr );
     106}
     107
    81108ast::ObjectDecl * makeVtableForward(
    82109                CodeLocation const & location, std::string const & name,
     
    84111        assert( vtableType );
    85112        return makeVtableDeclaration( location, name, vtableType, nullptr );
     113}
     114
     115ObjectDecl * 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 );
    86154}
    87155
     
    156224}
    157225
     226FunctionDecl * 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
    158259ast::FunctionDecl * makeGetExceptionForward(
    159260                CodeLocation const & location,
     
    183284}
    184285
     286FunctionDecl * 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
    185298ast::FunctionDecl * makeGetExceptionFunction(
    186299                CodeLocation const & location,
     
    196309}
    197310
     311ObjectDecl * 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        );
     328}
     329
    198330ast::ObjectDecl * makeTypeIdInstance(
    199331                CodeLocation const & location,
  • src/Virtual/Tables.h

    rfc12f05 r0030b508  
    1818#include <string>
    1919#include "AST/Fwd.hpp"
     20class Declaration;
     21class Expression;
     22class FunctionDecl;
     23class Initializer;
     24class ObjectDecl;
     25class StructDecl;
     26class StructInstType;
     27class Type;
    2028
    2129namespace Virtual {
     
    2937bool isVTableInstanceName( std::string const & name );
    3038
     39ObjectDecl * makeVtableForward(
     40        std::string const & name, StructInstType * vtableType );
    3141/* Create a forward declaration of a vtable of the given type.
    3242 * vtableType node is consumed.
     
    3646        ast::StructInstType const * vtableType );
    3747
     48ObjectDecl * makeVtableInstance(
     49        std::string const & name,
     50        StructInstType * vtableType, Type * objectType,
     51        Initializer * init = nullptr );
    3852/* Create an initialized definition of a vtable.
    3953 * vtableType and init (if provided) nodes are consumed.
     
    4761
    4862// Some special code for how exceptions interact with virtual tables.
    49 
     63FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType );
    5064/* Create a forward declaration of the exception virtual function
    5165 * linking the vtableType to the exceptType. Both nodes are consumed.
     
    5670        ast::Type const * exceptType );
    5771
     72FunctionDecl * makeGetExceptionFunction(
     73        ObjectDecl * vtableInstance, Type * exceptType );
    5874/* Create the definition of the exception virtual function.
    5975 * exceptType node is consumed.
     
    6379        ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType );
    6480
     81ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
    6582/* Build an instance of the type-id from the type of the type-id.
    6683 * TODO: Should take the parent type. Currently locked to the exception_t.
  • src/main.cc

    rfc12f05 r0030b508  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Nov  1 21:12:58 2023
    13 // Update Count     : 690
     12// Last Modified On : Thu Sep 28 22:28:45 2023
     13// Update Count     : 687
    1414//
    1515
     
    2929#include <string>                           // for char_traits, operator<<
    3030
     31#include "AST/Convert.hpp"
    3132#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
    4142#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4243#include "Common/DeclStats.hpp"             // for printDeclStats
     
    6465#include "ResolvExpr/EraseWith.hpp"         // for eraseWith
    6566#include "ResolvExpr/Resolver.h"            // for resolve
     67#include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
     68#include "SynTree/Declaration.h"            // for Declaration
    6669#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
    6770#include "Validate/Autogen.hpp"             // for autogenerateRoutines
     
    9194        using namespace Stats::Counters;
    9295        {
    93                 static auto group = build<CounterGroup>( "Pass Visitor Template" );
     96                static auto group = build<CounterGroup>( "Pass Visitor" );
    9497                auto pass = build<CounterGroup>( name, group );
    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 );
     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 );
    98106        }
    99107}
     
    124132
    125133static void parse_cmdline( int argc, char * argv[] );
     134static void dump( list< Declaration * > & translationUnit, ostream & out = cout );
    126135static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
    127136
     
    237246        FILE * input;                                                                           // use FILE rather than istream because yyin is FILE
    238247        ostream * output = & cout;
     248        list< Declaration * > translationUnit;
    239249        ast::TranslationUnit transUnit;
    240250
     
    250260
    251261        parse_cmdline( argc, argv );                                            // process command-line arguments
     262        CodeGen::FixMain::setReplaceMain( !nomainp );
    252263
    253264        if ( waiting_for_gdb ) {
     
    279290
    280291                        // Read to gcc builtins, if not generating the cfa library
    281                         FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cfa").c_str(), "r" );
     292                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" );
    282293                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
    283294                        parse( gcc_builtins, ast::Linkage::Compiler );
    284295
    285296                        // read the extra prelude in, if not generating the cfa library
    286                         FILE * extras = fopen( (PreludeDirector + "/extras.cfa").c_str(), "r" );
     297                        FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" );
    287298                        assertf( extras, "cannot open extras.cf\n" );
    288299                        parse( extras, ast::Linkage::BuiltinC );
     
    295306
    296307                                // Read to cfa builtins, if not generating the cfa library
    297                                 FILE * builtins = fopen( (PreludeDirector + "/builtins.cfa").c_str(), "r" );
     308                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" );
    298309                                assertf( builtins, "cannot open builtins.cf\n" );
    299310                                parse( builtins, ast::Linkage::BuiltinCFA );
     
    308319
    309320                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                }
    310326
    311327                PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
     
    393409                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
    394410                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
    395                 PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp );
    396411
    397412                // Needs to happen before tuple types are expanded.
     
    412427                PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit );
    413428
     429                translationUnit = convert( std::move( transUnit ) );
     430
    414431                // Code has been lowered to C, now we can start generation.
    415432
    416                 DUMP( bcodegenp, std::move( transUnit ) );
     433                DUMP( bcodegenp, translationUnit );
    417434
    418435                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    420437                } // if
    421438
    422                 PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false );
    423                 CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() );
    424 
     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() );
    425444                if ( output != &cout ) {
    426445                        delete output;
     
    429448                if ( errorp ) {
    430449                        cerr << "---AST at error:---" << endl;
    431                         dump( std::move( transUnit ), cerr );
     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                        }
    432457                        cerr << endl << "---End of AST, begin error message:---\n" << endl;
    433458                } // if
     
    455480        } // try
    456481
     482        deleteAll( translationUnit );
    457483        Stats::print();
    458484        return EXIT_SUCCESS;
     
    684710} // parse_cmdline
    685711
    686 static bool notPrelude( ast::ptr<ast::Decl> & decl ) {
    687         return !decl->linkage.is_builtin;
    688 }
    689 
    690 static void dump( ast::TranslationUnit && unit, std::ostream & out ) {
    691         // May filter out all prelude declarations.
     712static bool notPrelude( Declaration * decl ) {
     713        return ! LinkageSpec::isBuiltin( decl->get_linkage() );
     714} // notPrelude
     715
     716static void dump( list< Declaration * > & translationUnit, ostream & out ) {
     717        list< Declaration * > decls;
     718
    692719        if ( genproto ) {
    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.
     720                filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude );
     721        } else {
     722                decls = translationUnit;
     723        } // if
     724
     725        // depending on commandline options, either generate code or dump the AST
    700726        if ( codegenp ) {
    701                 CodeGen::generate( unit, out, !genproto, prettycodegenp, false, false, false );
     727                CodeGen::generate( decls, out, ! genproto, prettycodegenp );
    702728        } else {
    703                 ast::printAll( out, unit.decls );
    704         }
     729                printAll( decls, out );
     730        } // if
     731        deleteAll( translationUnit );
     732} // dump
     733
     734static void dump( ast::TranslationUnit && transUnit, ostream & out ) {
     735        std::list< Declaration * > translationUnit = convert( std::move( transUnit ) );
     736        dump( translationUnit, out );
    705737}
    706738
  • tests/collections/.expect/string-istream-manip.txt

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

    rfc12f05 r0030b508  
    3838        void echoTillX(const char * casename) {
    3939            string s;
    40             // loop assumes behaviour not tested until main-case #15:
    41             // on reading nothing, the prior string value is left alone
    4240            do {
    43                 s = "";
    4441                forceStringHeapFreeSpaceTo(9);
    4542                sin | s;
     
    5754            string s;
    5855            do {
    59                 s = "";
    6056                sin | plainjane( s );
    6157                sout | casename | s;
     
    7268            string_res s;
    7369            do {
    74                 s = "";
    7570                sin | plainjane( s );
    7671                sout | casename | s;
     
    8782            string s;
    8883            do {
    89                 s = "";
    9084                sin | skip("-\n");
    9185                sin | incl( ".:|# x", s );
     
    10397            string s;
    10498            do {
    105                 s = "";
    10699                sin | skip("-\n");
    107100                sin | excl( "-\n", s );
     
    120113            string s;
    121114            do {
    122                 s = "";
    123115                sin | getline( s );
    124116                sout | casename | s;
     
    135127            string s;
    136128            do {
    137                 s = "";
    138129                sin | getline( s, '@' );
    139130                sout | casename | s;
  • tests/concurrency/actors/.expect/dynamic.txt

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

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

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

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

    rfc12f05 r0030b508  
    11#include <cofor.hfa>
     2
    23
    34void add_num( long * total, long val ) { __atomic_fetch_add( total, (long)val, __ATOMIC_SEQ_CST ); }
     
    78    processor p[4];
    89    long total = 0;
    9     cofor( i; 10 ) {
    10         __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST );
    11     }
     10    COFOR( i, 0, 10, __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST ); );
    1211    {
    1312        corun;      // does nothing
  • tests/concurrency/waitfor/parse.cfa

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

    rfc12f05 r0030b508  
    2626        for( ;; ) {
    2727            if ( useAnd ) {
    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++; }
     28                waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }
     29                and waituntil( (in2 << B) ) { assert( B_removes == in2 ); B_removes++; removes++; }
    3030                continue;
    3131            }
    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++; }
     32            waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }
     33            or waituntil( (in << B) ) { assert( 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) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( A_removes == in ); A_removes++; removes++; }
     39            waituntil( (in << A) ) { 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) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( B_removes == in ); B_removes++; removes++; }
     44            waituntil( (in << B) ) { 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

    rfc12f05 r0030b508  
    1010// Created On       : Tue Dec 25 14:42:46 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct 20 09:13:26 2023
    13 // Update Count     : 15
     12// Last Modified On : Tue Dec 25 14:46:33 2018
     13// Update Count     : 2
    1414//
    1515
    16 #include <fstream.hfa>
    1716#include <limits.hfa>
    1817
    19 forall( T )
     18forall(T)
    2019union ByteView {
    2120        T val;
     
    2423
    2524forall(T)
    26 void 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;
     25void 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);
    2928        }
    3029}
    3130
    3231forall(T)
    33 void f( ByteView(T) x, T val ) {
    34         print( x );
    35         sout | " ";
     32void f(ByteView(T) x, T val) {
     33        print(x);
     34        printf(" ");
    3635        x.val = val;
    37         print( x );
    38         sout | nl;
     36        print(x);
     37        printf("\n");
    3938}
    4039
    4140int main() {
    42         sout | nlOff;
    4341        ByteView(unsigned) u = { 0 };
    4442        ByteView(int) i = { 0 };
    45         f( u, MAX );
    46         f( i, -1 );
     43        f(u, MAX);
     44        f(i, -1);
    4745}
    4846
  • tests/io/.expect/manipulatorsInput.arm64.txt

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

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

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

    rfc12f05 r0030b508  
    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
    227 0 1 1 1.0 1
    228 1 2 2 2.0 2
    229 2 4 4 4.0 4
    230 3 8 8 8.0 8
    231 4 16 16 16.0 16
    232 5 32 32 32.0 32
    233 6 64 64 64.0 64
    234 7 128 128 128.0 128
    235 8 256 256 256.0 256
    236 9 512 512 512.0 512
    237 10 1024 1.024K 1.0K 1K
    238 11 2048 2.048K 2.0K 2K
    239 12 4096 4.096K 4.1K 4K
    240 13 8192 8.192K 8.2K 8K
    241 14 16384 16.384K 16.4K 16K
    242 15 32768 32.768K 32.8K 33K
    243 16 65536 65.536K 65.5K 66K
    244 17 131072 131.072K 131.1K 131K
    245 18 262144 262.144K 262.1K 262K
    246 19 524288 524.288K 524.3K 524K
    247 20 1048576 1.04858M 1.0M 1M
    248 21 2097152 2.09715M 2.1M 2M
    249 22 4194304 4.1943M 4.2M 4M
    250 23 8388608 8.38861M 8.4M 8M
    251 24 16777216 16.7772M 16.8M 17M
    252 25 33554432 33.5544M 33.6M 34M
    253 26 67108864 67.1089M 67.1M 67M
    254 27 134217728 134.218M 134.2M 134M
    255 28 268435456 268.435M 268.4M 268M
    256 29 536870912 536.871M 536.9M 537M
    257 30 1073741824 1.07374G 1.1G 1G
    258 31 2147483648 2.14748G 2.1G 2G
  • tests/io/manipulatorsOutput4.cfa

    rfc12f05 r0030b508  
    77// Created On       : Tue Apr 13 17:55:02 2021
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Tue Oct 17 08:37:42 2023
    10 // Update Count     : 5
     9// Last Modified On : Tue Apr 13 18:00:33 2021
     10// Update Count     : 4
    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
    4944} // main
    5045
Note: See TracChangeset for help on using the changeset viewer.