- Timestamp:
- Jan 24, 2024, 8:19:18 AM (20 months ago)
- Branches:
- master
- Children:
- 64c4b4d
- Parents:
- bad9c8f (diff), 71b5aad5 (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. - Location:
- src
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Decl.hpp
rbad9c8f r221c542e 312 312 ptr<Type> base; 313 313 enum class EnumHiding { Visible, Hide } hide; 314 315 314 EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false, 316 315 std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall, -
src/CodeGen/CodeGenerator.cpp
rbad9c8f r221c542e 1135 1135 if ( clause->when_cond ) { 1136 1136 output << "when("; 1137 stmt->timeout_cond->accept( *visitor );1137 clause->when_cond->accept( *visitor ); 1138 1138 output << ") "; 1139 1139 } -
src/InitTweak/FixInit.cpp
rbad9c8f r221c542e 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. -
src/Parser/ExpressionNode.cc
rbad9c8f r221c542e 673 673 ast::LogicalFlag flag ) { 674 674 return new ast::LogicalExpr( location, 675 notZeroExpr( maybeMoveBuild( expr_node1 )),676 notZeroExpr( maybeMoveBuild( expr_node2 )),675 maybeMoveBuild( expr_node1 ), 676 maybeMoveBuild( expr_node2 ), 677 677 flag 678 678 ); … … 713 713 ExpressionNode * expr_node3 ) { 714 714 return new ast::ConditionalExpr( location, 715 notZeroExpr( maybeMoveBuild( expr_node1 )),715 maybeMoveBuild( expr_node1 ), 716 716 maybeMoveBuild( expr_node2 ), 717 717 maybeMoveBuild( expr_node3 ) -
src/Parser/parserutility.cc
rbad9c8f r221c542e 27 27 // if ( (int)(x != 0) ) ... 28 28 29 ast::Expr * notZeroExpr( ast::Expr * orig ) {29 ast::Expr * notZeroExpr( const ast::Expr * orig ) { 30 30 return ( !orig ) ? nullptr : new ast::CastExpr( orig->location, 31 31 ast::UntypedExpr::createCall( orig->location, -
src/Parser/parserutility.h
rbad9c8f r221c542e 21 21 } 22 22 23 ast::Expr * notZeroExpr( ast::Expr *orig );23 ast::Expr * notZeroExpr( const ast::Expr *orig ); 24 24 25 25 template< typename T > -
src/ResolvExpr/CandidateFinder.cpp
rbad9c8f r221c542e 46 46 #include "AST/Type.hpp" 47 47 #include "Common/utility.h" // for move, copy 48 #include "Parser/parserutility.h" // for notZeroExpr 48 49 #include "SymTab/Mangler.h" 49 50 #include "Tuples/Tuples.h" // for handleTupleAssignment … … 1502 1503 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1503 1504 CandidateFinder finder1( context, tenv ); 1504 finder1.find( logicalExpr->arg1, ResolveMode::withAdjustment() ); 1505 ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 ); 1506 finder1.find( arg1, ResolveMode::withAdjustment() ); 1505 1507 if ( finder1.candidates.empty() ) return; 1506 1508 1507 1509 CandidateFinder finder2( context, tenv ); 1508 finder2.find( logicalExpr->arg2, ResolveMode::withAdjustment() ); 1510 ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 ); 1511 finder2.find( arg2, ResolveMode::withAdjustment() ); 1509 1512 if ( finder2.candidates.empty() ) return; 1510 1513 … … 1532 1535 // candidates for condition 1533 1536 CandidateFinder finder1( context, tenv ); 1534 finder1.find( conditionalExpr->arg1, ResolveMode::withAdjustment() ); 1537 ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 ); 1538 finder1.find( arg1, ResolveMode::withAdjustment() ); 1535 1539 if ( finder1.candidates.empty() ) return; 1536 1540 -
src/Validate/Autogen.cpp
rbad9c8f r221c542e 803 803 } 804 804 805 struct PseudoFuncGenerateRoutine final :806 public ast::WithDeclsToAdd<>,807 public ast::WithShortCircuiting {808 void previsit( const ast::EnumDecl * enumDecl );809 };810 811 void PseudoFuncGenerateRoutine::previsit( const ast::EnumDecl * enumDecl ) {812 const CodeLocation& location = enumDecl->location;813 if ( enumDecl->members.size() == 0 || !enumDecl->base || enumDecl->name == "" ) return;814 815 std::vector<ast::ptr<ast::Init>> inits;816 std::vector<ast::ptr<ast::Init>> labels;817 for ( const ast::Decl * mem: enumDecl->members ) {818 auto memAsObjectDecl = dynamic_cast< const ast::ObjectDecl * >( mem );819 inits.emplace_back( memAsObjectDecl->init );820 labels.emplace_back( new ast::SingleInit(821 location, ast::ConstantExpr::from_string(location, mem->name) ) );822 }823 auto init = new ast::ListInit( location, std::move( inits ) );824 auto label_strings = new ast::ListInit( location, std::move(labels) );825 auto values = new ast::ObjectDecl(826 location,827 "__enum_values_"+enumDecl->name,828 new ast::ArrayType(829 // new ast::PointerType( new ast::BasicType{ ast::BasicType::Char} ),830 enumDecl->base,831 ast::ConstantExpr::from_int( location, enumDecl->members.size() ),832 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim833 )834 ,init835 ,836 ast::Storage::Static,837 ast::Linkage::AutoGen838 );839 auto label_arr = new ast::ObjectDecl(840 location,841 "__enum_labels_"+enumDecl->name,842 new ast::ArrayType(843 new ast::PointerType( new ast::BasicType{ ast::BasicType::Char} ),844 ast::ConstantExpr::from_int( location, enumDecl->members.size() ),845 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim846 ),847 label_strings,848 ast::Storage::Static,849 ast::Linkage::AutoGen850 );851 852 declsToAddAfter.push_back( values );853 declsToAddAfter.push_back( label_arr );854 }855 856 805 } // namespace 857 806 858 807 void autogenerateRoutines( ast::TranslationUnit & translationUnit ) { 859 808 ast::Pass<AutogenerateRoutines>::run( translationUnit ); 860 // ast::Pass<PseudoFuncGenerateRoutine>::run( translationUnit );861 809 } 862 810 -
src/Validate/ReplacePseudoFunc.cpp
rbad9c8f r221c542e 1 #include "ReplacePseudoFunc.hpp" 2 3 #include <set> 4 1 5 #include "AST/Decl.hpp" 6 #include "AST/Inspect.hpp" 2 7 #include "AST/Pass.hpp" 3 8 #include "AST/Stmt.hpp" 4 #include "AST/Inspect.hpp"5 9 #include "Common/utility.h" 6 #include "Re placePseudoFunc.hpp"7 10 #include "ResolvExpr/Resolver.h" 11 #include "SymTab/Mangler.h" // for Mangler 8 12 namespace Validate { 9 13 10 14 namespace { 11 15 12 struct ReplacePseudoFuncCore { 13 ast::Expr const * postvisit( ast::ApplicationExpr const * decl ); 16 std::set<std::string> queryLabels; 17 std::set<std::string> queryValues; 18 19 struct FindGenEnumArray final : public ast::WithShortCircuiting { 20 void previsit(const ast::ApplicationExpr* enumDecl); 14 21 }; 22 23 void FindGenEnumArray::previsit(const ast::ApplicationExpr* expr) { 24 auto fname = ast::getFunctionName(expr); 25 if (fname == "labelE" || fname == "valueE") { 26 if (expr->args.size() != 1) { 27 SemanticError(expr, "Position Expression only take one parameter"); 28 } 29 const ast::VariableExpr* arg = 30 expr->args.front().as<const ast::VariableExpr>(); 31 if (!arg) { 32 SemanticError(expr, "Unimplement Pseudo Function Cases"); 33 } 34 const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>(); 35 const std::string referredName = argAsVar->name; 36 const ast::EnumInstType* argType = 37 argAsVar->type.as<const ast::EnumInstType>(); 38 if (!argType) { 39 SemanticError( 40 argAsVar, 41 "Position can only be used on an enumeration instance"); 42 } 43 ast::ptr<ast::EnumDecl> base = argType->base; 44 assert(base); 45 if (fname == "labelE") queryLabels.insert(base->name); 46 if (fname == "valueE") queryValues.insert(base->name); 47 } 15 48 } 16 49 17 ast::Expr const * ReplacePseudoFuncCore::postvisit( ast::ApplicationExpr const * expr) { 18 auto fname = ast::getFunctionName( expr ); 19 if ( fname == "posE" ) { 20 // std::cerr << "Found App in ReplacePseudoFunc" << std::endl; 21 if ( expr->args.size() != 1 ) { 22 SemanticError( expr, "Position Expression only take one parameter" ); 50 struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>, 51 public ast::WithSymbolTable, 52 public ast::WithShortCircuiting { 53 void previsit(const ast::EnumDecl* enumDecl); 54 }; 55 56 void PseudoFuncGenerateRoutine::previsit(const ast::EnumDecl* enumDecl) { 57 visit_children = false; 58 const CodeLocation& location = enumDecl->location; 59 if (enumDecl->members.size() == 0 || !enumDecl->base) return; 60 61 std::vector<ast::ptr<ast::Init>> inits; 62 std::vector<ast::ptr<ast::Init>> labels; 63 for (const ast::Decl* mem : enumDecl->members) { 64 auto memAsObjectDecl = dynamic_cast<const ast::ObjectDecl*>(mem); 65 inits.emplace_back(memAsObjectDecl->init); 66 labels.emplace_back(new ast::SingleInit( 67 location, ast::ConstantExpr::from_string(location, mem->name))); 68 } 69 if (queryValues.count(enumDecl->name)) { 70 auto init = new ast::ListInit(location, std::move(inits)); 71 auto values = new ast::ObjectDecl( 72 location, "values_" + enumDecl->name, 73 new ast::ArrayType( 74 enumDecl->base, 75 ast::ConstantExpr::from_int(location, enumDecl->members.size()), 76 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim), 77 init, ast::Storage::Static, ast::Linkage::AutoGen); 78 symtab.addId(values); 79 values->mangleName = Mangle::mangle(values); 80 declsToAddAfter.push_back(values); 81 } 82 if (queryLabels.count(enumDecl->name)) { 83 auto label_strings = new ast::ListInit(location, std::move(labels)); 84 auto label_arr = new ast::ObjectDecl( 85 location, "labels_" + enumDecl->name, 86 new ast::ArrayType( 87 new ast::PointerType(new ast::BasicType{ast::BasicType::Char}), 88 ast::ConstantExpr::from_int(location, enumDecl->members.size()), 89 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim), 90 label_strings, ast::Storage::Static, ast::Linkage::AutoGen); 91 symtab.addId(label_arr); 92 label_arr->mangleName = Mangle::mangle(label_arr); 93 declsToAddAfter.push_back(label_arr); 94 } 95 } 96 97 struct ReplacePseudoFuncCore : public ast::WithShortCircuiting, 98 public ast::WithSymbolTable, 99 public ast::WithConstTranslationUnit { 100 ast::Expr const* postvisit(ast::ApplicationExpr const* decl); 101 }; 102 103 ast::Expr const* ReplacePseudoFuncCore::postvisit( 104 ast::ApplicationExpr const* expr) { 105 auto fname = ast::getFunctionName(expr); 106 auto location = expr->location; 107 if (fname == "posE" || fname == "valueE" || fname == "labelE") { 108 if (expr->args.size() != 1) { 109 SemanticError(expr, 110 "Pseudo Enum Expression only take one parameter"); 23 111 } 24 const ast::VariableExpr * arg = expr->args.front().as<const ast::VariableExpr>(); 25 if ( !arg ) { 26 SemanticError( expr, "Unimplement Pseudo Function Cases" ); 112 ast::ptr<ast::VariableExpr> arg = 113 expr->args.front().as<const ast::VariableExpr>(); 114 if (!arg) { 115 SemanticError(expr, "Unimplement Pseudo Function Cases"); 27 116 } 28 const ast::ObjectDecl 117 const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>(); 29 118 const std::string referredName = argAsVar->name; 30 const ast::EnumInstType * argType = argAsVar->type.as<const ast::EnumInstType>(); 31 if ( !argType ) { 32 SemanticError( argAsVar, "Position can only be used on an enumeration instance" ); 119 const ast::EnumInstType* argType = 120 argAsVar->type.as<const ast::EnumInstType>(); 121 if (!argType) { 122 SemanticError(argAsVar, 123 "Pseudo Enum Expression can only be used on an " 124 "enumeration instance"); 33 125 } 34 const ast::EnumDecl * base = argType->base; 35 for ( size_t i = 0; i < base->members.size(); i++ ) { 36 if ( base->members[i]->name == referredName ) { 37 return ast::ConstantExpr::from_int( expr->location, i ); 126 const ast::EnumDecl* base = argType->base; 127 for (size_t i = 0; i < base->members.size(); i++) { 128 if (base->members[i]->name == referredName) { 129 if (fname == "posE") 130 return ast::ConstantExpr::from_int(expr->location, i); 131 else if (fname == "labelE") 132 return ast::ConstantExpr::from_string(expr->location, 133 referredName); 134 else 135 return new ast::TypeExpr(expr->location, argType); 136 } 137 } 138 139 ResolvExpr::ResolveContext context{symtab, transUnit().global}; 140 141 if (fname == "labelE") { 142 ast::Expr* toResolve = 143 new ast::NameExpr(expr->location, "labels_" + base->name); 144 auto result = ResolvExpr::findVoidExpression(toResolve, context); 145 if (result.get()) { 146 auto arrAsVar = result.strict_as<ast::VariableExpr>(); 147 auto untyped = new ast::UntypedExpr( 148 location, new ast::NameExpr(location, "?[?]"), 149 {new ast::VariableExpr(*arrAsVar), 150 ast::ConstantExpr::from_int( 151 location, 152 0)}); /// TODO: dummy value. 153 /// To make it works need to change the unifier 154 155 auto typedResult = 156 ResolvExpr::findVoidExpression(untyped, context); 157 if (result.get()) { 158 ast::ptr<ast::ApplicationExpr> ret = 159 typedResult.strict_as<ast::ApplicationExpr>(); 160 return new ast::ApplicationExpr(*ret); 161 } 162 } 163 } 164 165 if (fname == "valueE") { 166 ast::Expr* toResolve = 167 new ast::NameExpr(expr->location, "values_" + base->name); 168 auto result = ResolvExpr::findVoidExpression(toResolve, context); 169 if (result.get()) { 170 auto arrAsVar = result.strict_as<ast::VariableExpr>(); 171 auto untyped = new ast::UntypedExpr( 172 location, new ast::NameExpr(location, "?[?]"), 173 {new ast::VariableExpr(*arrAsVar), 174 ast::ConstantExpr::from_int( 175 location, 176 0)}); /// TODO: dummy value. 177 /// To make it works need to change the unifier 178 179 auto typedResult = 180 ResolvExpr::findVoidExpression(untyped, context); 181 if (result.get()) { 182 ast::ptr<ast::ApplicationExpr> ret = 183 typedResult.strict_as<ast::ApplicationExpr>(); 184 return new ast::ApplicationExpr(*ret); 185 } 38 186 } 39 187 } … … 42 190 } 43 191 192 } // namespace 44 193 45 46 void replacePseudoFunc( ast::TranslationUnit & translationUnit ) { 47 ast::Pass<ReplacePseudoFuncCore>::run( translationUnit ); 194 void replacePseudoFunc(ast::TranslationUnit& translationUnit) { 195 ast::Pass<FindGenEnumArray>::run(translationUnit); 196 ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit); 197 ast::Pass<ReplacePseudoFuncCore>::run(translationUnit); 48 198 } 49 50 } 199 } // namespace Validate -
src/main.cc
rbad9c8f r221c542e 82 82 #include "Validate/ReturnCheck.hpp" // for checkReturnStatements 83 83 #include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign 84 #include "Validate/ReplacePseudoFunc.hpp" 84 #include "Validate/ReplacePseudoFunc.hpp" // for replacePseudoFunc 85 85 #include "Virtual/ExpandCasts.h" // for expandCasts 86 86 #include "Virtual/VirtualDtor.hpp" // for implementVirtDtors
Note:
See TracChangeset
for help on using the changeset viewer.