Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r0e315a5 r02fdb8e  
    5454#include "SynTree/Type.h"              // for Type, Type::StorageClasses
    5555#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
    56 #include "SynTree/DeclReplacer.h"      // for DeclReplacer
    5756#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    58 #include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    5957
    6058bool ctordtorp = false; // print all debug
     
    6866namespace InitTweak {
    6967        namespace {
     68                typedef std::unordered_map< int, int > UnqCount;
     69
    7070                struct SelfAssignChecker {
    7171                        void previsit( ApplicationExpr * appExpr );
    72                 };
    73 
    74                 struct StmtExprResult {
    75                         static void link( std::list< Declaration * > & translationUnit );
    76 
    77                         void previsit( StmtExpr * stmtExpr );
    7872                };
    7973
     
    8680                };
    8781
    88                 struct ResolveCopyCtors final : public WithStmtsToAdd, public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution, public WithVisitorRef<ResolveCopyCtors> {
     82                struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
    8983                        /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
    9084                        /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    9185                        /// arguments and return value temporaries
    92                         static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
    93 
    94                         Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
    95                         void premutate( StmtExpr * stmtExpr );
    96                         void premutate( UniqueExpr * unqExpr );
     86                        static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount );
     87
     88                        ResolveCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ) {}
     89
     90                        void postvisit( ImplicitCopyCtorExpr * impCpCtorExpr );
     91                        void postvisit( StmtExpr * stmtExpr );
     92                        void previsit( UniqueExpr * unqExpr );
     93                        void postvisit( UniqueExpr * unqExpr );
    9794
    9895                        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
     
    10198                        bool skipCopyConstruct( Type * type );
    10299                        void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal );
    103                         void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr, Expression *& arg );
     100                        void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
     101
     102                        UnqCount & unqCount; // count the number of times each unique expr ID appears
     103                        std::unordered_set< int > vars;
    104104                };
    105105
     
    162162                        using Parent::previsit;
    163163
     164                        void previsit( ObjectDecl * objDecl );
    164165                        void previsit( FunctionDecl * funcDecl );
    165166
     167                        void previsit( CompoundStmt * compoundStmt );
     168                        void postvisit( CompoundStmt * compoundStmt );
     169                        void previsit( ReturnStmt * returnStmt );
    166170                        void previsit( BranchStmt * stmt );
    167171                private:
     
    181185
    182186                        std::list< Declaration * > staticDtorDecls;
     187                };
     188
     189                class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithConstTypeSubstitution {
     190                  public:
     191                        FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
     192                        /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, call expression,
     193                        /// and destructors
     194                        static void fixCopyCtors( std::list< Declaration * > &translationUnit, UnqCount & unqCount );
     195
     196                        Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
     197                        void premutate( StmtExpr * stmtExpr );
     198                        void premutate( UniqueExpr * unqExpr );
     199
     200                        UnqCount & unqCount;
    183201                };
    184202
     
    218236                        Expression * postmutate( ConstructorExpr * ctorExpr );
    219237                };
    220 
    221                 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
    222                         /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
    223                         static void split( std::list< Declaration * > &translationUnit );
    224 
    225                         Statement * postmutate( ExprStmt * stmt );
    226                         void premutate( TupleAssignExpr * expr );
    227                 };
    228238        } // namespace
    229239
     
    232242                acceptAll( translationUnit, checker );
    233243
    234                 // fixes StmtExpr to properly link to their resulting expression
    235                 StmtExprResult::link( translationUnit );
    236 
    237244                // fixes ConstructorInit for global variables. should happen before fixInitializers.
    238245                InitTweak::fixGlobalInit( translationUnit, inLibrary );
    239246
    240                 // must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
    241                 SplitExpressions::split( translationUnit );
     247                UnqCount unqCount;
    242248
    243249                InsertImplicitCalls::insert( translationUnit );
    244 
    245                 // Needs to happen before ResolveCopyCtors, because argument/return temporaries should not be considered in
    246                 // error checking branch statements
     250                ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
    247251                InsertDtors::insert( translationUnit );
    248 
    249                 ResolveCopyCtors::resolveImplicitCalls( translationUnit );
    250252                FixInit::fixInitializers( translationUnit );
     253
     254                // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
     255                FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
     256
    251257                GenStructMemberCalls::generate( translationUnit );
    252258
    253                 // Needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
    254                 // don't have the correct form, and a member can be constructed more than once.
     259                // xxx - ctor expansion currently has to be after FixCopyCtors, because there is currently a
     260                // hack in the way untyped assignments are generated, where the first argument cannot have
     261                // its address taken because of the way codegeneration handles UntypedExpr vs. ApplicationExpr.
     262                // Thus such assignment exprs must never pushed through expression resolution (and thus should
     263                // not go through the FixCopyCtors pass), otherwise they will fail -- guaranteed.
     264                // Also needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
     265                // don't look right, and a member can be constructed more than once.
    255266                FixCtorExprs::fix( translationUnit );
    256267        }
    257268
    258269        namespace {
    259                 /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk
    260                 /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration
    261                 DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * input, std::list< Statement * > & stmtsToAdd ) {
    262                         // unwrap implicit statement wrapper
    263                         Statement * dtor = input;
    264                         if ( ImplicitCtorDtorStmt * implicit = dynamic_cast< ImplicitCtorDtorStmt * >( input ) ) {
    265                                 // dtor = implicit->callStmt;
    266                                 // implicit->callStmt = nullptr;
    267                         }
    268                         assert( dtor );
    269                         std::list< Expression * > matches;
    270                         collectCtorDtorCalls( dtor, matches );
    271 
    272                         if ( dynamic_cast< ExprStmt * >( dtor ) ) {
    273                                 // only one destructor call in the expression
    274                                 if ( matches.size() == 1 ) {
    275                                         DeclarationWithType * func = getFunction( matches.front() );
    276                                         assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
    277 
    278                                         // cleanup argument must be a function, not an object (including function pointer)
    279                                         if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
    280                                                 if ( dtorFunc->type->forall.empty() ) {
    281                                                         // simple case where the destructor is a monomorphic function call - can simply
    282                                                         // use that function as the cleanup function.
    283                                                         delete dtor;
    284                                                         return func;
    285                                                 }
    286                                         }
    287                                 }
    288                         }
    289 
    290                         // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
    291                         // wraps the more complicated code.
    292                         static UniqueName dtorNamer( "__cleanup_dtor" );
    293                         FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt() );
    294                         stmtsToAdd.push_back( new DeclStmt( dtorFunc ) );
    295 
    296                         // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
    297                         ObjectDecl * thisParam = getParamThis( dtorFunc->type );
    298                         Expression * replacement = new VariableExpr( thisParam );
    299 
    300                         Type * base = replacement->result->stripReferences();
    301                         if ( dynamic_cast< ArrayType * >( base ) || dynamic_cast< TupleType * > ( base ) ) {
    302                                 // need to cast away reference for array types, since the destructor is generated without the reference type,
    303                                 // and for tuple types since tuple indexing does not work directly on a reference
    304                                 replacement = new CastExpr( replacement, base->clone() );
    305                         }
    306                         DeclReplacer::replace( dtor, { std::make_pair( objDecl, replacement ) } );
    307                         dtorFunc->statements->push_back( strict_dynamic_cast<Statement *>( dtor ) );
    308 
    309                         return dtorFunc;
    310                 }
    311 
    312                 void StmtExprResult::link( std::list< Declaration * > & translationUnit ) {
    313                         PassVisitor<StmtExprResult> linker;
    314                         acceptAll( translationUnit, linker );
    315                 }
    316 
    317                 void SplitExpressions::split( std::list< Declaration * > & translationUnit ) {
    318                         PassVisitor<SplitExpressions> splitter;
    319                         mutateAll( translationUnit, splitter );
    320                 }
    321 
    322270                void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
    323271                        PassVisitor<InsertImplicitCalls> inserter;
     
    325273                }
    326274
    327                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
    328                         PassVisitor<ResolveCopyCtors> resolver;
    329                         mutateAll( translationUnit, resolver );
     275                void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
     276                        PassVisitor<ResolveCopyCtors> resolver( unqCount );
     277                        acceptAll( translationUnit, resolver );
    330278                }
    331279
     
    355303                }
    356304
     305                void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
     306                        PassVisitor<FixCopyCtors> fixer( unqCount );
     307                        mutateAll( translationUnit, fixer );
     308                }
     309
    357310                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
    358311                        PassVisitor<GenStructMemberCalls> warner;
     
    365318                }
    366319
    367                 void StmtExprResult::previsit( StmtExpr * stmtExpr ) {
    368                         // we might loose the result expression here so add a pointer to trace back
    369                         assert( stmtExpr->result );
    370                         Type * result = stmtExpr->result;
    371                         if ( ! result->isVoid() ) {
    372                                 CompoundStmt * body = stmtExpr->statements;
    373                                 assert( ! body->kids.empty() );
    374                                 stmtExpr->resultExpr = strict_dynamic_cast< ExprStmt * >( body->kids.back() );
    375                         }
    376                 }
    377 
    378                 Statement * SplitExpressions::postmutate( ExprStmt * stmt ) {
    379                         // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
    380                         // in the correct places
    381                         CompoundStmt * ret = new CompoundStmt( { stmt } );
    382                         return ret;
    383                 }
    384 
    385                 void SplitExpressions::premutate( TupleAssignExpr * ) {
    386                         // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
    387                         visit_children = false;
    388                 }
    389 
    390                 // Relatively simple structural comparison for expressions, needed to determine
    391                 // if two expressions are "the same" (used to determine if self assignment occurs)
    392                 struct StructuralChecker {
    393                         Expression * stripCasts( Expression * expr ) {
    394                                 // this might be too permissive. It's possible that only particular casts are relevant.
    395                                 while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
    396                                         expr = cast->arg;
    397                                 }
    398                                 return expr;
    399                         }
    400 
    401                         void previsit( Expression * ) {
    402                                 // anything else does not qualify
    403                                 isSimilar = false;
    404                         }
    405 
    406                         template<typename T>
    407                         T * cast( Expression * node ) {
    408                                 // all expressions need to ignore casts, so this bit has been factored out
    409                                 return dynamic_cast< T * >( stripCasts( node ) );
    410                         }
    411 
    412                         // ignore casts
    413                         void previsit( CastExpr * ) {}
    414 
    415                         void previsit( MemberExpr * memExpr ) {
    416                                 if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
    417                                         if ( otherMember->member == memExpr->member ) {
    418                                                 other = otherMember->aggregate;
     320                namespace {
     321                        // Relatively simple structural comparison for expressions, needed to determine
     322                        // if two expressions are "the same" (used to determine if self assignment occurs)
     323                        struct StructuralChecker {
     324                                Expression * stripCasts( Expression * expr ) {
     325                                        // this might be too permissive. It's possible that only particular casts are relevant.
     326                                        while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
     327                                                expr = cast->arg;
     328                                        }
     329                                        return expr;
     330                                }
     331
     332                                void previsit( Expression * ) {
     333                                        // anything else does not qualify
     334                                        isSimilar = false;
     335                                }
     336
     337                                template<typename T>
     338                                T * cast( Expression * node ) {
     339                                        // all expressions need to ignore casts, so this bit has been factored out
     340                                        return dynamic_cast< T * >( stripCasts( node ) );
     341                                }
     342
     343                                // ignore casts
     344                                void previsit( CastExpr * ) {}
     345
     346                                void previsit( MemberExpr * memExpr ) {
     347                                        if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
     348                                                if ( otherMember->member == memExpr->member ) {
     349                                                        other = otherMember->aggregate;
     350                                                        return;
     351                                                }
     352                                        }
     353                                        isSimilar = false;
     354                                }
     355
     356                                void previsit( VariableExpr * varExpr ) {
     357                                        if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
     358                                                if ( otherVar->var == varExpr->var ) {
     359                                                        return;
     360                                                }
     361                                        }
     362                                        isSimilar = false;
     363                                }
     364
     365                                void previsit( AddressExpr * ) {
     366                                        if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
     367                                                other = addrExpr->arg;
    419368                                                return;
    420369                                        }
    421                                 }
    422                                 isSimilar = false;
    423                         }
    424 
    425                         void previsit( VariableExpr * varExpr ) {
    426                                 if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
    427                                         if ( otherVar->var == varExpr->var ) {
    428                                                 return;
    429                                         }
    430                                 }
    431                                 isSimilar = false;
    432                         }
    433 
    434                         void previsit( AddressExpr * ) {
    435                                 if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
    436                                         other = addrExpr->arg;
    437                                         return;
    438                                 }
    439                                 isSimilar = false;
    440                         }
    441 
    442                         Expression * other = nullptr;
    443                         bool isSimilar = true;
    444                 };
    445 
    446                 bool structurallySimilar( Expression * e1, Expression * e2 ) {
    447                         PassVisitor<StructuralChecker> checker;
    448                         checker.pass.other = e2;
    449                         e1->accept( checker );
    450                         return checker.pass.isSimilar;
     370                                        isSimilar = false;
     371                                }
     372
     373                                Expression * other = nullptr;
     374                                bool isSimilar = true;
     375                        };
     376
     377                        bool structurallySimilar( Expression * e1, Expression * e2 ) {
     378                                PassVisitor<StructuralChecker> checker;
     379                                checker.pass.other = e2;
     380                                e1->accept( checker );
     381                                return checker.pass.isSimilar;
     382                        }
    451383                }
    452384
     
    525457                        if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
    526458                                // fix newly generated StmtExpr
    527                                 premutate( assign->stmtExpr );
     459                                postvisit( assign->stmtExpr );
    528460                        }
    529461                        return resolved;
     
    557489                                        // so that the object isn't changed inside of the polymorphic function
    558490                                        if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
    559                                         // xxx - leaking tmp
    560491                                }
    561492                        }
     
    565496
    566497                        // replace argument to function call with temporary
    567                         stmtsToAddBefore.push_back( new DeclStmt( tmp ) );
    568                         arg = cpCtor;
    569                         destructRet( tmp, impCpCtorExpr, arg );
    570 
    571                         // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    572                 }
    573 
    574                 void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * /*impCpCtorExpr*/, Expression *& arg ) {
    575                         // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
    576                         // check for existing cleanup attribute before adding another(?)
    577                         // need to add __Destructor for _tmp_cp variables as well
    578 
    579                         assertf( Validate::dtorStruct && Validate::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." );
    580                         assertf( Validate::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
    581 
    582                         // generate a __Destructor for ret that calls the destructor
    583                         Expression * dtor = makeCtorDtor( "^?{}", ret );
    584 
    585                         // if the chosen destructor is intrinsic, elide the generated dtor handler
    586                         if ( arg && isIntrinsicCallExpr( dtor ) ) {
    587                                 arg = new CommaExpr( arg, new VariableExpr( ret ) );
    588                                 return;
    589                         }
    590 
    591                         if ( ! dtor->env ) dtor->env = maybeClone( env );
    592                         DeclarationWithType * dtorFunc = getDtorFunc( ret, new ExprStmt( dtor ), stmtsToAddBefore );
    593 
    594                         StructInstType * dtorStructType = new StructInstType( Type::Qualifiers(), Validate::dtorStruct );
    595                         dtorStructType->parameters.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
    596 
    597                         // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
    598                         FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
    599                         dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
    600                         Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
    601 
    602                         static UniqueName namer( "_ret_dtor" );
    603                         ObjectDecl * retDtor = ObjectDecl::newObject( namer.newName(), dtorStructType, new ListInit( { new SingleInit( new ConstantExpr( Constant::null() ) ), new SingleInit( new CastExpr( new VariableExpr( dtorFunc ), dtorType ) ) } ) );
    604                         retDtor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
    605                         stmtsToAddBefore.push_back( new DeclStmt( retDtor ) );
    606 
    607                         if ( arg ) {
    608                                 Expression * member = new MemberExpr( strict_dynamic_cast<DeclarationWithType *>( Validate::dtorStruct->members.front() ), new VariableExpr( retDtor ) );
    609                                 Expression * object = new CastExpr( new AddressExpr( new VariableExpr( ret ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
    610                                 Expression * assign = createBitwiseAssignment( member, object );
    611                                 arg = new CommaExpr( new CommaExpr( arg, assign ), new VariableExpr( ret ) );
    612                         }
    613 
    614                         // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    615                 }
    616 
    617                 Expression * ResolveCopyCtors::postmutate( ImplicitCopyCtorExpr *impCpCtorExpr ) {
     498                        arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
     499                        impCpCtorExpr->tempDecls.push_back( tmp );
     500                        impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
     501                }
     502
     503                void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
     504                        impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
     505                }
     506
     507                void ResolveCopyCtors::postvisit( ImplicitCopyCtorExpr *impCpCtorExpr ) {
    618508                        CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
    619509
    620510                        ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
    621                         ObjectDecl * returnDecl = nullptr;
    622511
    623512                        // take each argument and attempt to copy construct it.
     
    628517                        for ( Expression * & arg : appExpr->args ) {
    629518                                Type * formal = nullptr;
    630                                 if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
     519                                if ( iter != params.end() ) {
    631520                                        DeclarationWithType * param = *iter++;
    632521                                        formal = param->get_type();
     
    646535                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    647536                                ret->type->set_const( false );
    648                                 returnDecl = ret;
    649                                 stmtsToAddBefore.push_back( new DeclStmt( ret ) );
     537                                impCpCtorExpr->returnDecls.push_back( ret );
    650538                                CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
     539                                if ( ! dynamic_cast< ReferenceType * >( result ) ) {
     540                                        // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
     541                                        destructRet( ret, impCpCtorExpr );
     542                                }
    651543                        } // for
    652544                        CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
    653                         // ------------------------------------------------------
    654 
    655                         CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
    656 
    657                         // detach fields from wrapper node so that it can be deleted without deleting too much
    658                         impCpCtorExpr->callExpr = nullptr;
    659                         std::swap( impCpCtorExpr->env, appExpr->env );
    660                         assert( impCpCtorExpr->env == nullptr );
    661                         delete impCpCtorExpr;
    662 
    663                         if ( returnDecl ) {
    664                                 Expression * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), appExpr );
    665                                 if ( ! dynamic_cast< ReferenceType * >( result ) ) {
    666                                         // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
    667                                         destructRet( returnDecl, impCpCtorExpr, assign );
    668                                 } else {
    669                                         assign = new CommaExpr( assign, new VariableExpr( returnDecl ) );
    670                                 }
    671                                 // move env from appExpr to retExpr
    672                                 std::swap( assign->env, appExpr->env );
    673                                 return assign;
    674                         } else {
    675                                 return appExpr;
    676                         } // if
    677                 }
    678 
    679                 void ResolveCopyCtors::premutate( StmtExpr * stmtExpr ) {
    680                         // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
    681                         // since temporaries can be shared across sub-expressions, e.g.
    682                         //   [A, A] f();       // decl
    683                         //   g([A] x, [A] y);  // decl
    684                         //   g(f());           // call
    685                         // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
    686                         // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
    687                         // to the outer context, rather than inside of the statement expression.
    688                         visit_children = false;
    689 
     545                }
     546
     547                void ResolveCopyCtors::postvisit( StmtExpr * stmtExpr ) {
    690548                        assert( env );
    691 
    692                         indexer.enterScope();
    693                         // visit all statements
    694                         std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
    695                         for ( Statement *& stmt : stmts ) {
    696                                 stmt = stmt->acceptMutator( *visitor );
    697                         } // for
    698                         indexer.leaveScope();
    699 
    700                         assert( stmtExpr->result );
    701                         Type * result = stmtExpr->result;
     549                        assert( stmtExpr->get_result() );
     550                        Type * result = stmtExpr->get_result();
    702551                        if ( ! result->isVoid() ) {
    703552                                static UniqueName retNamer("_tmp_stmtexpr_ret");
     
    713562                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    714563                                ret->type->set_const( false );
    715                                 stmtsToAddBefore.push_back( new DeclStmt( ret ) );
    716 
    717                                 if(!stmtExpr->resultExpr) {
    718                                         SemanticError(stmtExpr, "Statment-Expression should have a resulting expression");
    719                                 }
    720                                 ExprStmt * last = stmtExpr->resultExpr;
    721                                 try {
    722                                         last->expr = makeCtorDtor( "?{}", ret, last->expr );
    723                                 } catch(...) {
    724                                         std::cerr << "=======================" << std::endl;
    725                                         std::cerr << "ERROR, can't resolve" << std::endl;
    726                                         ret->print(std::cerr);
    727                                         std::cerr << std::endl << "---" << std::endl;
    728                                         last->expr->print(std::cerr);
    729 
    730                                         abort();
    731                                 }
    732 
    733                                 // add destructors after current statement
    734                                 stmtsToAddAfter.push_back( new ExprStmt( makeCtorDtor( "^?{}", ret ) ) );
     564                                stmtExpr->returnDecls.push_front( ret );
    735565
    736566                                // must have a non-empty body, otherwise it wouldn't have a result
    737                                 assert( ! stmts.empty() );
    738 
    739                                 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    740                                 stmts.push_back( new ExprStmt( new VariableExpr( ret ) ) );
     567                                CompoundStmt * body = stmtExpr->statements;
     568                                assert( ! body->get_kids().empty() );
     569                                // must be an ExprStmt, otherwise it wouldn't have a result
     570                                ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->get_kids().back() );
     571                                last->expr = makeCtorDtor( "?{}", ret, last->get_expr() );
     572
     573                                stmtExpr->dtors.push_front( makeCtorDtor( "^?{}", ret ) );
    741574                        } // if
    742 
    743                         assert( stmtExpr->returnDecls.empty() );
    744                         assert( stmtExpr->dtors.empty() );
     575                }
     576
     577                void ResolveCopyCtors::previsit( UniqueExpr * unqExpr ) {
     578                        unqCount[ unqExpr->get_id() ]++;  // count the number of unique expressions for each ID
     579                        if ( vars.count( unqExpr->get_id() ) ) {
     580                                // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     581                                visit_children = false;
     582                        }
    745583                }
    746584
     
    759597                }
    760598
    761                 void ResolveCopyCtors::premutate( UniqueExpr * unqExpr ) {
     599                void ResolveCopyCtors::postvisit( UniqueExpr * unqExpr ) {
     600                        if ( vars.count( unqExpr->get_id() ) ) {
     601                                // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     602                                return;
     603                        }
     604
     605                        // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     606                        assert( unqExpr->get_result() );
     607                        if ( ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast<ImplicitCopyCtorExpr*>( unqExpr->get_expr() ) ) {
     608                                // note the variable used as the result from the call
     609                                assert( impCpCtorExpr->get_result() && impCpCtorExpr->get_returnDecls().size() == 1 );
     610                                unqExpr->set_var( new VariableExpr( impCpCtorExpr->get_returnDecls().front() ) );
     611                        } else {
     612                                // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
     613                                unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), makeInit( unqExpr->get_result() ) ) );
     614                                unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) );
     615                        }
     616                        vars.insert( unqExpr->get_id() );
     617                }
     618
     619                Expression * FixCopyCtors::postmutate( ImplicitCopyCtorExpr * impCpCtorExpr ) {
     620                        CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; )
     621
     622                        std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls();
     623                        std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls();
     624                        std::list< Expression * > & dtors = impCpCtorExpr->get_dtors();
     625
     626                        // add all temporary declarations and their constructors
     627                        for ( ObjectDecl * obj : tempDecls ) {
     628                                stmtsToAddBefore.push_back( new DeclStmt( obj ) );
     629                        } // for
     630                        for ( ObjectDecl * obj : returnDecls ) {
     631                                stmtsToAddBefore.push_back( new DeclStmt( obj ) );
     632                        } // for
     633
     634                        // add destructors after current statement
     635                        for ( Expression * dtor : dtors ) {
     636                                // take relevant bindings from environment
     637                                assert( ! dtor->env );
     638                                dtor->env =  maybeClone( env );
     639                                stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
     640                        } // for
     641
     642                        ObjectDecl * returnDecl = returnDecls.empty() ? nullptr : returnDecls.front();
     643                        Expression * callExpr = impCpCtorExpr->get_callExpr();
     644
     645                        CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
     646
     647                        // detach fields from wrapper node so that it can be deleted without deleting too much
     648                        dtors.clear();
     649                        tempDecls.clear();
     650                        returnDecls.clear();
     651                        impCpCtorExpr->set_callExpr( nullptr );
     652                        std::swap( impCpCtorExpr->env, callExpr->env );
     653                        assert( impCpCtorExpr->env == nullptr );
     654                        delete impCpCtorExpr;
     655
     656                        if ( returnDecl ) {
     657                                ApplicationExpr * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), callExpr );
     658                                Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) );
     659                                // move env from callExpr to retExpr
     660                                std::swap( retExpr->env, callExpr->env );
     661                                return retExpr;
     662                        } else {
     663                                return callExpr;
     664                        } // if
     665                }
     666
     667                void FixCopyCtors::premutate( StmtExpr * stmtExpr ) {
     668                        // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
     669                        // since temporaries can be shared across sub-expressions, e.g.
     670                        //   [A, A] f();
     671                        //   g([A] x, [A] y);
     672                        //   g(f());
     673                        // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
     674                        // Explicitly mutating children instead of mutating the inner compound statment forces the temporaries to be added
     675                        // to the outer context, rather than inside of the statement expression.
    762676                        visit_children = false;
    763                         // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     677                        std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
     678                        for ( Statement *& stmt : stmts ) {
     679                                stmt = stmt->acceptMutator( *visitor );
     680                        } // for
     681                        assert( stmtExpr->result );
     682                        Type * result = stmtExpr->result;
     683                        if ( ! result->isVoid() ) {
     684                                for ( ObjectDecl * obj : stmtExpr->returnDecls ) {
     685                                        stmtsToAddBefore.push_back( new DeclStmt( obj ) );
     686                                } // for
     687                                // add destructors after current statement
     688                                for ( Expression * dtor : stmtExpr->dtors ) {
     689                                        stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
     690                                } // for
     691                                // must have a non-empty body, otherwise it wouldn't have a result
     692                                assert( ! stmts.empty() );
     693                                assertf( ! stmtExpr->returnDecls.empty() || stmtExpr->dtors.empty(), "StmtExpr returns non-void, but no return decls: %s", toString( stmtExpr ).c_str() );
     694                                // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
     695                                if ( ! stmtExpr->returnDecls.empty() ) {
     696                                        stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->returnDecls.front() ) ) );
     697                                }
     698                                stmtExpr->returnDecls.clear();
     699                                stmtExpr->dtors.clear();
     700                        }
     701                        assert( stmtExpr->returnDecls.empty() );
     702                        assert( stmtExpr->dtors.empty() );
     703                }
     704
     705                void FixCopyCtors::premutate( UniqueExpr * unqExpr ) {
     706                        visit_children = false;
     707                        unqCount[ unqExpr->get_id() ]--;
     708                        static std::unordered_map< int, std::list< Statement * > > dtors;
    764709                        static std::unordered_map< int, UniqueExpr * > unqMap;
    765                         if ( ! unqMap.count( unqExpr->get_id() ) ) {
    766                                 // resolve expr and find its
    767 
    768                                 ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( unqExpr->expr );
    769                                 // PassVisitor<ResolveCopyCtors> fixer;
    770                                 unqExpr->expr = unqExpr->expr->acceptMutator( *visitor );
    771 
    772                                 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
    773                                 assert( unqExpr->result );
    774                                 if ( impCpCtorExpr ) {
    775                                         CommaExpr * comma = strict_dynamic_cast< CommaExpr * >( unqExpr->expr );
    776                                         VariableExpr * var = strict_dynamic_cast<VariableExpr *>( comma->arg2 );
    777                                         // note the variable used as the result from the call
    778                                         unqExpr->var = var->clone();
    779                                 } else {
    780                                         // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
    781                                         unqExpr->object = ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->result->clone(), makeInit( unqExpr->result ) );
    782                                         unqExpr->var = new VariableExpr( unqExpr->object );
    783                                 }
    784 
    785                                 // stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
    786                                 // stmtsToAddAfter.splice( stmtsToAddAfter.end(), fixer.pass.stmtsToAddAfter );
    787                                 unqMap[unqExpr->get_id()] = unqExpr;
    788                         } else {
     710                        // has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes
     711                        if ( unqMap.count( unqExpr->get_id() ) ) {
    789712                                // take data from other UniqueExpr to ensure consistency
    790713                                delete unqExpr->get_expr();
    791                                 unqExpr->expr = unqMap[unqExpr->get_id()]->expr->clone();
    792                                 delete unqExpr->result;
    793                                 unqExpr->result = maybeClone( unqExpr->expr->result );
    794                         }
     714                                unqExpr->set_expr( unqMap[unqExpr->get_id()]->get_expr()->clone() );
     715                                delete unqExpr->get_result();
     716                                unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
     717                                if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
     718                                        stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
     719                                }
     720                                return;
     721                        }
     722                        PassVisitor<FixCopyCtors> fixer( unqCount );
     723                        unqExpr->set_expr( unqExpr->get_expr()->acceptMutator( fixer ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
     724                        stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
     725                        unqMap[unqExpr->get_id()] = unqExpr;
     726                        if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
     727                                stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
     728                        } else { // remember dtors for last instance of unique expr
     729                                dtors[ unqExpr->get_id() ] = fixer.pass.stmtsToAddAfter;
     730                        }
     731                        return;
    795732                }
    796733
     
    907844                                                        ctorInit->ctor = nullptr;
    908845                                                }
    909 
    910                                                 Statement * dtor = ctorInit->dtor;
    911                                                 if ( dtor ) {
    912                                                         ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
    913                                                         Statement * dtorStmt = implicit->callStmt;
    914 
    915                                                         // don't need to call intrinsic dtor, because it does nothing, but
    916                                                         // non-intrinsic dtors must be called
    917                                                         if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
    918                                                                 // set dtor location to the object's location for error messages
    919                                                                 DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
    920                                                                 objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
    921                                                                 ctorInit->dtor = nullptr;
    922                                                         } // if
    923                                                 }
    924846                                        } // if
    925847                                } else if ( Initializer * init = ctorInit->init ) {
     
    964886
    965887
     888                template<typename Iterator, typename OutputIterator>
     889                void insertDtors( Iterator begin, Iterator end, OutputIterator out ) {
     890                        for ( Iterator it = begin ; it != end ; ++it ) {
     891                                // extract destructor statement from the object decl and insert it into the output. Note that this is
     892                                // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually
     893                                // calls an intrinsic dtor then the call must (and will) still be generated since the argument may
     894                                // contain side effects.
     895                                ObjectDecl * objDecl = *it;
     896                                ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() );
     897                                assert( ctorInit && ctorInit->get_dtor() );
     898                                *out++ = ctorInit->get_dtor()->clone();
     899                        } // for
     900                }
     901
     902                void InsertDtors::previsit( ObjectDecl * objDecl ) {
     903                        // remember non-static destructed objects so that their destructors can be inserted later
     904                        if ( ! objDecl->get_storageClasses().is_static ) {
     905                                if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
     906                                        // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     907                                        assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
     908                                        Statement * dtor = ctorInit->get_dtor();
     909                                        // don't need to call intrinsic dtor, because it does nothing, but
     910                                        // non-intrinsic dtors must be called
     911                                        if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
     912                                                // set dtor location to the object's location for error messages
     913                                                ctorInit->dtor->location = objDecl->location;
     914                                                reverseDeclOrder.front().push_front( objDecl );
     915                                        } // if
     916                                } // if
     917                        } // if
     918                }
     919
    966920                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    967921                        // each function needs to have its own set of labels
     
    976930                }
    977931
     932                void InsertDtors::previsit( CompoundStmt * compoundStmt ) {
     933                        // visit statements - this will also populate reverseDeclOrder list.  don't want to dump all destructors
     934                        // when block is left, just the destructors associated with variables defined in this block, so push a new
     935                        // list to the top of the stack so that we can differentiate scopes
     936                        reverseDeclOrder.push_front( OrderedDecls() );
     937                        Parent::previsit( compoundStmt );
     938                }
     939
     940                void InsertDtors::postvisit( CompoundStmt * compoundStmt ) {
     941                        // add destructors for the current scope that we're exiting, unless the last statement is a return, which
     942                        // causes unreachable code warnings
     943                        std::list< Statement * > & statements = compoundStmt->get_kids();
     944                        if ( ! statements.empty() && ! dynamic_cast< ReturnStmt * >( statements.back() ) ) {
     945                                insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) );
     946                        }
     947                        reverseDeclOrder.pop_front();
     948                }
     949
     950                void InsertDtors::previsit( ReturnStmt * ) {
     951                        // return exits all scopes, so dump destructors for all scopes
     952                        for ( OrderedDecls & od : reverseDeclOrder ) {
     953                                insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) );
     954                        } // for
     955                }
     956
    978957                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    979958                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    1003982                        if ( ! diff.empty() ) {
    1004983                                SemanticError( stmt, std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " " );
     984                        } // if
     985                        // S_G-S_L results in set of objects that must be destructed
     986                        diff.clear();
     987                        std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) );
     988                        DTOR_PRINT(
     989                                std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl;
     990                        )
     991                        if ( ! diff.empty() ) {
     992                                // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.
     993                                std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );
     994
     995                                // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor
     996                                OrderedDecls ordered;
     997                                for ( OrderedDecls & rdo : reverseDeclOrder ) {
     998                                        // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order.
     999                                        copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );
     1000                                } // for
     1001                                insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) );
    10051002                        } // if
    10061003                }
     
    11191116                                                        callStmt->acceptMutator( *visitor );
    11201117                                                        if ( isCtor ) {
    1121                                                                 function->statements->push_front( callStmt );
    1122                                                         } else { // TODO: don't generate destructor function/object for intrinsic calls
     1118                                                                function->get_statements()->push_front( callStmt );
     1119                                                        } else {
    11231120                                                                // destructor statements should be added at the end
    1124                                                                 // function->get_statements()->push_back( callStmt );
    1125 
    1126                                                                 // Optimization: do not need to call intrinsic destructors on members
    1127                                                                 if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;;
    1128 
    1129                                                                 // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
    1130                                                                 std::list< Statement * > stmtsToAdd;
    1131 
    1132                                                                 static UniqueName memberDtorNamer = { "__memberDtor" };
    1133                                                                 assertf( Validate::dtorStruct, "builtin __Destructor not found." );
    1134                                                                 assertf( Validate::dtorStructDestroy, "builtin __destroy_Destructor not found." );
    1135 
    1136                                                                 Expression * thisExpr = new CastExpr( new AddressExpr( new VariableExpr( thisParam ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
    1137                                                                 Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
    1138 
    1139                                                                 // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
    1140                                                                 FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
    1141                                                                 dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
    1142                                                                 Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
    1143 
    1144                                                                 ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), Validate::dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( new CastExpr( dtorExpr, dtorType ) ) } ) );
    1145                                                                 function->statements->push_front( new DeclStmt( destructor ) );
    1146                                                                 destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
    1147 
    1148                                                                 function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
     1121                                                                function->get_statements()->push_back( callStmt );
    11491122                                                        }
    11501123                                                } catch ( SemanticErrorException & error ) {
Note: See TracChangeset for help on using the changeset viewer.