Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r6a9d4b4 r02fdb8e  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 21 17:35:05 2017
    13 // Update Count     : 74
     12// Last Modified On : Wed Feb 13 18:15:56 2019
     13// Update Count     : 76
    1414//
    1515#include "FixInit.h"
     
    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 );
    7272                };
    7373
    74                 struct InsertImplicitCalls : public WithTypeSubstitution {
     74                struct InsertImplicitCalls : public WithConstTypeSubstitution {
    7575                        /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
    7676                        /// function calls need their parameters to be copy constructed
     
    8080                };
    8181
    82                 struct ResolveCopyCtors final : public WithStmtsToAdd, public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution, public WithVisitorRef<ResolveCopyCtors> {
     82                struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
    8383                        /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
    8484                        /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    8585                        /// arguments and return value temporaries
    86                         static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
    87 
    88                         Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
    89                         void premutate( StmtExpr * stmtExpr );
    90                         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 );
    9194
    9295                        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
     
    9598                        bool skipCopyConstruct( Type * type );
    9699                        void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal );
    97                         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;
    98104                };
    99105
     
    156162                        using Parent::previsit;
    157163
     164                        void previsit( ObjectDecl * objDecl );
    158165                        void previsit( FunctionDecl * funcDecl );
    159166
     167                        void previsit( CompoundStmt * compoundStmt );
     168                        void postvisit( CompoundStmt * compoundStmt );
     169                        void previsit( ReturnStmt * returnStmt );
    160170                        void previsit( BranchStmt * stmt );
    161171                private:
     
    175185
    176186                        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;
    177201                };
    178202
     
    212236                        Expression * postmutate( ConstructorExpr * ctorExpr );
    213237                };
    214 
    215                 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
    216                         /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
    217                         static void split( std::list< Declaration * > &translationUnit );
    218 
    219                         Statement * postmutate( ExprStmt * stmt );
    220                         void premutate( TupleAssignExpr * expr );
    221                 };
    222238        } // namespace
    223239
     
    229245                InitTweak::fixGlobalInit( translationUnit, inLibrary );
    230246
    231                 // must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
    232                 SplitExpressions::split( translationUnit );
     247                UnqCount unqCount;
    233248
    234249                InsertImplicitCalls::insert( translationUnit );
    235 
    236                 // Needs to happen before ResolveCopyCtors, because argument/return temporaries should not be considered in
    237                 // error checking branch statements
     250                ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
    238251                InsertDtors::insert( translationUnit );
    239 
    240                 ResolveCopyCtors::resolveImplicitCalls( translationUnit );
    241252                FixInit::fixInitializers( translationUnit );
     253
     254                // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
     255                FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
     256
    242257                GenStructMemberCalls::generate( translationUnit );
    243258
    244                 // Needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
    245                 // 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.
    246266                FixCtorExprs::fix( translationUnit );
    247267        }
    248268
    249269        namespace {
    250                 /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk
    251                 /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration
    252                 DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * input, std::list< Statement * > & stmtsToAdd ) {
    253                         // unwrap implicit statement wrapper
    254                         Statement * dtor = input;
    255                         if ( ImplicitCtorDtorStmt * implicit = dynamic_cast< ImplicitCtorDtorStmt * >( input ) ) {
    256                                 // dtor = implicit->callStmt;
    257                                 // implicit->callStmt = nullptr;
    258                         }
    259                         assert( dtor );
    260                         std::list< Expression * > matches;
    261                         collectCtorDtorCalls( dtor, matches );
    262 
    263                         if ( dynamic_cast< ExprStmt * >( dtor ) ) {
    264                                 // only one destructor call in the expression
    265                                 if ( matches.size() == 1 ) {
    266                                         DeclarationWithType * func = getFunction( matches.front() );
    267                                         assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
    268 
    269                                         // cleanup argument must be a function, not an object (including function pointer)
    270                                         if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
    271                                                 if ( dtorFunc->type->forall.empty() ) {
    272                                                         // simple case where the destructor is a monomorphic function call - can simply
    273                                                         // use that function as the cleanup function.
    274                                                         delete dtor;
    275                                                         return func;
    276                                                 }
    277                                         }
    278                                 }
    279                         }
    280 
    281                         // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
    282                         // wraps the more complicated code.
    283                         static UniqueName dtorNamer( "__cleanup_dtor" );
    284                         FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt() );
    285                         stmtsToAdd.push_back( new DeclStmt( dtorFunc ) );
    286 
    287                         // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
    288                         ObjectDecl * thisParam = getParamThis( dtorFunc->type );
    289                         Expression * replacement = new VariableExpr( thisParam );
    290 
    291                         Type * base = replacement->result->stripReferences();
    292                         if ( dynamic_cast< ArrayType * >( base ) || dynamic_cast< TupleType * > ( base ) ) {
    293                                 // need to cast away reference for array types, since the destructor is generated without the reference type,
    294                                 // and for tuple types since tuple indexing does not work directly on a reference
    295                                 replacement = new CastExpr( replacement, base->clone() );
    296                         }
    297                         DeclReplacer::replace( dtor, { std::make_pair( objDecl, replacement ) } );
    298                         dtorFunc->statements->push_back( strict_dynamic_cast<Statement *>( dtor ) );
    299 
    300                         return dtorFunc;
    301                 }
    302 
    303                 void SplitExpressions::split( std::list< Declaration * > & translationUnit ) {
    304                         PassVisitor<SplitExpressions> splitter;
    305                         mutateAll( translationUnit, splitter );
    306                 }
    307 
    308270                void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
    309271                        PassVisitor<InsertImplicitCalls> inserter;
     
    311273                }
    312274
    313                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
    314                         PassVisitor<ResolveCopyCtors> resolver;
    315                         mutateAll( translationUnit, resolver );
     275                void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
     276                        PassVisitor<ResolveCopyCtors> resolver( unqCount );
     277                        acceptAll( translationUnit, resolver );
    316278                }
    317279
     
    341303                }
    342304
     305                void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
     306                        PassVisitor<FixCopyCtors> fixer( unqCount );
     307                        mutateAll( translationUnit, fixer );
     308                }
     309
    343310                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
    344311                        PassVisitor<GenStructMemberCalls> warner;
     
    351318                }
    352319
    353                 Statement * SplitExpressions::postmutate( ExprStmt * stmt ) {
    354                         // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
    355                         // in the correct places
    356                         CompoundStmt * ret = new CompoundStmt( { stmt } );
    357                         return ret;
    358                 }
    359 
    360                 void SplitExpressions::premutate( TupleAssignExpr * ) {
    361                         // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
    362                         visit_children = false;
    363                 }
    364 
    365                 // Relatively simple structural comparison for expressions, needed to determine
    366                 // if two expressions are "the same" (used to determine if self assignment occurs)
    367                 struct StructuralChecker {
    368                         Expression * stripCasts( Expression * expr ) {
    369                                 // this might be too permissive. It's possible that only particular casts are relevant.
    370                                 while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
    371                                         expr = cast->arg;
    372                                 }
    373                                 return expr;
    374                         }
    375 
    376                         void previsit( Expression * ) {
    377                                 // anything else does not qualify
    378                                 isSimilar = false;
    379                         }
    380 
    381                         template<typename T>
    382                         T * cast( Expression * node ) {
    383                                 // all expressions need to ignore casts, so this bit has been factored out
    384                                 return dynamic_cast< T * >( stripCasts( node ) );
    385                         }
    386 
    387                         // ignore casts
    388                         void previsit( CastExpr * ) {}
    389 
    390                         void previsit( MemberExpr * memExpr ) {
    391                                 if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
    392                                         if ( otherMember->member == memExpr->member ) {
    393                                                 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;
    394368                                                return;
    395369                                        }
    396                                 }
    397                                 isSimilar = false;
    398                         }
    399 
    400                         void previsit( VariableExpr * varExpr ) {
    401                                 if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
    402                                         if ( otherVar->var == varExpr->var ) {
    403                                                 return;
    404                                         }
    405                                 }
    406                                 isSimilar = false;
    407                         }
    408 
    409                         void previsit( AddressExpr * ) {
    410                                 if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
    411                                         other = addrExpr->arg;
    412                                         return;
    413                                 }
    414                                 isSimilar = false;
    415                         }
    416 
    417                         Expression * other = nullptr;
    418                         bool isSimilar = true;
    419                 };
    420 
    421                 bool structurallySimilar( Expression * e1, Expression * e2 ) {
    422                         PassVisitor<StructuralChecker> checker;
    423                         checker.pass.other = e2;
    424                         e1->accept( checker );
    425                         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                        }
    426383                }
    427384
     
    500457                        if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
    501458                                // fix newly generated StmtExpr
    502                                 premutate( assign->stmtExpr );
     459                                postvisit( assign->stmtExpr );
    503460                        }
    504461                        return resolved;
     
    532489                                        // so that the object isn't changed inside of the polymorphic function
    533490                                        if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
    534                                         // xxx - leaking tmp
    535491                                }
    536492                        }
     
    540496
    541497                        // replace argument to function call with temporary
    542                         stmtsToAddBefore.push_back( new DeclStmt( tmp ) );
    543                         arg = cpCtor;
    544                         destructRet( tmp, impCpCtorExpr, arg );
    545 
    546                         // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    547                 }
    548 
    549                 void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * /*impCpCtorExpr*/, Expression *& arg ) {
    550                         // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
    551                         // check for existing cleanup attribute before adding another(?)
    552                         // need to add __Destructor for _tmp_cp variables as well
    553 
    554                         assertf( Validate::dtorStruct && Validate::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." );
    555                         assertf( Validate::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
    556 
    557                         // generate a __Destructor for ret that calls the destructor
    558                         Expression * dtor = makeCtorDtor( "^?{}", ret );
    559 
    560                         // if the chosen destructor is intrinsic, elide the generated dtor handler
    561                         if ( arg && isIntrinsicCallExpr( dtor ) ) {
    562                                 arg = new CommaExpr( arg, new VariableExpr( ret ) );
    563                                 return;
    564                         }
    565 
    566                         if ( ! dtor->env ) dtor->env = maybeClone( env );
    567                         DeclarationWithType * dtorFunc = getDtorFunc( ret, new ExprStmt( dtor ), stmtsToAddBefore );
    568 
    569                         StructInstType * dtorStructType = new StructInstType( Type::Qualifiers(), Validate::dtorStruct );
    570                         dtorStructType->parameters.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
    571 
    572                         // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
    573                         FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
    574                         dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
    575                         Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
    576 
    577                         static UniqueName namer( "_ret_dtor" );
    578                         ObjectDecl * retDtor = ObjectDecl::newObject( namer.newName(), dtorStructType, new ListInit( { new SingleInit( new ConstantExpr( Constant::null() ) ), new SingleInit( new CastExpr( new VariableExpr( dtorFunc ), dtorType ) ) } ) );
    579                         retDtor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
    580                         stmtsToAddBefore.push_back( new DeclStmt( retDtor ) );
    581 
    582                         if ( arg ) {
    583                                 Expression * member = new MemberExpr( strict_dynamic_cast<DeclarationWithType *>( Validate::dtorStruct->members.front() ), new VariableExpr( retDtor ) );
    584                                 Expression * object = new CastExpr( new AddressExpr( new VariableExpr( ret ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
    585                                 Expression * assign = createBitwiseAssignment( member, object );
    586                                 arg = new CommaExpr( new CommaExpr( arg, assign ), new VariableExpr( ret ) );
    587                         }
    588 
    589                         // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    590                 }
    591 
    592                 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 ) {
    593508                        CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
    594509
    595510                        ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
    596                         ObjectDecl * returnDecl = nullptr;
    597511
    598512                        // take each argument and attempt to copy construct it.
     
    603517                        for ( Expression * & arg : appExpr->args ) {
    604518                                Type * formal = nullptr;
    605                                 if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
     519                                if ( iter != params.end() ) {
    606520                                        DeclarationWithType * param = *iter++;
    607521                                        formal = param->get_type();
     
    621535                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    622536                                ret->type->set_const( false );
    623                                 returnDecl = ret;
    624                                 stmtsToAddBefore.push_back( new DeclStmt( ret ) );
     537                                impCpCtorExpr->returnDecls.push_back( ret );
    625538                                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                                }
    626543                        } // for
    627544                        CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
    628                         // ------------------------------------------------------
    629 
    630                         CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
    631 
    632                         // detach fields from wrapper node so that it can be deleted without deleting too much
    633                         impCpCtorExpr->callExpr = nullptr;
    634                         std::swap( impCpCtorExpr->env, appExpr->env );
    635                         assert( impCpCtorExpr->env == nullptr );
    636                         delete impCpCtorExpr;
    637 
    638                         if ( returnDecl ) {
    639                                 Expression * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), appExpr );
    640                                 if ( ! dynamic_cast< ReferenceType * >( result ) ) {
    641                                         // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
    642                                         destructRet( returnDecl, impCpCtorExpr, assign );
    643                                 } else {
    644                                         assign = new CommaExpr( assign, new VariableExpr( returnDecl ) );
    645                                 }
    646                                 // move env from appExpr to retExpr
    647                                 std::swap( assign->env, appExpr->env );
    648                                 return assign;
    649                         } else {
    650                                 return appExpr;
    651                         } // if
    652                 }
    653 
    654                 void ResolveCopyCtors::premutate( StmtExpr * stmtExpr ) {
    655                         // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
    656                         // since temporaries can be shared across sub-expressions, e.g.
    657                         //   [A, A] f();
    658                         //   g([A] x, [A] y);
    659                         //   g(f());
    660                         // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
    661                         // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
    662                         // to the outer context, rather than inside of the statement expression.
    663                         visit_children = false;
    664 
     545                }
     546
     547                void ResolveCopyCtors::postvisit( StmtExpr * stmtExpr ) {
    665548                        assert( env );
    666 
    667                         // visit all statements
    668                         std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
    669                         for ( Statement *& stmt : stmts ) {
    670                                 stmt = stmt->acceptMutator( *visitor );
    671                         } // for
    672 
    673                         assert( stmtExpr->result );
    674                         Type * result = stmtExpr->result;
     549                        assert( stmtExpr->get_result() );
     550                        Type * result = stmtExpr->get_result();
    675551                        if ( ! result->isVoid() ) {
    676552                                static UniqueName retNamer("_tmp_stmtexpr_ret");
     
    686562                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    687563                                ret->type->set_const( false );
    688                                 stmtsToAddBefore.push_back( new DeclStmt( ret ) );
     564                                stmtExpr->returnDecls.push_front( ret );
    689565
    690566                                // must have a non-empty body, otherwise it wouldn't have a result
    691567                                CompoundStmt * body = stmtExpr->statements;
    692                                 assert( ! body->kids.empty() );
     568                                assert( ! body->get_kids().empty() );
    693569                                // must be an ExprStmt, otherwise it wouldn't have a result
    694                                 ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->kids.back() );
    695                                 last->expr = makeCtorDtor( "?{}", ret, last->expr );
    696 
    697                                 // add destructors after current statement
    698                                 stmtsToAddAfter.push_back( new ExprStmt( makeCtorDtor( "^?{}", ret ) ) );
    699 
    700                                 // must have a non-empty body, otherwise it wouldn't have a result
    701                                 assert( ! stmts.empty() );
    702 
    703                                 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    704                                 stmts.push_back( new ExprStmt( new VariableExpr( ret ) ) );
     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 ) );
    705574                        } // if
    706 
    707                         assert( stmtExpr->returnDecls.empty() );
    708                         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                        }
    709583                }
    710584
     
    723597                }
    724598
    725                 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.
    726676                        visit_children = false;
    727                         // 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;
    728709                        static std::unordered_map< int, UniqueExpr * > unqMap;
    729                         if ( ! unqMap.count( unqExpr->get_id() ) ) {
    730                                 // resolve expr and find its
    731 
    732                                 ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( unqExpr->expr );
    733                                 // PassVisitor<ResolveCopyCtors> fixer;
    734                                 unqExpr->expr = unqExpr->expr->acceptMutator( *visitor );
    735 
    736                                 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
    737                                 assert( unqExpr->result );
    738                                 if ( impCpCtorExpr ) {
    739                                         CommaExpr * comma = strict_dynamic_cast< CommaExpr * >( unqExpr->expr );
    740                                         VariableExpr * var = strict_dynamic_cast<VariableExpr *>( comma->arg2 );
    741                                         // note the variable used as the result from the call
    742                                         unqExpr->var = var->clone();
    743                                 } else {
    744                                         // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
    745                                         unqExpr->object = ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->result->clone(), makeInit( unqExpr->result ) );
    746                                         unqExpr->var = new VariableExpr( unqExpr->object );
    747                                 }
    748 
    749                                 // stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
    750                                 // stmtsToAddAfter.splice( stmtsToAddAfter.end(), fixer.pass.stmtsToAddAfter );
    751                                 unqMap[unqExpr->get_id()] = unqExpr;
    752                         } 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() ) ) {
    753712                                // take data from other UniqueExpr to ensure consistency
    754713                                delete unqExpr->get_expr();
    755                                 unqExpr->expr = unqMap[unqExpr->get_id()]->expr->clone();
    756                                 delete unqExpr->result;
    757                                 unqExpr->result = maybeClone( unqExpr->expr->result );
    758                         }
     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;
    759732                }
    760733
     
    871844                                                        ctorInit->ctor = nullptr;
    872845                                                }
    873 
    874                                                 Statement * dtor = ctorInit->dtor;
    875                                                 if ( dtor ) {
    876                                                         ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
    877                                                         Statement * dtorStmt = implicit->callStmt;
    878 
    879                                                         // don't need to call intrinsic dtor, because it does nothing, but
    880                                                         // non-intrinsic dtors must be called
    881                                                         if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
    882                                                                 // set dtor location to the object's location for error messages
    883                                                                 DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
    884                                                                 objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
    885                                                                 ctorInit->dtor = nullptr;
    886                                                         } // if
    887                                                 }
    888846                                        } // if
    889847                                } else if ( Initializer * init = ctorInit->init ) {
     
    928886
    929887
     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
    930920                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    931921                        // each function needs to have its own set of labels
     
    940930                }
    941931
     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
    942957                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    943958                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    967982                        if ( ! diff.empty() ) {
    968983                                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 ) );
    9691002                        } // if
    9701003                }
     
    10831116                                                        callStmt->acceptMutator( *visitor );
    10841117                                                        if ( isCtor ) {
    1085                                                                 function->statements->push_front( callStmt );
    1086                                                         } else { // TODO: don't generate destructor function/object for intrinsic calls
     1118                                                                function->get_statements()->push_front( callStmt );
     1119                                                        } else {
    10871120                                                                // destructor statements should be added at the end
    1088                                                                 // function->get_statements()->push_back( callStmt );
    1089 
    1090                                                                 // Optimization: do not need to call intrinsic destructors on members
    1091                                                                 if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;;
    1092 
    1093                                                                 // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
    1094                                                                 std::list< Statement * > stmtsToAdd;
    1095 
    1096                                                                 static UniqueName memberDtorNamer = { "__memberDtor" };
    1097                                                                 assertf( Validate::dtorStruct, "builtin __Destructor not found." );
    1098                                                                 assertf( Validate::dtorStructDestroy, "builtin __destroy_Destructor not found." );
    1099 
    1100                                                                 Expression * thisExpr = new CastExpr( new AddressExpr( new VariableExpr( thisParam ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
    1101                                                                 Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
    1102 
    1103                                                                 // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
    1104                                                                 FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
    1105                                                                 dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
    1106                                                                 Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
    1107 
    1108                                                                 ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), Validate::dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( new CastExpr( dtorExpr, dtorType ) ) } ) );
    1109                                                                 function->statements->push_front( new DeclStmt( destructor ) );
    1110                                                                 destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
    1111 
    1112                                                                 function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
     1121                                                                function->get_statements()->push_back( callStmt );
    11131122                                                        }
    11141123                                                } catch ( SemanticErrorException & error ) {
Note: See TracChangeset for help on using the changeset viewer.