Ignore:
Timestamp:
Aug 27, 2018, 4:40:34 PM (7 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
b7c89aa
Parents:
f9feab8 (diff), 305581d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into cleanup-dtors

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/SymTab/Indexer.cc

    rf9feab8 r90152a4  
    2626#include "Common/SemanticError.h"  // for SemanticError
    2727#include "Common/utility.h"        // for cloneAll
     28#include "GenPoly/GenPoly.h"
    2829#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    2930#include "Mangler.h"               // for Mangler
     
    105106                if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
    106107
    107                 // helpful data structure
     108                // helpful data structure to organize properties for a type
    108109                struct ValueType {
    109                         struct DeclBall {
     110                        struct DeclBall { // properties for this particular decl
    110111                                IdData decl;
    111                                 bool isUserDefinedFunc; // properties for this particular decl
    112                                 bool isDefaultCtor;
    113                                 bool isDtor;
     112                                bool isUserDefinedFunc;
    114113                                bool isCopyFunc;
    115114                        };
    116115                        // properties for this type
    117                         bool existsUserDefinedFunc = false;    // any user-defined function found
    118                         bool existsUserDefinedCtor = false;    // any user-defined constructor found
    119                         bool existsUserDefinedDtor = false;    // any user-defined destructor found
    120116                        bool existsUserDefinedCopyFunc = false;    // user-defined copy ctor found
    121                         bool existsUserDefinedDefaultCtor = false; // user-defined default ctor found
     117                        BaseSyntaxNode * deleteStmt = nullptr;     // non-null if a user-defined function is found
    122118                        std::list< DeclBall > decls;
    123119
     
    126122                        ValueType & operator+=( IdData data ) {
    127123                                DeclarationWithType * function = data.id;
    128                                 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->get_linkage() );
    129                                 bool isDefaultCtor = InitTweak::isDefaultConstructor( function );
    130                                 bool isDtor = InitTweak::isDestructor( function );
    131                                 bool isCopyFunc = InitTweak::isCopyFunction( function, function->get_name() );
    132                                 decls.push_back( DeclBall{ data, isUserDefinedFunc, isDefaultCtor, isDtor, isCopyFunc } );
    133                                 existsUserDefinedFunc = existsUserDefinedFunc || isUserDefinedFunc;
    134                                 existsUserDefinedCtor = existsUserDefinedCtor || (isUserDefinedFunc && CodeGen::isConstructor( function->get_name() ) );
    135                                 existsUserDefinedDtor = existsUserDefinedDtor || (isUserDefinedFunc && isDtor);
     124                                bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
     125                                bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
     126                                decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
    136127                                existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc);
    137                                 existsUserDefinedDefaultCtor = existsUserDefinedDefaultCtor || (isUserDefinedFunc && isDefaultCtor);
     128                                if ( isUserDefinedFunc && ! deleteStmt ) {
     129                                        // any user-defined function can act as an implicit delete statement for generated constructors.
     130                                        // a delete stmt should not act as an implicit delete statement.
     131                                        deleteStmt = data.id;
     132                                }
    138133                                return *this;
    139134                        }
     
    147142                for ( auto decl : copy ) {
    148143                        if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
    149                                 std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
     144                                std::list< DeclarationWithType * > & params = function->type->parameters;
    150145                                assert( ! params.empty() );
    151146                                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
     
    159154
    160155                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine
    161                 // the set of ctor/dtor/assign that are seen by the requester. In particular, if the user defines
    162                 // a default ctor, then the generated default ctor should never be seen, likewise for copy ctor
    163                 // and dtor. If the user defines any ctor/dtor, then no generated field ctors should be seen.
    164                 // If the user defines any ctor then the generated default ctor should not be seen (intrinsic default
    165                 // ctor must be overridden exactly).
     156                // the set of ctor/dtor/assign that can be used  by the requester. In particular, if the user defines
     157                // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor
     158                // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available.
     159                // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default
     160                // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor,
     161                // then the generated copy constructor is unavailable, and likewise for the assignment operator.
    166162                for ( std::pair< const std::string, ValueType > & pair : funcMap ) {
    167163                        ValueType & val = pair.second;
    168164                        for ( ValueType::DeclBall ball : val.decls ) {
    169                                 bool noUserDefinedFunc = ! val.existsUserDefinedFunc;
    170                                 bool isUserDefinedFunc = ball.isUserDefinedFunc;
    171                                 bool isAcceptableDefaultCtor = (! val.existsUserDefinedCtor || (! val.existsUserDefinedDefaultCtor && ball.decl.id->get_linkage() == LinkageSpec::Intrinsic)) && ball.isDefaultCtor; // allow default constructors only when no user-defined constructors exist, except in the case of intrinsics, which require exact overrides
    172                                 bool isAcceptableCopyFunc = ! val.existsUserDefinedCopyFunc && ball.isCopyFunc; // handles copy ctor and assignment operator
    173                                 bool isAcceptableDtor = ! val.existsUserDefinedDtor && ball.isDtor;
    174                                 if ( noUserDefinedFunc || isUserDefinedFunc || isAcceptableDefaultCtor || isAcceptableCopyFunc || isAcceptableDtor ) {
    175                                         // decl conforms to the rules described above, so it should be seen by the requester
    176                                         out.push_back( ball.decl );
     165                                bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic;
     166                                bool isCopyFunc = ball.isCopyFunc;
     167                                bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc;
     168
     169                                // only implicitly delete non-user defined functions that are not intrinsic, and are
     170                                // not copy functions (assignment or copy constructor). If a  user-defined copy function exists,
     171                                // do not pass along the non-user-defined copy functions since signatures do not have to match,
     172                                // and the generated functions will often be cheaper.
     173                                if ( isNotUserDefinedFunc ) {
     174                                        if ( isCopyFunc ) {
     175                                                // Skip over non-user-defined copy functions when there is a user-defined copy function.
     176                                                // Since their signatures do not have to be exact, deleting them is the wrong choice.
     177                                                if ( existsUserDefinedCopyFunc ) continue;
     178                                        } else {
     179                                                // delete non-user-defined non-copy functions if applicable.
     180                                                // deleteStmt will be non-null only if a user-defined function is found.
     181                                                ball.decl.deleteStmt = val.deleteStmt;
     182                                        }
    177183                                }
     184                                out.push_back( ball.decl );
    178185                        }
    179186                }
     
    265272        }
    266273
     274        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
     275                return lookupTypeAtScope( id, 0 );
     276        }
     277
     278        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
     279                return lookupStructAtScope( id, 0 );
     280        }
     281
     282        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
     283                return lookupUnionAtScope( id, 0 );
     284        }
     285
     286        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
     287                return lookupEnumAtScope( id, 0 );
     288        }
     289
    267290        EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    268291                if ( ! tables ) return 0;
     
    286309        }
    287310
    288         DeclarationWithType *Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    289                 if ( ! tables ) return 0;
    290                 if ( tables->scope < scope ) return 0;
     311        const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
     312                if ( ! tables ) return nullptr;
     313                if ( tables->scope < scope ) return nullptr;
    291314
    292315                IdTable::const_iterator decls = tables->idTable.find( id );
     
    294317                        const MangleTable &mangleTable = decls->second;
    295318                        MangleTable::const_iterator decl = mangleTable.find( mangleName );
    296                         if ( decl != mangleTable.end() ) return decl->second.id;
     319                        if ( decl != mangleTable.end() ) return &decl->second;
    297320                }
    298321
    299322                return tables->base.lookupIdAtScope( id, mangleName, scope );
     323        }
     324
     325        Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
     326                return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
    300327        }
    301328
     
    336363                if ( ! tables ) return 0;
    337364                if ( tables->scope < scope ) return 0;
     365                if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope );
    338366
    339367                TypeTable::const_iterator ret = tables->typeTable.find( id );
     
    344372                if ( ! tables ) return 0;
    345373                if ( tables->scope < scope ) return 0;
     374                if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope );
    346375
    347376                StructTable::const_iterator ret = tables->structTable.find( id );
     
    352381                if ( ! tables ) return 0;
    353382                if ( tables->scope < scope ) return 0;
     383                if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope );
    354384
    355385                EnumTable::const_iterator ret = tables->enumTable.find( id );
     
    360390                if ( ! tables ) return 0;
    361391                if ( tables->scope < scope ) return 0;
     392                if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope );
    362393
    363394                UnionTable::const_iterator ret = tables->unionTable.find( id );
     
    368399                if ( ! tables ) return 0;
    369400                if ( tables->scope < scope ) return 0;
     401                if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope );
    370402
    371403                TraitTable::const_iterator ret = tables->traitTable.find( id );
     
    373405        }
    374406
    375         bool addedIdConflicts( DeclarationWithType *existing, DeclarationWithType *added ) {
     407        bool isFunction( DeclarationWithType * decl ) {
     408                return GenPoly::getFunctionType( decl->get_type() );
     409        }
     410
     411        bool isObject( DeclarationWithType * decl ) {
     412                return ! isFunction( decl );
     413        }
     414
     415        bool isDefinition( DeclarationWithType * decl ) {
     416                if ( FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ) ) {
     417                        // a function is a definition if it has a body
     418                        return func->statements;
     419                } else {
     420                        // an object is a definition if it is not marked extern.
     421                        // both objects must be marked extern
     422                        return ! decl->get_storageClasses().is_extern;
     423                }
     424        }
     425
     426        bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
    376427                // if we're giving the same name mangling to things of different types then there is something wrong
    377                 assert( (dynamic_cast<ObjectDecl*>( added ) && dynamic_cast<ObjectDecl*>( existing ) )
    378                         || (dynamic_cast<FunctionDecl*>( added ) && dynamic_cast<FunctionDecl*>( existing ) ) );
    379 
    380                 if ( LinkageSpec::isOverridable( existing->get_linkage() ) ) {
     428                assert( (isObject( added ) && isObject( existing.id ) )
     429                        || ( isFunction( added ) && isFunction( existing.id ) ) );
     430
     431                if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
    381432                        // new definition shadows the autogenerated one, even at the same scope
    382433                        return false;
    383                 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing->get_type(), Indexer() ) ) {
    384                         // typesCompatible doesn't really do the right thing here. When checking compatibility of function types,
    385                         // we should ignore outermost pointer qualifiers, except _Atomic?
    386                         FunctionDecl *newentry = dynamic_cast< FunctionDecl* >( added );
    387                         FunctionDecl *oldentry = dynamic_cast< FunctionDecl* >( existing );
    388                         if ( newentry && oldentry ) {
    389                                 if ( newentry->get_statements() && oldentry->get_statements() ) {
    390                                         throw SemanticError( "duplicate function definition for ", added );
    391                                 } // if
    392                         } else {
    393                                 // two objects with the same mangled name defined in the same scope.
    394                                 // both objects must be marked extern or both must be intrinsic for this to be okay
    395                                 // xxx - perhaps it's actually if either is intrinsic then this is okay?
    396                                 //       might also need to be same storage class?
    397                                 ObjectDecl *newobj = dynamic_cast< ObjectDecl* >( added );
    398                                 ObjectDecl *oldobj = dynamic_cast< ObjectDecl* >( existing );
    399                                 if ( ! newobj->get_storageClasses().is_extern && ! oldobj->get_storageClasses().is_extern ) {
    400                                         throw SemanticError( "duplicate object definition for ", added );
     434                } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
     435
     436                        // it is a conflict if one declaration is deleted and the other is not
     437                        if ( deleteStmt && ! existing.deleteStmt ) {
     438                                return handleConflicts( existing, "deletion of defined identifier " );
     439                        } else if ( ! deleteStmt && existing.deleteStmt ) {
     440                                return handleConflicts( existing, "definition of deleted identifier " );
     441                        }
     442
     443                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
     444                                if ( isFunction( added ) ) {
     445                                        return handleConflicts( existing, "duplicate function definition for " );
     446                                } else {
     447                                        return handleConflicts( existing, "duplicate object definition for " );
    401448                                } // if
    402449                        } // if
    403450                } else {
    404                         throw SemanticError( "duplicate definition for ", added );
     451                        return handleConflicts( existing, "duplicate definition for " );
    405452                } // if
    406453
     
    408455        }
    409456
    410         void Indexer::addId( DeclarationWithType *decl, Expression * baseExpr ) {
     457        void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
     458                if ( decl->name == "" ) return;
    411459                debugPrint( "Adding Id " << decl->name << std::endl );
    412460                makeWritable();
     
    430478                        // isomorphic to C type-compatibility, which it may not be.
    431479                        if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
    432                                 throw SemanticError( "conflicting overload of C function ", decl );
    433                         }
    434                 } else {
    435                         // Check that a Cforall declaration doesn't overload any C declaration
     480                                SemanticError( decl, "conflicting overload of C function " );
     481                        }
     482                } else {
     483                        // Check that a Cforall declaration doesn't override any C declaration
    436484                        if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    437                                 throw SemanticError( "Cforall declaration hides C function ", decl );
     485                                SemanticError( decl, "Cforall declaration hides C function " );
    438486                        }
    439487                }
    440488
    441489                // Skip repeat declarations of the same identifier
    442                 DeclarationWithType *existing = lookupIdAtScope( name, mangleName, scope );
    443                 if ( existing && addedIdConflicts( existing, decl ) ) return;
     490                IdData * existing = lookupIdAtScope( name, mangleName, scope );
     491                if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
    444492
    445493                // add to indexer
    446                 tables->idTable[ name ][ mangleName ] = { decl, baseExpr };
     494                tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt };
    447495                ++tables->size;
    448496        }
    449497
     498        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
     499                // default handling of conflicts is to raise an error
     500                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
     501        }
     502
     503        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
     504                // default handling of conflicts is to raise an error
     505                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
     506        }
     507
    450508        bool addedTypeConflicts( NamedTypeDecl *existing, NamedTypeDecl *added ) {
    451                 if ( existing->get_base() == 0 ) {
     509                if ( existing->base == nullptr ) {
    452510                        return false;
    453                 } else if ( added->get_base() == 0 ) {
     511                } else if ( added->base == nullptr ) {
    454512                        return true;
    455513                } else {
    456                         throw SemanticError( "redeclaration of ", added );
    457                 }
     514                        assert( existing->base && added->base );
     515                        // typedef redeclarations are errors only if types are different
     516                        if ( ! ResolvExpr::typesCompatible( existing->base, added->base, Indexer() ) ) {
     517                                SemanticError( added->location, "redeclaration of " + added->name );
     518                        }
     519                }
     520                // does not need to be added to the table if both existing and added have a base that are the same
     521                return true;
    458522        }
    459523
     
    462526                makeWritable();
    463527
    464                 const std::string &id = decl->get_name();
     528                const std::string &id = decl->name;
    465529                TypeTable::iterator existing = tables->typeTable.find( id );
    466530                if ( existing == tables->typeTable.end() ) {
     
    478542
    479543        bool addedDeclConflicts( AggregateDecl *existing, AggregateDecl *added ) {
    480                 if ( existing->get_members().empty() ) {
     544                if ( ! existing->body ) {
    481545                        return false;
    482                 } else if ( ! added->get_members().empty() ) {
    483                         throw SemanticError( "redeclaration of ", added );
     546                } else if ( added->body ) {
     547                        SemanticError( added, "redeclaration of " );
    484548                } // if
    485549                return true;
     
    495559                makeWritable();
    496560
    497                 const std::string &id = decl->get_name();
     561                const std::string &id = decl->name;
    498562                StructTable::iterator existing = tables->structTable.find( id );
    499563                if ( existing == tables->structTable.end() ) {
     
    514578                makeWritable();
    515579
    516                 const std::string &id = decl->get_name();
     580                const std::string &id = decl->name;
    517581                EnumTable::iterator existing = tables->enumTable.find( id );
    518582                if ( existing == tables->enumTable.end() ) {
     
    538602                makeWritable();
    539603
    540                 const std::string &id = decl->get_name();
     604                const std::string &id = decl->name;
    541605                UnionTable::iterator existing = tables->unionTable.find( id );
    542606                if ( existing == tables->unionTable.end() ) {
     
    557621                makeWritable();
    558622
    559                 const std::string &id = decl->get_name();
     623                const std::string &id = decl->name;
    560624                TraitTable::iterator existing = tables->traitTable.find( id );
    561625                if ( existing == tables->traitTable.end() ) {
     
    572636        }
    573637
    574         void Indexer::addWith( WithStmt * stmt ) {
    575                 for ( Expression * expr : stmt->exprs ) {
     638        void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
     639                for ( Declaration * decl : aggr->members ) {
     640                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     641                                addId( dwt, handleConflicts, expr );
     642                                if ( dwt->name == "" ) {
     643                                        Type * t = dwt->get_type()->stripReferences();
     644                                        if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
     645                                                Expression * base = expr->clone();
     646                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     647                                                ResolvExpr::referenceToRvalueConversion( base, cost );
     648                                                addMembers( t->getAggr(), new MemberExpr( dwt, base ), handleConflicts );
     649                                        }
     650                                }
     651                        }
     652                }
     653        }
     654
     655        void Indexer::addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ) {
     656                for ( Expression * expr : withExprs ) {
    576657                        if ( expr->result ) {
    577658                                AggregateDecl * aggr = expr->result->stripReferences()->getAggr();
    578659                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    579660
    580                                 for ( Declaration * decl : aggr->members ) {
    581                                         if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
    582                                                 addId( dwt, expr );
    583                                         }
    584                                 }
     661                                addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
     662                                        // on conflict, delete the identifier
     663                                        existing.deleteStmt = withStmt;
     664                                        return true;
     665                                });
    585666                        }
    586667                }
     
    641722
    642723        void Indexer::print( std::ostream &os, int indent ) const {
    643             using std::cerr;
     724                using std::cerr;
    644725
    645726                if ( tables ) {
     
    666747        }
    667748
    668         Expression * Indexer::IdData::combine() const {
     749        Expression * Indexer::IdData::combine( ResolvExpr::Cost & cost ) const {
     750                Expression * ret = nullptr;
    669751                if ( baseExpr ) {
    670752                        Expression * base = baseExpr->clone();
    671                         ResolvExpr::referenceToRvalueConversion( base );
    672                         Expression * ret = new MemberExpr( id, base );
     753                        ResolvExpr::referenceToRvalueConversion( base, cost );
     754                        ret = new MemberExpr( id, base );
    673755                        // xxx - this introduces hidden environments, for now remove them.
    674756                        // std::swap( base->env, ret->env );
    675757                        delete base->env;
    676758                        base->env = nullptr;
    677                         return ret;
    678                 } else {
    679                         return new VariableExpr( id );
    680                 }
     759                } else {
     760                        ret = new VariableExpr( id );
     761                }
     762                if ( deleteStmt ) ret = new DeletedExpr( ret, deleteStmt );
     763                return ret;
    681764        }
    682765} // namespace SymTab
Note: See TracChangeset for help on using the changeset viewer.