Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r1be845b rb54ad9c  
    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
    5758
     
    162163                        using Parent::previsit;
    163164
    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 );
    170167                        void previsit( BranchStmt * stmt );
    171168                private:
     
    207204                        static void generate( std::list< Declaration * > & translationUnit );
    208205
     206                        void premutate( StructDecl * structDecl );
     207
    209208                        void premutate( FunctionDecl * funcDecl );
    210209                        DeclarationWithType * postmutate( FunctionDecl * funcDecl );
     
    228227                        bool isCtor = false; // true if current function is a constructor
    229228                        StructDecl * structDecl = nullptr;
     229
     230                        // special built-in functions necessary for this to work
     231                        StructDecl * dtorStruct = nullptr;
     232                        FunctionDecl * dtorStructDestroy = nullptr;
    230233                };
    231234
     
    732735                }
    733736
     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
    734788                DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) {
    735789                        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate)
     
    844898                                                        ctorInit->ctor = nullptr;
    845899                                                }
     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                                                }
    846915                                        } // if
    847916                                } else if ( Initializer * init = ctorInit->init ) {
     
    886955
    887956
    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 
    920957                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    921958                        // each function needs to have its own set of labels
     
    930967                }
    931968
    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 
    957969                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    958970                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    982994                        if ( ! diff.empty() ) {
    983995                                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 ) );
    1002996                        } // if
    1003997                }
     
    10251019                }
    10261020
     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                        }
    10391044
    10401045                        function = funcDecl;
     
    10481053                                if ( structType ) {
    10491054                                        structDecl = structType->get_baseStruct();
     1055                                        if ( structDecl == dtorStruct ) return;
    10501056                                        for ( Declaration * member : structDecl->get_members() ) {
    10511057                                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
     
    11161122                                                        callStmt->acceptMutator( *visitor );
    11171123                                                        if ( isCtor ) {
    1118                                                                 function->get_statements()->push_front( callStmt );
    1119                                                         } else {
     1124                                                                function->statements->push_front( callStmt );
     1125                                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
    11201126                                                                // destructor statements should be added at the end
    1121                                                                 function->get_statements()->push_back( callStmt );
     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 );
    11221149                                                        }
    11231150                                                } catch ( SemanticErrorException & error ) {
Note: See TracChangeset for help on using the changeset viewer.