Changes in src/InitTweak/FixInit.cc [1bc749f:e41306d]
- File:
-
- 1 edited
-
src/InitTweak/FixInit.cc (modified) (28 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixInit.cc
r1bc749f re41306d 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 VarExprReplacer57 56 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 58 57 … … 94 93 /// true if type does not need to be copy constructed to ensure correctness 95 94 bool skipCopyConstruct( Type * type ); 96 void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr );95 void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal ); 97 96 void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr ); 98 97 … … 159 158 using Parent::previsit; 160 159 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 ); 163 166 void previsit( BranchStmt * stmt ); 164 167 private: … … 176 179 177 180 DeclarationWithType * postmutate( ObjectDecl *objDecl ); 178 179 DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * dtor );180 181 181 182 std::list< Declaration * > staticDtorDecls; … … 213 214 void emit( CodeLocation, const Params &... params ); 214 215 215 FunctionDecl * function = 0;216 FunctionDecl * function = nullptr; 216 217 std::set< DeclarationWithType * > unhandled; 217 218 std::map< DeclarationWithType *, CodeLocation > usedUninit; 218 ObjectDecl * thisParam = 0;219 ObjectDecl * thisParam = nullptr; 219 220 bool isCtor = false; // true if current function is a constructor 220 StructDecl * structDecl = 0;221 StructDecl * structDecl = nullptr; 221 222 }; 222 223 … … 259 260 260 261 GenStructMemberCalls::generate( translationUnit ); 262 261 263 // xxx - ctor expansion currently has to be after FixCopyCtors, because there is currently a 262 264 // hack in the way untyped assignments are generated, where the first argument cannot have … … 288 290 for ( std::list< Declaration * >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) { 289 291 try { 290 *i =maybeMutate( *i, fixer );292 maybeMutate( *i, fixer ); 291 293 translationUnit.splice( i, fixer.pass.staticDtorDecls ); 292 294 } catch( SemanticError &e ) { … … 322 324 323 325 Expression * InsertImplicitCalls::postmutate( ApplicationExpr * appExpr ) { 324 assert( appExpr );325 326 326 if ( VariableExpr * function = dynamic_cast< VariableExpr * > ( appExpr->get_function() ) ) { 327 if ( LinkageSpec::isBuiltin( function->get_var()->get_linkage() )) {327 if ( function->var->linkage.is_builtin ) { 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-> get_parameters().size() == 2 ) {334 Type * t1 = getPointerBase( ftype-> get_parameters().front()->get_type() );335 Type * t2 = ftype-> get_parameters().back()->get_type();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(); 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 * untyped = exprStmt->get_expr(); 368 Expression * resolved = exprStmt->expr; 369 exprStmt->expr = nullptr; // take ownership of expr 369 370 370 371 // resolve copy constructor 371 372 // should only be one alternative for copy ctor and dtor expressions, since all arguments are fixed 372 373 // (VariableExpr and already resolved expression) 373 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; )374 Expression * resolved = ResolvExpr::findVoidExpression( untyped, indexer );374 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << resolved << std::endl; ) 375 ResolvExpr::findVoidExpression( resolved, indexer ); 375 376 assert( resolved ); 376 377 if ( resolved->get_env() ) { … … 380 381 resolved->set_env( nullptr ); 381 382 } // if 382 383 383 delete stmt; 384 384 return resolved; 385 385 } 386 386 387 void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr ) {387 void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal ) { 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-> has_result());392 Type * result = arg-> get_result();391 assert( arg->result ); 392 Type * result = arg->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 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). 396 397 result = result->clone(); 397 env->apply ( result );398 env->applyFree( result ); 398 399 ObjectDecl * tmp = ObjectDecl::newObject( "__tmp", result, nullptr ); 399 400 tmp->get_type()->set_const( false ); … … 406 407 // if the chosen constructor is intrinsic, the copy is unnecessary, so 407 408 // don't create the temporary and don't call the copy constructor 408 VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() ); 409 assert( function ); 410 if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) return; 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 } 411 415 } 412 416 … … 416 420 // replace argument to function call with temporary 417 421 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 418 impCpCtorExpr-> get_tempDecls().push_back( tmp );419 impCpCtorExpr-> get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) );422 impCpCtorExpr->tempDecls.push_back( tmp ); 423 impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) ); 420 424 } 421 425 … … 427 431 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 428 432 429 ApplicationExpr * appExpr = impCpCtorExpr-> get_callExpr();433 ApplicationExpr * appExpr = impCpCtorExpr->callExpr; 430 434 431 435 // take each argument and attempt to copy construct it. 432 for ( Expression * & arg : appExpr->get_args() ) { 433 copyConstructArg( arg, impCpCtorExpr ); 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 ); 434 448 } // for 435 449 … … 437 451 // initialized with the return value and is destructed later 438 452 // xxx - handle named return values? 439 Type * result = appExpr-> get_result();453 Type * result = appExpr->result; 440 454 if ( ! result->isVoid() ) { 441 455 static UniqueName retNamer("_tmp_cp_ret"); … … 443 457 env->apply( result ); 444 458 ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr ); 445 ret-> get_type()->set_const( false );446 impCpCtorExpr-> get_returnDecls().push_back( ret );459 ret->type->set_const( false ); 460 impCpCtorExpr->returnDecls.push_back( ret ); 447 461 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 448 462 if ( ! dynamic_cast< ReferenceType * >( result ) ) { … … 551 565 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) ); 552 566 // move env from callExpr to retExpr 553 retExpr->set_env( callExpr->get_env() ); 554 callExpr->set_env( nullptr ); 567 std::swap( retExpr->env, callExpr->env ); 555 568 return retExpr; 556 569 } else { … … 623 636 } 624 637 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 simply632 // 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 that641 // 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 654 638 DeclarationWithType * FixInit::postmutate( ObjectDecl *objDecl ) { 655 639 // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postmutate) … … 750 734 } else { 751 735 ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * > ( ctor ); 752 ExprStmt * ctorStmt = dynamic_cast< ExprStmt * >( implicit-> get_callStmt());736 ExprStmt * ctorStmt = dynamic_cast< ExprStmt * >( implicit->callStmt ); 753 737 ApplicationExpr * ctorCall = nullptr; 754 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt-> get_expr())) && ctorCall->get_args().size() == 2 ) {738 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->get_args().size() == 2 ) { 755 739 // clean up intrinsic copy constructor calls by making them into SingleInits 756 objDecl->set_init( new SingleInit( ctorCall->get_args().back() ) ); 757 ctorCall->get_args().pop_back(); 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(); 758 745 } else { 759 746 stmtsToAddAfter.push_back( ctor ); 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 747 objDecl->init = nullptr; 748 ctorInit->ctor = nullptr; 777 749 } 778 750 } // if 779 } else if ( Initializer * init = ctorInit-> get_init()) {780 objDecl-> set_init( init );781 ctorInit-> set_init( nullptr );751 } else if ( Initializer * init = ctorInit->init ) { 752 objDecl->init = init; 753 ctorInit->init = nullptr; 782 754 } else { 783 755 // no constructor and no initializer, which is okay 784 objDecl-> set_init( nullptr );756 objDecl->init = nullptr; 785 757 } // if 786 758 delete ctorInit; … … 818 790 819 791 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 is 796 // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually 797 // calls an intrinsic dtor then the call must (and will) still be generated since the argument may 798 // 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 } // for 804 } 805 806 void InsertDtors::previsit( ObjectDecl * objDecl ) { 807 // remember non-static destructed objects so that their destructors can be inserted later 808 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-NULL 811 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, but 814 // non-intrinsic dtors must be called 815 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 816 // set dtor location to the object's location for error messages 817 ctorInit->dtor->location = objDecl->location; 818 reverseDeclOrder.front().push_front( objDecl ); 819 } // if 820 } // if 821 } // if 822 } 823 820 824 void InsertDtors::previsit( FunctionDecl * funcDecl ) { 821 825 // each function needs to have its own set of labels 822 826 GuardValue( labelVars ); 823 827 labelVars.clear(); 828 // LabelFinder does not recurse into FunctionDecl, so need to visit 829 // its children manually. 824 830 maybeAccept( funcDecl->type, finder ); 825 831 maybeAccept( funcDecl->statements, finder ); 826 832 827 833 // 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 destructors 838 // when block is left, just the destructors associated with variables defined in this block, so push a new 839 // list to the top of the stack so that we can differentiate scopes 840 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, which 846 // causes unreachable code warnings 847 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 scopes 856 for ( OrderedDecls & od : reverseDeclOrder ) { 857 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) ); 858 } // for 828 859 } 829 860 … … 855 886 if ( ! diff.empty() ) { 856 887 throw SemanticError( std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " ", stmt ); 888 } // if 889 // S_G-S_L results in set of objects that must be destructed 890 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 destructor 900 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 } // for 905 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) ); 857 906 } // if 858 907 } … … 880 929 } 881 930 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 882 944 void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) { 883 GuardValue( func Decl);945 GuardValue( function ); 884 946 GuardValue( unhandled ); 885 947 GuardValue( usedUninit ); … … 914 976 } 915 977 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 929 978 void GenStructMemberCalls::postvisit( FunctionDecl * funcDecl ) { 930 979 // remove the unhandled objects from usedUninit, because a call is inserted … … 1079 1128 } 1080 1129 1081 DeclarationWithType * MutatingResolver::mutate( ObjectDecl * objectDecl ) {1130 DeclarationWithType * MutatingResolver::mutate( ObjectDecl * objectDecl ) { 1082 1131 // add object to the indexer assumes that there will be no name collisions 1083 1132 // in generated code. If this changes, add mutate methods for entities with … … 1087 1136 } 1088 1137 1089 Expression* MutatingResolver::mutate( UntypedExpr *untypedExpr ) { 1090 return strict_dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untypedExpr, indexer ) ); 1138 Expression * MutatingResolver::mutate( UntypedExpr * untypedExpr ) { 1139 Expression * newExpr = untypedExpr; 1140 ResolvExpr::findVoidExpression( newExpr, indexer ); 1141 return newExpr; 1091 1142 } 1092 1143 … … 1094 1145 static UniqueName tempNamer( "_tmp_ctor_expr" ); 1095 1146 // xxx - is the size check necessary? 1096 assert( ctorExpr-> has_result()&& ctorExpr->get_result()->size() == 1 );1147 assert( ctorExpr->result && ctorExpr->get_result()->size() == 1 ); 1097 1148 1098 1149 // 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. … … 1113 1164 1114 1165 // resolve assignment and dispose of new env 1115 Expression * resolvedAssign = ResolvExpr::findVoidExpression( assign, indexer ); 1116 delete resolvedAssign->env; 1117 resolvedAssign->env = nullptr; 1118 delete assign; 1166 ResolvExpr::findVoidExpression( assign, indexer ); 1167 delete assign->env; 1168 assign->env = nullptr; 1119 1169 1120 1170 // for constructor expr: … … 1125 1175 // T & tmp; 1126 1176 // &tmp = &x, ?{}(tmp), tmp 1127 CommaExpr * commaExpr = new CommaExpr( resolvedAssign, new CommaExpr( callExpr, new VariableExpr( tmp ) ) );1177 CommaExpr * commaExpr = new CommaExpr( assign, new CommaExpr( callExpr, new VariableExpr( tmp ) ) ); 1128 1178 commaExpr->set_env( env ); 1129 1179 return commaExpr;
Note:
See TracChangeset
for help on using the changeset viewer.