Ignore:
Timestamp:
May 29, 2019, 3:45:00 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
0aedb01
Parents:
157a816 (diff), ebc0a85 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'cleanup-dtors'

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r157a816 rf57dd25  
    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
     58#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    5759
    5860bool ctordtorp = false; // print all debug
     
    6668namespace InitTweak {
    6769        namespace {
    68                 typedef std::unordered_map< int, int > UnqCount;
    69 
    7070                struct SelfAssignChecker {
    7171                        void previsit( ApplicationExpr * appExpr );
     
    8080                };
    8181
    82                 struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
     82                struct ResolveCopyCtors final : public WithStmtsToAdd, public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution, public WithVisitorRef<ResolveCopyCtors> {
    8383                        /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
    8484                        /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    8585                        /// arguments and return value temporaries
    86                         static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount );
    87 
    88                         ResolveCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ) {}
    89 
    90                         void postvisit( ImplicitCopyCtorExpr * impCpCtorExpr );
    91                         void postvisit( StmtExpr * stmtExpr );
    92                         void previsit( UniqueExpr * unqExpr );
    93                         void postvisit( UniqueExpr * unqExpr );
     86                        static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
     87
     88                        Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
     89                        void premutate( StmtExpr * stmtExpr );
     90                        void premutate( UniqueExpr * unqExpr );
    9491
    9592                        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
     
    9895                        bool skipCopyConstruct( Type * type );
    9996                        void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal );
    100                         void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
    101 
    102                         UnqCount & unqCount; // count the number of times each unique expr ID appears
    103                         std::unordered_set< int > vars;
     97                        void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr, Expression *& arg );
    10498                };
    10599
     
    162156                        using Parent::previsit;
    163157
    164                         void previsit( ObjectDecl * objDecl );
    165158                        void previsit( FunctionDecl * funcDecl );
    166159
    167                         void previsit( CompoundStmt * compoundStmt );
    168                         void postvisit( CompoundStmt * compoundStmt );
    169                         void previsit( ReturnStmt * returnStmt );
    170160                        void previsit( BranchStmt * stmt );
    171161                private:
     
    185175
    186176                        std::list< Declaration * > staticDtorDecls;
    187                 };
    188 
    189                 class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithConstTypeSubstitution {
    190                   public:
    191                         FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
    192                         /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, call expression,
    193                         /// and destructors
    194                         static void fixCopyCtors( std::list< Declaration * > &translationUnit, UnqCount & unqCount );
    195 
    196                         Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
    197                         void premutate( StmtExpr * stmtExpr );
    198                         void premutate( UniqueExpr * unqExpr );
    199 
    200                         UnqCount & unqCount;
    201177                };
    202178
     
    236212                        Expression * postmutate( ConstructorExpr * ctorExpr );
    237213                };
     214
     215                struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
     216                        /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
     217                        static void split( std::list< Declaration * > &translationUnit );
     218
     219                        Statement * postmutate( ExprStmt * stmt );
     220                        void premutate( TupleAssignExpr * expr );
     221                };
    238222        } // namespace
    239223
     
    245229                InitTweak::fixGlobalInit( translationUnit, inLibrary );
    246230
    247                 UnqCount unqCount;
     231                // must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
     232                SplitExpressions::split( translationUnit );
    248233
    249234                InsertImplicitCalls::insert( translationUnit );
    250                 ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
     235
     236                // Needs to happen before ResolveCopyCtors, because argument/return temporaries should not be considered in
     237                // error checking branch statements
    251238                InsertDtors::insert( translationUnit );
     239
     240                ResolveCopyCtors::resolveImplicitCalls( translationUnit );
    252241                FixInit::fixInitializers( translationUnit );
    253 
    254                 // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
    255                 FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
    256 
    257242                GenStructMemberCalls::generate( translationUnit );
    258243
    259                 // xxx - ctor expansion currently has to be after FixCopyCtors, because there is currently a
    260                 // hack in the way untyped assignments are generated, where the first argument cannot have
    261                 // its address taken because of the way codegeneration handles UntypedExpr vs. ApplicationExpr.
    262                 // Thus such assignment exprs must never pushed through expression resolution (and thus should
    263                 // not go through the FixCopyCtors pass), otherwise they will fail -- guaranteed.
    264                 // Also needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
    265                 // don't look right, and a member can be constructed more than once.
     244                // Needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
     245                // don't have the correct form, and a member can be constructed more than once.
    266246                FixCtorExprs::fix( translationUnit );
    267247        }
    268248
    269249        namespace {
     250                /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk
     251                /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration
     252                DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * input, std::list< Statement * > & stmtsToAdd ) {
     253                        // unwrap implicit statement wrapper
     254                        Statement * dtor = input;
     255                        if ( ImplicitCtorDtorStmt * implicit = dynamic_cast< ImplicitCtorDtorStmt * >( input ) ) {
     256                                // dtor = implicit->callStmt;
     257                                // implicit->callStmt = nullptr;
     258                        }
     259                        assert( dtor );
     260                        std::list< Expression * > matches;
     261                        collectCtorDtorCalls( dtor, matches );
     262
     263                        if ( dynamic_cast< ExprStmt * >( dtor ) ) {
     264                                // only one destructor call in the expression
     265                                if ( matches.size() == 1 ) {
     266                                        DeclarationWithType * func = getFunction( matches.front() );
     267                                        assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
     268
     269                                        // cleanup argument must be a function, not an object (including function pointer)
     270                                        if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
     271                                                if ( dtorFunc->type->forall.empty() ) {
     272                                                        // simple case where the destructor is a monomorphic function call - can simply
     273                                                        // use that function as the cleanup function.
     274                                                        delete dtor;
     275                                                        return func;
     276                                                }
     277                                        }
     278                                }
     279                        }
     280
     281                        // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
     282                        // wraps the more complicated code.
     283                        static UniqueName dtorNamer( "__cleanup_dtor" );
     284                        FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt() );
     285                        stmtsToAdd.push_back( new DeclStmt( dtorFunc ) );
     286
     287                        // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
     288                        ObjectDecl * thisParam = getParamThis( dtorFunc->type );
     289                        Expression * replacement = new VariableExpr( thisParam );
     290
     291                        Type * base = replacement->result->stripReferences();
     292                        if ( dynamic_cast< ArrayType * >( base ) || dynamic_cast< TupleType * > ( base ) ) {
     293                                // need to cast away reference for array types, since the destructor is generated without the reference type,
     294                                // and for tuple types since tuple indexing does not work directly on a reference
     295                                replacement = new CastExpr( replacement, base->clone() );
     296                        }
     297                        DeclReplacer::replace( dtor, { std::make_pair( objDecl, replacement ) } );
     298                        dtorFunc->statements->push_back( strict_dynamic_cast<Statement *>( dtor ) );
     299
     300                        return dtorFunc;
     301                }
     302
     303                void SplitExpressions::split( std::list< Declaration * > & translationUnit ) {
     304                        PassVisitor<SplitExpressions> splitter;
     305                        mutateAll( translationUnit, splitter );
     306                }
     307
    270308                void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
    271309                        PassVisitor<InsertImplicitCalls> inserter;
     
    273311                }
    274312
    275                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    276                         PassVisitor<ResolveCopyCtors> resolver( unqCount );
    277                         acceptAll( translationUnit, resolver );
     313                void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
     314                        PassVisitor<ResolveCopyCtors> resolver;
     315                        mutateAll( translationUnit, resolver );
    278316                }
    279317
     
    303341                }
    304342
    305                 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    306                         PassVisitor<FixCopyCtors> fixer( unqCount );
    307                         mutateAll( translationUnit, fixer );
    308                 }
    309 
    310343                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
    311344                        PassVisitor<GenStructMemberCalls> warner;
     
    318351                }
    319352
    320                 namespace {
    321                         // Relatively simple structural comparison for expressions, needed to determine
    322                         // if two expressions are "the same" (used to determine if self assignment occurs)
    323                         struct StructuralChecker {
    324                                 Expression * stripCasts( Expression * expr ) {
    325                                         // this might be too permissive. It's possible that only particular casts are relevant.
    326                                         while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
    327                                                 expr = cast->arg;
    328                                         }
    329                                         return expr;
    330                                 }
    331 
    332                                 void previsit( Expression * ) {
    333                                         // anything else does not qualify
    334                                         isSimilar = false;
    335                                 }
    336 
    337                                 template<typename T>
    338                                 T * cast( Expression * node ) {
    339                                         // all expressions need to ignore casts, so this bit has been factored out
    340                                         return dynamic_cast< T * >( stripCasts( node ) );
    341                                 }
    342 
    343                                 // ignore casts
    344                                 void previsit( CastExpr * ) {}
    345 
    346                                 void previsit( MemberExpr * memExpr ) {
    347                                         if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
    348                                                 if ( otherMember->member == memExpr->member ) {
    349                                                         other = otherMember->aggregate;
    350                                                         return;
    351                                                 }
    352                                         }
    353                                         isSimilar = false;
    354                                 }
    355 
    356                                 void previsit( VariableExpr * varExpr ) {
    357                                         if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
    358                                                 if ( otherVar->var == varExpr->var ) {
    359                                                         return;
    360                                                 }
    361                                         }
    362                                         isSimilar = false;
    363                                 }
    364 
    365                                 void previsit( AddressExpr * ) {
    366                                         if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
    367                                                 other = addrExpr->arg;
     353                Statement * SplitExpressions::postmutate( ExprStmt * stmt ) {
     354                        // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
     355                        // in the correct places
     356                        CompoundStmt * ret = new CompoundStmt( { stmt } );
     357                        return ret;
     358                }
     359
     360                void SplitExpressions::premutate( TupleAssignExpr * ) {
     361                        // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
     362                        visit_children = false;
     363                }
     364
     365                // Relatively simple structural comparison for expressions, needed to determine
     366                // if two expressions are "the same" (used to determine if self assignment occurs)
     367                struct StructuralChecker {
     368                        Expression * stripCasts( Expression * expr ) {
     369                                // this might be too permissive. It's possible that only particular casts are relevant.
     370                                while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
     371                                        expr = cast->arg;
     372                                }
     373                                return expr;
     374                        }
     375
     376                        void previsit( Expression * ) {
     377                                // anything else does not qualify
     378                                isSimilar = false;
     379                        }
     380
     381                        template<typename T>
     382                        T * cast( Expression * node ) {
     383                                // all expressions need to ignore casts, so this bit has been factored out
     384                                return dynamic_cast< T * >( stripCasts( node ) );
     385                        }
     386
     387                        // ignore casts
     388                        void previsit( CastExpr * ) {}
     389
     390                        void previsit( MemberExpr * memExpr ) {
     391                                if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
     392                                        if ( otherMember->member == memExpr->member ) {
     393                                                other = otherMember->aggregate;
    368394                                                return;
    369395                                        }
    370                                         isSimilar = false;
    371                                 }
    372 
    373                                 Expression * other = nullptr;
    374                                 bool isSimilar = true;
    375                         };
    376 
    377                         bool structurallySimilar( Expression * e1, Expression * e2 ) {
    378                                 PassVisitor<StructuralChecker> checker;
    379                                 checker.pass.other = e2;
    380                                 e1->accept( checker );
    381                                 return checker.pass.isSimilar;
    382                         }
     396                                }
     397                                isSimilar = false;
     398                        }
     399
     400                        void previsit( VariableExpr * varExpr ) {
     401                                if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
     402                                        if ( otherVar->var == varExpr->var ) {
     403                                                return;
     404                                        }
     405                                }
     406                                isSimilar = false;
     407                        }
     408
     409                        void previsit( AddressExpr * ) {
     410                                if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
     411                                        other = addrExpr->arg;
     412                                        return;
     413                                }
     414                                isSimilar = false;
     415                        }
     416
     417                        Expression * other = nullptr;
     418                        bool isSimilar = true;
     419                };
     420
     421                bool structurallySimilar( Expression * e1, Expression * e2 ) {
     422                        PassVisitor<StructuralChecker> checker;
     423                        checker.pass.other = e2;
     424                        e1->accept( checker );
     425                        return checker.pass.isSimilar;
    383426                }
    384427
     
    457500                        if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
    458501                                // fix newly generated StmtExpr
    459                                 postvisit( assign->stmtExpr );
     502                                premutate( assign->stmtExpr );
    460503                        }
    461504                        return resolved;
     
    489532                                        // so that the object isn't changed inside of the polymorphic function
    490533                                        if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
     534                                        // xxx - leaking tmp
    491535                                }
    492536                        }
     
    496540
    497541                        // replace argument to function call with temporary
    498                         arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
    499                         impCpCtorExpr->tempDecls.push_back( tmp );
    500                         impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    501                 }
    502 
    503                 void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
    504                         impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    505                 }
    506 
    507                 void ResolveCopyCtors::postvisit( ImplicitCopyCtorExpr *impCpCtorExpr ) {
     542                        stmtsToAddBefore.push_back( new DeclStmt( tmp ) );
     543                        arg = cpCtor;
     544                        destructRet( tmp, impCpCtorExpr, arg );
     545
     546                        // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
     547                }
     548
     549                void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * /*impCpCtorExpr*/, Expression *& arg ) {
     550                        // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
     551                        // check for existing cleanup attribute before adding another(?)
     552                        // need to add __Destructor for _tmp_cp variables as well
     553
     554                        assertf( Validate::dtorStruct && Validate::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." );
     555                        assertf( Validate::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
     556
     557                        // generate a __Destructor for ret that calls the destructor
     558                        Expression * dtor = makeCtorDtor( "^?{}", ret );
     559
     560                        // if the chosen destructor is intrinsic, elide the generated dtor handler
     561                        if ( arg && isIntrinsicCallExpr( dtor ) ) {
     562                                arg = new CommaExpr( arg, new VariableExpr( ret ) );
     563                                return;
     564                        }
     565
     566                        if ( ! dtor->env ) dtor->env = maybeClone( env );
     567                        DeclarationWithType * dtorFunc = getDtorFunc( ret, new ExprStmt( dtor ), stmtsToAddBefore );
     568
     569                        StructInstType * dtorStructType = new StructInstType( Type::Qualifiers(), Validate::dtorStruct );
     570                        dtorStructType->parameters.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
     571
     572                        // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     573                        FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
     574                        dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
     575                        Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
     576
     577                        static UniqueName namer( "_ret_dtor" );
     578                        ObjectDecl * retDtor = ObjectDecl::newObject( namer.newName(), dtorStructType, new ListInit( { new SingleInit( new ConstantExpr( Constant::null() ) ), new SingleInit( new CastExpr( new VariableExpr( dtorFunc ), dtorType ) ) } ) );
     579                        retDtor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
     580                        stmtsToAddBefore.push_back( new DeclStmt( retDtor ) );
     581
     582                        if ( arg ) {
     583                                Expression * member = new MemberExpr( strict_dynamic_cast<DeclarationWithType *>( Validate::dtorStruct->members.front() ), new VariableExpr( retDtor ) );
     584                                Expression * object = new CastExpr( new AddressExpr( new VariableExpr( ret ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
     585                                Expression * assign = createBitwiseAssignment( member, object );
     586                                arg = new CommaExpr( new CommaExpr( arg, assign ), new VariableExpr( ret ) );
     587                        }
     588
     589                        // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
     590                }
     591
     592                Expression * ResolveCopyCtors::postmutate( ImplicitCopyCtorExpr *impCpCtorExpr ) {
    508593                        CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
    509594
    510595                        ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
     596                        ObjectDecl * returnDecl = nullptr;
    511597
    512598                        // take each argument and attempt to copy construct it.
     
    517603                        for ( Expression * & arg : appExpr->args ) {
    518604                                Type * formal = nullptr;
    519                                 if ( iter != params.end() ) {
     605                                if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
    520606                                        DeclarationWithType * param = *iter++;
    521607                                        formal = param->get_type();
     
    535621                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    536622                                ret->type->set_const( false );
    537                                 impCpCtorExpr->returnDecls.push_back( ret );
     623                                returnDecl = ret;
     624                                stmtsToAddBefore.push_back( new DeclStmt( ret ) );
    538625                                CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
     626                        } // for
     627                        CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
     628                        // ------------------------------------------------------
     629
     630                        CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
     631
     632                        // detach fields from wrapper node so that it can be deleted without deleting too much
     633                        impCpCtorExpr->callExpr = nullptr;
     634                        std::swap( impCpCtorExpr->env, appExpr->env );
     635                        assert( impCpCtorExpr->env == nullptr );
     636                        delete impCpCtorExpr;
     637
     638                        if ( returnDecl ) {
     639                                Expression * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), appExpr );
    539640                                if ( ! dynamic_cast< ReferenceType * >( result ) ) {
    540641                                        // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
    541                                         destructRet( ret, impCpCtorExpr );
    542                                 }
     642                                        destructRet( returnDecl, impCpCtorExpr, assign );
     643                                } else {
     644                                        assign = new CommaExpr( assign, new VariableExpr( returnDecl ) );
     645                                }
     646                                // move env from appExpr to retExpr
     647                                std::swap( assign->env, appExpr->env );
     648                                return assign;
     649                        } else {
     650                                return appExpr;
     651                        } // if
     652                }
     653
     654                void ResolveCopyCtors::premutate( StmtExpr * stmtExpr ) {
     655                        // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
     656                        // since temporaries can be shared across sub-expressions, e.g.
     657                        //   [A, A] f();
     658                        //   g([A] x, [A] y);
     659                        //   g(f());
     660                        // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
     661                        // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
     662                        // to the outer context, rather than inside of the statement expression.
     663                        visit_children = false;
     664
     665                        assert( env );
     666
     667                        // visit all statements
     668                        std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
     669                        for ( Statement *& stmt : stmts ) {
     670                                stmt = stmt->acceptMutator( *visitor );
    543671                        } // for
    544                         CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
    545                 }
    546 
    547                 void ResolveCopyCtors::postvisit( StmtExpr * stmtExpr ) {
    548                         assert( env );
    549                         assert( stmtExpr->get_result() );
    550                         Type * result = stmtExpr->get_result();
     672
     673                        assert( stmtExpr->result );
     674                        Type * result = stmtExpr->result;
    551675                        if ( ! result->isVoid() ) {
    552676                                static UniqueName retNamer("_tmp_stmtexpr_ret");
     
    562686                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    563687                                ret->type->set_const( false );
    564                                 stmtExpr->returnDecls.push_front( ret );
     688                                stmtsToAddBefore.push_back( new DeclStmt( ret ) );
    565689
    566690                                // must have a non-empty body, otherwise it wouldn't have a result
    567691                                CompoundStmt * body = stmtExpr->statements;
    568                                 assert( ! body->get_kids().empty() );
     692                                assert( ! body->kids.empty() );
    569693                                // must be an ExprStmt, otherwise it wouldn't have a result
    570                                 ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->get_kids().back() );
    571                                 last->expr = makeCtorDtor( "?{}", ret, last->get_expr() );
    572 
    573                                 stmtExpr->dtors.push_front( makeCtorDtor( "^?{}", ret ) );
     694                                ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->kids.back() );
     695                                last->expr = makeCtorDtor( "?{}", ret, last->expr );
     696
     697                                // add destructors after current statement
     698                                stmtsToAddAfter.push_back( new ExprStmt( makeCtorDtor( "^?{}", ret ) ) );
     699
     700                                // must have a non-empty body, otherwise it wouldn't have a result
     701                                assert( ! stmts.empty() );
     702
     703                                // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
     704                                stmts.push_back( new ExprStmt( new VariableExpr( ret ) ) );
    574705                        } // if
    575                 }
    576 
    577                 void ResolveCopyCtors::previsit( UniqueExpr * unqExpr ) {
    578                         unqCount[ unqExpr->get_id() ]++;  // count the number of unique expressions for each ID
    579                         if ( vars.count( unqExpr->get_id() ) ) {
    580                                 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
    581                                 visit_children = false;
    582                         }
     706
     707                        assert( stmtExpr->returnDecls.empty() );
     708                        assert( stmtExpr->dtors.empty() );
    583709                }
    584710
     
    597723                }
    598724
    599                 void ResolveCopyCtors::postvisit( UniqueExpr * unqExpr ) {
    600                         if ( vars.count( unqExpr->get_id() ) ) {
    601                                 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
    602                                 return;
    603                         }
    604 
    605                         // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
    606                         assert( unqExpr->get_result() );
    607                         if ( ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast<ImplicitCopyCtorExpr*>( unqExpr->get_expr() ) ) {
    608                                 // note the variable used as the result from the call
    609                                 assert( impCpCtorExpr->get_result() && impCpCtorExpr->get_returnDecls().size() == 1 );
    610                                 unqExpr->set_var( new VariableExpr( impCpCtorExpr->get_returnDecls().front() ) );
     725                void ResolveCopyCtors::premutate( UniqueExpr * unqExpr ) {
     726                        visit_children = false;
     727                        // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     728                        static std::unordered_map< int, UniqueExpr * > unqMap;
     729                        if ( ! unqMap.count( unqExpr->get_id() ) ) {
     730                                // resolve expr and find its
     731
     732                                ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( unqExpr->expr );
     733                                // PassVisitor<ResolveCopyCtors> fixer;
     734                                unqExpr->expr = unqExpr->expr->acceptMutator( *visitor );
     735
     736                                // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     737                                assert( unqExpr->result );
     738                                if ( impCpCtorExpr ) {
     739                                        CommaExpr * comma = strict_dynamic_cast< CommaExpr * >( unqExpr->expr );
     740                                        VariableExpr * var = strict_dynamic_cast<VariableExpr *>( comma->arg2 );
     741                                        // note the variable used as the result from the call
     742                                        unqExpr->var = var->clone();
     743                                } else {
     744                                        // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
     745                                        unqExpr->object = ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->result->clone(), makeInit( unqExpr->result ) );
     746                                        unqExpr->var = new VariableExpr( unqExpr->object );
     747                                }
     748
     749                                // stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
     750                                // stmtsToAddAfter.splice( stmtsToAddAfter.end(), fixer.pass.stmtsToAddAfter );
     751                                unqMap[unqExpr->get_id()] = unqExpr;
    611752                        } else {
    612                                 // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
    613                                 unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), makeInit( unqExpr->get_result() ) ) );
    614                                 unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) );
    615                         }
    616                         vars.insert( unqExpr->get_id() );
    617                 }
    618 
    619                 Expression * FixCopyCtors::postmutate( ImplicitCopyCtorExpr * impCpCtorExpr ) {
    620                         CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; )
    621 
    622                         std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls();
    623                         std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls();
    624                         std::list< Expression * > & dtors = impCpCtorExpr->get_dtors();
    625 
    626                         // add all temporary declarations and their constructors
    627                         for ( ObjectDecl * obj : tempDecls ) {
    628                                 stmtsToAddBefore.push_back( new DeclStmt( obj ) );
    629                         } // for
    630                         for ( ObjectDecl * obj : returnDecls ) {
    631                                 stmtsToAddBefore.push_back( new DeclStmt( obj ) );
    632                         } // for
    633 
    634                         // add destructors after current statement
    635                         for ( Expression * dtor : dtors ) {
    636                                 // take relevant bindings from environment
    637                                 assert( ! dtor->env );
    638                                 dtor->env =  maybeClone( env );
    639                                 stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
    640                         } // for
    641 
    642                         ObjectDecl * returnDecl = returnDecls.empty() ? nullptr : returnDecls.front();
    643                         Expression * callExpr = impCpCtorExpr->get_callExpr();
    644 
    645                         CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
    646 
    647                         // detach fields from wrapper node so that it can be deleted without deleting too much
    648                         dtors.clear();
    649                         tempDecls.clear();
    650                         returnDecls.clear();
    651                         impCpCtorExpr->set_callExpr( nullptr );
    652                         std::swap( impCpCtorExpr->env, callExpr->env );
    653                         assert( impCpCtorExpr->env == nullptr );
    654                         delete impCpCtorExpr;
    655 
    656                         if ( returnDecl ) {
    657                                 ApplicationExpr * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), callExpr );
    658                                 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) );
    659                                 // move env from callExpr to retExpr
    660                                 std::swap( retExpr->env, callExpr->env );
    661                                 return retExpr;
    662                         } else {
    663                                 return callExpr;
    664                         } // if
    665                 }
    666 
    667                 void FixCopyCtors::premutate( StmtExpr * stmtExpr ) {
    668                         // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
    669                         // since temporaries can be shared across sub-expressions, e.g.
    670                         //   [A, A] f();
    671                         //   g([A] x, [A] y);
    672                         //   g(f());
    673                         // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
    674                         // Explicitly mutating children instead of mutating the inner compound statment forces the temporaries to be added
    675                         // to the outer context, rather than inside of the statement expression.
    676                         visit_children = false;
    677                         std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
    678                         for ( Statement *& stmt : stmts ) {
    679                                 stmt = stmt->acceptMutator( *visitor );
    680                         } // for
    681                         assert( stmtExpr->result );
    682                         Type * result = stmtExpr->result;
    683                         if ( ! result->isVoid() ) {
    684                                 for ( ObjectDecl * obj : stmtExpr->returnDecls ) {
    685                                         stmtsToAddBefore.push_back( new DeclStmt( obj ) );
    686                                 } // for
    687                                 // add destructors after current statement
    688                                 for ( Expression * dtor : stmtExpr->dtors ) {
    689                                         stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
    690                                 } // for
    691                                 // must have a non-empty body, otherwise it wouldn't have a result
    692                                 assert( ! stmts.empty() );
    693                                 assertf( ! stmtExpr->returnDecls.empty() || stmtExpr->dtors.empty(), "StmtExpr returns non-void, but no return decls: %s", toString( stmtExpr ).c_str() );
    694                                 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    695                                 if ( ! stmtExpr->returnDecls.empty() ) {
    696                                         stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->returnDecls.front() ) ) );
    697                                 }
    698                                 stmtExpr->returnDecls.clear();
    699                                 stmtExpr->dtors.clear();
    700                         }
    701                         assert( stmtExpr->returnDecls.empty() );
    702                         assert( stmtExpr->dtors.empty() );
    703                 }
    704 
    705                 void FixCopyCtors::premutate( UniqueExpr * unqExpr ) {
    706                         visit_children = false;
    707                         unqCount[ unqExpr->get_id() ]--;
    708                         static std::unordered_map< int, std::list< Statement * > > dtors;
    709                         static std::unordered_map< int, UniqueExpr * > unqMap;
    710                         // has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes
    711                         if ( unqMap.count( unqExpr->get_id() ) ) {
    712753                                // take data from other UniqueExpr to ensure consistency
    713754                                delete unqExpr->get_expr();
    714                                 unqExpr->set_expr( unqMap[unqExpr->get_id()]->get_expr()->clone() );
    715                                 delete unqExpr->get_result();
    716                                 unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
    717                                 if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
    718                                         stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
    719                                 }
    720                                 return;
    721                         }
    722                         PassVisitor<FixCopyCtors> fixer( unqCount );
    723                         unqExpr->set_expr( unqExpr->get_expr()->acceptMutator( fixer ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
    724                         stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
    725                         unqMap[unqExpr->get_id()] = unqExpr;
    726                         if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
    727                                 stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
    728                         } else { // remember dtors for last instance of unique expr
    729                                 dtors[ unqExpr->get_id() ] = fixer.pass.stmtsToAddAfter;
    730                         }
    731                         return;
     755                                unqExpr->expr = unqMap[unqExpr->get_id()]->expr->clone();
     756                                delete unqExpr->result;
     757                                unqExpr->result = maybeClone( unqExpr->expr->result );
     758                        }
    732759                }
    733760
     
    844871                                                        ctorInit->ctor = nullptr;
    845872                                                }
     873
     874                                                Statement * dtor = ctorInit->dtor;
     875                                                if ( dtor ) {
     876                                                        ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
     877                                                        Statement * dtorStmt = implicit->callStmt;
     878
     879                                                        // don't need to call intrinsic dtor, because it does nothing, but
     880                                                        // non-intrinsic dtors must be called
     881                                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     882                                                                // set dtor location to the object's location for error messages
     883                                                                DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     884                                                                objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
     885                                                                ctorInit->dtor = nullptr;
     886                                                        } // if
     887                                                }
    846888                                        } // if
    847889                                } else if ( Initializer * init = ctorInit->init ) {
     
    886928
    887929
    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 
    920930                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    921931                        // each function needs to have its own set of labels
     
    930940                }
    931941
    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 
    957942                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    958943                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    982967                        if ( ! diff.empty() ) {
    983968                                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 ) );
    1002969                        } // if
    1003970                }
     
    11161083                                                        callStmt->acceptMutator( *visitor );
    11171084                                                        if ( isCtor ) {
    1118                                                                 function->get_statements()->push_front( callStmt );
    1119                                                         } else {
     1085                                                                function->statements->push_front( callStmt );
     1086                                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
    11201087                                                                // destructor statements should be added at the end
    1121                                                                 function->get_statements()->push_back( callStmt );
     1088                                                                // function->get_statements()->push_back( callStmt );
     1089
     1090                                                                // Optimization: do not need to call intrinsic destructors on members
     1091                                                                if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;;
     1092
     1093                                                                // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
     1094                                                                std::list< Statement * > stmtsToAdd;
     1095
     1096                                                                static UniqueName memberDtorNamer = { "__memberDtor" };
     1097                                                                assertf( Validate::dtorStruct, "builtin __Destructor not found." );
     1098                                                                assertf( Validate::dtorStructDestroy, "builtin __destroy_Destructor not found." );
     1099
     1100                                                                Expression * thisExpr = new CastExpr( new AddressExpr( new VariableExpr( thisParam ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
     1101                                                                Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
     1102
     1103                                                                // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     1104                                                                FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
     1105                                                                dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
     1106                                                                Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
     1107
     1108                                                                ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), Validate::dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( new CastExpr( dtorExpr, dtorType ) ) } ) );
     1109                                                                function->statements->push_front( new DeclStmt( destructor ) );
     1110                                                                destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
     1111
     1112                                                                function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
    11221113                                                        }
    11231114                                                } catch ( SemanticErrorException & error ) {
Note: See TracChangeset for help on using the changeset viewer.