Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r02fdb8e r0e315a5  
    5454#include "SynTree/Type.h"              // for Type, Type::StorageClasses
    5555#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
     56#include "SynTree/DeclReplacer.h"      // for DeclReplacer
    5657#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
     58#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    5759
    5860bool ctordtorp = false; // print all debug
     
    6668namespace InitTweak {
    6769        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 );
    7278                };
    7379
     
    8086                };
    8187
    82                 struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
     88                struct ResolveCopyCtors final : public WithStmtsToAdd, public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution, public WithVisitorRef<ResolveCopyCtors> {
    8389                        /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
    8490                        /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    8591                        /// arguments and return value temporaries
    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 );
     92                        static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
     93
     94                        Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
     95                        void premutate( StmtExpr * stmtExpr );
     96                        void premutate( UniqueExpr * unqExpr );
    9497
    9598                        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
     
    98101                        bool skipCopyConstruct( Type * type );
    99102                        void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal );
    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;
     103                        void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr, Expression *& arg );
    104104                };
    105105
     
    162162                        using Parent::previsit;
    163163
    164                         void previsit( ObjectDecl * objDecl );
    165164                        void previsit( FunctionDecl * funcDecl );
    166165
    167                         void previsit( CompoundStmt * compoundStmt );
    168                         void postvisit( CompoundStmt * compoundStmt );
    169                         void previsit( ReturnStmt * returnStmt );
    170166                        void previsit( BranchStmt * stmt );
    171167                private:
     
    185181
    186182                        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;
    201183                };
    202184
     
    236218                        Expression * postmutate( ConstructorExpr * ctorExpr );
    237219                };
     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                };
    238228        } // namespace
    239229
     
    242232                acceptAll( translationUnit, checker );
    243233
     234                // fixes StmtExpr to properly link to their resulting expression
     235                StmtExprResult::link( translationUnit );
     236
    244237                // fixes ConstructorInit for global variables. should happen before fixInitializers.
    245238                InitTweak::fixGlobalInit( translationUnit, inLibrary );
    246239
    247                 UnqCount unqCount;
     240                // must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
     241                SplitExpressions::split( translationUnit );
    248242
    249243                InsertImplicitCalls::insert( translationUnit );
    250                 ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
     244
     245                // Needs to happen before ResolveCopyCtors, because argument/return temporaries should not be considered in
     246                // error checking branch statements
    251247                InsertDtors::insert( translationUnit );
     248
     249                ResolveCopyCtors::resolveImplicitCalls( translationUnit );
    252250                FixInit::fixInitializers( translationUnit );
    253 
    254                 // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
    255                 FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
    256 
    257251                GenStructMemberCalls::generate( translationUnit );
    258252
    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.
     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.
    266255                FixCtorExprs::fix( translationUnit );
    267256        }
    268257
    269258        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
    270322                void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
    271323                        PassVisitor<InsertImplicitCalls> inserter;
     
    273325                }
    274326
    275                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    276                         PassVisitor<ResolveCopyCtors> resolver( unqCount );
    277                         acceptAll( translationUnit, resolver );
     327                void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
     328                        PassVisitor<ResolveCopyCtors> resolver;
     329                        mutateAll( translationUnit, resolver );
    278330                }
    279331
     
    303355                }
    304356
    305                 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    306                         PassVisitor<FixCopyCtors> fixer( unqCount );
    307                         mutateAll( translationUnit, fixer );
    308                 }
    309 
    310357                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
    311358                        PassVisitor<GenStructMemberCalls> warner;
     
    318365                }
    319366
    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;
     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;
    368419                                                return;
    369420                                        }
    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                         }
     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;
    383451                }
    384452
     
    457525                        if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
    458526                                // fix newly generated StmtExpr
    459                                 postvisit( assign->stmtExpr );
     527                                premutate( assign->stmtExpr );
    460528                        }
    461529                        return resolved;
     
    489557                                        // so that the object isn't changed inside of the polymorphic function
    490558                                        if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
     559                                        // xxx - leaking tmp
    491560                                }
    492561                        }
     
    496565
    497566                        // replace argument to function call with temporary
    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 ) {
     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 ) {
    508618                        CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
    509619
    510620                        ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
     621                        ObjectDecl * returnDecl = nullptr;
    511622
    512623                        // take each argument and attempt to copy construct it.
     
    517628                        for ( Expression * & arg : appExpr->args ) {
    518629                                Type * formal = nullptr;
    519                                 if ( iter != params.end() ) {
     630                                if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
    520631                                        DeclarationWithType * param = *iter++;
    521632                                        formal = param->get_type();
     
    535646                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    536647                                ret->type->set_const( false );
    537                                 impCpCtorExpr->returnDecls.push_back( ret );
     648                                returnDecl = ret;
     649                                stmtsToAddBefore.push_back( new DeclStmt( ret ) );
    538650                                CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
     651                        } // for
     652                        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 );
    539665                                if ( ! dynamic_cast< ReferenceType * >( result ) ) {
    540666                                        // 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                                 }
     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
     690                        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 );
    543697                        } // for
    544                         CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
    545                 }
    546 
    547                 void ResolveCopyCtors::postvisit( StmtExpr * stmtExpr ) {
    548                         assert( env );
    549                         assert( stmtExpr->get_result() );
    550                         Type * result = stmtExpr->get_result();
     698                        indexer.leaveScope();
     699
     700                        assert( stmtExpr->result );
     701                        Type * result = stmtExpr->result;
    551702                        if ( ! result->isVoid() ) {
    552703                                static UniqueName retNamer("_tmp_stmtexpr_ret");
     
    562713                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    563714                                ret->type->set_const( false );
    564                                 stmtExpr->returnDecls.push_front( ret );
     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 ) ) );
    565735
    566736                                // must have a non-empty body, otherwise it wouldn't have a result
    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 ) );
     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 ) ) );
    574741                        } // if
    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                         }
     742
     743                        assert( stmtExpr->returnDecls.empty() );
     744                        assert( stmtExpr->dtors.empty() );
    583745                }
    584746
     
    597759                }
    598760
    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() ) );
     761                void ResolveCopyCtors::premutate( UniqueExpr * unqExpr ) {
     762                        visit_children = false;
     763                        // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     764                        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;
    611788                        } 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.
    676                         visit_children = false;
    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;
    709                         static std::unordered_map< int, UniqueExpr * > unqMap;
    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() ) ) {
    712789                                // take data from other UniqueExpr to ensure consistency
    713790                                delete unqExpr->get_expr();
    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;
     791                                unqExpr->expr = unqMap[unqExpr->get_id()]->expr->clone();
     792                                delete unqExpr->result;
     793                                unqExpr->result = maybeClone( unqExpr->expr->result );
     794                        }
    732795                }
    733796
     
    844907                                                        ctorInit->ctor = nullptr;
    845908                                                }
     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                                                }
    846924                                        } // if
    847925                                } else if ( Initializer * init = ctorInit->init ) {
     
    886964
    887965
    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 
    920966                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    921967                        // each function needs to have its own set of labels
     
    930976                }
    931977
    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 
    957978                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    958979                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    9821003                        if ( ! diff.empty() ) {
    9831004                                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 ) );
    10021005                        } // if
    10031006                }
     
    11161119                                                        callStmt->acceptMutator( *visitor );
    11171120                                                        if ( isCtor ) {
    1118                                                                 function->get_statements()->push_front( callStmt );
    1119                                                         } else {
     1121                                                                function->statements->push_front( callStmt );
     1122                                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
    11201123                                                                // destructor statements should be added at the end
    1121                                                                 function->get_statements()->push_back( callStmt );
     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 );
    11221149                                                        }
    11231150                                                } catch ( SemanticErrorException & error ) {
Note: See TracChangeset for help on using the changeset viewer.