Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r88e79ad rddae809  
    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:
     
    200203                        static void generate( std::list< Declaration * > & translationUnit );
    201204
    202                         void previsit( StructDecl * structDecl );
    203 
    204205                        void previsit( FunctionDecl * funcDecl );
    205206                        void postvisit( FunctionDecl * funcDecl );
     
    219220                        bool isCtor = false; // true if current function is a constructor
    220221                        StructDecl * structDecl = nullptr;
    221 
    222                         // special built-in functions necessary for this to work
    223                         StructDecl * dtorStruct = nullptr;
    224                         FunctionDecl * dtorStructDestroy = nullptr;
    225222                };
    226223
     
    504501                }
    505502
     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
    506517                void ResolveCopyCtors::postvisit( UniqueExpr * unqExpr ) {
    507518                        if ( vars.count( unqExpr->get_id() ) ) {
     
    518529                        } else {
    519530                                // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
    520                                 unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), nullptr ) );
     531                                unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), makeInit( unqExpr->get_result() ) ) );
    521532                                unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) );
    522533                        }
     
    639650                }
    640651
    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 
    670652                DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) {
    671653                        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate)
     
    780762                                                        ctorInit->ctor = nullptr;
    781763                                                }
    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                                                 }
    797764                                        } // if
    798765                                } else if ( Initializer * init = ctorInit->init ) {
     
    837804
    838805
     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
    839838                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    840839                        // each function needs to have its own set of labels
     
    849848                }
    850849
     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
    851875                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    852876                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    876900                        if ( ! diff.empty() ) {
    877901                                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 ) );
    878920                        } // if
    879921                }
     
    914956                }
    915957
    916                 void GenStructMemberCalls::previsit( StructDecl * structDecl ) {
    917                         if ( ! dtorStruct && structDecl->name == "__Destructor" ) {
    918                                 dtorStruct = structDecl;
    919                         }
    920                 }
    921 
    922958                void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) {
    923959                        GuardValue( function );
     
    932968                        unhandled.clear();
    933969                        usedUninit.clear();
    934 
    935                         if ( ! dtorStructDestroy && funcDecl->name == "__destroy_Destructor" ) {
    936                                 dtorStructDestroy = funcDecl;
    937                                 return;
    938                         }
    939970
    940971                        function = funcDecl;
     
    948979                                if ( structType ) {
    949980                                        structDecl = structType->get_baseStruct();
    950                                         if ( structDecl == dtorStruct ) return;
    951981                                        for ( Declaration * member : structDecl->get_members() ) {
    952982                                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
     
    10201050                                                        callStmt->acceptMutator( resolver );
    10211051                                                        if ( isCtor ) {
    1022                                                                 function->statements->push_front( callStmt );
     1052                                                                function->get_statements()->push_front( callStmt );
    10231053                                                        } else {
    10241054                                                                // destructor statements should be added at the end
    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 );
     1055                                                                function->get_statements()->push_back( callStmt );
    10421056                                                        }
    10431057                                                } catch ( SemanticError & error ) {
Note: See TracChangeset for help on using the changeset viewer.