Changeset 1bc749f


Ignore:
Timestamp:
Sep 27, 2017, 4:19:01 PM (4 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
arm-eh, cleanup-dtors, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr
Children:
b96ec83
Parents:
a139c11
Message:

Insert cleanup attribute for implicitly generated destructors of local variables

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    ra139c11 r1bc749f  
    5454#include "SynTree/Type.h"              // for Type, Type::StorageClasses
    5555#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
     56#include "SynTree/VarExprReplacer.h"   // for VarExprReplacer
    5657#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    5758
     
    158159                        using Parent::previsit;
    159160
    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 );
    166163                        void previsit( BranchStmt * stmt );
    167164                private:
     
    179176
    180177                        DeclarationWithType * postmutate( ObjectDecl *objDecl );
     178
     179                        DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * dtor );
    181180
    182181                        std::list< Declaration * > staticDtorDecls;
     
    624623                }
    625624
    626                 DeclarationWithType *FixInit::postmutate( ObjectDecl *objDecl ) {
     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
     654                DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) {
    627655                        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate)
    628656                        if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
     
    733761                                                        ctorInit->set_ctor( nullptr );
    734762                                                }
     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
     777                                                }
    735778                                        } // if
    736779                                } else if ( Initializer * init = ctorInit->get_init() ) {
     
    775818
    776819
    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                 }
    808 
    809820                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    810821                        // each function needs to have its own set of labels
     
    815826
    816827                        // 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
    842828                }
    843829
     
    869855                        if ( ! diff.empty() ) {
    870856                                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 ) );
    889857                        } // if
    890858                }
Note: See TracChangeset for help on using the changeset viewer.