Changes in / [92d41a4:709e0e0]


Ignore:
Location:
src
Files:
1 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • src/Common/PassVisitor.cc

    r92d41a4 r709e0e0  
    1717
    1818PassVisitorStats pass_visitor_stats;
    19 Stats::Counters::SimpleCounter* BaseSyntaxNode::new_nodes = nullptr;
  • src/Common/Stats/Counter.h

    r92d41a4 r709e0e0  
    3737                        class SimpleCounter {
    3838                        public:
    39                                 inline void operator++() {}
    4039                                inline void operator++(int) {}
    4140                                inline void operator+=(size_t) {}
     
    8584                                virtual void print(std::ostream & os) override { os << count; }
    8685
    87                                 inline void operator++()             { if(!enabled) return; count++;        }
    8886                                inline void operator++(int)          { if(!enabled) return; count++;        }
    8987                                inline void operator+=(size_t value) { if(!enabled) return; count += value; }
  • src/SymTab/Indexer.cc

    r92d41a4 r709e0e0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Mar  8 13:55:00 2019
    13 // Update Count     : 21
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Aug 17 16:08:40 2017
     13// Update Count     : 20
    1414//
    1515
     
    1717
    1818#include <cassert>                 // for assert, strict_dynamic_cast
     19#include <iostream>                // for operator<<, basic_ostream, ostream
    1920#include <string>                  // for string, operator<<, operator!=
    20 #include <memory>                  // for shared_ptr, make_shared
    2121#include <unordered_map>           // for operator!=, unordered_map<>::const...
    2222#include <unordered_set>           // for unordered_set
    2323#include <utility>                 // for pair, make_pair, move
    24 #include <vector>                  // for vector
    2524
    2625#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2726#include "Common/SemanticError.h"  // for SemanticError
    2827#include "Common/utility.h"        // for cloneAll
    29 #include "Common/Stats/Counter.h"  // for counters
    30 #include "GenPoly/GenPoly.h"       // for getFunctionType
     28#include "Common/Stats/Counter.h" // for counters
     29#include "GenPoly/GenPoly.h"
    3130#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3231#include "Mangler.h"               // for Mangler
     
    4039#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
    4140
     41#define debugPrint(x) if ( doDebug ) { std::cerr << x; }
     42
    4243namespace SymTab {
    4344
    4445        // Statistics block
    4546        namespace {
    46                 static inline auto stats() {
     47
     48                static inline auto stats_idtable() {
     49                        using namespace Stats::Counters;
     50                        static auto group = build<CounterGroup>("IdTable");
     51                        static struct {
     52                                SimpleCounter * find;
     53                                AverageCounter<double> * size;
     54                                AverageCounter<double> * key;
     55                        } ret = {
     56                                .find = build<SimpleCounter>("Find calls", group),
     57                                .size = build<AverageCounter<double>>("Average Size", group),
     58                                .key  = build<AverageCounter<double>>("Average Key Size", group),
     59                        };
     60                        return ret;
     61                }
     62
     63                static inline auto stats_indexers() {
    4764                        using namespace Stats::Counters;
    4865                        static auto group   = build<CounterGroup>("Indexers");
     
    5067                                SimpleCounter * count;
    5168                                AverageCounter<double> * size;
    52                                 SimpleCounter * new_scopes;
    53                                 SimpleCounter * lazy_scopes;
    54                                 AverageCounter<double> * avg_scope_depth;
    55                                 MaxCounter<size_t> * max_scope_depth;
    56                                 SimpleCounter * add_calls;
    57                                 SimpleCounter * lookup_calls;
    58                                 SimpleCounter * map_lookups;
    59                                 SimpleCounter * map_mutations;
     69                                AverageCounter<double> * depth_a;
     70                                MaxCounter<size_t> * depth_m;
    6071                        } ret = {
    6172                                .count   = build<SimpleCounter>("Count", group),
    6273                                .size    = build<AverageCounter<double>>("Average Size", group),
    63                                 .new_scopes = build<SimpleCounter>("Scopes", group),
    64                                 .lazy_scopes = build<SimpleCounter>("Lazy Scopes", group),
    65                                 .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group),
    66                                 .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group),
    67                                 .add_calls = build<SimpleCounter>("Add Calls", group),
    68                                 .lookup_calls = build<SimpleCounter>("Lookup Calls", group),
    69                                 .map_lookups = build<SimpleCounter>("Map Lookups", group),
    70                                 .map_mutations = build<SimpleCounter>("Map Mutations", group)
     74                                .depth_a = build<AverageCounter<double>>("Average Depth", group),
     75                                .depth_m = build<MaxCounter<size_t>>("Max Depth", group),
    7176                        };
    7277                        return ret;
     
    7479        }
    7580
    76         Indexer::Indexer()
    77         : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
    78           prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
     81        std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) {
     82                return out << "(" << data.id << "," << data.baseExpr << ")";
     83        }
     84
     85        typedef std::unordered_map< std::string, Indexer::IdData > MangleTable;
     86        typedef std::unordered_map< std::string, MangleTable > IdTable;
     87        typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable;
     88        typedef std::unordered_map< std::string, StructDecl* > StructTable;
     89        typedef std::unordered_map< std::string, EnumDecl* > EnumTable;
     90        typedef std::unordered_map< std::string, UnionDecl* > UnionTable;
     91        typedef std::unordered_map< std::string, TraitDecl* > TraitTable;
     92
     93        void dump( const IdTable &table, std::ostream &os ) {
     94                for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) {
     95                        for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) {
     96                                os << mangle->second << std::endl;
     97                        }
     98                }
     99        }
     100
     101        template< typename Decl >
     102        void dump( const std::unordered_map< std::string, Decl* > &table, std::ostream &os ) {
     103                for ( typename std::unordered_map< std::string, Decl* >::const_iterator it = table.begin(); it != table.end(); ++it ) {
     104                        os << it->second << std::endl;
     105                } // for
     106        }
     107
     108        struct Indexer::Impl {
     109                Impl( unsigned long _scope ) : refCount(1), scope( _scope ), size( 0 ), base(),
     110                                idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
     111                Impl( unsigned long _scope, Indexer &&_base ) : refCount(1), scope( _scope ), size( 0 ), base( _base ),
     112                                idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
     113                unsigned long refCount;   ///< Number of references to these tables
     114                unsigned long scope;      ///< Scope these tables are associated with
     115                unsigned long size;       ///< Number of elements stored in this table
     116                const Indexer base;       ///< Base indexer this extends
     117
     118                IdTable idTable;          ///< Identifier namespace
     119                TypeTable typeTable;      ///< Type namespace
     120                StructTable structTable;  ///< Struct namespace
     121                EnumTable enumTable;      ///< Enum namespace
     122                UnionTable unionTable;    ///< Union namespace
     123                TraitTable traitTable;    ///< Trait namespace
     124        };
     125
     126        Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) {
     127                if ( ! toClone ) return 0;
     128
     129                // shorten the search chain by skipping empty links
     130                Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone;
     131                if ( ret ) { ++ret->refCount; }
     132
     133                return ret;
     134        }
     135
     136        void Indexer::deleteRef( Indexer::Impl *toFree ) {
     137                if ( ! toFree ) return;
     138
     139                if ( --toFree->refCount == 0 ) delete toFree;
     140        }
     141
     142        void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
     143                // only need to perform this step for constructors, destructors, and assignment functions
     144                if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
     145
     146                // helpful data structure to organize properties for a type
     147                struct ValueType {
     148                        struct DeclBall { // properties for this particular decl
     149                                IdData decl;
     150                                bool isUserDefinedFunc;
     151                                bool isCopyFunc;
     152                        };
     153                        // properties for this type
     154                        bool existsUserDefinedCopyFunc = false;    // user-defined copy ctor found
     155                        BaseSyntaxNode * deleteStmt = nullptr;     // non-null if a user-defined function is found
     156                        std::list< DeclBall > decls;
     157
     158                        // another FunctionDecl for the current type was found - determine
     159                        // if it has special properties and update data structure accordingly
     160                        ValueType & operator+=( IdData data ) {
     161                                DeclarationWithType * function = data.id;
     162                                bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
     163                                bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
     164                                decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
     165                                existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc);
     166                                if ( isUserDefinedFunc && ! deleteStmt ) {
     167                                        // any user-defined function can act as an implicit delete statement for generated constructors.
     168                                        // a delete stmt should not act as an implicit delete statement.
     169                                        deleteStmt = data.id;
     170                                }
     171                                return *this;
     172                        }
     173                }; // ValueType
     174
     175                std::list< IdData > copy;
     176                copy.splice( copy.end(), out );
     177
     178                // organize discovered declarations by type
     179                std::unordered_map< std::string, ValueType > funcMap;
     180                for ( auto decl : copy ) {
     181                        if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
     182                                std::list< DeclarationWithType * > & params = function->type->parameters;
     183                                assert( ! params.empty() );
     184                                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
     185                                Type * base = InitTweak::getPointerBase( params.front()->get_type() );
     186                                assert( base );
     187                                funcMap[ Mangler::mangle( base ) ] += decl;
     188                        } else {
     189                                out.push_back( decl );
     190                        }
     191                }
     192
     193                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine
     194                // the set of ctor/dtor/assign that can be used  by the requester. In particular, if the user defines
     195                // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor
     196                // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available.
     197                // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default
     198                // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor,
     199                // then the generated copy constructor is unavailable, and likewise for the assignment operator.
     200                for ( std::pair< const std::string, ValueType > & pair : funcMap ) {
     201                        ValueType & val = pair.second;
     202                        for ( ValueType::DeclBall ball : val.decls ) {
     203                                bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic;
     204                                bool isCopyFunc = ball.isCopyFunc;
     205                                bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc;
     206
     207                                // only implicitly delete non-user defined functions that are not intrinsic, and are
     208                                // not copy functions (assignment or copy constructor). If a  user-defined copy function exists,
     209                                // do not pass along the non-user-defined copy functions since signatures do not have to match,
     210                                // and the generated functions will often be cheaper.
     211                                if ( isNotUserDefinedFunc ) {
     212                                        if ( isCopyFunc ) {
     213                                                // Skip over non-user-defined copy functions when there is a user-defined copy function.
     214                                                // Since their signatures do not have to be exact, deleting them is the wrong choice.
     215                                                if ( existsUserDefinedCopyFunc ) continue;
     216                                        } else {
     217                                                // delete non-user-defined non-copy functions if applicable.
     218                                                // deleteStmt will be non-null only if a user-defined function is found.
     219                                                ball.decl.deleteStmt = val.deleteStmt;
     220                                        }
     221                                }
     222                                out.push_back( ball.decl );
     223                        }
     224                }
     225        }
     226
     227        void Indexer::makeWritable() {
     228                if ( ! tables ) {
     229                        // create indexer if not yet set
     230                        tables = new Indexer::Impl( scope );
     231                } else if ( tables->refCount > 1 || tables->scope != scope ) {
     232                        // make this indexer the base of a fresh indexer at the current scope
     233                        tables = new Indexer::Impl( scope, std::move( *this ) );
     234                }
     235        }
     236
     237        Indexer::Indexer() : tables( 0 ), scope( 0 ) {
     238                (*stats_indexers().count)++;
     239        }
     240
     241        Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) {
     242                (*stats_indexers().count)++;
     243        }
     244
     245        Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) {
     246                that.tables = 0;
     247        }
    79248
    80249        Indexer::~Indexer() {
    81                 stats().size->push( idTable ? idTable->size() : 0 );
    82         }
    83 
    84         void Indexer::lazyInitScope() {
    85                 if ( repScope < scope ) {
    86                         ++*stats().lazy_scopes;
    87                         // create rollback
    88                         prevScope = std::make_shared<Indexer>( *this );
    89                         // update repScope
    90                         repScope = scope;
    91                 }
    92         }
    93 
    94         void Indexer::enterScope() {
    95                 ++scope;
    96 
    97                 ++*stats().new_scopes;
    98                 stats().avg_scope_depth->push( scope );
    99                 stats().max_scope_depth->push( scope );
    100         }
    101 
    102         void Indexer::leaveScope() {
    103                 if ( repScope == scope ) {
    104                         Ptr prev = prevScope;           // make sure prevScope stays live
    105                         *this = std::move(*prevScope);  // replace with previous scope
    106                 }
    107 
    108                 --scope;
     250                if(tables) {
     251                        stats_indexers().size->push( tables->idTable.size() );
     252                        size_t depth = 1;
     253                        for( auto crnt = tables->base.tables; crnt; crnt = crnt->base.tables ) {
     254                                ++depth;
     255                        }
     256                        stats_indexers().depth_a->push( depth );
     257                        stats_indexers().depth_m->push( depth );
     258                }
     259                deleteRef( tables );
     260        }
     261
     262        Indexer& Indexer::operator= ( const Indexer &that ) {
     263                deleteRef( tables );
     264
     265                tables = newRef( that.tables );
     266                scope = that.scope;
     267                doDebug = that.doDebug;
     268
     269                return *this;
     270        }
     271
     272        Indexer& Indexer::operator= ( Indexer &&that ) {
     273                deleteRef( tables );
     274
     275                tables = that.tables;
     276                scope = that.scope;
     277                doDebug = that.doDebug;
     278
     279                that.tables = 0;
     280
     281                return *this;
    109282        }
    110283
    111284        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    112                 ++*stats().lookup_calls;
    113                 if ( ! idTable ) return;
    114 
    115                 ++*stats().map_lookups;
    116                 auto decls = idTable->find( id );
    117                 if ( decls == idTable->end() ) return;
    118 
    119                 for ( auto decl : *(decls->second) ) {
    120                         out.push_back( decl.second );
    121                 }
     285                std::unordered_set< std::string > foundMangleNames;
     286
     287                Indexer::Impl *searchTables = tables;
     288                while ( searchTables ) {
     289
     290                        (*stats_idtable().find)++;
     291                        stats_idtable().key->push( id.size() );
     292                        stats_idtable().size->push( searchTables->idTable.size() );
     293                        IdTable::const_iterator decls = searchTables->idTable.find( id );
     294                        if ( decls != searchTables->idTable.end() ) {
     295                                const MangleTable &mangleTable = decls->second;
     296                                for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
     297                                        // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found
     298                                        if ( foundMangleNames.insert( decl->first ).second == false ) continue;
     299
     300                                        out.push_back( decl->second );
     301                                }
     302                        }
     303
     304                        // get declarations from base indexers
     305                        searchTables = searchTables->base.tables;
     306                }
     307
     308                // some special functions, e.g. constructors and destructors
     309                // remove autogenerated functions when they are defined so that
     310                // they can never be matched
     311                removeSpecialOverrides( id, out );
    122312        }
    123313
    124314        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    125                 ++*stats().lookup_calls;
    126                 if ( ! typeTable ) return nullptr;
    127                 ++*stats().map_lookups;
    128                 auto it = typeTable->find( id );
    129                 return it == typeTable->end() ? nullptr : it->second.decl;
     315                if ( ! tables ) return 0;
     316
     317                TypeTable::const_iterator ret = tables->typeTable.find( id );
     318                return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id );
    130319        }
    131320
    132321        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    133                 ++*stats().lookup_calls;
    134                 if ( ! structTable ) return nullptr;
    135                 ++*stats().map_lookups;
    136                 auto it = structTable->find( id );
    137                 return it == structTable->end() ? nullptr : it->second.decl;
     322                if ( ! tables ) return 0;
     323
     324                StructTable::const_iterator ret = tables->structTable.find( id );
     325                return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id );
     326        }
     327
     328        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
     329                return lookupTypeAtScope( id, 0 );
     330        }
     331
     332        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
     333                return lookupStructAtScope( id, 0 );
     334        }
     335
     336        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
     337                return lookupUnionAtScope( id, 0 );
     338        }
     339
     340        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
     341                return lookupEnumAtScope( id, 0 );
    138342        }
    139343
    140344        EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    141                 ++*stats().lookup_calls;
    142                 if ( ! enumTable ) return nullptr;
    143                 ++*stats().map_lookups;
    144                 auto it = enumTable->find( id );
    145                 return it == enumTable->end() ? nullptr : it->second.decl;
     345                if ( ! tables ) return 0;
     346
     347                EnumTable::const_iterator ret = tables->enumTable.find( id );
     348                return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id );
    146349        }
    147350
    148351        UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
    149                 ++*stats().lookup_calls;
    150                 if ( ! unionTable ) return nullptr;
    151                 ++*stats().map_lookups;
    152                 auto it = unionTable->find( id );
    153                 return it == unionTable->end() ? nullptr : it->second.decl;
     352                if ( ! tables ) return 0;
     353
     354                UnionTable::const_iterator ret = tables->unionTable.find( id );
     355                return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id );
    154356        }
    155357
    156358        TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
    157                 ++*stats().lookup_calls;
    158                 if ( ! traitTable ) return nullptr;
    159                 ++*stats().map_lookups;
    160                 auto it = traitTable->find( id );
    161                 return it == traitTable->end() ? nullptr : it->second.decl;
    162         }
    163 
    164         const Indexer* Indexer::atScope( unsigned long target ) const {
    165                 // by lazy construction, final indexer in list has repScope 0, cannot be > target
    166                 // otherwise, will find first scope representing the target
    167                 const Indexer* indexer = this;
    168                 while ( indexer->repScope > target ) {
    169                         indexer = indexer->prevScope.get();
    170                 }
    171                 return indexer;
    172         }
    173 
    174         NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
    175                 return atScope( 0 )->lookupType( id );
    176         }
    177 
    178         StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
    179                 return atScope( 0 )->lookupStruct( id );
    180         }
    181 
    182         UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
    183                 return atScope( 0 )->lookupUnion( id );
    184         }
    185 
    186         EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
    187                 return atScope( 0 )->lookupEnum( id );
     359                if ( ! tables ) return 0;
     360
     361                TraitTable::const_iterator ret = tables->traitTable.find( id );
     362                return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id );
     363        }
     364
     365        const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
     366                if ( ! tables ) return nullptr;
     367                if ( tables->scope < scope ) return nullptr;
     368
     369                (*stats_idtable().find)++;
     370                stats_idtable().key->push( id.size() );
     371                stats_idtable().size->push( tables->idTable.size() );
     372                IdTable::const_iterator decls = tables->idTable.find( id );
     373                if ( decls != tables->idTable.end() ) {
     374                        const MangleTable &mangleTable = decls->second;
     375                        MangleTable::const_iterator decl = mangleTable.find( mangleName );
     376                        if ( decl != mangleTable.end() ) return &decl->second;
     377                }
     378
     379                return tables->base.lookupIdAtScope( id, mangleName, scope );
     380        }
     381
     382        Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
     383                return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
     384        }
     385
     386        bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
     387                if ( ! tables ) return false;
     388                if ( tables->scope < scope ) return false;
     389
     390                (*stats_idtable().find)++;
     391                stats_idtable().key->push( id.size() );
     392                stats_idtable().size->push( tables->idTable.size() );
     393                IdTable::const_iterator decls = tables->idTable.find( id );
     394                if ( decls != tables->idTable.end() ) {
     395                        const MangleTable &mangleTable = decls->second;
     396                        for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
     397                                // check for C decls with the same name, skipping those with a compatible type (by mangleName)
     398                                if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true;
     399                        }
     400                }
     401
     402                return tables->base.hasIncompatibleCDecl( id, mangleName, scope );
     403        }
     404
     405        bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
     406                if ( ! tables ) return false;
     407                if ( tables->scope < scope ) return false;
     408
     409                (*stats_idtable().find)++;
     410                stats_idtable().key->push( id.size() );
     411                stats_idtable().size->push( tables->idTable.size() );
     412                IdTable::const_iterator decls = tables->idTable.find( id );
     413                if ( decls != tables->idTable.end() ) {
     414                        const MangleTable &mangleTable = decls->second;
     415                        for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
     416                                // check for C decls with the same name, skipping
     417                                // those with an incompatible type (by mangleName)
     418                                if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true;
     419                        }
     420                }
     421
     422                return tables->base.hasCompatibleCDecl( id, mangleName, scope );
     423        }
     424
     425        NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const {
     426                if ( ! tables ) return 0;
     427                if ( tables->scope < scope ) return 0;
     428                if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope );
     429
     430                TypeTable::const_iterator ret = tables->typeTable.find( id );
     431                return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope );
     432        }
     433
     434        StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const {
     435                if ( ! tables ) return 0;
     436                if ( tables->scope < scope ) return 0;
     437                if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope );
     438
     439                StructTable::const_iterator ret = tables->structTable.find( id );
     440                return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope );
     441        }
     442
     443        EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const {
     444                if ( ! tables ) return 0;
     445                if ( tables->scope < scope ) return 0;
     446                if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope );
     447
     448                EnumTable::const_iterator ret = tables->enumTable.find( id );
     449                return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope );
     450        }
     451
     452        UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const {
     453                if ( ! tables ) return 0;
     454                if ( tables->scope < scope ) return 0;
     455                if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope );
     456
     457                UnionTable::const_iterator ret = tables->unionTable.find( id );
     458                return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope );
     459        }
     460
     461        TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const {
     462                if ( ! tables ) return 0;
     463                if ( tables->scope < scope ) return 0;
     464                if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope );
     465
     466                TraitTable::const_iterator ret = tables->traitTable.find( id );
     467                return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope );
    188468        }
    189469
     
    207487        }
    208488
    209        
    210         bool Indexer::addedIdConflicts(
    211                         const Indexer::IdData & existing, DeclarationWithType *added,
    212                         Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) {
    213                 // if we're giving the same name mangling to things of different types then there is
    214                 // something wrong
     489        bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
     490                // if we're giving the same name mangling to things of different types then there is something wrong
    215491                assert( (isObject( added ) && isObject( existing.id ) )
    216492                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    217493
    218                 if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
     494                if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
    219495                        // new definition shadows the autogenerated one, even at the same scope
    220496                        return false;
    221                 } else if ( LinkageSpec::isMangled( added->linkage )
    222                                 || ResolvExpr::typesCompatible(
    223                                         added->get_type(), existing.id->get_type(), Indexer() ) ) {
     497                } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
    224498
    225499                        // it is a conflict if one declaration is deleted and the other is not
    226500                        if ( deleteStmt && ! existing.deleteStmt ) {
    227                                 if ( handleConflicts.mode == OnConflict::Error ) {
    228                                         SemanticError( added, "deletion of defined identifier " );
    229                                 }
    230                                 return true;
     501                                return handleConflicts( existing, "deletion of defined identifier " );
    231502                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    232                                 if ( handleConflicts.mode == OnConflict::Error ) {
    233                                         SemanticError( added, "definition of deleted identifier " );
    234                                 }
    235                                 return true;
     503                                return handleConflicts( existing, "definition of deleted identifier " );
    236504                        }
    237505
    238506                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    239                                 if ( handleConflicts.mode == OnConflict::Error ) {
    240                                         SemanticError( added,
    241                                                 isFunction( added ) ?
    242                                                         "duplicate function definition for " :
    243                                                         "duplicate object definition for " );
    244                                 }
    245                                 return true;
     507                                if ( isFunction( added ) ) {
     508                                        return handleConflicts( existing, "duplicate function definition for " );
     509                                } else {
     510                                        return handleConflicts( existing, "duplicate object definition for " );
     511                                } // if
    246512                        } // if
    247513                } else {
    248                         if ( handleConflicts.mode == OnConflict::Error ) {
    249                                 SemanticError( added, "duplicate definition for " );
    250                         }
    251                         return true;
     514                        return handleConflicts( existing, "duplicate definition for " );
    252515                } // if
    253516
     
    255518        }
    256519
    257         bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
    258                 if ( ! idTable ) return false;
    259 
    260                 ++*stats().map_lookups;
    261                 auto decls = idTable->find( id );
    262                 if ( decls == idTable->end() ) return false;
    263 
    264                 for ( auto decl : *(decls->second) ) {
    265                         // skip other scopes (hidden by this decl)
    266                         if ( decl.second.scope != scope ) continue;
    267                         // check for C decl with compatible type (by mangleName)
    268                         if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) {
    269                                 return true;
    270                         }
    271                 }
    272                
    273                 return false;
    274         }
    275 
    276         bool Indexer::hasIncompatibleCDecl(
    277                         const std::string &id, const std::string &mangleName ) const {
    278                 if ( ! idTable ) return false;
    279 
    280                 ++*stats().map_lookups;
    281                 auto decls = idTable->find( id );
    282                 if ( decls == idTable->end() ) return false;
    283 
    284                 for ( auto decl : *(decls->second) ) {
    285                         // skip other scopes (hidden by this decl)
    286                         if ( decl.second.scope != scope ) continue;
    287                         // check for C decl with incompatible type (by manglename)
    288                         if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) {
    289                                 return true;
    290                         }
    291                 }
    292 
    293                 return false;
    294         }
    295 
    296         /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
    297         std::string getOtypeKey( FunctionDecl* function ) {
    298                 auto& params = function->type->parameters;
    299                 assert( ! params.empty() );
    300                 // use base type of pointer, so that qualifiers on the pointer type aren't considered.
    301                 Type* base = InitTweak::getPointerBase( params.front()->get_type() );
    302                 assert( base );
    303                 return Mangler::mangle( base );
    304         }
    305 
    306         /// gets the declaration for the function acting on a type specified by otype key,
    307         /// nullptr if none such
    308         FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) {
    309                 FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl );
    310                 if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
    311                 return func;
    312         }
    313 
    314         bool Indexer::removeSpecialOverrides(
    315                         Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) {
    316                 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
    317                 // determinethe set of ctor/dtor/assign that can be used  by the requester. In particular,
    318                 // if the user defines a default ctor, then the generated default ctor is unavailable,
    319                 // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
    320                 // field ctors are available. If the user defines any ctor then the generated default ctor
    321                 // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
    322                 // anything that looks like a copy constructor, then the generated copy constructor is
    323                 // unavailable, and likewise for the assignment operator.
    324 
    325                 // only relevant on function declarations
    326                 FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id );
    327                 if ( ! function ) return true;
    328                 // only need to perform this check for constructors, destructors, and assignment functions
    329                 if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
    330 
    331                 // set up information for this type
    332                 bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
    333                 bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name );
    334                 std::string dataOtypeKey = getOtypeKey( function );
    335 
    336                 if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
    337                         // this is a user-defined copy function
    338                         // if this is the first such, delete/remove non-user-defined overloads as needed
    339                         std::vector< std::string > removed;
    340                         std::vector< MangleTable::value_type > deleted;
    341                         bool alreadyUserDefinedFunc = false;
    342                        
    343                         for ( const auto& entry : *mangleTable ) {
    344                                 // skip decls that aren't functions or are for the wrong type
    345                                 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
    346                                 if ( ! decl ) continue;
    347 
    348                                 bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name );
    349                                 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) {
    350                                         // matching user-defined function
    351                                         if ( isCopyFunc ) {
    352                                                 // mutation already performed, return early
    353                                                 return true;
    354                                         } else {
    355                                                 // note that non-copy deletions already performed
    356                                                 alreadyUserDefinedFunc = true;
    357                                         }
    358                                 } else {
    359                                         // non-user-defined function; mark for deletion/removal as appropriate
    360                                         if ( isCopyFunc ) {
    361                                                 removed.push_back( entry.first );
    362                                         } else if ( ! alreadyUserDefinedFunc ) {
    363                                                 deleted.push_back( entry );
    364                                         }
    365                                 }
    366                         }
    367 
    368                         // perform removals from mangle table, and deletions if necessary
    369                         for ( const auto& key : removed ) {
    370                                 ++*stats().map_mutations;
    371                                 mangleTable = mangleTable->erase( key );
    372                         }
    373                         if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
    374                                 ++*stats().map_mutations;
    375                                 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
    376                         }
    377                 } else if ( dataIsUserDefinedFunc ) {
    378                         // this is a user-defined non-copy function
    379                         // if this is the first user-defined function, delete non-user-defined overloads
    380                         std::vector< MangleTable::value_type > deleted;
    381                        
    382                         for ( const auto& entry : *mangleTable ) {
    383                                 // skip decls that aren't functions or are for the wrong type
    384                                 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
    385                                 if ( ! decl ) continue;
    386 
    387                                 // exit early if already a matching user-defined function;
    388                                 // earlier function will have mutated table
    389                                 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true;
    390 
    391                                 // skip mutating intrinsic functions
    392                                 if ( decl->linkage == LinkageSpec::Intrinsic ) continue;
    393 
    394                                 // user-defined non-copy functions do not override copy functions
    395                                 if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue;
    396 
    397                                 // this function to be deleted after mangleTable iteration is complete
    398                                 deleted.push_back( entry );
    399                         }
    400 
    401                         // mark deletions to update mangle table
    402                         // this needs to be a separate loop because of iterator invalidation
    403                         for ( const auto& entry : deleted ) {
    404                                 ++*stats().map_mutations;
    405                                 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
    406                         }
    407                 } else if ( function->linkage != LinkageSpec::Intrinsic ) {
    408                         // this is an overridable generated function
    409                         // if there already exists a matching user-defined function, delete this appropriately
    410                         for ( const auto& entry : *mangleTable ) {
    411                                 // skip decls that aren't functions or are for the wrong type
    412                                 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
    413                                 if ( ! decl ) continue;
    414 
    415                                 // skip non-user-defined functions
    416                                 if ( LinkageSpec::isOverridable( decl->linkage ) ) continue;
    417 
    418                                 if ( dataIsCopyFunc ) {
    419                                         // remove current function if exists a user-defined copy function
    420                                         // since the signatures for copy functions don't need to match exactly, using
    421                                         // a delete statement is the wrong approach
    422                                         if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false;
    423                                 } else {
    424                                         // mark current function deleted by first user-defined function found
    425                                         data.deleteStmt = decl;
    426                                         return true;
    427                                 }
    428                         }
    429                 }
    430                
    431                 // nothing (more) to fix, return true
    432                 return true;
    433         }
    434 
    435         void Indexer::addId(
    436                         DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr,
    437                         BaseSyntaxNode * deleteStmt ) {
    438                 ++*stats().add_calls;
     520        void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
     521                if ( decl->name == "" ) return;
     522                debugPrint( "Adding Id " << decl->name << std::endl );
     523                makeWritable();
     524
    439525                const std::string &name = decl->name;
    440                 if ( name == "" ) return;
    441                
    442526                std::string mangleName;
    443527                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    444                         // mangle the name without including the appropriate suffix, so overridable routines
    445                         // are placed into the same "bucket" as their user defined versions.
     528                        // mangle the name without including the appropriate suffix, so overridable routines are placed into the
     529                        // same "bucket" as their user defined versions.
    446530                        mangleName = Mangler::mangle( decl, false );
    447531                } else {
     
    449533                } // if
    450534
    451                 // this ensures that no two declarations with the same unmangled name at the same scope
    452                 // both have C linkage
    453                 if ( LinkageSpec::isMangled( decl->linkage ) ) {
     535                // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage
     536                if ( ! LinkageSpec::isMangled( decl->linkage ) ) {
     537                        // NOTE this is broken in Richard's original code in such a way that it never triggers (it
     538                        // doesn't check decls that have the same manglename, and all C-linkage decls are defined to
     539                        // have their name as their manglename, hence the error can never trigger).
     540                        // The code here is closer to correct, but name mangling would have to be completely
     541                        // isomorphic to C type-compatibility, which it may not be.
     542                        if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
     543                                SemanticError( decl, "conflicting overload of C function " );
     544                        }
     545                } else {
    454546                        // Check that a Cforall declaration doesn't override any C declaration
    455                         if ( hasCompatibleCDecl( name, mangleName ) ) {
     547                        if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    456548                                SemanticError( decl, "Cforall declaration hides C function " );
    457549                        }
    458                 } else {
    459                         // NOTE: only correct if name mangling is completely isomorphic to C
    460                         // type-compatibility, which it may not be.
    461                         if ( hasIncompatibleCDecl( name, mangleName ) ) {
    462                                 SemanticError( decl, "conflicting overload of C function " );
    463                         }
    464                 }
    465 
    466                 // ensure tables exist and add identifier
    467                 MangleTable::Ptr mangleTable;
    468                 if ( ! idTable ) {
    469                         idTable = IdTable::new_ptr();
    470                         mangleTable = MangleTable::new_ptr();
    471                 } else {
    472                         ++*stats().map_lookups;
    473                         auto decls = idTable->find( name );
    474                         if ( decls == idTable->end() ) {
    475                                 mangleTable = MangleTable::new_ptr();
    476                         } else {
    477                                 mangleTable = decls->second;
    478                                 // skip in-scope repeat declarations of same identifier
    479                                 ++*stats().map_lookups;
    480                                 auto existing = mangleTable->find( mangleName );
    481                                 if ( existing != mangleTable->end()
    482                                                 && existing->second.scope == scope
    483                                                 && existing->second.id ) {
    484                                         if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) {
    485                                                 if ( handleConflicts.mode == OnConflict::Delete ) {
    486                                                         // set delete expression for conflicting identifier
    487                                                         lazyInitScope();
    488                                                         *stats().map_mutations += 2;
    489                                                         idTable = idTable->set(
    490                                                                 name,
    491                                                                 mangleTable->set(
    492                                                                         mangleName,
    493                                                                         IdData{ existing->second, handleConflicts.deleteStmt } ) );
    494                                                 }
    495                                                 return;
    496                                         }
    497                                 }
    498                         }
    499                 }
    500 
    501                 // add/overwrite with new identifier
    502                 lazyInitScope();
    503                 IdData data{ decl, baseExpr, deleteStmt, scope };
    504                 // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
    505                 if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
    506                 *stats().map_mutations += 2;
    507                 idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
     550                }
     551
     552                // Skip repeat declarations of the same identifier
     553                IdData * existing = lookupIdAtScope( name, mangleName, scope );
     554                if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
     555
     556                // add to indexer
     557                tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt };
     558                ++tables->size;
    508559        }
    509560
    510561        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
    511562                // default handling of conflicts is to raise an error
    512                 addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     563                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
    513564        }
    514565
    515566        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
    516567                // default handling of conflicts is to raise an error
    517                 addId( decl, OnConflict::error(), nullptr, deleteStmt );
     568                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
    518569        }
    519570
     
    530581                        }
    531582                }
    532                 // does not need to be added to the table if both existing and added have a base that are
    533                 // the same
     583                // does not need to be added to the table if both existing and added have a base that are the same
    534584                return true;
    535585        }
    536586
    537587        void Indexer::addType( NamedTypeDecl *decl ) {
    538                 ++*stats().add_calls;
     588                debugPrint( "Adding type " << decl->name << std::endl );
     589                makeWritable();
     590
    539591                const std::string &id = decl->name;
    540 
    541                 if ( ! typeTable ) {
    542                         typeTable = TypeTable::new_ptr();
    543                 } else {
    544                         ++*stats().map_lookups;
    545                         auto existing = typeTable->find( id );
    546                         if ( existing != typeTable->end()
    547                                 && existing->second.scope == scope
    548                                 && addedTypeConflicts( existing->second.decl, decl ) ) return;
    549                 }
    550                
    551                 lazyInitScope();
    552                 ++*stats().map_mutations;
    553                 typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } );
     592                TypeTable::iterator existing = tables->typeTable.find( id );
     593                if ( existing == tables->typeTable.end() ) {
     594                        NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope );
     595                        if ( ! parent || ! addedTypeConflicts( parent, decl ) ) {
     596                                tables->typeTable.insert( existing, std::make_pair( id, decl ) );
     597                                ++tables->size;
     598                        }
     599                } else {
     600                        if ( ! addedTypeConflicts( existing->second, decl ) ) {
     601                                existing->second = decl;
     602                        }
     603                }
    554604        }
    555605
     
    564614
    565615        void Indexer::addStruct( const std::string &id ) {
     616                debugPrint( "Adding fwd decl for struct " << id << std::endl );
    566617                addStruct( new StructDecl( id ) );
    567618        }
    568619
    569620        void Indexer::addStruct( StructDecl *decl ) {
    570                 ++*stats().add_calls;
     621                debugPrint( "Adding struct " << decl->name << std::endl );
     622                makeWritable();
     623
    571624                const std::string &id = decl->name;
    572 
    573                 if ( ! structTable ) {
    574                         structTable = StructTable::new_ptr();
    575                 } else {
    576                         ++*stats().map_lookups;
    577                         auto existing = structTable->find( id );
    578                         if ( existing != structTable->end() 
    579                                 && existing->second.scope == scope
    580                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    581                 }
    582 
    583                 lazyInitScope();
    584                 ++*stats().map_mutations;
    585                 structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } );
     625                StructTable::iterator existing = tables->structTable.find( id );
     626                if ( existing == tables->structTable.end() ) {
     627                        StructDecl *parent = tables->base.lookupStructAtScope( id, scope );
     628                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     629                                tables->structTable.insert( existing, std::make_pair( id, decl ) );
     630                                ++tables->size;
     631                        }
     632                } else {
     633                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     634                                existing->second = decl;
     635                        }
     636                }
    586637        }
    587638
    588639        void Indexer::addEnum( EnumDecl *decl ) {
    589                 ++*stats().add_calls;
     640                debugPrint( "Adding enum " << decl->name << std::endl );
     641                makeWritable();
     642
    590643                const std::string &id = decl->name;
    591 
    592                 if ( ! enumTable ) {
    593                         enumTable = EnumTable::new_ptr();
    594                 } else {
    595                         ++*stats().map_lookups;
    596                         auto existing = enumTable->find( id );
    597                         if ( existing != enumTable->end() 
    598                                 && existing->second.scope == scope
    599                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    600                 }
    601                
    602                 lazyInitScope();
    603                 ++*stats().map_mutations;
    604                 enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } );
     644                EnumTable::iterator existing = tables->enumTable.find( id );
     645                if ( existing == tables->enumTable.end() ) {
     646                        EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope );
     647                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     648                                tables->enumTable.insert( existing, std::make_pair( id, decl ) );
     649                                ++tables->size;
     650                        }
     651                } else {
     652                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     653                                existing->second = decl;
     654                        }
     655                }
    605656        }
    606657
    607658        void Indexer::addUnion( const std::string &id ) {
     659                debugPrint( "Adding fwd decl for union " << id << std::endl );
    608660                addUnion( new UnionDecl( id ) );
    609661        }
    610662
    611663        void Indexer::addUnion( UnionDecl *decl ) {
    612                 ++*stats().add_calls;
     664                debugPrint( "Adding union " << decl->name << std::endl );
     665                makeWritable();
     666
    613667                const std::string &id = decl->name;
    614 
    615                 if ( ! unionTable ) {
    616                         unionTable = UnionTable::new_ptr();
    617                 } else {
    618                         ++*stats().map_lookups;
    619                         auto existing = unionTable->find( id );
    620                         if ( existing != unionTable->end()
    621                                 && existing->second.scope == scope
    622                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    623                 }
    624 
    625                 lazyInitScope();
    626                 ++*stats().map_mutations;
    627                 unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } );
     668                UnionTable::iterator existing = tables->unionTable.find( id );
     669                if ( existing == tables->unionTable.end() ) {
     670                        UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope );
     671                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     672                                tables->unionTable.insert( existing, std::make_pair( id, decl ) );
     673                                ++tables->size;
     674                        }
     675                } else {
     676                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     677                                existing->second = decl;
     678                        }
     679                }
    628680        }
    629681
    630682        void Indexer::addTrait( TraitDecl *decl ) {
    631                 ++*stats().add_calls;
     683                debugPrint( "Adding trait " << decl->name << std::endl );
     684                makeWritable();
     685
    632686                const std::string &id = decl->name;
    633 
    634                 if ( ! traitTable ) {
    635                         traitTable = TraitTable::new_ptr();
    636                 } else {
    637                         ++*stats().map_lookups;
    638                         auto existing = traitTable->find( id );
    639                         if ( existing != traitTable->end()
    640                                 && existing->second.scope == scope
    641                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    642                 }
    643 
    644                 lazyInitScope();
    645                 ++*stats().map_mutations;
    646                 traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } );
    647         }
    648 
    649         void Indexer::addMembers( AggregateDecl * aggr, Expression * expr,
    650                         OnConflict handleConflicts ) {
     687                TraitTable::iterator existing = tables->traitTable.find( id );
     688                if ( existing == tables->traitTable.end() ) {
     689                        TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope );
     690                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     691                                tables->traitTable.insert( existing, std::make_pair( id, decl ) );
     692                                ++tables->size;
     693                        }
     694                } else {
     695                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     696                                existing->second = decl;
     697                        }
     698                }
     699        }
     700
     701        void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
    651702                for ( Declaration * decl : aggr->members ) {
    652703                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     
    654705                                if ( dwt->name == "" ) {
    655706                                        Type * t = dwt->get_type()->stripReferences();
    656                                         if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
     707                                        if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
    657708                                                Expression * base = expr->clone();
    658709                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    671722                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    672723
    673                                 addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
     724                                addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
     725                                        // on conflict, delete the identifier
     726                                        existing.deleteStmt = withStmt;
     727                                        return true;
     728                                });
    674729                        }
    675730                }
     
    693748                addIds( ftype->returnVals );
    694749                addIds( ftype->parameters );
     750        }
     751
     752        void Indexer::enterScope() {
     753                ++scope;
     754
     755                if ( doDebug ) {
     756                        std::cerr << "--- Entering scope " << scope << std::endl;
     757                }
     758        }
     759
     760        void Indexer::leaveScope() {
     761                using std::cerr;
     762
     763                assert( scope > 0 && "cannot leave initial scope" );
     764                if ( doDebug ) {
     765                        cerr << "--- Leaving scope " << scope << " containing" << std::endl;
     766                }
     767                --scope;
     768
     769                while ( tables && tables->scope > scope ) {
     770                        if ( doDebug ) {
     771                                dump( tables->idTable, cerr );
     772                                dump( tables->typeTable, cerr );
     773                                dump( tables->structTable, cerr );
     774                                dump( tables->enumTable, cerr );
     775                                dump( tables->unionTable, cerr );
     776                                dump( tables->traitTable, cerr );
     777                        }
     778
     779                        // swap tables for base table until we find one at an appropriate scope
     780                        Indexer::Impl *base = newRef( tables->base.tables );
     781                        deleteRef( tables );
     782                        tables = base;
     783                }
     784        }
     785
     786        void Indexer::print( std::ostream &os, int indent ) const {
     787                using std::cerr;
     788
     789                if ( tables ) {
     790                        os << "--- scope " << tables->scope << " ---" << std::endl;
     791
     792                        os << "===idTable===" << std::endl;
     793                        dump( tables->idTable, os );
     794                        os << "===typeTable===" << std::endl;
     795                        dump( tables->typeTable, os );
     796                        os << "===structTable===" << std::endl;
     797                        dump( tables->structTable, os );
     798                        os << "===enumTable===" << std::endl;
     799                        dump( tables->enumTable, os );
     800                        os << "===unionTable===" << std::endl;
     801                        dump( tables->unionTable, os );
     802                        os << "===contextTable===" << std::endl;
     803                        dump( tables->traitTable, os );
     804
     805                        tables->base.print( os, indent );
     806                } else {
     807                        os << "--- end ---" << std::endl;
     808                }
     809
    695810        }
    696811
  • src/SymTab/Indexer.h

    r92d41a4 r709e0e0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:38:55 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Mar  8 13:55:00 2019
    13 // Update Count     : 9
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Aug 17 16:09:12 2017
     13// Update Count     : 8
    1414//
    1515
    1616#pragma once
    1717
    18 #include <functional>              // for function
    19 #include <list>                    // for list
    20 #include <memory>                  // for shared_ptr, enable_shared_from_this
    21 #include <string>                  // for string
     18#include <iosfwd>             // for ostream
     19#include <list>               // for list
     20#include <string>             // for string
     21#include <functional>         // for function
    2222
    23 #include "Common/PersistentMap.h"  // for PersistentMap
    24 #include "SynTree/SynTree.h"       // for AST nodes
     23#include "SynTree/Visitor.h"  // for Visitor
     24#include "SynTree/SynTree.h"  // for AST nodes
    2525
    2626namespace ResolvExpr {
    27         class Cost;
     27class Cost;
    2828}
    2929
    3030namespace SymTab {
    31         class Indexer : public std::enable_shared_from_this<SymTab::Indexer> {
    32         public:
     31        class Indexer {
     32          public:
    3333                explicit Indexer();
     34
     35                Indexer( const Indexer &that );
     36                Indexer( Indexer &&that );
    3437                virtual ~Indexer();
     38                Indexer& operator= ( const Indexer &that );
     39                Indexer& operator= ( Indexer &&that );
    3540
    36                 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to
    37                 // tell the indexer explicitly when scopes begin and end
     41                // when using an indexer manually (e.g., within a mutator traversal), it is necessary to tell the indexer
     42                // explicitly when scopes begin and end
    3843                void enterScope();
    3944                void leaveScope();
     
    4550                        /// non-null if this declaration is deleted
    4651                        BaseSyntaxNode * deleteStmt = nullptr;
    47                         /// scope of identifier
    48                         unsigned long scope = 0;
    4952
    5053                        // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members.
    5154                        IdData() = default;
    52                         IdData(
    53                                 DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt,
    54                                 unsigned long scope )
    55                                 : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ), scope( scope ) {}
    56                         IdData( const IdData& o, BaseSyntaxNode * deleteStmt )
    57                                 : id( o.id ), baseExpr( o.baseExpr ), deleteStmt( deleteStmt ), scope( o.scope ) {}
     55                        IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {}
    5856
    5957                        Expression * combine( ResolvExpr::Cost & cost ) const;
     
    8280                EnumDecl *globalLookupEnum( const std::string &id ) const;
    8381
     82                void print( std::ostream &os, int indent = 0 ) const;
     83
     84                /// looks up a specific mangled ID at the given scope
     85                IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope );
     86                const IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
     87                /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
     88                bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
     89                /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
     90                bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
     91                // equivalents to lookup functions that only look at tables at scope `scope` (which should be >= tables->scope)
     92                NamedTypeDecl *lookupTypeAtScope( const std::string &id, unsigned long scope ) const;
     93                StructDecl *lookupStructAtScope( const std::string &id, unsigned long scope ) const;
     94                EnumDecl *lookupEnumAtScope( const std::string &id, unsigned long scope ) const;
     95                UnionDecl *lookupUnionAtScope( const std::string &id, unsigned long scope ) const;
     96                TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;
     97
     98                typedef std::function<bool(IdData &, const std::string &)> ConflictFunction;
     99
    84100                void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr );
    85101                void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt );
     
    96112                void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt );
    97113
     114                /// adds all of the members of the Aggregate (addWith helper)
     115                void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );
     116
    98117                /// convenience function for adding a list of Ids to the indexer
    99118                void addIds( const std::list< DeclarationWithType * > & decls );
     
    105124                void addFunctionType( FunctionType * ftype );
    106125
     126                bool doDebug = false; ///< Display debugging trace?
    107127          private:
    108                 /// Wraps a Decl* with a scope
    109                 template<typename Decl>
    110                 struct Scoped {
    111                         Decl* decl;           ///< declaration
    112                         unsigned long scope;  ///< scope of this declaration
     128                struct Impl;
    113129
    114                         Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}
    115                 };
     130                Impl *tables;         ///< Copy-on-write instance of table data structure
     131                unsigned long scope;  ///< Scope index of this pointer
    116132
    117                 using Ptr = std::shared_ptr<const Indexer>;
     133                /// Takes a new ref to a table (returns null if null)
     134                static Impl *newRef( Impl *toClone );
     135                /// Clears a ref to a table (does nothing if null)
     136                static void deleteRef( Impl *toFree );
    118137
    119                 using MangleTable = PersistentMap< std::string, IdData >;
    120                 using IdTable = PersistentMap< std::string, MangleTable::Ptr >;
    121                 using TypeTable = PersistentMap< std::string, Scoped<NamedTypeDecl> >;
    122                 using StructTable = PersistentMap< std::string, Scoped<StructDecl> >;
    123                 using EnumTable = PersistentMap< std::string, Scoped<EnumDecl> >;
    124                 using UnionTable = PersistentMap< std::string, Scoped<UnionDecl> >;
    125                 using TraitTable = PersistentMap< std::string, Scoped<TraitDecl> >;
     138                // Removes matching autogenerated constructors and destructors
     139                // so that they will not be selected
     140                // void removeSpecialOverrides( FunctionDecl *decl );
     141                void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const;
    126142
    127                 IdTable::Ptr idTable;          ///< identifier namespace
    128                 TypeTable::Ptr typeTable;      ///< type namespace
    129                 StructTable::Ptr structTable;  ///< struct namespace
    130                 EnumTable::Ptr enumTable;      ///< enum namespace
    131                 UnionTable::Ptr unionTable;    ///< union namespace
    132                 TraitTable::Ptr traitTable;    ///< trait namespace
    133 
    134                 Ptr prevScope;                 ///< reference to indexer for parent scope
    135                 unsigned long scope;           ///< Scope index of this indexer
    136                 unsigned long repScope;        ///< Scope index of currently represented scope
    137 
    138                 /// Ensures that a proper backtracking scope exists before a mutation
    139                 void lazyInitScope();
    140 
    141                 /// Gets the indexer at the given scope
    142                 const Indexer* atScope( unsigned long scope ) const;
    143 
    144                 /// Removes matching autogenerated constructors and destructors so that they will not be
    145                 /// selected. If returns false, passed decl should not be added.
    146                 bool removeSpecialOverrides( IdData& decl, MangleTable::Ptr& mangleTable );
    147 
    148                 /// Options for handling identifier conflicts
    149                 struct OnConflict {
    150                         enum {
    151                                 Error,  ///< Throw a semantic error
    152                                 Delete  ///< Delete the earlier version with the delete statement
    153                         } mode;
    154                         BaseSyntaxNode * deleteStmt;  ///< Statement that deletes this expression
    155 
    156                 private:
    157                         OnConflict() : mode(Error), deleteStmt(nullptr) {}
    158                         OnConflict( BaseSyntaxNode * d ) : mode(Delete), deleteStmt(d) {}
    159                 public:
    160                         OnConflict( const OnConflict& ) = default;
    161 
    162                         static OnConflict error() { return {}; }
    163                         static OnConflict deleteWith( BaseSyntaxNode * d ) { return { d }; }
    164                 };
    165 
    166                 /// true if the existing identifier conflicts with the added identifier
    167                 bool addedIdConflicts(
    168                         const IdData& existing, DeclarationWithType * added, OnConflict handleConflicts,
    169                         BaseSyntaxNode * deleteStmt );
     143                /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
     144                void makeWritable();
    170145
    171146                /// common code for addId, addDeletedId, etc.
    172                 void addId(
    173                         DeclarationWithType * decl, OnConflict handleConflicts,
    174                         Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
    175 
    176                 /// adds all of the members of the Aggregate (addWith helper)
    177                 void addMembers( AggregateDecl * aggr, Expression * expr, OnConflict handleConflicts );
    178 
    179                 /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
    180                 bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
    181                 /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
    182                 bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
     147                void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
    183148        };
    184149} // namespace SymTab
  • src/SynTree/BaseSyntaxNode.h

    r92d41a4 r709e0e0  
    1818#include "Common/CodeLocation.h"
    1919#include "Common/Indenter.h"
    20 #include "Common/Stats.h"
    21 
    2220class Visitor;
    2321class Mutator;
     
    2523class BaseSyntaxNode {
    2624  public:
    27   static Stats::Counters::SimpleCounter* new_nodes;
    28 
    2925        CodeLocation location;
    30 
    31   BaseSyntaxNode() { ++*new_nodes; }
    32   BaseSyntaxNode( const BaseSyntaxNode& ) { ++*new_nodes; }
    3326
    3427        virtual ~BaseSyntaxNode() {}
  • src/main.cc

    r92d41a4 r709e0e0  
    6565using namespace std;
    6666
     67
    6768void NewPass(const char * const name) {
    6869        Stats::Heap::newPass(name);
    6970        using namespace Stats::Counters;
    70        
    71         {
    72                 static auto group = build<CounterGroup>("Pass Visitor");
    73                 auto pass = build<CounterGroup>(name, group);
    74                 pass_visitor_stats.depth = 0;
    75                 pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass);
    76                 pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass);
    77         }
    78 
    79         {
    80                 static auto group = build<CounterGroup>("Syntax Node");
    81                 auto pass = build<CounterGroup>(name, group);
    82                 BaseSyntaxNode::new_nodes = build<SimpleCounter>("Allocs", pass);
    83         }
     71        static auto pass_visitor_group = build<CounterGroup>("Pass Visitor");
     72        auto pass = build<CounterGroup>(name, pass_visitor_group);
     73        pass_visitor_stats.depth = 0;
     74        pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass);
     75        pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass);
    8476}
    8577
Note: See TracChangeset for help on using the changeset viewer.