Changes in src/InitTweak/FixInit.cc [e41306d:1bc749f]
- File:
-
- 1 edited
-
src/InitTweak/FixInit.cc (modified) (28 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixInit.cc
re41306d r1bc749f 54 54 #include "SynTree/Type.h" // for Type, Type::StorageClasses 55 55 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution, operator<< 56 #include "SynTree/VarExprReplacer.h" // for VarExprReplacer 56 57 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 57 58 … … 93 94 /// true if type does not need to be copy constructed to ensure correctness 94 95 bool skipCopyConstruct( Type * type ); 95 void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr , Type * formal);96 void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr ); 96 97 void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr ); 97 98 … … 158 159 using Parent::previsit; 159 160 160 void previsit( ObjectDecl * objDecl );161 161 void previsit( FunctionDecl * funcDecl ); 162 162 163 void previsit( CompoundStmt * compoundStmt );164 void postvisit( CompoundStmt * compoundStmt );165 void previsit( ReturnStmt * returnStmt );166 163 void previsit( BranchStmt * stmt ); 167 164 private: … … 179 176 180 177 DeclarationWithType * postmutate( ObjectDecl *objDecl ); 178 179 DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * dtor ); 181 180 182 181 std::list< Declaration * > staticDtorDecls; … … 214 213 void emit( CodeLocation, const Params &... params ); 215 214 216 FunctionDecl * function = nullptr;215 FunctionDecl * function = 0; 217 216 std::set< DeclarationWithType * > unhandled; 218 217 std::map< DeclarationWithType *, CodeLocation > usedUninit; 219 ObjectDecl * thisParam = nullptr;218 ObjectDecl * thisParam = 0; 220 219 bool isCtor = false; // true if current function is a constructor 221 StructDecl * structDecl = nullptr;220 StructDecl * structDecl = 0; 222 221 }; 223 222 … … 260 259 261 260 GenStructMemberCalls::generate( translationUnit ); 262 263 261 // xxx - ctor expansion currently has to be after FixCopyCtors, because there is currently a 264 262 // hack in the way untyped assignments are generated, where the first argument cannot have … … 290 288 for ( std::list< Declaration * >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) { 291 289 try { 292 maybeMutate( *i, fixer );290 *i = maybeMutate( *i, fixer ); 293 291 translationUnit.splice( i, fixer.pass.staticDtorDecls ); 294 292 } catch( SemanticError &e ) { … … 324 322 325 323 Expression * InsertImplicitCalls::postmutate( ApplicationExpr * appExpr ) { 324 assert( appExpr ); 325 326 326 if ( VariableExpr * function = dynamic_cast< VariableExpr * > ( appExpr->get_function() ) ) { 327 if ( function->var->linkage.is_builtin) {327 if ( LinkageSpec::isBuiltin( function->get_var()->get_linkage() ) ) { 328 328 // optimization: don't need to copy construct in order to call intrinsic functions 329 329 return appExpr; … … 331 331 FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) ); 332 332 assertf( ftype, "Function call without function type: %s", toString( funcDecl ).c_str() ); 333 if ( CodeGen::isConstructor( funcDecl->get_name() ) && ftype-> parameters.size() == 2 ) {334 Type * t1 = getPointerBase( ftype-> parameters.front()->get_type() );335 Type * t2 = ftype-> parameters.back()->get_type();333 if ( CodeGen::isConstructor( funcDecl->get_name() ) && ftype->get_parameters().size() == 2 ) { 334 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() ); 335 Type * t2 = ftype->get_parameters().back()->get_type(); 336 336 assert( t1 ); 337 337 … … 366 366 ImplicitCtorDtorStmt * stmt = genCtorDtor( fname, var, cpArg ); 367 367 ExprStmt * exprStmt = strict_dynamic_cast< ExprStmt * >( stmt->get_callStmt() ); 368 Expression * resolved = exprStmt->expr; 369 exprStmt->expr = nullptr; // take ownership of expr 368 Expression * untyped = exprStmt->get_expr(); 370 369 371 370 // resolve copy constructor 372 371 // should only be one alternative for copy ctor and dtor expressions, since all arguments are fixed 373 372 // (VariableExpr and already resolved expression) 374 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << resolved << std::endl; )375 ResolvExpr::findVoidExpression( resolved, indexer );373 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; ) 374 Expression * resolved = ResolvExpr::findVoidExpression( untyped, indexer ); 376 375 assert( resolved ); 377 376 if ( resolved->get_env() ) { … … 381 380 resolved->set_env( nullptr ); 382 381 } // if 382 383 383 delete stmt; 384 384 return resolved; 385 385 } 386 386 387 void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr , Type * formal) {387 void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr ) { 388 388 static UniqueName tempNamer("_tmp_cp"); 389 389 assert( env ); 390 390 CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; ) 391 assert( arg-> result);392 Type * result = arg-> result;391 assert( arg->has_result() ); 392 Type * result = arg->get_result(); 393 393 if ( skipCopyConstruct( result ) ) return; // skip certain non-copyable types 394 394 395 // type may involve type variables, so apply type substitution to get temporary variable's actual type. 396 // Use applyFree so that types bound in function pointers are not substituted, e.g. in forall(dtype T) void (*)(T). 395 // type may involve type variables, so apply type substitution to get temporary variable's actual type 397 396 result = result->clone(); 398 env->apply Free( result );397 env->apply( result ); 399 398 ObjectDecl * tmp = ObjectDecl::newObject( "__tmp", result, nullptr ); 400 399 tmp->get_type()->set_const( false ); … … 407 406 // if the chosen constructor is intrinsic, the copy is unnecessary, so 408 407 // don't create the temporary and don't call the copy constructor 409 VariableExpr * function = strict_dynamic_cast< VariableExpr * >( appExpr->function ); 410 if ( function->var->linkage == LinkageSpec::Intrinsic ) { 411 // arguments that need to be boxed need a temporary regardless of whether the copy constructor is intrinsic, 412 // so that the object isn't changed inside of the polymorphic function 413 if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return; 414 } 408 VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() ); 409 assert( function ); 410 if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) return; 415 411 } 416 412 … … 420 416 // replace argument to function call with temporary 421 417 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 422 impCpCtorExpr-> tempDecls.push_back( tmp );423 impCpCtorExpr-> dtors.push_front( makeCtorDtor( "^?{}", tmp ) );418 impCpCtorExpr->get_tempDecls().push_back( tmp ); 419 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) ); 424 420 } 425 421 … … 431 427 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 432 428 433 ApplicationExpr * appExpr = impCpCtorExpr-> callExpr;429 ApplicationExpr * appExpr = impCpCtorExpr->get_callExpr(); 434 430 435 431 // take each argument and attempt to copy construct it. 436 FunctionType * ftype = GenPoly::getFunctionType( appExpr->function->result ); 437 assert( ftype ); 438 auto & params = ftype->parameters; 439 auto iter = params.begin(); 440 for ( Expression * & arg : appExpr->args ) { 441 Type * formal = nullptr; 442 if ( iter != params.end() ) { 443 DeclarationWithType * param = *iter++; 444 formal = param->get_type(); 445 } 446 447 copyConstructArg( arg, impCpCtorExpr, formal ); 432 for ( Expression * & arg : appExpr->get_args() ) { 433 copyConstructArg( arg, impCpCtorExpr ); 448 434 } // for 449 435 … … 451 437 // initialized with the return value and is destructed later 452 438 // xxx - handle named return values? 453 Type * result = appExpr-> result;439 Type * result = appExpr->get_result(); 454 440 if ( ! result->isVoid() ) { 455 441 static UniqueName retNamer("_tmp_cp_ret"); … … 457 443 env->apply( result ); 458 444 ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr ); 459 ret-> type->set_const( false );460 impCpCtorExpr-> returnDecls.push_back( ret );445 ret->get_type()->set_const( false ); 446 impCpCtorExpr->get_returnDecls().push_back( ret ); 461 447 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 462 448 if ( ! dynamic_cast< ReferenceType * >( result ) ) { … … 565 551 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) ); 566 552 // move env from callExpr to retExpr 567 std::swap( retExpr->env, callExpr->env ); 553 retExpr->set_env( callExpr->get_env() ); 554 callExpr->set_env( nullptr ); 568 555 return retExpr; 569 556 } else { … … 636 623 } 637 624 625 DeclarationWithType * FixInit::getDtorFunc( ObjectDecl * objDecl, Statement * dtor ) { 626 if ( dynamic_cast< ExprStmt * >( dtor ) ) { 627 if ( DeclarationWithType * func = getFunction( getCtorDtorCall( dtor ) ) ) { 628 // cleanup argument must be a function, not an object (including function pointer) 629 if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) { 630 if ( dtorFunc->type->forall.empty() ) { 631 // simple case where the destructor is a monomorphic function call - can simply 632 // use that function as the cleanup function. 633 delete dtor; 634 return func; 635 } 636 } 637 } 638 } 639 640 // otherwise the cleanup is more complicated - need to build a single argument cleanup function that 641 // wraps the more complicated code. 642 static UniqueName dtorNamer( "__cleanup_dtor" ); 643 FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type ), new CompoundStmt( noLabels ) ); 644 stmtsToAddBefore.push_back( new DeclStmt( noLabels, dtorFunc ) ); 645 646 // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter. 647 ObjectDecl * thisParam = getThisParam( dtorFunc->type ); 648 VarExprReplacer::replace( dtor, { std::make_pair( objDecl, thisParam ) } ); 649 dtorFunc->statements->push_back( dtor ); 650 651 return dtorFunc; 652 } 653 638 654 DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) { 639 655 // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate) … … 734 750 } else { 735 751 ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * > ( ctor ); 736 ExprStmt * ctorStmt = dynamic_cast< ExprStmt * >( implicit-> callStmt);752 ExprStmt * ctorStmt = dynamic_cast< ExprStmt * >( implicit->get_callStmt() ); 737 753 ApplicationExpr * ctorCall = nullptr; 738 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt-> expr)) && ctorCall->get_args().size() == 2 ) {754 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->get_expr() )) && ctorCall->get_args().size() == 2 ) { 739 755 // clean up intrinsic copy constructor calls by making them into SingleInits 740 Expression * ctorArg = ctorCall->args.back(); 741 std::swap( ctorArg->env, ctorCall->env ); 742 objDecl->init = new SingleInit( ctorArg ); 743 744 ctorCall->args.pop_back(); 756 objDecl->set_init( new SingleInit( ctorCall->get_args().back() ) ); 757 ctorCall->get_args().pop_back(); 745 758 } else { 746 759 stmtsToAddAfter.push_back( ctor ); 747 objDecl->init = nullptr; 748 ctorInit->ctor = nullptr; 760 objDecl->set_init( nullptr ); 761 ctorInit->set_ctor( nullptr ); 762 } 763 764 Statement * dtor = ctorInit->dtor; 765 if ( dtor ) { 766 ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor ); 767 Statement * dtorStmt = implicit->callStmt; 768 // don't need to call intrinsic dtor, because it does nothing, but 769 // non-intrinsic dtors must be called 770 if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) { 771 // set dtor location to the object's location for error messages 772 DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt ); 773 objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) ); 774 // objDecl->attributes.push_back( new Attribute( "cleanup", { new NameExpr( dtorFunc->name ) } ) ); 775 ctorInit->dtor = nullptr; 776 } // if 749 777 } 750 778 } // if 751 } else if ( Initializer * init = ctorInit-> init) {752 objDecl-> init = init;753 ctorInit-> init = nullptr;779 } else if ( Initializer * init = ctorInit->get_init() ) { 780 objDecl->set_init( init ); 781 ctorInit->set_init( nullptr ); 754 782 } else { 755 783 // no constructor and no initializer, which is okay 756 objDecl-> init = nullptr;784 objDecl->set_init( nullptr ); 757 785 } // if 758 786 delete ctorInit; … … 790 818 791 819 792 template<typename Iterator, typename OutputIterator>793 void insertDtors( Iterator begin, Iterator end, OutputIterator out ) {794 for ( Iterator it = begin ; it != end ; ++it ) {795 // extract destructor statement from the object decl and insert it into the output. Note that this is796 // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually797 // calls an intrinsic dtor then the call must (and will) still be generated since the argument may798 // contain side effects.799 ObjectDecl * objDecl = *it;800 ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() );801 assert( ctorInit && ctorInit->get_dtor() );802 *out++ = ctorInit->get_dtor()->clone();803 } // for804 }805 806 void InsertDtors::previsit( ObjectDecl * objDecl ) {807 // remember non-static destructed objects so that their destructors can be inserted later808 if ( ! objDecl->get_storageClasses().is_static ) {809 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {810 // a decision should have been made by the resolver, so ctor and init are not both non-NULL811 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );812 Statement * dtor = ctorInit->get_dtor();813 // don't need to call intrinsic dtor, because it does nothing, but814 // non-intrinsic dtors must be called815 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {816 // set dtor location to the object's location for error messages817 ctorInit->dtor->location = objDecl->location;818 reverseDeclOrder.front().push_front( objDecl );819 } // if820 } // if821 } // if822 }823 824 820 void InsertDtors::previsit( FunctionDecl * funcDecl ) { 825 821 // each function needs to have its own set of labels 826 822 GuardValue( labelVars ); 827 823 labelVars.clear(); 828 // LabelFinder does not recurse into FunctionDecl, so need to visit829 // its children manually.830 824 maybeAccept( funcDecl->type, finder ); 831 825 maybeAccept( funcDecl->statements, finder ); 832 826 833 827 // all labels for this function have been collected, insert destructors as appropriate via implicit recursion. 834 }835 836 void InsertDtors::previsit( CompoundStmt * compoundStmt ) {837 // visit statements - this will also populate reverseDeclOrder list. don't want to dump all destructors838 // when block is left, just the destructors associated with variables defined in this block, so push a new839 // list to the top of the stack so that we can differentiate scopes840 reverseDeclOrder.push_front( OrderedDecls() );841 Parent::previsit( compoundStmt );842 }843 844 void InsertDtors::postvisit( CompoundStmt * compoundStmt ) {845 // add destructors for the current scope that we're exiting, unless the last statement is a return, which846 // causes unreachable code warnings847 std::list< Statement * > & statements = compoundStmt->get_kids();848 if ( ! statements.empty() && ! dynamic_cast< ReturnStmt * >( statements.back() ) ) {849 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) );850 }851 reverseDeclOrder.pop_front();852 }853 854 void InsertDtors::previsit( ReturnStmt * ) {855 // return exits all scopes, so dump destructors for all scopes856 for ( OrderedDecls & od : reverseDeclOrder ) {857 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) );858 } // for859 828 } 860 829 … … 886 855 if ( ! diff.empty() ) { 887 856 throw SemanticError( std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " ", stmt ); 888 } // if889 // S_G-S_L results in set of objects that must be destructed890 diff.clear();891 std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) );892 DTOR_PRINT(893 std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl;894 )895 if ( ! diff.empty() ) {896 // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.897 std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );898 899 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor900 OrderedDecls ordered;901 for ( OrderedDecls & rdo : reverseDeclOrder ) {902 // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order.903 copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );904 } // for905 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) );906 857 } // if 907 858 } … … 929 880 } 930 881 931 void addIds( SymTab::Indexer & indexer, const std::list< DeclarationWithType * > & decls ) {932 for ( auto d : decls ) {933 indexer.addId( d );934 }935 }936 937 void addTypes( SymTab::Indexer & indexer, const std::list< TypeDecl * > & tds ) {938 for ( auto td : tds ) {939 indexer.addType( td );940 addIds( indexer, td->assertions );941 }942 }943 944 882 void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) { 945 GuardValue( func tion);883 GuardValue( funcDecl ); 946 884 GuardValue( unhandled ); 947 885 GuardValue( usedUninit ); … … 976 914 } 977 915 916 void addIds( SymTab::Indexer & indexer, const std::list< DeclarationWithType * > & decls ) { 917 for ( auto d : decls ) { 918 indexer.addId( d ); 919 } 920 } 921 922 void addTypes( SymTab::Indexer & indexer, const std::list< TypeDecl * > & tds ) { 923 for ( auto td : tds ) { 924 indexer.addType( td ); 925 addIds( indexer, td->assertions ); 926 } 927 } 928 978 929 void GenStructMemberCalls::postvisit( FunctionDecl * funcDecl ) { 979 930 // remove the unhandled objects from usedUninit, because a call is inserted … … 1128 1079 } 1129 1080 1130 DeclarationWithType * MutatingResolver::mutate( ObjectDecl * objectDecl ) {1081 DeclarationWithType * MutatingResolver::mutate( ObjectDecl *objectDecl ) { 1131 1082 // add object to the indexer assumes that there will be no name collisions 1132 1083 // in generated code. If this changes, add mutate methods for entities with … … 1136 1087 } 1137 1088 1138 Expression * MutatingResolver::mutate( UntypedExpr * untypedExpr ) { 1139 Expression * newExpr = untypedExpr; 1140 ResolvExpr::findVoidExpression( newExpr, indexer ); 1141 return newExpr; 1089 Expression* MutatingResolver::mutate( UntypedExpr *untypedExpr ) { 1090 return strict_dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untypedExpr, indexer ) ); 1142 1091 } 1143 1092 … … 1145 1094 static UniqueName tempNamer( "_tmp_ctor_expr" ); 1146 1095 // xxx - is the size check necessary? 1147 assert( ctorExpr-> result&& ctorExpr->get_result()->size() == 1 );1096 assert( ctorExpr->has_result() && ctorExpr->get_result()->size() == 1 ); 1148 1097 1149 1098 // 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. … … 1164 1113 1165 1114 // resolve assignment and dispose of new env 1166 ResolvExpr::findVoidExpression( assign, indexer ); 1167 delete assign->env; 1168 assign->env = nullptr; 1115 Expression * resolvedAssign = ResolvExpr::findVoidExpression( assign, indexer ); 1116 delete resolvedAssign->env; 1117 resolvedAssign->env = nullptr; 1118 delete assign; 1169 1119 1170 1120 // for constructor expr: … … 1175 1125 // T & tmp; 1176 1126 // &tmp = &x, ?{}(tmp), tmp 1177 CommaExpr * commaExpr = new CommaExpr( assign, new CommaExpr( callExpr, new VariableExpr( tmp ) ) );1127 CommaExpr * commaExpr = new CommaExpr( resolvedAssign, new CommaExpr( callExpr, new VariableExpr( tmp ) ) ); 1178 1128 commaExpr->set_env( env ); 1179 1129 return commaExpr;
Note:
See TracChangeset
for help on using the changeset viewer.