Changeset 71b5aad5 for src/InitTweak


Ignore:
Timestamp:
Jan 24, 2024, 6:05:54 AM (5 months ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
16afb2a, 221c542e, 8a33777
Parents:
544deb9 (diff), 61e362f (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.cpp

    r544deb9 r71b5aad5  
    4949        if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
    5050                return inst->base->params;
    51         }
    52         if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
     51        } else if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
    5352                return inst->base->params;
    5453        }
     
    245244const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) {
    246245        const CodeLocation loc = input->location;
    247         // unwrap implicit statement wrapper
    248         // Statement * dtor = input;
    249246        assert( input );
    250         // std::list< const ast::Expr * > matches;
    251247        auto matches = collectCtorDtorCalls( input );
    252248
    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                                 }
     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;
    266260                        }
    267261                }
     
    301295        for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) {
    302296                try {
    303                         // maybeAccept( *i, fixer ); translationUnit should never contain null
    304297                        *i = (*i)->accept(fixer);
    305298                        translationUnit.decls.splice( i, fixer.core.staticDtorDecls );
     
    314307
    315308const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) {
    316         // we might loose the result expression here so add a pointer to trace back
    317309        assert( stmtExpr->result );
    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;
     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;
    327317}
    328318
     
    330320        // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
    331321        // in the correct places
    332         ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } );
    333         return ret;
     322        return new ast::CompoundStmt( stmt->location, { stmt } );
    334323}
    335324
     
    556545        arg = cpCtor;
    557546        return destructRet( tmp, arg );
    558 
    559         // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    560547}
    561548
     
    608595        }
    609596        return nullptr;
    610         // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    611597}
    612598
     
    625611        for ( auto & arg : appExpr->args ) {
    626612                const ast::Type * formal = nullptr;
    627                 if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
    628                         // DeclarationWithType * param = *iter++;
     613                // Do not copy construct C-style variadic arguments.
     614                if ( iter != params.end() ) {
    629615                        formal = *iter++;
    630616                }
     
    659645        // deletion of wrapper should be handled by pass template now
    660646
    661         // impCpCtorExpr->callExpr = nullptr;
    662647        assert (appExpr->env == nullptr);
    663648        appExpr->env = impCpCtorExpr->env;
    664         // std::swap( impCpCtorExpr->env, appExpr->env );
    665         // assert( impCpCtorExpr->env == nullptr );
    666         // delete impCpCtorExpr;
    667649
    668650        if ( returnDecl ) {
     
    676658                }
    677659                // move env from appExpr to retExpr
    678                 // std::swap( assign->env, appExpr->env );
    679660                assign->env = appExpr->env;
    680661                // actual env is handled by common routine that replaces WithTypeSubstitution
     
    716697
    717698        assert( stmtExpr->result );
    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
     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 ) ) );
    767750
    768751        assert( stmtExpr->returnDecls.empty() );
     
    798781        auto mutExpr = mutate(unqExpr);
    799782        if ( ! unqMap.count( unqExpr->id ) ) {
    800                 // resolve expr and find its
    801 
    802783                auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>();
    803                 // PassVisitor<ResolveCopyCtors> fixer;
    804 
    805784                mutExpr->expr = mutExpr->expr->accept( *visitor );
    806785                // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     
    820799        } else {
    821800                // take data from other UniqueExpr to ensure consistency
    822                 // delete unqExpr->get_expr();
    823801                mutExpr->expr = unqMap[mutExpr->id]->expr;
    824                 // delete unqExpr->result;
    825802                mutExpr->result = mutExpr->expr->result;
    826803        }
     
    832809
    833810        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit)
    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                                 }
     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;
    941908                        } else {
    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;
     909                                objDecl->init = nullptr;
     910                                return objDecl;
     911                        }
    979912                } else {
    980                         // no constructor and no initializer, which is okay
    981                         objDecl->init = nullptr;
     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                        }
    982941                } // if
    983                 // delete ctorInit;
    984                 return objDecl;
     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;
    985947        } // if
    986         return _objDecl;
     948        return objDecl;
    987949}
    988950
     
    1006968
    1007969void LabelFinder::previsit( const ast::CompoundStmt * stmt ) {
    1008         previsit( (const ast::Stmt *) stmt );
     970        previsit( (const ast::Stmt *)stmt );
    1009971        Parent::previsit( stmt );
    1010972}
     
    1022984        // its children manually.
    1023985        if (funcDecl->type) funcDecl->type->accept(finder);
    1024         // maybeAccept( funcDecl->type, finder );
    1025         if (funcDecl->stmts) funcDecl->stmts->accept(finder) ;
     986        if (funcDecl->stmts) funcDecl->stmts->accept(finder);
    1026987
    1027988        // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.
     
    10781039}
    10791040
     1041/// Should we check for warnings? (The function is user-defined constrctor or destructor.)
    10801042bool checkWarnings( const ast::FunctionDecl * funcDecl ) {
    1081         // only check for warnings if the current function is a user-defined constructor or destructor
    10821043        if ( ! funcDecl ) return false;
    10831044        if ( ! funcDecl->stmts ) return false;
     
    11051066
    11061067        isCtor = CodeGen::isConstructor( function->name );
    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                                 }
     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 );
    11211081                        }
    11221082                }
     
    11641124
    11651125                        // insert and resolve default/copy constructor call for each field that's unhandled
    1166                         // std::list< const ast::Stmt * > stmt;
    11671126                        ast::Expr * arg2 = nullptr;
    11681127                        if ( function->name == "?{}" && isCopyFunction( function ) ) {
    11691128                                // if copy ctor, need to pass second-param-of-this-function.field
    1170                                 // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
    11711129                                assert( function->params.size() == 2 );
    11721130                                arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) );
     
    11791137
    11801138                        if ( callStmt ) {
    1181                                 // auto & callStmt = stmt.front();
    1182 
    11831139                                try {
    11841140                                        callStmt = callStmt->accept( *visitor );
     
    11861142                                                mutStmts->push_front( callStmt );
    11871143                                        } 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 );
    11901144
    11911145                                                // Optimization: do not need to call intrinsic destructors on members
     
    12221176                throw errors;
    12231177        }
    1224         // return funcDecl;
    12251178        return function;
    12261179}
     
    12561209
    12571210        std::string fname = getFunctionName( appExpr );
    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                         }
     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 );
    12721224                }
    12731225        }
     
    13151267        ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>();
    13161268        ast::ptr<ast::TypeSubstitution> env = ctorExpr->env;
    1317         // ctorExpr->set_callExpr( nullptr );
    1318         // ctorExpr->set_env( nullptr );
    13191269
    13201270        // 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.