Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    rb54ad9c r1be845b  
    5454#include "SynTree/Type.h"              // for Type, Type::StorageClasses
    5555#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
    56 #include "SynTree/DeclReplacer.h"      // for DeclReplacer
    5756#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    5857
     
    163162                        using Parent::previsit;
    164163
     164                        void previsit( ObjectDecl * objDecl );
    165165                        void previsit( FunctionDecl * funcDecl );
    166166
     167                        void previsit( CompoundStmt * compoundStmt );
     168                        void postvisit( CompoundStmt * compoundStmt );
     169                        void previsit( ReturnStmt * returnStmt );
    167170                        void previsit( BranchStmt * stmt );
    168171                private:
     
    204207                        static void generate( std::list< Declaration * > & translationUnit );
    205208
    206                         void premutate( StructDecl * structDecl );
    207 
    208209                        void premutate( FunctionDecl * funcDecl );
    209210                        DeclarationWithType * postmutate( FunctionDecl * funcDecl );
     
    227228                        bool isCtor = false; // true if current function is a constructor
    228229                        StructDecl * structDecl = nullptr;
    229 
    230                         // special built-in functions necessary for this to work
    231                         StructDecl * dtorStruct = nullptr;
    232                         FunctionDecl * dtorStructDestroy = nullptr;
    233230                };
    234231
     
    735732                }
    736733
    737                 DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * input, std::list< Statement * > & stmtsToAdd ) {
    738                         // unwrap implicit statement wrapper
    739                         Statement * dtor = input;
    740                         if ( ImplicitCtorDtorStmt * implicit = dynamic_cast< ImplicitCtorDtorStmt * >( input ) ) {
    741                                 // dtor = implicit->callStmt;
    742                                 // implicit->callStmt = nullptr;
    743                         }
    744                         assert( dtor );
    745                         std::list< Expression * > matches;
    746                         collectCtorDtorCalls( dtor, matches );
    747 
    748                         if ( dynamic_cast< ExprStmt * >( dtor ) ) {
    749                                 // only one destructor call in the expression
    750                                 if ( matches.size() == 1 ) {
    751                                         DeclarationWithType * func = getFunction( matches.front() );
    752                                         assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
    753 
    754                                         // cleanup argument must be a function, not an object (including function pointer)
    755                                         if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
    756                                                 if ( dtorFunc->type->forall.empty() ) {
    757                                                         // simple case where the destructor is a monomorphic function call - can simply
    758                                                         // use that function as the cleanup function.
    759                                                         delete dtor;
    760                                                         return func;
    761                                                 }
    762                                         }
    763                                 }
    764                         }
    765 
    766                         // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
    767                         // wraps the more complicated code.
    768                         static UniqueName dtorNamer( "__cleanup_dtor" );
    769                         FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt() );
    770                         stmtsToAdd.push_back( new DeclStmt( dtorFunc ) );
    771 
    772                         // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
    773                         ObjectDecl * thisParam = getParamThis( dtorFunc->type );
    774                         Expression * replacement = new VariableExpr( thisParam );
    775 
    776                         Type * base = replacement->result->stripReferences();
    777                         if ( dynamic_cast< ArrayType * >( base ) || dynamic_cast< TupleType * > ( base ) ) {
    778                                 // need to cast away reference for array types, since the destructor is generated without the reference type,
    779                                 // and for tuple types since tuple indexing does not work directly on a reference
    780                                 replacement = new CastExpr( replacement, base->clone() );
    781                         }
    782                         DeclReplacer::replace( dtor, { std::make_pair( objDecl, replacement ) } );
    783                         dtorFunc->statements->push_back( strict_dynamic_cast<Statement *>( dtor ) );
    784 
    785                         return dtorFunc;
    786                 }
    787 
    788734                DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) {
    789735                        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate)
     
    898844                                                        ctorInit->ctor = nullptr;
    899845                                                }
    900 
    901                                                 Statement * dtor = ctorInit->dtor;
    902                                                 if ( dtor ) {
    903                                                         ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
    904                                                         Statement * dtorStmt = implicit->callStmt;
    905 
    906                                                         // don't need to call intrinsic dtor, because it does nothing, but
    907                                                         // non-intrinsic dtors must be called
    908                                                         if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
    909                                                                 // set dtor location to the object's location for error messages
    910                                                                 DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
    911                                                                 objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
    912                                                                 ctorInit->dtor = nullptr;
    913                                                         } // if
    914                                                 }
    915846                                        } // if
    916847                                } else if ( Initializer * init = ctorInit->init ) {
     
    955886
    956887
     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
    957920                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    958921                        // each function needs to have its own set of labels
     
    967930                }
    968931
     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
    969957                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    970958                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    994982                        if ( ! diff.empty() ) {
    995983                                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 ) );
    9961002                        } // if
    9971003                }
     
    10191025                }
    10201026
    1021                 void GenStructMemberCalls::premutate( StructDecl * structDecl ) {
    1022                         if ( ! dtorStruct && structDecl->name == "__Destructor" ) {
    1023                                 dtorStruct = structDecl;
    1024                         }
    1025                 }
    1026 
    10271027                void GenStructMemberCalls::premutate( FunctionDecl * funcDecl ) {
    10281028                        GuardValue( function );
     
    10371037                        unhandled.clear();
    10381038                        usedUninit.clear();
    1039 
    1040                         if ( ! dtorStructDestroy && funcDecl->name == "__destroy_Destructor" ) {
    1041                                 dtorStructDestroy = funcDecl;
    1042                                 return;
    1043                         }
    10441039
    10451040                        function = funcDecl;
     
    10531048                                if ( structType ) {
    10541049                                        structDecl = structType->get_baseStruct();
    1055                                         if ( structDecl == dtorStruct ) return;
    10561050                                        for ( Declaration * member : structDecl->get_members() ) {
    10571051                                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
     
    11221116                                                        callStmt->acceptMutator( *visitor );
    11231117                                                        if ( isCtor ) {
    1124                                                                 function->statements->push_front( callStmt );
    1125                                                         } else { // TODO: don't generate destructor function/object for intrinsic calls
     1118                                                                function->get_statements()->push_front( callStmt );
     1119                                                        } else {
    11261120                                                                // destructor statements should be added at the end
    1127                                                                 // function->get_statements()->push_back( callStmt );
    1128 
    1129                                                                 // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
    1130                                                                 std::list< Statement * > stmtsToAdd;
    1131 
    1132                                                                 static UniqueName memberDtorNamer = { "__memberDtor" };
    1133                                                                 assertf( dtorStruct, "builtin __Destructor not found." );
    1134                                                                 assertf( 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(), 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( dtorStructDestroy ) } ) );
    1147 
    1148                                                                 function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
     1121                                                                function->get_statements()->push_back( callStmt );
    11491122                                                        }
    11501123                                                } catch ( SemanticErrorException & error ) {
Note: See TracChangeset for help on using the changeset viewer.