Changeset 71b5aad5 for src/InitTweak
- Timestamp:
- Jan 24, 2024, 6:05:54 AM (5 months ago)
- 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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixInit.cpp
r544deb9 r71b5aad5 49 49 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) { 50 50 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 ) ) { 53 52 return inst->base->params; 54 53 } … … 245 244 const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) { 246 245 const CodeLocation loc = input->location; 247 // unwrap implicit statement wrapper248 // Statement * dtor = input;249 246 assert( input ); 250 // std::list< const ast::Expr * > matches;251 247 auto matches = collectCtorDtorCalls( input ); 252 248 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; 266 260 } 267 261 } … … 301 295 for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) { 302 296 try { 303 // maybeAccept( *i, fixer ); translationUnit should never contain null304 297 *i = (*i)->accept(fixer); 305 298 translationUnit.decls.splice( i, fixer.core.staticDtorDecls ); … … 314 307 315 308 const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) { 316 // we might loose the result expression here so add a pointer to trace back317 309 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; 327 317 } 328 318 … … 330 320 // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed 331 321 // 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 } ); 334 323 } 335 324 … … 556 545 arg = cpCtor; 557 546 return destructRet( tmp, arg ); 558 559 // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );560 547 } 561 548 … … 608 595 } 609 596 return nullptr; 610 // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );611 597 } 612 598 … … 625 611 for ( auto & arg : appExpr->args ) { 626 612 const ast::Type * formal = nullptr; 627 if ( iter != params.end() ) { // does not copy construct C-style variadic arguments628 // DeclarationWithType * param = *iter++;613 // Do not copy construct C-style variadic arguments. 614 if ( iter != params.end() ) { 629 615 formal = *iter++; 630 616 } … … 659 645 // deletion of wrapper should be handled by pass template now 660 646 661 // impCpCtorExpr->callExpr = nullptr;662 647 assert (appExpr->env == nullptr); 663 648 appExpr->env = impCpCtorExpr->env; 664 // std::swap( impCpCtorExpr->env, appExpr->env );665 // assert( impCpCtorExpr->env == nullptr );666 // delete impCpCtorExpr;667 649 668 650 if ( returnDecl ) { … … 676 658 } 677 659 // move env from appExpr to retExpr 678 // std::swap( assign->env, appExpr->env );679 660 assign->env = appExpr->env; 680 661 // actual env is handled by common routine that replaces WithTypeSubstitution … … 716 697 717 698 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 ) ) ); 767 750 768 751 assert( stmtExpr->returnDecls.empty() ); … … 798 781 auto mutExpr = mutate(unqExpr); 799 782 if ( ! unqMap.count( unqExpr->id ) ) { 800 // resolve expr and find its801 802 783 auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>(); 803 // PassVisitor<ResolveCopyCtors> fixer;804 805 784 mutExpr->expr = mutExpr->expr->accept( *visitor ); 806 785 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought … … 820 799 } else { 821 800 // take data from other UniqueExpr to ensure consistency 822 // delete unqExpr->get_expr();823 801 mutExpr->expr = unqMap[mutExpr->id]->expr; 824 // delete unqExpr->result;825 802 mutExpr->result = mutExpr->expr->result; 826 803 } … … 832 809 833 810 // 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; 941 908 } 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 } 979 912 } 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 } 982 941 } // 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; 985 947 } // if 986 return _objDecl;948 return objDecl; 987 949 } 988 950 … … 1006 968 1007 969 void LabelFinder::previsit( const ast::CompoundStmt * stmt ) { 1008 previsit( (const ast::Stmt *) 970 previsit( (const ast::Stmt *)stmt ); 1009 971 Parent::previsit( stmt ); 1010 972 } … … 1022 984 // its children manually. 1023 985 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); 1026 987 1027 988 // all labels for this function have been collected, insert destructors as appropriate via implicit recursion. … … 1078 1039 } 1079 1040 1041 /// Should we check for warnings? (The function is user-defined constrctor or destructor.) 1080 1042 bool checkWarnings( const ast::FunctionDecl * funcDecl ) { 1081 // only check for warnings if the current function is a user-defined constructor or destructor1082 1043 if ( ! funcDecl ) return false; 1083 1044 if ( ! funcDecl->stmts ) return false; … … 1105 1066 1106 1067 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 ); 1121 1081 } 1122 1082 } … … 1164 1124 1165 1125 // insert and resolve default/copy constructor call for each field that's unhandled 1166 // std::list< const ast::Stmt * > stmt;1167 1126 ast::Expr * arg2 = nullptr; 1168 1127 if ( function->name == "?{}" && isCopyFunction( function ) ) { 1169 1128 // if copy ctor, need to pass second-param-of-this-function.field 1170 // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();1171 1129 assert( function->params.size() == 2 ); 1172 1130 arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) ); … … 1179 1137 1180 1138 if ( callStmt ) { 1181 // auto & callStmt = stmt.front();1182 1183 1139 try { 1184 1140 callStmt = callStmt->accept( *visitor ); … … 1186 1142 mutStmts->push_front( callStmt ); 1187 1143 } else { // TODO: don't generate destructor function/object for intrinsic calls 1188 // destructor statements should be added at the end1189 // function->get_statements()->push_back( callStmt );1190 1144 1191 1145 // Optimization: do not need to call intrinsic destructors on members … … 1222 1176 throw errors; 1223 1177 } 1224 // return funcDecl;1225 1178 return function; 1226 1179 } … … 1256 1209 1257 1210 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 ); 1272 1224 } 1273 1225 } … … 1315 1267 ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>(); 1316 1268 ast::ptr<ast::TypeSubstitution> env = ctorExpr->env; 1317 // ctorExpr->set_callExpr( nullptr );1318 // ctorExpr->set_env( nullptr );1319 1269 1320 1270 // 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.