Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    rddae809 r88e79ad  
    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:
     
    203200                        static void generate( std::list< Declaration * > & translationUnit );
    204201
     202                        void previsit( StructDecl * structDecl );
     203
    205204                        void previsit( FunctionDecl * funcDecl );
    206205                        void postvisit( FunctionDecl * funcDecl );
     
    220219                        bool isCtor = false; // true if current function is a constructor
    221220                        StructDecl * structDecl = nullptr;
     221
     222                        // special built-in functions necessary for this to work
     223                        StructDecl * dtorStruct = nullptr;
     224                        FunctionDecl * dtorStructDestroy = nullptr;
    222225                };
    223226
     
    501504                }
    502505
    503                 // to prevent warnings (‘_unq0’ may be used uninitialized in this function),
    504                 // insert an appropriate zero initializer for UniqueExpr temporaries.
    505                 Initializer * makeInit( Type * t ) {
    506                         if ( StructInstType * inst = dynamic_cast< StructInstType * >( t ) ) {
    507                                 // initizer for empty struct must be empty
    508                                 if ( inst->baseStruct->members.empty() ) return new ListInit({});
    509                         } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( t ) ) {
    510                                 // initizer for empty union must be empty
    511                                 if ( inst->baseUnion->members.empty() ) return new ListInit({});
    512                         }
    513 
    514                         return new ListInit( { new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) } );
    515                 }
    516 
    517506                void ResolveCopyCtors::postvisit( UniqueExpr * unqExpr ) {
    518507                        if ( vars.count( unqExpr->get_id() ) ) {
     
    529518                        } else {
    530519                                // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
    531                                 unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), makeInit( unqExpr->get_result() ) ) );
     520                                unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), nullptr ) );
    532521                                unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) );
    533522                        }
     
    650639                }
    651640
     641                DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * dtor, std::list< Statement * > & stmtsToAdd ) {
     642                        if ( dynamic_cast< ExprStmt * >( dtor ) ) {
     643                                if ( DeclarationWithType * func = getFunction( getCtorDtorCall( dtor ) ) ) {
     644                                        // cleanup argument must be a function, not an object (including function pointer)
     645                                        if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
     646                                                if ( dtorFunc->type->forall.empty() ) {
     647                                                        // simple case where the destructor is a monomorphic function call - can simply
     648                                                        // use that function as the cleanup function.
     649                                                        delete dtor;
     650                                                        return func;
     651                                                }
     652                                        }
     653                                }
     654                        }
     655
     656                        // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
     657                        // wraps the more complicated code.
     658                        static UniqueName dtorNamer( "__cleanup_dtor" );
     659                        FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt( noLabels ) );
     660                        stmtsToAdd.push_back( new DeclStmt( noLabels, dtorFunc ) );
     661
     662                        // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
     663                        ObjectDecl * thisParam = getParamThis( dtorFunc->type );
     664                        VarExprReplacer::replace( dtor, { std::make_pair( objDecl, thisParam ) } );
     665                        dtorFunc->statements->push_back( dtor );
     666
     667                        return dtorFunc;
     668                }
     669
    652670                DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) {
    653671                        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate)
     
    762780                                                        ctorInit->ctor = nullptr;
    763781                                                }
     782
     783                                                Statement * dtor = ctorInit->dtor;
     784                                                if ( dtor ) {
     785                                                        ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
     786                                                        Statement * dtorStmt = implicit->callStmt;
     787                                                        // don't need to call intrinsic dtor, because it does nothing, but
     788                                                        // non-intrinsic dtors must be called
     789                                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     790                                                                // set dtor location to the object's location for error messages
     791                                                                DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     792                                                                objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
     793                                                                // objDecl->attributes.push_back( new Attribute( "cleanup", { new NameExpr( dtorFunc->name ) } ) );
     794                                                                ctorInit->dtor = nullptr;
     795                                                        } // if
     796                                                }
    764797                                        } // if
    765798                                } else if ( Initializer * init = ctorInit->init ) {
     
    804837
    805838
    806                 template<typename Iterator, typename OutputIterator>
    807                 void insertDtors( Iterator begin, Iterator end, OutputIterator out ) {
    808                         for ( Iterator it = begin ; it != end ; ++it ) {
    809                                 // extract destructor statement from the object decl and insert it into the output. Note that this is
    810                                 // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually
    811                                 // calls an intrinsic dtor then the call must (and will) still be generated since the argument may
    812                                 // contain side effects.
    813                                 ObjectDecl * objDecl = *it;
    814                                 ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() );
    815                                 assert( ctorInit && ctorInit->get_dtor() );
    816                                 *out++ = ctorInit->get_dtor()->clone();
    817                         } // for
    818                 }
    819 
    820                 void InsertDtors::previsit( ObjectDecl * objDecl ) {
    821                         // remember non-static destructed objects so that their destructors can be inserted later
    822                         if ( ! objDecl->get_storageClasses().is_static ) {
    823                                 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
    824                                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    825                                         assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    826                                         Statement * dtor = ctorInit->get_dtor();
    827                                         // don't need to call intrinsic dtor, because it does nothing, but
    828                                         // non-intrinsic dtors must be called
    829                                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    830                                                 // set dtor location to the object's location for error messages
    831                                                 ctorInit->dtor->location = objDecl->location;
    832                                                 reverseDeclOrder.front().push_front( objDecl );
    833                                         } // if
    834                                 } // if
    835                         } // if
    836                 }
    837 
    838839                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    839840                        // each function needs to have its own set of labels
     
    848849                }
    849850
    850                 void InsertDtors::previsit( CompoundStmt * compoundStmt ) {
    851                         // visit statements - this will also populate reverseDeclOrder list.  don't want to dump all destructors
    852                         // when block is left, just the destructors associated with variables defined in this block, so push a new
    853                         // list to the top of the stack so that we can differentiate scopes
    854                         reverseDeclOrder.push_front( OrderedDecls() );
    855                         Parent::previsit( compoundStmt );
    856                 }
    857 
    858                 void InsertDtors::postvisit( CompoundStmt * compoundStmt ) {
    859                         // add destructors for the current scope that we're exiting, unless the last statement is a return, which
    860                         // causes unreachable code warnings
    861                         std::list< Statement * > & statements = compoundStmt->get_kids();
    862                         if ( ! statements.empty() && ! dynamic_cast< ReturnStmt * >( statements.back() ) ) {
    863                                 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) );
    864                         }
    865                         reverseDeclOrder.pop_front();
    866                 }
    867 
    868                 void InsertDtors::previsit( ReturnStmt * ) {
    869                         // return exits all scopes, so dump destructors for all scopes
    870                         for ( OrderedDecls & od : reverseDeclOrder ) {
    871                                 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) );
    872                         } // for
    873                 }
    874 
    875851                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    876852                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    900876                        if ( ! diff.empty() ) {
    901877                                throw SemanticError( std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " ", stmt );
    902                         } // if
    903                         // S_G-S_L results in set of objects that must be destructed
    904                         diff.clear();
    905                         std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) );
    906                         DTOR_PRINT(
    907                                 std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl;
    908                         )
    909                         if ( ! diff.empty() ) {
    910                                 // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.
    911                                 std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );
    912 
    913                                 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor
    914                                 OrderedDecls ordered;
    915                                 for ( OrderedDecls & rdo : reverseDeclOrder ) {
    916                                         // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order.
    917                                         copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );
    918                                 } // for
    919                                 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) );
    920878                        } // if
    921879                }
     
    956914                }
    957915
     916                void GenStructMemberCalls::previsit( StructDecl * structDecl ) {
     917                        if ( ! dtorStruct && structDecl->name == "__Destructor" ) {
     918                                dtorStruct = structDecl;
     919                        }
     920                }
     921
    958922                void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) {
    959923                        GuardValue( function );
     
    968932                        unhandled.clear();
    969933                        usedUninit.clear();
     934
     935                        if ( ! dtorStructDestroy && funcDecl->name == "__destroy_Destructor" ) {
     936                                dtorStructDestroy = funcDecl;
     937                                return;
     938                        }
    970939
    971940                        function = funcDecl;
     
    979948                                if ( structType ) {
    980949                                        structDecl = structType->get_baseStruct();
     950                                        if ( structDecl == dtorStruct ) return;
    981951                                        for ( Declaration * member : structDecl->get_members() ) {
    982952                                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
     
    10501020                                                        callStmt->acceptMutator( resolver );
    10511021                                                        if ( isCtor ) {
    1052                                                                 function->get_statements()->push_front( callStmt );
     1022                                                                function->statements->push_front( callStmt );
    10531023                                                        } else {
    10541024                                                                // destructor statements should be added at the end
    1055                                                                 function->get_statements()->push_back( callStmt );
     1025                                                                // function->get_statements()->push_back( callStmt );
     1026
     1027                                                                // Destructor _dtor0 = { &b.a1, _destroy_A };
     1028                                                                std::list< Statement * > stmtsToAdd;
     1029
     1030                                                                static UniqueName memberDtorNamer = { "__memberDtor" };
     1031                                                                assertf( dtorStruct, "builtin __Destructor not found." );
     1032                                                                assertf( dtorStructDestroy, "builtin __destroy_Destructor not found." );
     1033
     1034                                                                Expression * thisExpr = new AddressExpr( new VariableExpr( thisParam ) );
     1035                                                                Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
     1036
     1037                                                                ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( dtorExpr ) } ) );
     1038                                                                function->statements->push_front( new DeclStmt( noLabels, destructor ) );
     1039                                                                destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorStructDestroy ) } ) );
     1040
     1041                                                                function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
    10561042                                                        }
    10571043                                                } catch ( SemanticError & error ) {
Note: See TracChangeset for help on using the changeset viewer.