Ignore:
Timestamp:
Oct 29, 2019, 4:01:24 PM (6 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:
773db65, 9421f3d8
Parents:
7951100 (diff), 8364209 (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 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r7951100 rb067d9b  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 21 17:35:05 2017
    13 // Update Count     : 74
     12// Last Modified On : Wed Feb 13 18:15:56 2019
     13// Update Count     : 76
    1414//
    1515#include "FixInit.h"
     
    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 );
    7272                };
    7373
    74                 struct InsertImplicitCalls : public WithTypeSubstitution {
     74                struct StmtExprResult {
     75                        static void link( std::list< Declaration * > & translationUnit );
     76
     77                        void previsit( StmtExpr * stmtExpr );
     78                };
     79
     80                struct InsertImplicitCalls : public WithConstTypeSubstitution {
    7581                        /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
    7682                        /// function calls need their parameters to be copy constructed
     
    8086                };
    8187
    82                 struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
     88                struct ResolveCopyCtors final : public WithStmtsToAdd, public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution, public WithVisitorRef<ResolveCopyCtors> {
    8389                        /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
    8490                        /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    8591                        /// 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 );
     92                        static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
     93
     94                        Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
     95                        void premutate( StmtExpr * stmtExpr );
     96                        void premutate( UniqueExpr * unqExpr );
    9497
    9598                        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
     
    98101                        bool skipCopyConstruct( Type * type );
    99102                        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;
     103                        void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr, Expression *& arg );
    104104                };
    105105
     
    162162                        using Parent::previsit;
    163163
    164                         void previsit( ObjectDecl * objDecl );
    165164                        void previsit( FunctionDecl * funcDecl );
    166165
    167                         void previsit( CompoundStmt * compoundStmt );
    168                         void postvisit( CompoundStmt * compoundStmt );
    169                         void previsit( ReturnStmt * returnStmt );
    170166                        void previsit( BranchStmt * stmt );
    171167                private:
     
    185181
    186182                        std::list< Declaration * > staticDtorDecls;
    187                 };
    188 
    189                 class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithTypeSubstitution {
    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;
    201183                };
    202184
     
    236218                        Expression * postmutate( ConstructorExpr * ctorExpr );
    237219                };
     220
     221                struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
     222                        /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
     223                        static void split( std::list< Declaration * > &translationUnit );
     224
     225                        Statement * postmutate( ExprStmt * stmt );
     226                        void premutate( TupleAssignExpr * expr );
     227                };
    238228        } // namespace
    239229
    240         void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) {
     230        void fix( std::list< Declaration * > & translationUnit, bool inLibrary ) {
    241231                PassVisitor<SelfAssignChecker> checker;
    242232                acceptAll( translationUnit, checker );
    243233
     234                // fixes StmtExpr to properly link to their resulting expression
     235                StmtExprResult::link( translationUnit );
     236
    244237                // fixes ConstructorInit for global variables. should happen before fixInitializers.
    245                 InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
    246 
    247                 UnqCount unqCount;
     238                InitTweak::fixGlobalInit( translationUnit, inLibrary );
     239
     240                // must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
     241                SplitExpressions::split( translationUnit );
    248242
    249243                InsertImplicitCalls::insert( translationUnit );
    250                 ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
     244
     245                // Needs to happen before ResolveCopyCtors, because argument/return temporaries should not be considered in
     246                // error checking branch statements
    251247                InsertDtors::insert( translationUnit );
     248
     249                ResolveCopyCtors::resolveImplicitCalls( translationUnit );
    252250                FixInit::fixInitializers( translationUnit );
    253 
    254                 // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
    255                 FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
    256 
    257251                GenStructMemberCalls::generate( translationUnit );
    258252
    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.
     253                // Needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
     254                // don't have the correct form, and a member can be constructed more than once.
    266255                FixCtorExprs::fix( translationUnit );
    267256        }
    268257
    269258        namespace {
     259                /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk
     260                /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration
     261                DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * input, std::list< Statement * > & stmtsToAdd ) {
     262                        // unwrap implicit statement wrapper
     263                        Statement * dtor = input;
     264                        assert( dtor );
     265                        std::list< Expression * > matches;
     266                        collectCtorDtorCalls( dtor, matches );
     267
     268                        if ( dynamic_cast< ExprStmt * >( dtor ) ) {
     269                                // only one destructor call in the expression
     270                                if ( matches.size() == 1 ) {
     271                                        DeclarationWithType * func = getFunction( matches.front() );
     272                                        assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
     273
     274                                        // cleanup argument must be a function, not an object (including function pointer)
     275                                        if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
     276                                                if ( dtorFunc->type->forall.empty() ) {
     277                                                        // simple case where the destructor is a monomorphic function call - can simply
     278                                                        // use that function as the cleanup function.
     279                                                        delete dtor;
     280                                                        return func;
     281                                                }
     282                                        }
     283                                }
     284                        }
     285
     286                        // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
     287                        // wraps the more complicated code.
     288                        static UniqueName dtorNamer( "__cleanup_dtor" );
     289                        std::string name = dtorNamer.newName();
     290                        FunctionDecl * dtorFunc = FunctionDecl::newFunction( name, SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt() );
     291                        stmtsToAdd.push_back( new DeclStmt( dtorFunc ) );
     292
     293                        // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
     294                        ObjectDecl * thisParam = getParamThis( dtorFunc->type );
     295                        Expression * replacement = new VariableExpr( thisParam );
     296
     297                        Type * base = replacement->result->stripReferences();
     298                        if ( dynamic_cast< ArrayType * >( base ) || dynamic_cast< TupleType * > ( base ) ) {
     299                                // need to cast away reference for array types, since the destructor is generated without the reference type,
     300                                // and for tuple types since tuple indexing does not work directly on a reference
     301                                replacement = new CastExpr( replacement, base->clone() );
     302                        }
     303                        DeclReplacer::replace( dtor, { std::make_pair( objDecl, replacement ) } );
     304                        dtorFunc->statements->push_back( strict_dynamic_cast<Statement *>( dtor ) );
     305
     306                        return dtorFunc;
     307                }
     308
     309                void StmtExprResult::link( std::list< Declaration * > & translationUnit ) {
     310                        PassVisitor<StmtExprResult> linker;
     311                        acceptAll( translationUnit, linker );
     312                }
     313
     314                void SplitExpressions::split( std::list< Declaration * > & translationUnit ) {
     315                        PassVisitor<SplitExpressions> splitter;
     316                        mutateAll( translationUnit, splitter );
     317                }
     318
    270319                void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
    271320                        PassVisitor<InsertImplicitCalls> inserter;
     
    273322                }
    274323
    275                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    276                         PassVisitor<ResolveCopyCtors> resolver( unqCount );
    277                         acceptAll( translationUnit, resolver );
     324                void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
     325                        PassVisitor<ResolveCopyCtors> resolver;
     326                        mutateAll( translationUnit, resolver );
    278327                }
    279328
     
    303352                }
    304353
    305                 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    306                         PassVisitor<FixCopyCtors> fixer( unqCount );
    307                         mutateAll( translationUnit, fixer );
    308                 }
    309 
    310354                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
    311355                        PassVisitor<GenStructMemberCalls> warner;
     
    318362                }
    319363
    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;
     364                void StmtExprResult::previsit( StmtExpr * stmtExpr ) {
     365                        // we might loose the result expression here so add a pointer to trace back
     366                        assert( stmtExpr->result );
     367                        Type * result = stmtExpr->result;
     368                        if ( ! result->isVoid() ) {
     369                                CompoundStmt * body = stmtExpr->statements;
     370                                assert( ! body->kids.empty() );
     371                                stmtExpr->resultExpr = strict_dynamic_cast< ExprStmt * >( body->kids.back() );
     372                        }
     373                }
     374
     375                Statement * SplitExpressions::postmutate( ExprStmt * stmt ) {
     376                        // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
     377                        // in the correct places
     378                        CompoundStmt * ret = new CompoundStmt( { stmt } );
     379                        return ret;
     380                }
     381
     382                void SplitExpressions::premutate( TupleAssignExpr * ) {
     383                        // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
     384                        visit_children = false;
     385                }
     386
     387                // Relatively simple structural comparison for expressions, needed to determine
     388                // if two expressions are "the same" (used to determine if self assignment occurs)
     389                struct StructuralChecker {
     390                        Expression * stripCasts( Expression * expr ) {
     391                                // this might be too permissive. It's possible that only particular casts are relevant.
     392                                while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
     393                                        expr = cast->arg;
     394                                }
     395                                return expr;
     396                        }
     397
     398                        void previsit( Expression * ) {
     399                                // anything else does not qualify
     400                                isSimilar = false;
     401                        }
     402
     403                        template<typename T>
     404                        T * cast( Expression * node ) {
     405                                // all expressions need to ignore casts, so this bit has been factored out
     406                                return dynamic_cast< T * >( stripCasts( node ) );
     407                        }
     408
     409                        // ignore casts
     410                        void previsit( CastExpr * ) {}
     411
     412                        void previsit( MemberExpr * memExpr ) {
     413                                if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
     414                                        if ( otherMember->member == memExpr->member ) {
     415                                                other = otherMember->aggregate;
    368416                                                return;
    369417                                        }
    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                         }
     418                                }
     419                                isSimilar = false;
     420                        }
     421
     422                        void previsit( VariableExpr * varExpr ) {
     423                                if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
     424                                        if ( otherVar->var == varExpr->var ) {
     425                                                return;
     426                                        }
     427                                }
     428                                isSimilar = false;
     429                        }
     430
     431                        void previsit( AddressExpr * ) {
     432                                if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
     433                                        other = addrExpr->arg;
     434                                        return;
     435                                }
     436                                isSimilar = false;
     437                        }
     438
     439                        Expression * other = nullptr;
     440                        bool isSimilar = true;
     441                };
     442
     443                bool structurallySimilar( Expression * e1, Expression * e2 ) {
     444                        PassVisitor<StructuralChecker> checker;
     445                        checker.pass.other = e2;
     446                        e1->accept( checker );
     447                        return checker.pass.isSimilar;
    383448                }
    384449
     
    457522                        if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
    458523                                // fix newly generated StmtExpr
    459                                 postvisit( assign->stmtExpr );
     524                                premutate( assign->stmtExpr );
    460525                        }
    461526                        return resolved;
     
    489554                                        // so that the object isn't changed inside of the polymorphic function
    490555                                        if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
     556                                        // xxx - leaking tmp
    491557                                }
    492558                        }
     
    496562
    497563                        // 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 ) {
     564                        stmtsToAddBefore.push_back( new DeclStmt( tmp ) );
     565                        arg = cpCtor;
     566                        destructRet( tmp, impCpCtorExpr, arg );
     567
     568                        // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
     569                }
     570
     571                void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * /*impCpCtorExpr*/, Expression *& arg ) {
     572                        // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
     573                        // check for existing cleanup attribute before adding another(?)
     574                        // need to add __Destructor for _tmp_cp variables as well
     575
     576                        assertf( Validate::dtorStruct && Validate::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." );
     577                        assertf( Validate::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
     578
     579                        // generate a __Destructor for ret that calls the destructor
     580                        Expression * dtor = makeCtorDtor( "^?{}", ret );
     581
     582                        // if the chosen destructor is intrinsic, elide the generated dtor handler
     583                        if ( arg && isIntrinsicCallExpr( dtor ) ) {
     584                                arg = new CommaExpr( arg, new VariableExpr( ret ) );
     585                                return;
     586                        }
     587
     588                        if ( ! dtor->env ) dtor->env = maybeClone( env );
     589                        DeclarationWithType * dtorFunc = getDtorFunc( ret, new ExprStmt( dtor ), stmtsToAddBefore );
     590
     591                        StructInstType * dtorStructType = new StructInstType( Type::Qualifiers(), Validate::dtorStruct );
     592                        dtorStructType->parameters.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
     593
     594                        // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     595                        FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
     596                        dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
     597                        Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
     598
     599                        static UniqueName namer( "_ret_dtor" );
     600                        ObjectDecl * retDtor = ObjectDecl::newObject( namer.newName(), dtorStructType, new ListInit( { new SingleInit( new ConstantExpr( Constant::null() ) ), new SingleInit( new CastExpr( new VariableExpr( dtorFunc ), dtorType ) ) } ) );
     601                        retDtor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
     602                        stmtsToAddBefore.push_back( new DeclStmt( retDtor ) );
     603
     604                        if ( arg ) {
     605                                Expression * member = new MemberExpr( strict_dynamic_cast<DeclarationWithType *>( Validate::dtorStruct->members.front() ), new VariableExpr( retDtor ) );
     606                                Expression * object = new CastExpr( new AddressExpr( new VariableExpr( ret ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
     607                                Expression * assign = createBitwiseAssignment( member, object );
     608                                arg = new CommaExpr( new CommaExpr( arg, assign ), new VariableExpr( ret ) );
     609                        }
     610
     611                        // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
     612                }
     613
     614                Expression * ResolveCopyCtors::postmutate( ImplicitCopyCtorExpr *impCpCtorExpr ) {
    508615                        CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
    509616
    510617                        ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
     618                        ObjectDecl * returnDecl = nullptr;
    511619
    512620                        // take each argument and attempt to copy construct it.
     
    517625                        for ( Expression * & arg : appExpr->args ) {
    518626                                Type * formal = nullptr;
    519                                 if ( iter != params.end() ) {
     627                                if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
    520628                                        DeclarationWithType * param = *iter++;
    521629                                        formal = param->get_type();
     
    535643                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    536644                                ret->type->set_const( false );
    537                                 impCpCtorExpr->returnDecls.push_back( ret );
     645                                returnDecl = ret;
     646                                stmtsToAddBefore.push_back( new DeclStmt( ret ) );
    538647                                CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
     648                        } // for
     649                        CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
     650                        // ------------------------------------------------------
     651
     652                        CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
     653
     654                        // detach fields from wrapper node so that it can be deleted without deleting too much
     655                        impCpCtorExpr->callExpr = nullptr;
     656                        std::swap( impCpCtorExpr->env, appExpr->env );
     657                        assert( impCpCtorExpr->env == nullptr );
     658                        delete impCpCtorExpr;
     659
     660                        if ( returnDecl ) {
     661                                Expression * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), appExpr );
    539662                                if ( ! dynamic_cast< ReferenceType * >( result ) ) {
    540663                                        // 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                                 }
     664                                        destructRet( returnDecl, impCpCtorExpr, assign );
     665                                } else {
     666                                        assign = new CommaExpr( assign, new VariableExpr( returnDecl ) );
     667                                }
     668                                // move env from appExpr to retExpr
     669                                std::swap( assign->env, appExpr->env );
     670                                return assign;
     671                        } else {
     672                                return appExpr;
     673                        } // if
     674                }
     675
     676                void ResolveCopyCtors::premutate( StmtExpr * stmtExpr ) {
     677                        // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
     678                        // since temporaries can be shared across sub-expressions, e.g.
     679                        //   [A, A] f();       // decl
     680                        //   g([A] x, [A] y);  // decl
     681                        //   g(f());           // call
     682                        // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
     683                        // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
     684                        // to the outer context, rather than inside of the statement expression.
     685                        visit_children = false;
     686
     687                        assert( env );
     688
     689                        indexer.enterScope();
     690                        // visit all statements
     691                        std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
     692                        for ( Statement *& stmt : stmts ) {
     693                                stmt = stmt->acceptMutator( *visitor );
    543694                        } // 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();
     695                        indexer.leaveScope();
     696
     697                        assert( stmtExpr->result );
     698                        Type * result = stmtExpr->result;
    551699                        if ( ! result->isVoid() ) {
    552700                                static UniqueName retNamer("_tmp_stmtexpr_ret");
     
    562710                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    563711                                ret->type->set_const( false );
    564                                 stmtExpr->returnDecls.push_front( ret );
     712                                stmtsToAddBefore.push_back( new DeclStmt( ret ) );
     713
     714                                assertf(
     715                                        stmtExpr->resultExpr,
     716                                        "Statement-Expression should have a resulting expression at %s:%d",
     717                                        stmtExpr->location.filename.c_str(),
     718                                        stmtExpr->location.first_line
     719                                );
     720
     721                                ExprStmt * last = stmtExpr->resultExpr;
     722                                try {
     723                                        last->expr = makeCtorDtor( "?{}", ret, last->expr );
     724                                } catch(...) {
     725                                        std::cerr << "*CFA internal error: ";
     726                                        std::cerr << "can't resolve implicit constructor";
     727                                        std::cerr << " at " << stmtExpr->location.filename;
     728                                        std::cerr << ":" << stmtExpr->location.first_line << std::endl;
     729
     730                                        abort();
     731                                }
     732
     733                                // add destructors after current statement
     734                                stmtsToAddAfter.push_back( new ExprStmt( makeCtorDtor( "^?{}", ret ) ) );
    565735
    566736                                // must have a non-empty body, otherwise it wouldn't have a result
    567                                 CompoundStmt * body = stmtExpr->statements;
    568                                 assert( ! body->get_kids().empty() );
    569                                 // 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 ) );
     737                                assert( ! stmts.empty() );
     738
     739                                // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
     740                                stmts.push_back( new ExprStmt( new VariableExpr( ret ) ) );
    574741                        } // 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                         }
     742
     743                        assert( stmtExpr->returnDecls.empty() );
     744                        assert( stmtExpr->dtors.empty() );
    583745                }
    584746
     
    597759                }
    598760
    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() ) );
     761                void ResolveCopyCtors::premutate( UniqueExpr * unqExpr ) {
     762                        visit_children = false;
     763                        // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     764                        static std::unordered_map< int, UniqueExpr * > unqMap;
     765                        if ( ! unqMap.count( unqExpr->get_id() ) ) {
     766                                // resolve expr and find its
     767
     768                                ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( unqExpr->expr );
     769                                // PassVisitor<ResolveCopyCtors> fixer;
     770                                unqExpr->expr = unqExpr->expr->acceptMutator( *visitor );
     771
     772                                // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     773                                assert( unqExpr->result );
     774                                if ( impCpCtorExpr ) {
     775                                        CommaExpr * comma = strict_dynamic_cast< CommaExpr * >( unqExpr->expr );
     776                                        VariableExpr * var = strict_dynamic_cast<VariableExpr *>( comma->arg2 );
     777                                        // note the variable used as the result from the call
     778                                        unqExpr->var = var->clone();
     779                                } else {
     780                                        // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
     781                                        unqExpr->object = ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->result->clone(), makeInit( unqExpr->result ) );
     782                                        unqExpr->var = new VariableExpr( unqExpr->object );
     783                                }
     784
     785                                // stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
     786                                // stmtsToAddAfter.splice( stmtsToAddAfter.end(), fixer.pass.stmtsToAddAfter );
     787                                unqMap[unqExpr->get_id()] = unqExpr;
    611788                        } 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() ) ) {
    712789                                // take data from other UniqueExpr to ensure consistency
    713790                                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;
     791                                unqExpr->expr = unqMap[unqExpr->get_id()]->expr->clone();
     792                                delete unqExpr->result;
     793                                unqExpr->result = maybeClone( unqExpr->expr->result );
     794                        }
    732795                }
    733796
     
    844907                                                        ctorInit->ctor = nullptr;
    845908                                                }
     909
     910                                                Statement * dtor = ctorInit->dtor;
     911                                                if ( dtor ) {
     912                                                        ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
     913                                                        Statement * dtorStmt = implicit->callStmt;
     914
     915                                                        // don't need to call intrinsic dtor, because it does nothing, but
     916                                                        // non-intrinsic dtors must be called
     917                                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     918                                                                // set dtor location to the object's location for error messages
     919                                                                DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     920                                                                objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
     921                                                                ctorInit->dtor = nullptr;
     922                                                        } // if
     923                                                }
    846924                                        } // if
    847925                                } else if ( Initializer * init = ctorInit->init ) {
     
    886964
    887965
    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 
    920966                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    921967                        // each function needs to have its own set of labels
     
    930976                }
    931977
    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 
    957978                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    958979                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    973994                                std::cerr << "S_L = " << printSet( lvars ) << std::endl;
    974995                        )
     996
     997
     998                        // std::set_difference requires that the inputs be sorted.
     999                        lvars.sort();
     1000                        curVars.sort();
    9751001
    9761002                        ObjectSet diff;
     
    9821008                        if ( ! diff.empty() ) {
    9831009                                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 ) );
    10021010                        } // if
    10031011                }
     
    11031111                                                arg2 = new MemberExpr( field, new VariableExpr( params.back() ) );
    11041112                                        }
    1105                                         InitExpander srcParam( arg2 );
     1113                                        InitExpander_old srcParam( arg2 );
    11061114                                        // cast away reference type and construct field.
    11071115                                        Expression * thisExpr = new CastExpr( new VariableExpr( thisParam ), thisParam->get_type()->stripReferences()->clone() );
     
    11161124                                                        callStmt->acceptMutator( *visitor );
    11171125                                                        if ( isCtor ) {
    1118                                                                 function->get_statements()->push_front( callStmt );
    1119                                                         } else {
     1126                                                                function->statements->push_front( callStmt );
     1127                                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
    11201128                                                                // destructor statements should be added at the end
    1121                                                                 function->get_statements()->push_back( callStmt );
     1129                                                                // function->get_statements()->push_back( callStmt );
     1130
     1131                                                                // Optimization: do not need to call intrinsic destructors on members
     1132                                                                if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;;
     1133
     1134                                                                // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
     1135                                                                std::list< Statement * > stmtsToAdd;
     1136
     1137                                                                static UniqueName memberDtorNamer = { "__memberDtor" };
     1138                                                                assertf( Validate::dtorStruct, "builtin __Destructor not found." );
     1139                                                                assertf( Validate::dtorStructDestroy, "builtin __destroy_Destructor not found." );
     1140
     1141                                                                Expression * thisExpr = new CastExpr( new AddressExpr( new VariableExpr( thisParam ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
     1142                                                                Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
     1143
     1144                                                                // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     1145                                                                FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
     1146                                                                dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
     1147                                                                Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
     1148
     1149                                                                ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), Validate::dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( new CastExpr( dtorExpr, dtorType ) ) } ) );
     1150                                                                function->statements->push_front( new DeclStmt( destructor ) );
     1151                                                                destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
     1152
     1153                                                                function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
    11221154                                                        }
    11231155                                                } catch ( SemanticErrorException & error ) {
     
    11631195
    11641196                        std::string fname = getFunctionName( appExpr );
    1165                         if ( fname == function->get_name() ) {
     1197                        if ( fname == function->name ) {
    11661198                                // call to same kind of function
    1167                                 Expression * firstParam = appExpr->get_args().front();
     1199                                Expression * firstParam = appExpr->args.front();
    11681200
    11691201                                if ( isThisExpression( firstParam, thisParam ) ) {
     
    11741206                                        // if first parameter is a member expression on the this parameter,
    11751207                                        // then remove the member from unhandled set.
    1176                                         if ( isThisExpression( memberExpr->get_aggregate(), thisParam ) ) {
    1177                                                 unhandled.erase( memberExpr->get_member() );
     1208                                        if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
     1209                                                unhandled.erase( memberExpr->member );
    11781210                                        }
    11791211                                }
Note: See TracChangeset for help on using the changeset viewer.