Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cpp

    r61e362f r5bf685f  
    4949        if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
    5050                return inst->base->params;
    51         } else if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
     51        }
     52        if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
    5253                return inst->base->params;
    5354        }
     
    244245const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) {
    245246        const CodeLocation loc = input->location;
     247        // unwrap implicit statement wrapper
     248        // Statement * dtor = input;
    246249        assert( input );
     250        // std::list< const ast::Expr * > matches;
    247251        auto matches = collectCtorDtorCalls( input );
    248252
    249         // The simple case requires a direct call and only one destructor call.
    250         if ( dynamic_cast< const ast::ExprStmt * >( input ) && matches.size() == 1 ) {
    251                 auto func = getFunction( matches.front() );
    252                 assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
    253 
    254                 // cleanup argument must be a function, not an object (including function pointer)
    255                 if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) {
    256                         if ( dtorFunc->type->forall.empty() ) {
    257                                 // simple case where the destructor is a monomorphic function call - can simply
    258                                 // use that function as the cleanup function.
    259                                 return func;
     253        if ( dynamic_cast< const ast::ExprStmt * >( input ) ) {
     254                // only one destructor call in the expression
     255                if ( matches.size() == 1 ) {
     256                        auto func = getFunction( matches.front() );
     257                        assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
     258
     259                        // cleanup argument must be a function, not an object (including function pointer)
     260                        if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) {
     261                                if ( dtorFunc->type->forall.empty() ) {
     262                                        // simple case where the destructor is a monomorphic function call - can simply
     263                                        // use that function as the cleanup function.
     264                                        return func;
     265                                }
    260266                        }
    261267                }
     
    295301        for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) {
    296302                try {
     303                        // maybeAccept( *i, fixer ); translationUnit should never contain null
    297304                        *i = (*i)->accept(fixer);
    298305                        translationUnit.decls.splice( i, fixer.core.staticDtorDecls );
     
    307314
    308315const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) {
     316        // we might loose the result expression here so add a pointer to trace back
    309317        assert( stmtExpr->result );
    310         if ( stmtExpr->result->isVoid() ) return stmtExpr;
    311 
    312         auto mutExpr = mutate( stmtExpr );
    313         const ast::CompoundStmt * body = mutExpr->stmts;
    314         assert( !body->kids.empty() );
    315         mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>();
    316         return mutExpr;
     318        const ast::Type * result = stmtExpr->result;
     319        if ( ! result->isVoid() ) {
     320                auto mutExpr = mutate(stmtExpr);
     321                const ast::CompoundStmt * body = mutExpr->stmts;
     322                assert( ! body->kids.empty() );
     323                mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>();
     324                return mutExpr;
     325        }
     326        return stmtExpr;
    317327}
    318328
     
    320330        // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
    321331        // in the correct places
    322         return new ast::CompoundStmt( stmt->location, { stmt } );
     332        ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } );
     333        return ret;
    323334}
    324335
     
    545556        arg = cpCtor;
    546557        return destructRet( tmp, arg );
     558
     559        // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    547560}
    548561
     
    595608        }
    596609        return nullptr;
     610        // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    597611}
    598612
     
    611625        for ( auto & arg : appExpr->args ) {
    612626                const ast::Type * formal = nullptr;
    613                 // Do not copy construct C-style variadic arguments.
    614                 if ( iter != params.end() ) {
     627                if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
     628                        // DeclarationWithType * param = *iter++;
    615629                        formal = *iter++;
    616630                }
     
    645659        // deletion of wrapper should be handled by pass template now
    646660
     661        // impCpCtorExpr->callExpr = nullptr;
    647662        assert (appExpr->env == nullptr);
    648663        appExpr->env = impCpCtorExpr->env;
     664        // std::swap( impCpCtorExpr->env, appExpr->env );
     665        // assert( impCpCtorExpr->env == nullptr );
     666        // delete impCpCtorExpr;
    649667
    650668        if ( returnDecl ) {
     
    658676                }
    659677                // move env from appExpr to retExpr
     678                // std::swap( assign->env, appExpr->env );
    660679                assign->env = appExpr->env;
    661680                // actual env is handled by common routine that replaces WithTypeSubstitution
     
    697716
    698717        assert( stmtExpr->result );
    699         if ( stmtExpr->result->isVoid() ) {
    700                 assert( stmtExpr->returnDecls.empty() );
    701                 assert( stmtExpr->dtors.empty() );
    702 
    703                 return stmtExpr;
    704         }
    705 
    706         static UniqueName retNamer("_tmp_stmtexpr_ret");
    707 
    708         auto result = env->apply( stmtExpr->result.get() ).node;
    709         if ( ! InitTweak::isConstructable( result ) ) {
    710                 return stmtExpr;
    711         }
    712         auto mutResult = result.get_and_mutate();
    713         mutResult->set_const(false);
    714 
    715         // create variable that will hold the result of the stmt expr
    716         auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr );
    717         stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
    718 
    719         assertf(
    720                 stmtExpr->resultExpr,
    721                 "Statement-Expression should have a resulting expression at %s:%d",
    722                 stmtExpr->location.filename.c_str(),
    723                 stmtExpr->location.first_line
    724         );
    725 
    726         const ast::ExprStmt * last = stmtExpr->resultExpr;
    727         // xxx - if this is non-unique, need to copy while making resultExpr ref
    728         assertf(last->unique(), "attempt to modify weakly shared statement");
    729         auto mutLast = mutate(last);
    730         // above assertion means in-place mutation is OK
    731         try {
    732                 mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr );
    733         } catch(...) {
    734                 std::cerr << "*CFA internal error: ";
    735                 std::cerr << "can't resolve implicit constructor";
    736                 std::cerr << " at " << stmtExpr->location.filename;
    737                 std::cerr << ":" << stmtExpr->location.first_line << std::endl;
    738 
    739                 abort();
    740         }
    741 
    742         // add destructors after current statement
    743         stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) );
    744 
    745         // must have a non-empty body, otherwise it wouldn't have a result
    746         assert( ! stmts.empty() );
    747 
    748         // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    749         stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) );
     718        // const ast::Type * result = stmtExpr->result;
     719        if ( ! stmtExpr->result->isVoid() ) {
     720                static UniqueName retNamer("_tmp_stmtexpr_ret");
     721
     722                // result = result->clone();
     723                auto result = env->apply( stmtExpr->result.get() ).node;
     724                if ( ! InitTweak::isConstructable( result ) ) {
     725                        // delete result;
     726                        return stmtExpr;
     727                }
     728                auto mutResult = result.get_and_mutate();
     729                mutResult->set_const(false);
     730
     731                // create variable that will hold the result of the stmt expr
     732                auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr );
     733                stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
     734
     735                assertf(
     736                        stmtExpr->resultExpr,
     737                        "Statement-Expression should have a resulting expression at %s:%d",
     738                        stmtExpr->location.filename.c_str(),
     739                        stmtExpr->location.first_line
     740                );
     741
     742                const ast::ExprStmt * last = stmtExpr->resultExpr;
     743                // xxx - if this is non-unique, need to copy while making resultExpr ref
     744                assertf(last->unique(), "attempt to modify weakly shared statement");
     745                auto mutLast = mutate(last);
     746                // above assertion means in-place mutation is OK
     747                try {
     748                        mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr );
     749                } catch(...) {
     750                        std::cerr << "*CFA internal error: ";
     751                        std::cerr << "can't resolve implicit constructor";
     752                        std::cerr << " at " << stmtExpr->location.filename;
     753                        std::cerr << ":" << stmtExpr->location.first_line << std::endl;
     754
     755                        abort();
     756                }
     757
     758                // add destructors after current statement
     759                stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) );
     760
     761                // must have a non-empty body, otherwise it wouldn't have a result
     762                assert( ! stmts.empty() );
     763
     764                // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
     765                stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) );
     766        } // if
    750767
    751768        assert( stmtExpr->returnDecls.empty() );
     
    781798        auto mutExpr = mutate(unqExpr);
    782799        if ( ! unqMap.count( unqExpr->id ) ) {
     800                // resolve expr and find its
     801
    783802                auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>();
     803                // PassVisitor<ResolveCopyCtors> fixer;
     804
    784805                mutExpr->expr = mutExpr->expr->accept( *visitor );
    785806                // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     
    799820        } else {
    800821                // take data from other UniqueExpr to ensure consistency
     822                // delete unqExpr->get_expr();
    801823                mutExpr->expr = unqMap[mutExpr->id]->expr;
     824                // delete unqExpr->result;
    802825                mutExpr->result = mutExpr->expr->result;
    803826        }
     
    809832
    810833        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit)
    811         ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>();
    812 
    813         if ( nullptr == ctorInit ) return _objDecl;
    814 
    815         auto objDecl = mutate(_objDecl);
    816 
    817         // could this be non-unique?
    818         if (objDecl != _objDecl) {
    819                 std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl;
    820         }
    821         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    822         assert( ! ctorInit->ctor || ! ctorInit->init );
    823         if ( const ast::Stmt * ctor = ctorInit->ctor ) {
    824                 if ( objDecl->storage.is_static ) {
    825                         addDataSectionAttribute(objDecl);
    826                         // originally wanted to take advantage of gcc nested functions, but
    827                         // we get memory errors with this approach. To remedy this, the static
    828                         // variable is hoisted when the destructor needs to be called.
    829                         //
    830                         // generate:
    831                         // static T __objName_static_varN;
    832                         // void __objName_dtor_atexitN() {
    833                         //   __dtor__...;
    834                         // }
    835                         // int f(...) {
    836                         //   ...
    837                         //   static bool __objName_uninitialized = true;
    838                         //   if (__objName_uninitialized) {
    839                         //     __ctor(__objName);
    840                         //     __objName_uninitialized = false;
    841                         //     atexit(__objName_dtor_atexitN);
    842                         //   }
    843                         //   ...
    844                         // }
    845 
    846                         static UniqueName dtorCallerNamer( "_dtor_atexit" );
    847 
    848                         // static bool __objName_uninitialized = true
    849                         auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool );
    850                         auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) );
    851                         auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall);
    852                         isUninitializedVar->fixUniqueId();
    853 
    854                         // __objName_uninitialized = false;
    855                         auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) );
    856                         setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) );
    857                         setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) );
    858 
    859                         // generate body of if
    860                         auto initStmts = new ast::CompoundStmt(loc);
    861                         auto & body = initStmts->kids;
    862                         body.push_back( ctor );
    863                         body.push_back( new ast::ExprStmt(loc, setTrue ) );
    864 
    865                         // put it all together
    866                         auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 );
    867                         stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) );
    868                         stmtsToAddAfter.push_back( ifStmt );
    869 
    870                         const ast::Stmt * dtor = ctorInit->dtor;
    871                         if ( dtor ) {
    872                                 // if the object has a non-trivial destructor, have to
    873                                 // hoist it and the object into the global space and
    874                                 // call the destructor function with atexit.
    875 
    876                                 // void __objName_dtor_atexitN(...) {...}
    877                                 ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C );
    878                                 dtorCaller->fixUniqueId();
    879 
    880                                 // atexit(dtor_atexit);
    881                                 auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) );
    882                                 callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) );
    883 
    884                                 body.push_back( new ast::ExprStmt(loc, callAtexit ) );
    885 
    886                                 // hoist variable and dtor caller decls to list of decls that will be added into global scope
    887                                 staticDtorDecls.push_back( objDecl );
    888                                 staticDtorDecls.push_back( dtorCaller );
    889 
    890                                 // need to rename object uniquely since it now appears
    891                                 // at global scope and there could be multiple function-scoped
    892                                 // static variables with the same name in different functions.
    893                                 // Note: it isn't sufficient to modify only the mangleName, because
    894                                 // then subsequent SymbolTable passes can choke on seeing the object's name
    895                                 // if another object has the same name and type. An unfortunate side-effect
    896                                 // of renaming the object is that subsequent NameExprs may fail to resolve,
    897                                 // but there shouldn't be any remaining past this point.
    898                                 static UniqueName staticNamer( "_static_var" );
    899                                 objDecl->name = objDecl->name + staticNamer.newName();
    900                                 objDecl->mangleName = Mangle::mangle( objDecl );
    901                                 objDecl->init = nullptr;
    902 
    903                                 // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
    904                                 // create a new object which is never used
    905                                 static UniqueName dummyNamer( "_dummy" );
    906                                 auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } );
    907                                 return dummy;
     834        if ( ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>() ) {
     835                auto objDecl = mutate(_objDecl);
     836
     837                // could this be non-unique?
     838                if (objDecl != _objDecl) {
     839                        std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl;
     840                }
     841                // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     842                assert( ! ctorInit->ctor || ! ctorInit->init );
     843                if ( const ast::Stmt * ctor = ctorInit->ctor ) {
     844                        if ( objDecl->storage.is_static ) {
     845                                addDataSectionAttribute(objDecl);
     846                                // originally wanted to take advantage of gcc nested functions, but
     847                                // we get memory errors with this approach. To remedy this, the static
     848                                // variable is hoisted when the destructor needs to be called.
     849                                //
     850                                // generate:
     851                                // static T __objName_static_varN;
     852                                // void __objName_dtor_atexitN() {
     853                                //   __dtor__...;
     854                                // }
     855                                // int f(...) {
     856                                //   ...
     857                                //   static bool __objName_uninitialized = true;
     858                                //   if (__objName_uninitialized) {
     859                                //     __ctor(__objName);
     860                                //     __objName_uninitialized = false;
     861                                //     atexit(__objName_dtor_atexitN);
     862                                //   }
     863                                //   ...
     864                                // }
     865
     866                                static UniqueName dtorCallerNamer( "_dtor_atexit" );
     867
     868                                // static bool __objName_uninitialized = true
     869                                auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool );
     870                                auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) );
     871                                auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall);
     872                                isUninitializedVar->fixUniqueId();
     873
     874                                // __objName_uninitialized = false;
     875                                auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) );
     876                                setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) );
     877                                setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) );
     878
     879                                // generate body of if
     880                                auto initStmts = new ast::CompoundStmt(loc);
     881                                auto & body = initStmts->kids;
     882                                body.push_back( ctor );
     883                                body.push_back( new ast::ExprStmt(loc, setTrue ) );
     884
     885                                // put it all together
     886                                auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 );
     887                                stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) );
     888                                stmtsToAddAfter.push_back( ifStmt );
     889
     890                                const ast::Stmt * dtor = ctorInit->dtor;
     891
     892                                // these should be automatically managed once reassigned
     893                                // objDecl->set_init( nullptr );
     894                                // ctorInit->set_ctor( nullptr );
     895                                // ctorInit->set_dtor( nullptr );
     896                                if ( dtor ) {
     897                                        // if the object has a non-trivial destructor, have to
     898                                        // hoist it and the object into the global space and
     899                                        // call the destructor function with atexit.
     900
     901                                        // Statement * dtorStmt = dtor->clone();
     902
     903                                        // void __objName_dtor_atexitN(...) {...}
     904                                        ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C );
     905                                        dtorCaller->fixUniqueId();
     906                                        // dtorCaller->stmts->push_back( dtor );
     907
     908                                        // atexit(dtor_atexit);
     909                                        auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) );
     910                                        callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) );
     911
     912                                        body.push_back( new ast::ExprStmt(loc, callAtexit ) );
     913
     914                                        // hoist variable and dtor caller decls to list of decls that will be added into global scope
     915                                        staticDtorDecls.push_back( objDecl );
     916                                        staticDtorDecls.push_back( dtorCaller );
     917
     918                                        // need to rename object uniquely since it now appears
     919                                        // at global scope and there could be multiple function-scoped
     920                                        // static variables with the same name in different functions.
     921                                        // Note: it isn't sufficient to modify only the mangleName, because
     922                                        // then subsequent SymbolTable passes can choke on seeing the object's name
     923                                        // if another object has the same name and type. An unfortunate side-effect
     924                                        // of renaming the object is that subsequent NameExprs may fail to resolve,
     925                                        // but there shouldn't be any remaining past this point.
     926                                        static UniqueName staticNamer( "_static_var" );
     927                                        objDecl->name = objDecl->name + staticNamer.newName();
     928                                        objDecl->mangleName = Mangle::mangle( objDecl );
     929                                        objDecl->init = nullptr;
     930
     931                                        // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
     932                                        // create a new object which is never used
     933                                        static UniqueName dummyNamer( "_dummy" );
     934                                        auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } );
     935                                        // delete ctorInit;
     936                                        return dummy;
     937                                } else {
     938                                        objDecl->init = nullptr;
     939                                        return objDecl;
     940                                }
    908941                        } else {
    909                                 objDecl->init = nullptr;
    910                                 return objDecl;
    911                         }
     942                                auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor );
     943                                auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>();
     944                                const ast::ApplicationExpr * ctorCall = nullptr;
     945                                if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) {
     946                                        // clean up intrinsic copy constructor calls by making them into SingleInits
     947                                        const ast::Expr * ctorArg = ctorCall->args.back();
     948                                        // ctorCall should be gone afterwards
     949                                        auto mutArg = mutate(ctorArg);
     950                                        mutArg->env = ctorCall->env;
     951                                        // std::swap( ctorArg->env, ctorCall->env );
     952                                        objDecl->init = new ast::SingleInit(loc, mutArg );
     953
     954                                        // ctorCall->args.pop_back();
     955                                } else {
     956                                        stmtsToAddAfter.push_back( ctor );
     957                                        objDecl->init = nullptr;
     958                                        // ctorInit->ctor = nullptr;
     959                                }
     960
     961                                const ast::Stmt * dtor = ctorInit->dtor;
     962                                if ( dtor ) {
     963                                        auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor );
     964                                        const ast::Stmt * dtorStmt = implicit->callStmt;
     965
     966                                        // don't need to call intrinsic dtor, because it does nothing, but
     967                                        // non-intrinsic dtors must be called
     968                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     969                                                // set dtor location to the object's location for error messages
     970                                                auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     971                                                objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) );
     972                                                // ctorInit->dtor = nullptr;
     973                                        } // if
     974                                }
     975                        } // if
     976                } else if ( const ast::Init * init = ctorInit->init ) {
     977                        objDecl->init = init;
     978                        // ctorInit->init = nullptr;
    912979                } else {
    913                         auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor );
    914                         auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>();
    915                         const ast::ApplicationExpr * ctorCall = nullptr;
    916                         if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) {
    917                                 // clean up intrinsic copy constructor calls by making them into SingleInits
    918                                 const ast::Expr * ctorArg = ctorCall->args.back();
    919                                 // ctorCall should be gone afterwards
    920                                 auto mutArg = mutate(ctorArg);
    921                                 mutArg->env = ctorCall->env;
    922                                 objDecl->init = new ast::SingleInit(loc, mutArg );
    923                         } else {
    924                                 stmtsToAddAfter.push_back( ctor );
    925                                 objDecl->init = nullptr;
    926                         }
    927 
    928                         const ast::Stmt * dtor = ctorInit->dtor;
    929                         if ( dtor ) {
    930                                 auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor );
    931                                 const ast::Stmt * dtorStmt = implicit->callStmt;
    932 
    933                                 // don't need to call intrinsic dtor, because it does nothing, but
    934                                 // non-intrinsic dtors must be called
    935                                 if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
    936                                         // set dtor location to the object's location for error messages
    937                                         auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
    938                                         objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) );
    939                                 } // if
    940                         }
     980                        // no constructor and no initializer, which is okay
     981                        objDecl->init = nullptr;
    941982                } // if
    942         } else if ( const ast::Init * init = ctorInit->init ) {
    943                 objDecl->init = init;
    944         } else {
    945                 // no constructor and no initializer, which is okay
    946                 objDecl->init = nullptr;
     983                // delete ctorInit;
     984                return objDecl;
    947985        } // if
    948         return objDecl;
     986        return _objDecl;
    949987}
    950988
     
    9681006
    9691007void LabelFinder::previsit( const ast::CompoundStmt * stmt ) {
    970         previsit( (const ast::Stmt *)stmt );
     1008        previsit( (const ast::Stmt *) stmt );
    9711009        Parent::previsit( stmt );
    9721010}
     
    9841022        // its children manually.
    9851023        if (funcDecl->type) funcDecl->type->accept(finder);
    986         if (funcDecl->stmts) funcDecl->stmts->accept(finder);
     1024        // maybeAccept( funcDecl->type, finder );
     1025        if (funcDecl->stmts) funcDecl->stmts->accept(finder) ;
    9871026
    9881027        // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.
     
    10391078}
    10401079
    1041 /// Should we check for warnings? (The function is user-defined constrctor or destructor.)
    10421080bool checkWarnings( const ast::FunctionDecl * funcDecl ) {
     1081        // only check for warnings if the current function is a user-defined constructor or destructor
    10431082        if ( ! funcDecl ) return false;
    10441083        if ( ! funcDecl->stmts ) return false;
     
    10661105
    10671106        isCtor = CodeGen::isConstructor( function->name );
    1068 
    1069         // Remaining code is only for warnings.
    1070         if ( ! checkWarnings( function ) ) return;
    1071         thisParam = function->params.front().strict_as<ast::ObjectDecl>();
    1072         auto thisType = getPointerBase( thisParam->get_type() );
    1073         auto structType = dynamic_cast< const ast::StructInstType * >( thisType );
    1074         if ( structType ) {
    1075                 structDecl = structType->base;
    1076                 for ( auto & member : structDecl->members ) {
    1077                         if ( auto field = member.as<ast::ObjectDecl>() ) {
    1078                                 // record all of the struct type's members that need to be constructed or
    1079                                 // destructed by the end of the function
    1080                                 unhandled.insert( field );
     1107        if ( checkWarnings( function ) ) {
     1108                // const ast::FunctionType * type = function->type;
     1109                // assert( ! type->params.empty() );
     1110                thisParam = function->params.front().strict_as<ast::ObjectDecl>();
     1111                auto thisType = getPointerBase( thisParam->get_type() );
     1112                auto structType = dynamic_cast< const ast::StructInstType * >( thisType );
     1113                if ( structType ) {
     1114                        structDecl = structType->base;
     1115                        for ( auto & member : structDecl->members ) {
     1116                                if ( auto field = member.as<ast::ObjectDecl>() ) {
     1117                                        // record all of the struct type's members that need to be constructed or
     1118                                        // destructed by the end of the function
     1119                                        unhandled.insert( field );
     1120                                }
    10811121                        }
    10821122                }
     
    11241164
    11251165                        // insert and resolve default/copy constructor call for each field that's unhandled
     1166                        // std::list< const ast::Stmt * > stmt;
    11261167                        ast::Expr * arg2 = nullptr;
    11271168                        if ( function->name == "?{}" && isCopyFunction( function ) ) {
    11281169                                // if copy ctor, need to pass second-param-of-this-function.field
     1170                                // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
    11291171                                assert( function->params.size() == 2 );
    11301172                                arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) );
     
    11371179
    11381180                        if ( callStmt ) {
     1181                                // auto & callStmt = stmt.front();
     1182
    11391183                                try {
    11401184                                        callStmt = callStmt->accept( *visitor );
     
    11421186                                                mutStmts->push_front( callStmt );
    11431187                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
     1188                                                // destructor statements should be added at the end
     1189                                                // function->get_statements()->push_back( callStmt );
    11441190
    11451191                                                // Optimization: do not need to call intrinsic destructors on members
     
    11761222                throw errors;
    11771223        }
     1224        // return funcDecl;
    11781225        return function;
    11791226}
     
    12091256
    12101257        std::string fname = getFunctionName( appExpr );
    1211         if ( fname != function->name ) return;
    1212 
    1213         // call to same kind of function
    1214         const ast::Expr * firstParam = appExpr->args.front();
    1215         if ( isThisExpression( firstParam, thisParam ) ) {
    1216                 // if calling another constructor on thisParam, assume that function handles
    1217                 // all members - if it doesn't a warning will appear in that function.
    1218                 unhandled.clear();
    1219         } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {
    1220                 // if first parameter is a member expression on the this parameter,
    1221                 // then remove the member from unhandled set.
    1222                 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
    1223                         unhandled.erase( memberExpr->member );
     1258        if ( fname == function->name ) {
     1259                // call to same kind of function
     1260                const ast::Expr * firstParam = appExpr->args.front();
     1261
     1262                if ( isThisExpression( firstParam, thisParam ) ) {
     1263                        // if calling another constructor on thisParam, assume that function handles
     1264                        // all members - if it doesn't a warning will appear in that function.
     1265                        unhandled.clear();
     1266                } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {
     1267                        // if first parameter is a member expression on the this parameter,
     1268                        // then remove the member from unhandled set.
     1269                        if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
     1270                                unhandled.erase( memberExpr->member );
     1271                        }
    12241272                }
    12251273        }
     
    12671315        ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>();
    12681316        ast::ptr<ast::TypeSubstitution> env = ctorExpr->env;
     1317        // ctorExpr->set_callExpr( nullptr );
     1318        // ctorExpr->set_env( nullptr );
    12691319
    12701320        // xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.
Note: See TracChangeset for help on using the changeset viewer.