Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r1bc749f rb0f601fa  
    5454#include "SynTree/Type.h"              // for Type, Type::StorageClasses
    5555#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
    56 #include "SynTree/VarExprReplacer.h"   // for VarExprReplacer
    5756#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    5857
     
    159158                        using Parent::previsit;
    160159
     160                        void previsit( ObjectDecl * objDecl );
    161161                        void previsit( FunctionDecl * funcDecl );
    162162
     163                        void previsit( CompoundStmt * compoundStmt );
     164                        void postvisit( CompoundStmt * compoundStmt );
     165                        void previsit( ReturnStmt * returnStmt );
    163166                        void previsit( BranchStmt * stmt );
    164167                private:
     
    176179
    177180                        DeclarationWithType * postmutate( ObjectDecl *objDecl );
    178 
    179                         DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * dtor );
    180181
    181182                        std::list< Declaration * > staticDtorDecls;
     
    213214                        void emit( CodeLocation, const Params &... params );
    214215
    215                         FunctionDecl * function = 0;
     216                        FunctionDecl * function = nullptr;
    216217                        std::set< DeclarationWithType * > unhandled;
    217218                        std::map< DeclarationWithType *, CodeLocation > usedUninit;
    218                         ObjectDecl * thisParam = 0;
     219                        ObjectDecl * thisParam = nullptr;
    219220                        bool isCtor = false; // true if current function is a constructor
    220                         StructDecl * structDecl = 0;
     221                        StructDecl * structDecl = nullptr;
    221222                };
    222223
     
    623624                }
    624625
    625                 DeclarationWithType * FixInit::getDtorFunc( ObjectDecl * objDecl, Statement * dtor ) {
    626                         if ( dynamic_cast< ExprStmt * >( dtor ) ) {
    627                                 if ( DeclarationWithType * func = getFunction( getCtorDtorCall( dtor ) ) ) {
    628                                         // cleanup argument must be a function, not an object (including function pointer)
    629                                         if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
    630                                                 if ( dtorFunc->type->forall.empty() ) {
    631                                                         // simple case where the destructor is a monomorphic function call - can simply
    632                                                         // use that function as the cleanup function.
    633                                                         delete dtor;
    634                                                         return func;
    635                                                 }
    636                                         }
    637                                 }
    638                         }
    639 
    640                         // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
    641                         // wraps the more complicated code.
    642                         static UniqueName dtorNamer( "__cleanup_dtor" );
    643                         FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type ), new CompoundStmt( noLabels ) );
    644                         stmtsToAddBefore.push_back( new DeclStmt( noLabels, dtorFunc ) );
    645 
    646                         // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
    647                         ObjectDecl * thisParam = getThisParam( dtorFunc->type );
    648                         VarExprReplacer::replace( dtor, { std::make_pair( objDecl, thisParam ) } );
    649                         dtorFunc->statements->push_back( dtor );
    650 
    651                         return dtorFunc;
    652                 }
    653 
    654626                DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) {
    655627                        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate)
     
    750722                                        } else {
    751723                                                ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * > ( ctor );
    752                                                 ExprStmt * ctorStmt = dynamic_cast< ExprStmt * >( implicit->get_callStmt() );
     724                                                ExprStmt * ctorStmt = dynamic_cast< ExprStmt * >( implicit->callStmt );
    753725                                                ApplicationExpr * ctorCall = nullptr;
    754                                                 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->get_expr() )) && ctorCall->get_args().size() == 2 ) {
     726                                                if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->get_args().size() == 2 ) {
    755727                                                        // clean up intrinsic copy constructor calls by making them into SingleInits
    756                                                         objDecl->set_init( new SingleInit( ctorCall->get_args().back() ) );
    757                                                         ctorCall->get_args().pop_back();
     728                                                        objDecl->init = new SingleInit( ctorCall->args.back() );
     729                                                        ctorCall->args.pop_back();
    758730                                                } else {
    759731                                                        stmtsToAddAfter.push_back( ctor );
    760                                                         objDecl->set_init( nullptr );
    761                                                         ctorInit->set_ctor( nullptr );
    762                                                 }
    763 
    764                                                 Statement * dtor = ctorInit->dtor;
    765                                                 if ( dtor ) {
    766                                                         ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
    767                                                         Statement * dtorStmt = implicit->callStmt;
    768                                                         // don't need to call intrinsic dtor, because it does nothing, but
    769                                                         // non-intrinsic dtors must be called
    770                                                         if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
    771                                                                 // set dtor location to the object's location for error messages
    772                                                                 DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt );
    773                                                                 objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
    774                                                                 // objDecl->attributes.push_back( new Attribute( "cleanup", { new NameExpr( dtorFunc->name ) } ) );
    775                                                                 ctorInit->dtor = nullptr;
    776                                                         } // if
     732                                                        objDecl->init = nullptr;
     733                                                        ctorInit->ctor = nullptr;
    777734                                                }
    778735                                        } // if
    779                                 } else if ( Initializer * init = ctorInit->get_init() ) {
    780                                         objDecl->set_init( init );
    781                                         ctorInit->set_init( nullptr );
     736                                } else if ( Initializer * init = ctorInit->init ) {
     737                                        objDecl->init = init;
     738                                        ctorInit->init = nullptr;
    782739                                } else {
    783740                                        // no constructor and no initializer, which is okay
    784                                         objDecl->set_init( nullptr );
     741                                        objDecl->init = nullptr;
    785742                                } // if
    786743                                delete ctorInit;
     
    817774                }
    818775
     776
     777                template<typename Iterator, typename OutputIterator>
     778                void insertDtors( Iterator begin, Iterator end, OutputIterator out ) {
     779                        for ( Iterator it = begin ; it != end ; ++it ) {
     780                                // extract destructor statement from the object decl and insert it into the output. Note that this is
     781                                // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually
     782                                // calls an intrinsic dtor then the call must (and will) still be generated since the argument may
     783                                // contain side effects.
     784                                ObjectDecl * objDecl = *it;
     785                                ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() );
     786                                assert( ctorInit && ctorInit->get_dtor() );
     787                                *out++ = ctorInit->get_dtor()->clone();
     788                        } // for
     789                }
     790
     791                void InsertDtors::previsit( ObjectDecl * objDecl ) {
     792                        // remember non-static destructed objects so that their destructors can be inserted later
     793                        if ( ! objDecl->get_storageClasses().is_static ) {
     794                                if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
     795                                        // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     796                                        assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
     797                                        Statement * dtor = ctorInit->get_dtor();
     798                                        // don't need to call intrinsic dtor, because it does nothing, but
     799                                        // non-intrinsic dtors must be called
     800                                        if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
     801                                                // set dtor location to the object's location for error messages
     802                                                ctorInit->dtor->location = objDecl->location;
     803                                                reverseDeclOrder.front().push_front( objDecl );
     804                                        } // if
     805                                } // if
     806                        } // if
     807                }
    819808
    820809                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
     
    826815
    827816                        // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.
     817                }
     818
     819                void InsertDtors::previsit( CompoundStmt * compoundStmt ) {
     820                        // visit statements - this will also populate reverseDeclOrder list.  don't want to dump all destructors
     821                        // when block is left, just the destructors associated with variables defined in this block, so push a new
     822                        // list to the top of the stack so that we can differentiate scopes
     823                        reverseDeclOrder.push_front( OrderedDecls() );
     824                        Parent::previsit( compoundStmt );
     825                }
     826
     827                void InsertDtors::postvisit( CompoundStmt * compoundStmt ) {
     828                        // add destructors for the current scope that we're exiting, unless the last statement is a return, which
     829                        // causes unreachable code warnings
     830                        std::list< Statement * > & statements = compoundStmt->get_kids();
     831                        if ( ! statements.empty() && ! dynamic_cast< ReturnStmt * >( statements.back() ) ) {
     832                                insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) );
     833                        }
     834                        reverseDeclOrder.pop_front();
     835                }
     836
     837                void InsertDtors::previsit( ReturnStmt * ) {
     838                        // return exits all scopes, so dump destructors for all scopes
     839                        for ( OrderedDecls & od : reverseDeclOrder ) {
     840                                insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) );
     841                        } // for
    828842                }
    829843
     
    855869                        if ( ! diff.empty() ) {
    856870                                throw SemanticError( std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " ", stmt );
     871                        } // if
     872                        // S_G-S_L results in set of objects that must be destructed
     873                        diff.clear();
     874                        std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) );
     875                        DTOR_PRINT(
     876                                std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl;
     877                        )
     878                        if ( ! diff.empty() ) {
     879                                // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.
     880                                std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );
     881
     882                                // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor
     883                                OrderedDecls ordered;
     884                                for ( OrderedDecls & rdo : reverseDeclOrder ) {
     885                                        // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order.
     886                                        copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );
     887                                } // for
     888                                insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) );
    857889                        } // if
    858890                }
     
    880912                }
    881913
     914                void addIds( SymTab::Indexer & indexer, const std::list< DeclarationWithType * > & decls ) {
     915                        for ( auto d : decls ) {
     916                                indexer.addId( d );
     917                        }
     918                }
     919
     920                void addTypes( SymTab::Indexer & indexer, const std::list< TypeDecl * > & tds ) {
     921                        for ( auto td : tds ) {
     922                                indexer.addType( td );
     923                                addIds( indexer, td->assertions );
     924                        }
     925                }
     926
    882927                void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) {
    883                         GuardValue( funcDecl );
     928                        GuardValue( function );
    884929                        GuardValue( unhandled );
    885930                        GuardValue( usedUninit );
     
    914959                }
    915960
    916                 void addIds( SymTab::Indexer & indexer, const std::list< DeclarationWithType * > & decls ) {
    917                         for ( auto d : decls ) {
    918                                 indexer.addId( d );
    919                         }
    920                 }
    921 
    922                 void addTypes( SymTab::Indexer & indexer, const std::list< TypeDecl * > & tds ) {
    923                         for ( auto td : tds ) {
    924                                 indexer.addType( td );
    925                                 addIds( indexer, td->assertions );
    926                         }
    927                 }
    928 
    929961                void GenStructMemberCalls::postvisit( FunctionDecl * funcDecl ) {
    930962                        // remove the unhandled objects from usedUninit, because a call is inserted
Note: See TracChangeset for help on using the changeset viewer.