Changes in / [4d5e57b:1ba5803]
- Location:
- src
- Files:
-
- 2 deleted
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
src/GenPoly/InstantiateGeneric.cc
r4d5e57b r1ba5803 27 27 #include "Common/utility.h" // for deleteAll, cloneAll 28 28 #include "GenPoly.h" // for isPolyType, typesPolyCompatible 29 #include "ResolvExpr/typeops.h" 29 30 #include "ScopedSet.h" // for ScopedSet, ScopedSet<>::iterator 30 31 #include "ScrubTyVars.h" // for ScrubTyVars … … 151 152 return gt; 152 153 } 154 155 /// Add cast to dtype-static member expressions so that type information is not lost in GenericInstantiator 156 struct FixDtypeStatic final { 157 Expression * postmutate( MemberExpr * memberExpr ); 158 159 template<typename AggrInst> 160 Expression * fixMemberExpr( AggrInst * inst, MemberExpr * memberExpr ); 161 }; 153 162 154 163 /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately … … 198 207 199 208 void instantiateGeneric( std::list< Declaration* > &translationUnit ) { 209 PassVisitor<FixDtypeStatic> fixer; 200 210 PassVisitor<GenericInstantiator> instantiator; 211 212 mutateAll( translationUnit, fixer ); 201 213 mutateAll( translationUnit, instantiator ); 214 } 215 216 bool isDtypeStatic( const std::list< TypeDecl* >& baseParams ) { 217 return std::all_of( baseParams.begin(), baseParams.end(), []( TypeDecl * td ) { return ! td->isComplete(); } ); 202 218 } 203 219 … … 479 495 } 480 496 497 template< typename AggrInst > 498 Expression * FixDtypeStatic::fixMemberExpr( AggrInst * inst, MemberExpr * memberExpr ) { 499 // need to cast dtype-static member expressions to their actual type before that type is erased. 500 auto & baseParams = *inst->get_baseParameters(); 501 if ( isDtypeStatic( baseParams ) ) { 502 if ( ! ResolvExpr::typesCompatible( memberExpr->result, memberExpr->member->get_type(), SymTab::Indexer() ) ) { 503 // type of member and type of expression differ, so add cast to actual type 504 return new CastExpr( memberExpr, memberExpr->result->clone() ); 505 } 506 } 507 return memberExpr; 508 } 509 510 Expression * FixDtypeStatic::postmutate( MemberExpr * memberExpr ) { 511 Type * aggrType = memberExpr->aggregate->result; 512 if ( isGenericType( aggrType ) ) { 513 if ( StructInstType * inst = dynamic_cast< StructInstType * >( aggrType ) ) { 514 return fixMemberExpr( inst, memberExpr ); 515 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( aggrType ) ) { 516 return fixMemberExpr( inst, memberExpr ); 517 } 518 } 519 return memberExpr; 520 } 521 481 522 } // namespace GenPoly 482 523 -
src/InitTweak/FixInit.cc
r4d5e57b r1ba5803 937 937 } 938 938 939 void addIds( SymTab::Indexer & indexer, const std::list< DeclarationWithType * > & decls ) {940 for ( auto d : decls ) {941 indexer.addId( d );942 }943 }944 945 void addTypes( SymTab::Indexer & indexer, const std::list< TypeDecl * > & tds ) {946 for ( auto td : tds ) {947 indexer.addType( td );948 addIds( indexer, td->assertions );949 }950 }951 952 939 void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) { 953 940 GuardValue( function ); … … 1006 993 // need to explicitly re-add function parameters to the indexer in order to resolve copy constructors 1007 994 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this]() { indexer.leaveScope(); } ); 1008 addTypes( indexer, function->type->forall ); 1009 addIds( indexer, function->type->returnVals ); 1010 addIds( indexer, function->type->parameters ); 995 indexer.addFunctionType( function->type ); 1011 996 1012 997 // need to iterate through members in reverse in order for … … 1023 1008 // insert and resolve default/copy constructor call for each field that's unhandled 1024 1009 std::list< Statement * > stmt; 1025 Expression * arg2 = 0;1010 Expression * arg2 = nullptr; 1026 1011 if ( isCopyConstructor( function ) ) { 1027 1012 // if copy ctor, need to pass second-param-of-this-function.field -
src/Parser/DeclarationNode.cc
r4d5e57b r1ba5803 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Sep 23 18:16:48201713 // Update Count : 10 2412 // Last Modified On : Mon Nov 20 09:21:52 2017 13 // Update Count : 1031 14 14 // 15 15 … … 509 509 510 510 DeclarationNode * DeclarationNode::addQualifiers( DeclarationNode * q ) { 511 if ( ! q ) { delete q; return this; } 511 if ( ! q ) { delete q; return this; } // empty qualifier 512 512 513 513 checkSpecifiers( q ); 514 514 copySpecifiers( q ); 515 515 516 if ( ! q->type ) { 517 delete q; 518 return this; 519 } // if 516 if ( ! q->type ) { delete q; return this; } 520 517 521 518 if ( ! type ) { 522 type = q->type; // reuse thisstructure519 type = q->type; // reuse structure 523 520 q->type = nullptr; 524 521 delete q; … … 526 523 } // if 527 524 528 if ( q->type->forall ) { 529 if ( type->forall ) { 530 type->forall->appendList( q->type->forall ); 525 if ( q->type->forall ) { // forall qualifier ? 526 if ( type->forall ) { // polymorphic routine ? 527 type->forall->appendList( q->type->forall ); // augment forall qualifier 531 528 } else { 532 if ( type->kind == TypeData::Aggregate ) { 533 type->aggregate.params = q->type->forall; 534 // change implicit typedef from TYPEDEFname to TYPEGENname 535 typedefTable.changeKind( *type->aggregate.name, TypedefTable::TG ); 536 } else { 537 type->forall = q->type->forall; 529 if ( type->kind == TypeData::Aggregate ) { // struct/union ? 530 if ( type->aggregate.params ) { // polymorphic ? 531 type->aggregate.params->appendList( q->type->forall ); // augment forall qualifier 532 } else { // not polymorphic 533 type->aggregate.params = q->type->forall; // make polymorphic type 534 // change implicit typedef from TYPEDEFname to TYPEGENname 535 typedefTable.changeKind( *type->aggregate.name, TypedefTable::TG ); 536 } // if 537 } else { // not polymorphic 538 type->forall = q->type->forall; // make polymorphic routine 538 539 } // if 539 540 } // if 540 q->type->forall = nullptr; 541 q->type->forall = nullptr; // forall qualifier moved 541 542 } // if 542 543 -
src/Parser/parser.yy
r4d5e57b r1ba5803 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 25 12:28:54201713 // Update Count : 2 89312 // Last Modified On : Mon Nov 20 09:45:36 2017 13 // Update Count : 2945 14 14 // 15 15 … … 114 114 } // for 115 115 } // distExt 116 117 // There is an ambiguity for inline generic-routine return-types and generic routines. 118 // forall( otype T ) struct S { int i; } bar( T ) {} 119 // Does the forall bind to the struct or the routine, and how would it be possible to explicitly specify the binding. 120 // forall( otype T ) struct S { int T; } forall( otype W ) bar( W ) {} 121 122 void rebindForall( DeclarationNode * declSpec, DeclarationNode * funcDecl ) { 123 if ( declSpec->type->kind == TypeData::Aggregate ) { // return is aggregate definition 124 funcDecl->type->forall = declSpec->type->aggregate.params; // move forall from aggregate to function type 125 declSpec->type->aggregate.params = nullptr; 126 } // if 127 } // rebindForall 116 128 117 129 bool forall = false; // aggregate have one or more forall qualifiers ? … … 348 360 349 361 350 // Handle single shift/reduce conflict for dangling else by shifting the ELSE token. For example, this string 351 // is ambiguous: 352 // .---------. matches IF '(' comma_expression ')' statement . (reduce) 353 // if ( C ) S1 else S2 354 // `-----------------' matches IF '(' comma_expression ')' statement . (shift) ELSE statement */ 362 // Handle shift/reduce conflict for dangling else by shifting the ELSE token. For example, this string is ambiguous: 363 // .---------. matches IF '(' comma_expression ')' statement . (reduce) 364 // if ( C ) S1 else S2 365 // `-----------------' matches IF '(' comma_expression ')' statement . (shift) ELSE statement */ 355 366 // Similar issues exit with the waitfor statement. 356 367 … … 361 372 %precedence TIMEOUT // token precedence for start of TIMEOUT in WAITFOR statement 362 373 %precedence ELSE // token precedence for start of else clause in IF/WAITFOR statement 374 375 // Handle shift/reduce conflict for generic type by shifting the '(' token. For example, this string is ambiguous: 376 // forall( otype T ) struct Foo { T v; }; 377 // .-----. matches pointer to function returning a generic (which is impossible without a type) 378 // Foo ( *fp )( int ); 379 // `---' matches start of TYPEGENname '(' 380 // Must be: 381 // Foo( int ) ( *fp )( int ); 382 383 // Order of these lines matters (low-to-high precedence). 384 %precedence TYPEGENname 385 %precedence '(' 363 386 364 387 %locations // support location tracking for error messages … … 1765 1788 1766 1789 typegen_name: // CFA 1767 TYPEGENname '(' ')' 1790 TYPEGENname 1791 { $$ = DeclarationNode::newFromTypeGen( $1, nullptr ); } 1792 | TYPEGENname '(' ')' 1768 1793 { $$ = DeclarationNode::newFromTypeGen( $1, nullptr ); } 1769 1794 | TYPEGENname '(' type_list ')' … … 1809 1834 } 1810 1835 | aggregate_key attribute_list_opt typegen_name // CFA 1811 { $$ = $3->addQualifiers( $2 ); } 1836 { 1837 // Create new generic declaration with same name as previous forward declaration, where the IDENTIFIER is 1838 // switched to a TYPEGENname. Link any generic arguments from typegen_name to new generic declaration and 1839 // delete newFromTypeGen. 1840 $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $3->type->symbolic.actuals, nullptr, false )->addQualifiers( $2 ); 1841 $3->type->symbolic.name = nullptr; 1842 $3->type->symbolic.actuals = nullptr; 1843 delete $3; 1844 } 1812 1845 ; 1813 1846 … … 2380 2413 | declaration_specifier function_declarator with_clause_opt compound_statement 2381 2414 { 2415 rebindForall( $1, $2 ); 2382 2416 typedefTable.addToEnclosingScope( TypedefTable::ID ); 2383 2417 typedefTable.leaveScope(); … … 2406 2440 | declaration_specifier KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2407 2441 { 2442 rebindForall( $1, $2 ); 2408 2443 typedefTable.addToEnclosingScope( TypedefTable::ID ); 2409 2444 typedefTable.leaveScope(); -
src/ResolvExpr/Alternative.cc
r4d5e57b r1ba5803 18 18 #include <ostream> // for operator<<, ostream, basic_o... 19 19 #include <string> // for operator<<, char_traits, string 20 #include <utility> // for move 20 21 21 22 #include "Common/utility.h" // for maybeClone … … 81 82 os << std::endl; 82 83 } 84 85 void splice( AltList& dst, AltList& src ) { 86 dst.reserve( dst.size() + src.size() ); 87 for ( Alternative& alt : src ) { 88 dst.push_back( std::move(alt) ); 89 } 90 src.clear(); 91 } 92 93 void spliceBegin( AltList& dst, AltList& src ) { 94 splice( src, dst ); 95 dst.swap( src ); 96 } 97 83 98 } // namespace ResolvExpr 84 99 -
src/ResolvExpr/Alternative.h
r4d5e57b r1ba5803 17 17 18 18 #include <iosfwd> // for ostream 19 #include < list> // for list19 #include <vector> // for vector 20 20 21 21 #include "Cost.h" // for Cost … … 25 25 26 26 namespace ResolvExpr { 27 struct Alternative;28 29 typedef std::list< Alternative > AltList;30 31 27 struct Alternative { 32 28 Alternative(); … … 46 42 TypeEnvironment env; 47 43 }; 44 45 typedef std::vector< Alternative > AltList; 46 47 /// Moves all elements from src to the end of dst 48 void splice( AltList& dst, AltList& src ); 49 50 /// Moves all elements from src to the beginning of dst 51 void spliceBegin( AltList& dst, AltList& src ); 48 52 } // namespace ResolvExpr 49 53 -
src/ResolvExpr/AlternativeFinder.cc
r4d5e57b r1ba5803 16 16 #include <algorithm> // for copy 17 17 #include <cassert> // for strict_dynamic_cast, assert, assertf 18 #include <cstddef> // for size_t 18 19 #include <iostream> // for operator<<, cerr, ostream, endl 19 20 #include <iterator> // for back_insert_iterator, back_inserter 20 21 #include <list> // for _List_iterator, list, _List_const_... 21 22 #include <map> // for _Rb_tree_iterator, map, _Rb_tree_c... 22 #include <memory> // for allocator_traits<>::value_type 23 #include <memory> // for allocator_traits<>::value_type, unique_ptr 23 24 #include <utility> // for pair 24 25 #include <vector> // for vector … … 50 51 #define PRINT( text ) if ( resolvep ) { text } 51 52 //#define DEBUG_COST 53 54 using std::move; 55 56 /// copies any copyable type 57 template<typename T> 58 T copy(const T& x) { return x; } 52 59 53 60 namespace ResolvExpr { … … 179 186 expr->accept( *this ); 180 187 if ( failFast && alternatives.empty() ) { 188 PRINT( 189 std::cerr << "No reasonable alternatives for expression " << expr << std::endl; 190 ) 181 191 throw SemanticError( "No reasonable alternatives for expression ", expr ); 182 192 } … … 187 197 printAlts( alternatives, std::cerr ); 188 198 ) 189 AltList ::iterator oldBegin = alternatives.begin();190 pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives) );191 if ( failFast && alternatives.begin() == oldBegin) {199 AltList pruned; 200 pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) ); 201 if ( failFast && pruned.empty() ) { 192 202 std::ostringstream stream; 193 203 AltList winners; … … 199 209 throw SemanticError( stream.str() ); 200 210 } 201 alternatives .erase( oldBegin, alternatives.end());211 alternatives = move(pruned); 202 212 PRINT( 203 213 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; … … 571 581 /// State to iteratively build a match of parameter expressions to arguments 572 582 struct ArgPack { 573 AltList actuals; ///< Arguments included in this pack 574 TypeEnvironment env; ///< Environment for this pack 575 AssertionSet need; ///< Assertions outstanding for this pack 576 AssertionSet have; ///< Assertions found for this pack 577 OpenVarSet openVars; ///< Open variables for this pack 578 unsigned nextArg; ///< Index of next argument in arguments list 579 std::vector<Alternative> expls; ///< Exploded actuals left over from last match 580 unsigned nextExpl; ///< Index of next exploded alternative to use 581 std::vector<unsigned> tupleEls; /// Number of elements in current tuple element(s) 583 std::size_t parent; ///< Index of parent pack 584 std::unique_ptr<Expression> expr; ///< The argument stored here 585 Cost cost; ///< The cost of this argument 586 TypeEnvironment env; ///< Environment for this pack 587 AssertionSet need; ///< Assertions outstanding for this pack 588 AssertionSet have; ///< Assertions found for this pack 589 OpenVarSet openVars; ///< Open variables for this pack 590 unsigned nextArg; ///< Index of next argument in arguments list 591 unsigned tupleStart; ///< Number of tuples that start at this index 592 // TODO fix this somehow 593 std::vector<Alternative> expls; ///< Exploded actuals left over from last match 594 595 ArgPack() 596 : parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0), 597 tupleStart(0), expls() {} 582 598 583 599 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 584 600 const OpenVarSet& openVars) 585 : actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0), 586 expls(), nextExpl(0), tupleEls() {} 587 588 /// Starts a new tuple expression 589 void beginTuple() { 590 if ( ! tupleEls.empty() ) ++tupleEls.back(); 591 tupleEls.push_back(0); 592 } 601 : parent(0), expr(), cost(Cost::zero), env(env), need(need), have(have), 602 openVars(openVars), nextArg(0), tupleStart(0), expls() {} 603 604 ArgPack(std::size_t parent, Expression* expr, TypeEnvironment&& env, AssertionSet&& need, 605 AssertionSet&& have, OpenVarSet&& openVars, unsigned nextArg, 606 unsigned tupleStart = 0, Cost cost = Cost::zero, 607 std::vector<Alternative>&& expls = std::vector<Alternative>{} ) 608 : parent(parent), expr(expr->clone()), cost(cost), env(move(env)), need(move(need)), 609 have(move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart), 610 expls(move(expls)) {} 611 612 ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have, 613 OpenVarSet&& openVars, unsigned nextArg, Cost added ) 614 : parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), cost(o.cost + added), 615 env(move(env)), need(move(need)), have(move(have)), openVars(move(openVars)), 616 nextArg(nextArg), tupleStart(o.tupleStart), expls() {} 617 618 619 // ArgPack(const ArgPack& o) 620 // : parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), env(o.env), 621 // need(o.need), have(o.have), openVars(o.openVars), nextArg(o.nextArg), 622 // tupleStart(o.tupleStart), expls(o.expls) {} 623 624 // ArgPack(ArgPack&&) = default; 593 625 594 626 /// Ends a tuple expression, consolidating the appropriate actuals 595 void endTuple( ) {596 // set up new Tuple alternative627 void endTuple( const std::vector<ArgPack>& packs ) { 628 // add all expressions in tuple to list, summing cost 597 629 std::list<Expression*> exprs; 598 Cost cost = Cost::zero; 599 600 // transfer elements into alternative 601 for (unsigned i = 0; i < tupleEls.back(); ++i) { 602 exprs.push_front( actuals.back().expr ); 603 actuals.back().expr = nullptr; 604 cost += actuals.back().cost; 605 actuals.pop_back(); 606 } 607 tupleEls.pop_back(); 608 609 // build new alternative 610 actuals.emplace_back( new TupleExpr( exprs ), this->env, cost ); 611 } 612 613 /// Clones and adds an actual, returns this 614 ArgPack& withArg( Expression* expr, Cost cost = Cost::zero ) { 615 actuals.emplace_back( expr->clone(), this->env, cost ); 616 if ( ! tupleEls.empty() ) ++tupleEls.back(); 617 return *this; 630 const ArgPack* pack = this; 631 if ( expr ) { exprs.push_front( expr.release() ); } 632 while ( pack->tupleStart == 0 ) { 633 pack = &packs[pack->parent]; 634 exprs.push_front( pack->expr->clone() ); 635 cost += pack->cost; 636 } 637 // reset pack to appropriate tuple 638 expr.reset( new TupleExpr( exprs ) ); 639 tupleStart = pack->tupleStart - 1; 640 parent = pack->parent; 618 641 } 619 642 }; … … 621 644 /// Instantiates an argument to match a formal, returns false if no results left 622 645 bool instantiateArgument( Type* formalType, Initializer* initializer, 623 const std::vector< AlternativeFinder >& args, 624 std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults, 625 const SymTab::Indexer& indexer ) { 646 const std::vector< AlternativeFinder >& args, std::vector<ArgPack>& results, 647 std::size_t& genStart, const SymTab::Indexer& indexer, unsigned nTuples = 0 ) { 626 648 if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) { 627 649 // formalType is a TupleType - group actuals into a TupleExpr 628 for ( ArgPack& result : results ) { result.beginTuple(); }650 ++nTuples; 629 651 for ( Type* type : *tupleType ) { 630 652 // xxx - dropping initializer changes behaviour from previous, but seems correct 631 if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) ) 653 if ( ! instantiateArgument( 654 type, nullptr, args, results, genStart, indexer, nTuples ) ) 632 655 return false; 633 } 634 for ( ArgPack& result : results ) { result.endTuple(); } 656 nTuples = 0; 657 } 658 // re-consititute tuples for final generation 659 for ( auto i = genStart; i < results.size(); ++i ) { 660 results[i].endTuple( results ); 661 } 635 662 return true; 636 663 } else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) { 637 664 // formalType is a ttype, consumes all remaining arguments 638 665 // xxx - mixing default arguments with variadic?? 639 std::vector<ArgPack> finalResults{}; /// list of completed tuples 640 // start tuples 641 for ( ArgPack& result : results ) { 642 result.beginTuple(); 643 644 // use rest of exploded tuple if present 645 while ( result.nextExpl < result.expls.size() ) { 646 const Alternative& actual = result.expls[result.nextExpl]; 647 result.env.addActual( actual.env, result.openVars ); 648 result.withArg( actual.expr ); 649 ++result.nextExpl; 650 } 651 } 666 667 // completed tuples; will be spliced to end of results to finish 668 std::vector<ArgPack> finalResults{}; 669 652 670 // iterate until all results completed 653 while ( ! results.empty() ) { 671 std::size_t genEnd; 672 ++nTuples; 673 do { 674 genEnd = results.size(); 675 654 676 // add another argument to results 655 for ( ArgPack& result : results ) { 656 // finish result when out of arguments 657 if ( result.nextArg >= args.size() ) { 658 Type* argType = result.actuals.back().expr->get_result(); 659 if ( result.tupleEls.back() == 1 && Tuples::isTtype( argType ) ) { 660 // the case where a ttype value is passed directly is special, e.g. for 661 // argument forwarding purposes 662 // xxx - what if passing multiple arguments, last of which is ttype? 663 // xxx - what would happen if unify was changed so that unifying tuple 664 // types flattened both before unifying lists? then pass in TupleType 665 // (ttype) below. 666 result.tupleEls.pop_back(); 667 } else { 668 // collapse leftover arguments into tuple 669 result.endTuple(); 670 argType = result.actuals.back().expr->get_result(); 671 } 672 // check unification for ttype before adding to final 673 if ( unify( ttype, argType, result.env, result.need, result.have, 674 result.openVars, indexer ) ) { 675 finalResults.push_back( std::move(result) ); 676 } 677 for ( std::size_t i = genStart; i < genEnd; ++i ) { 678 // use remainder of exploded tuple if present 679 if ( ! results[i].expls.empty() ) { 680 const Alternative& actual = results[i].expls.front(); 681 682 TypeEnvironment env = results[i].env; 683 OpenVarSet openVars = results[i].openVars; 684 685 env.addActual( actual.env, openVars ); 686 687 std::vector<Alternative> newExpls( 688 std::next( results[i].expls.begin() ), results[i].expls.end() ); 689 results.emplace_back( 690 i, actual.expr, move(env), copy(results[i].need), 691 copy(results[i].have), move(openVars), results[i].nextArg, nTuples, 692 Cost::zero, move(newExpls) ); 693 677 694 continue; 678 695 } 679 696 697 // finish result when out of arguments 698 if ( results[i].nextArg >= args.size() ) { 699 ArgPack newResult{ 700 results[i].env, results[i].need, results[i].have, 701 results[i].openVars }; 702 newResult.nextArg = results[i].nextArg; 703 Type* argType; 704 705 if ( nTuples > 0 ) { 706 // first iteration, push empty tuple expression 707 newResult.parent = i; 708 std::list<Expression*> emptyList; 709 newResult.expr.reset( new TupleExpr( emptyList ) ); 710 argType = newResult.expr->get_result(); 711 } else { 712 // clone result to collect tuple 713 newResult.parent = results[i].parent; 714 newResult.cost = results[i].cost; 715 newResult.tupleStart = results[i].tupleStart; 716 newResult.expr.reset( results[i].expr->clone() ); 717 argType = newResult.expr->get_result(); 718 719 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) { 720 // the case where a ttype value is passed directly is special, 721 // e.g. for argument forwarding purposes 722 // xxx - what if passing multiple arguments, last of which is 723 // ttype? 724 // xxx - what would happen if unify was changed so that unifying 725 // tuple 726 // types flattened both before unifying lists? then pass in 727 // TupleType (ttype) below. 728 --newResult.tupleStart; 729 } else { 730 // collapse leftover arguments into tuple 731 newResult.endTuple( results ); 732 argType = newResult.expr->get_result(); 733 } 734 } 735 736 // check unification for ttype before adding to final 737 if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have, 738 newResult.openVars, indexer ) ) { 739 finalResults.push_back( move(newResult) ); 740 } 741 742 continue; 743 } 744 680 745 // add each possible next argument 681 for ( const Alternative& actual : args[result.nextArg] ) { 682 ArgPack aResult = result; // copy to clone everything 683 // add details of actual to result 684 aResult.env.addActual( actual.env, aResult.openVars ); 685 Cost cost = actual.cost; 746 auto j = results[i].nextArg; 747 for ( const Alternative& actual : args[j] ) { 748 // fresh copies of parent parameters for this iteration 749 TypeEnvironment env = results[i].env; 750 OpenVarSet openVars = results[i].openVars; 751 752 env.addActual( actual.env, openVars ); 686 753 687 754 // explode argument 688 755 std::vector<Alternative> exploded; 689 756 Tuples::explode( actual, indexer, back_inserter( exploded ) ); 690 691 // add exploded argument to tuple 692 for ( Alternative& aActual : exploded ) { 693 aResult.withArg( aActual.expr, cost ); 694 cost = Cost::zero; 757 if ( exploded.empty() ) { 758 // skip empty tuple arguments by (near-)cloning parent into next gen 759 results.emplace_back( 760 results[i], move(env), copy(results[i].need), 761 copy(results[i].have), move(openVars), j + 1, actual.cost ); 762 763 continue; 695 764 } 696 ++aResult.nextArg; 697 nextResults.push_back( std::move(aResult) ); 765 766 // trim first element from exploded 767 std::vector<Alternative> newExpls; 768 newExpls.reserve( exploded.size() - 1 ); 769 for ( std::size_t i = 1; i < exploded.size(); ++i ) { 770 newExpls.push_back( move(exploded[i]) ); 771 } 772 // add new result 773 results.emplace_back( 774 i, exploded.front().expr, move(env), copy(results[i].need), 775 copy(results[i].have), move(openVars), results[i].nextArg + 1, 776 nTuples, actual.cost, move(newExpls) ); 698 777 } 699 778 } 700 779 701 780 // reset for next round 702 results.swap( nextResults ); 703 nextResults.clear(); 704 } 705 results.swap( finalResults ); 706 return ! results.empty(); 781 genStart = genEnd; 782 nTuples = 0; 783 } while ( genEnd != results.size() ); 784 785 // splice final results onto results 786 for ( std::size_t i = 0; i < finalResults.size(); ++i ) { 787 results.push_back( move(finalResults[i]) ); 788 } 789 return ! finalResults.empty(); 707 790 } 708 791 709 792 // iterate each current subresult 710 for ( unsigned iResult = 0; iResult < results.size(); ++iResult ) { 711 ArgPack& result = results[iResult]; 712 713 if ( result.nextExpl < result.expls.size() ) { 714 // use remainder of exploded tuple if present 715 const Alternative& actual = result.expls[result.nextExpl]; 716 result.env.addActual( actual.env, result.openVars ); 793 std::size_t genEnd = results.size(); 794 for ( std::size_t i = genStart; i < genEnd; ++i ) { 795 // use remainder of exploded tuple if present 796 if ( ! results[i].expls.empty() ) { 797 const Alternative& actual = results[i].expls.front(); 798 799 TypeEnvironment env = results[i].env; 800 AssertionSet need = results[i].need, have = results[i].have; 801 OpenVarSet openVars = results[i].openVars; 802 803 env.addActual( actual.env, openVars ); 717 804 Type* actualType = actual.expr->get_result(); 718 805 … … 725 812 ) 726 813 727 if ( unify( formalType, actualType, result.env, result.need, result.have, 728 result.openVars, indexer ) ) { 729 ++result.nextExpl; 730 nextResults.push_back( std::move(result.withArg( actual.expr )) ); 814 if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) { 815 std::vector<Alternative> newExpls( 816 std::next( results[i].expls.begin() ), results[i].expls.end() ); 817 results.emplace_back( 818 i, actual.expr, move(env), move(need), move(have), move(openVars), 819 results[i].nextArg, nTuples, Cost::zero, move(newExpls) );; 731 820 } 732 821 733 822 continue; 734 } else if ( result.nextArg >= args.size() ) { 735 // use default initializers if out of arguments 823 } 824 825 // use default initializers if out of arguments 826 if ( results[i].nextArg >= args.size() ) { 736 827 if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) { 737 828 if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) { 738 if ( unify( formalType, cnst->get_type(), result.env, result.need, 739 result.have, result.openVars, indexer ) ) { 740 nextResults.push_back( std::move(result.withArg( cnstExpr )) ); 829 TypeEnvironment env = results[i].env; 830 AssertionSet need = results[i].need, have = results[i].have; 831 OpenVarSet openVars = results[i].openVars; 832 833 if ( unify( formalType, cnst->get_type(), env, need, have, openVars, 834 indexer ) ) { 835 results.emplace_back( 836 i, cnstExpr, move(env), move(need), move(have), 837 move(openVars), results[i].nextArg, nTuples ); 741 838 } 742 839 } 743 840 } 841 744 842 continue; 745 843 } 746 844 747 845 // Check each possible next argument 748 for ( const Alternative& actual : args[result.nextArg] ) { 749 ArgPack aResult = result; // copy to clone everything 750 // add details of actual to result 751 aResult.env.addActual( actual.env, aResult.openVars ); 846 auto j = results[i].nextArg; 847 for ( const Alternative& actual : args[j] ) { 848 // fresh copies of parent parameters for this iteration 849 TypeEnvironment env = results[i].env; 850 AssertionSet need = results[i].need, have = results[i].have; 851 OpenVarSet openVars = results[i].openVars; 852 853 env.addActual( actual.env, openVars ); 752 854 753 855 // explode argument … … 755 857 Tuples::explode( actual, indexer, back_inserter( exploded ) ); 756 858 if ( exploded.empty() ) { 757 // skip empty tuple arguments 758 ++aResult.nextArg; 759 results.push_back( std::move(aResult) ); 859 // skip empty tuple arguments by (near-)cloning parent into next gen 860 results.emplace_back( 861 results[i], move(env), move(need), move(have), move(openVars), j + 1, 862 actual.cost ); 863 760 864 continue; 761 865 } … … 774 878 775 879 // attempt to unify types 776 if ( unify( formalType, actualType, aResult.env, aResult.need, aResult.have, aResult.openVars, indexer ) ) { 777 // add argument 778 aResult.withArg( aActual.expr, actual.cost ); 779 ++aResult.nextArg; 780 if ( exploded.size() > 1 ) { 781 // other parts of tuple left over 782 aResult.expls = std::move( exploded ); 783 aResult.nextExpl = 1; 880 if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) { 881 // trim first element from exploded 882 std::vector<Alternative> newExpls; 883 newExpls.reserve( exploded.size() - 1 ); 884 for ( std::size_t i = 1; i < exploded.size(); ++i ) { 885 newExpls.push_back( move(exploded[i]) ); 784 886 } 785 nextResults.push_back( std::move(aResult) ); 887 // add new result 888 results.emplace_back( 889 i, aActual.expr, move(env), move(need), move(have), move(openVars), 890 j + 1, nTuples, actual.cost, move(newExpls) ); 786 891 } 787 892 } … … 789 894 790 895 // reset for next parameter 791 results.swap( nextResults ); 792 nextResults.clear(); 793 794 return ! results.empty(); 896 genStart = genEnd; 897 898 return genEnd != results.size(); 899 } 900 901 template<typename OutputIterator> 902 void AlternativeFinder::validateFunctionAlternative( const Alternative &func, ArgPack& result, 903 const std::vector<ArgPack>& results, OutputIterator out ) { 904 ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() ); 905 // sum cost and accumulate actuals 906 std::list<Expression*>& args = appExpr->get_args(); 907 Cost cost = Cost::zero; 908 const ArgPack* pack = &result; 909 while ( pack->expr ) { 910 args.push_front( pack->expr->clone() ); 911 cost += pack->cost; 912 pack = &results[pack->parent]; 913 } 914 // build and validate new alternative 915 Alternative newAlt( appExpr, result.env, cost ); 916 PRINT( 917 std::cerr << "instantiate function success: " << appExpr << std::endl; 918 std::cerr << "need assertions:" << std::endl; 919 printAssertionSet( result.need, std::cerr, 8 ); 920 ) 921 inferParameters( result.need, result.have, newAlt, result.openVars, out ); 795 922 } 796 923 … … 818 945 819 946 // iteratively build matches, one parameter at a time 820 std::vector<ArgPack> results{ ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } }; 821 std::vector<ArgPack> nextResults{}; 947 std::vector<ArgPack> results; 948 results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } ); 949 std::size_t genStart = 0; 950 822 951 for ( DeclarationWithType* formal : funcType->get_parameters() ) { 823 952 ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal ); 824 953 if ( ! instantiateArgument( 825 obj->get_type(), obj->get_init(), args, results, nextResults, indexer ) )954 obj->get_type(), obj->get_init(), args, results, genStart, indexer ) ) 826 955 return; 827 956 } 828 957 829 // filter out results that don't use all the arguments, and aren't variadic830 std::vector<ArgPack> finalResults{};831 958 if ( funcType->get_isVarArgs() ) { 832 for ( ArgPack& result : results ) { 833 // use rest of exploded tuple if present 834 while ( result.nextExpl < result.expls.size() ) { 835 const Alternative& actual = result.expls[result.nextExpl]; 836 result.env.addActual( actual.env, result.openVars ); 837 result.withArg( actual.expr ); 838 ++result.nextExpl; 839 } 840 } 841 842 while ( ! results.empty() ) { 843 // build combinations for all remaining arguments 844 for ( ArgPack& result : results ) { 845 // keep if used all arguments 846 if ( result.nextArg >= args.size() ) { 847 finalResults.push_back( std::move(result) ); 959 // append any unused arguments to vararg pack 960 std::size_t genEnd; 961 do { 962 genEnd = results.size(); 963 964 // iterate results 965 for ( std::size_t i = genStart; i < genEnd; ++i ) { 966 // use remainder of exploded tuple if present 967 if ( ! results[i].expls.empty() ) { 968 const Alternative& actual = results[i].expls.front(); 969 970 TypeEnvironment env = results[i].env; 971 OpenVarSet openVars = results[i].openVars; 972 973 env.addActual( actual.env, openVars ); 974 975 std::vector<Alternative> newExpls( 976 std::next( results[i].expls.begin() ), results[i].expls.end() ); 977 results.emplace_back( 978 i, actual.expr, move(env), copy(results[i].need), 979 copy(results[i].have), move(openVars), results[i].nextArg, 0, 980 Cost::zero, move(newExpls) ); 981 848 982 continue; 849 983 } 850 984 985 // finish result when out of arguments 986 if ( results[i].nextArg >= args.size() ) { 987 validateFunctionAlternative( func, results[i], results, out ); 988 989 continue; 990 } 991 851 992 // add each possible next argument 852 for ( const Alternative& actual : args[result.nextArg] ) { 853 ArgPack aResult = result; // copy to clone everything 854 // add details of actual to result 855 aResult.env.addActual( actual.env, aResult.openVars ); 856 Cost cost = actual.cost; 993 auto j = results[i].nextArg; 994 for ( const Alternative& actual : args[j] ) { 995 // fresh copies of parent parameters for this iteration 996 TypeEnvironment env = results[i].env; 997 OpenVarSet openVars = results[i].openVars; 998 999 env.addActual( actual.env, openVars ); 857 1000 858 1001 // explode argument 859 1002 std::vector<Alternative> exploded; 860 1003 Tuples::explode( actual, indexer, back_inserter( exploded ) ); 861 862 // add exploded argument to arg list 863 for ( Alternative& aActual : exploded ) { 864 aResult.withArg( aActual.expr, cost ); 865 cost = Cost::zero; 1004 if ( exploded.empty() ) { 1005 // skip empty tuple arguments by (near-)cloning parent into next gen 1006 results.emplace_back( 1007 results[i], move(env), copy(results[i].need), 1008 copy(results[i].have), move(openVars), j + 1, actual.cost ); 1009 continue; 866 1010 } 867 ++aResult.nextArg; 868 nextResults.push_back( std::move(aResult) ); 1011 1012 // trim first element from exploded 1013 std::vector<Alternative> newExpls; 1014 newExpls.reserve( exploded.size() - 1 ); 1015 for ( std::size_t i = 1; i < exploded.size(); ++i ) { 1016 newExpls.push_back( move(exploded[i]) ); 1017 } 1018 // add new result 1019 results.emplace_back( 1020 i, exploded.front().expr, move(env), copy(results[i].need), 1021 copy(results[i].have), move(openVars), j + 1, 0, 1022 actual.cost, move(newExpls) ); 869 1023 } 870 1024 } 871 1025 872 // reset for next round 873 results.swap( nextResults ); 874 nextResults.clear(); 875 } 1026 genStart = genEnd; 1027 } while ( genEnd != results.size() ); 876 1028 } else { 877 1029 // filter out results that don't use all the arguments 878 for ( ArgPack& result : results ) { 879 if ( result.nextExpl >= result.expls.size() && result.nextArg >= args.size() ) { 880 finalResults.push_back( std::move(result) ); 1030 for ( std::size_t i = genStart; i < results.size(); ++i ) { 1031 ArgPack& result = results[i]; 1032 if ( result.expls.empty() && result.nextArg >= args.size() ) { 1033 validateFunctionAlternative( func, result, results, out ); 881 1034 } 882 1035 } 883 }884 885 // validate matching combos, add to final result list886 for ( ArgPack& result : finalResults ) {887 ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );888 Alternative newAlt( appExpr, result.env, sumCost( result.actuals ) );889 makeExprList( result.actuals, appExpr->get_args() );890 PRINT(891 std::cerr << "instantiate function success: " << appExpr << std::endl;892 std::cerr << "need assertions:" << std::endl;893 printAssertionSet( result.need, std::cerr, 8 );894 )895 inferParameters( result.need, result.have, newAlt, result.openVars, out );896 1036 } 897 1037 } … … 956 1096 if ( ! funcOpFinder.alternatives.empty() ) { 957 1097 // add function alternatives to front of argument list 958 argAlternatives.insert( argAlternatives.begin(), std::move(funcFinder) );1098 argAlternatives.insert( argAlternatives.begin(), move(funcFinder) ); 959 1099 960 1100 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); … … 982 1122 983 1123 // compute conversionsion costs 984 for ( Alt List::iterator withFunc = candidates.begin(); withFunc != candidates.end(); ++withFunc) {985 Cost cvtCost = computeApplicationConversionCost( *withFunc, indexer );1124 for ( Alternative& withFunc : candidates ) { 1125 Cost cvtCost = computeApplicationConversionCost( withFunc, indexer ); 986 1126 987 1127 PRINT( 988 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc ->expr );1128 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr ); 989 1129 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() ); 990 1130 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() ); … … 995 1135 printAll( appExpr->get_args(), std::cerr, 8 ); 996 1136 std::cerr << "bindings are:" << std::endl; 997 withFunc ->env.print( std::cerr, 8 );1137 withFunc.env.print( std::cerr, 8 ); 998 1138 std::cerr << "cost of conversion is:" << cvtCost << std::endl; 999 1139 ) 1000 1140 if ( cvtCost != Cost::infinity ) { 1001 withFunc ->cvtCost = cvtCost;1002 alternatives.push_back( *withFunc );1141 withFunc.cvtCost = cvtCost; 1142 alternatives.push_back( withFunc ); 1003 1143 } // if 1004 1144 } // for 1005 1145 1006 candidates.clear(); 1007 candidates.splice( candidates.end(), alternatives ); 1146 candidates = move(alternatives); 1008 1147 1009 1148 // use a new list so that alternatives are not examined by addAnonConversions twice. … … 1011 1150 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) ); 1012 1151 1013 // function may return struct or union value, in which case we need to add alternatives for implicit1014 // conversions to each of the anonymous members, must happen after findMinCost since anon conversions1015 // are never the cheapest expression1152 // function may return struct or union value, in which case we need to add alternatives 1153 // for implicitconversions to each of the anonymous members, must happen after findMinCost 1154 // since anon conversions are never the cheapest expression 1016 1155 for ( const Alternative & alt : winners ) { 1017 1156 addAnonConversions( alt ); 1018 1157 } 1019 alternatives.splice( alternatives.begin(), winners );1158 spliceBegin( alternatives, winners ); 1020 1159 1021 1160 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) { … … 1041 1180 AlternativeFinder finder( indexer, env ); 1042 1181 finder.find( addressExpr->get_arg() ); 1043 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) { 1044 if ( isLvalue( i->expr ) ) { 1045 alternatives.push_back( Alternative( new AddressExpr( i->expr->clone() ), i->env, i->cost ) ); 1182 for ( Alternative& alt : finder.alternatives ) { 1183 if ( isLvalue( alt.expr ) ) { 1184 alternatives.push_back( 1185 Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } ); 1046 1186 } // if 1047 1187 } // for … … 1049 1189 1050 1190 void AlternativeFinder::visit( LabelAddressExpr * expr ) { 1051 alternatives.push_back( Alternative ( expr->clone(), env, Cost::zero));1191 alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } ); 1052 1192 } 1053 1193 … … 1091 1231 1092 1232 AltList candidates; 1093 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i) {1233 for ( Alternative & alt : finder.alternatives ) { 1094 1234 AssertionSet needAssertions, haveAssertions; 1095 1235 OpenVarSet openVars; … … 1099 1239 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast 1100 1240 // to. 1101 int discardedValues = i->expr->get_result()->size() - castExpr->get_result()->size();1241 int discardedValues = alt.expr->get_result()->size() - castExpr->get_result()->size(); 1102 1242 if ( discardedValues < 0 ) continue; 1103 1243 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not 1104 1244 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3])) 1105 1245 // unification run for side-effects 1106 unify( castExpr->get_result(), i->expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer ); 1107 Cost thisCost = castCost( i->expr->get_result(), castExpr->get_result(), indexer, i->env ); 1246 unify( castExpr->get_result(), alt.expr->get_result(), alt.env, needAssertions, 1247 haveAssertions, openVars, indexer ); 1248 Cost thisCost = castCost( alt.expr->get_result(), castExpr->get_result(), indexer, 1249 alt.env ); 1250 PRINT( 1251 std::cerr << "working on cast with result: " << castExpr->result << std::endl; 1252 std::cerr << "and expr type: " << alt.expr->result << std::endl; 1253 std::cerr << "env: " << alt.env << std::endl; 1254 ) 1108 1255 if ( thisCost != Cost::infinity ) { 1256 PRINT( 1257 std::cerr << "has finite cost." << std::endl; 1258 ) 1109 1259 // count one safe conversion for each value that is thrown away 1110 1260 thisCost.incSafe( discardedValues ); 1111 Alternative newAlt( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost ); 1112 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) ); 1261 Alternative newAlt( restructureCast( alt.expr->clone(), toType ), alt.env, 1262 alt.cost, thisCost ); 1263 inferParameters( needAssertions, haveAssertions, newAlt, openVars, 1264 back_inserter( candidates ) ); 1113 1265 } // if 1114 1266 } // for … … 1397 1549 1398 1550 void AlternativeFinder::visit( UntypedTupleExpr *tupleExpr ) { 1399 std::list< AlternativeFinder > subExprAlternatives; 1400 findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) ); 1401 std::list< AltList > possibilities; 1402 combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) ); 1403 for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) { 1551 std::vector< AlternativeFinder > subExprAlternatives; 1552 findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), 1553 back_inserter( subExprAlternatives ) ); 1554 std::vector< AltList > possibilities; 1555 combos( subExprAlternatives.begin(), subExprAlternatives.end(), 1556 back_inserter( possibilities ) ); 1557 for ( const AltList& alts : possibilities ) { 1404 1558 std::list< Expression * > exprs; 1405 makeExprList( *i, exprs );1559 makeExprList( alts, exprs ); 1406 1560 1407 1561 TypeEnvironment compositeEnv; 1408 simpleCombineEnvironments( i->begin(), i->end(), compositeEnv ); 1409 alternatives.push_back( Alternative( new TupleExpr( exprs ) , compositeEnv, sumCost( *i ) ) ); 1562 simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv ); 1563 alternatives.push_back( 1564 Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } ); 1410 1565 } // for 1411 1566 } -
src/ResolvExpr/AlternativeFinder.h
r4d5e57b r1ba5803 31 31 32 32 namespace ResolvExpr { 33 struct ArgPack; 34 33 35 class AlternativeFinder : public Visitor { 34 36 public: … … 36 38 37 39 AlternativeFinder( const AlternativeFinder& o ) 38 : indexer(o.indexer), alternatives(o.alternatives), env(o.env), 40 : indexer(o.indexer), alternatives(o.alternatives), env(o.env), 39 41 targetType(o.targetType) {} 40 42 41 43 AlternativeFinder( AlternativeFinder&& o ) 42 : indexer(o.indexer), alternatives(std::move(o.alternatives)), env(o.env), 44 : indexer(o.indexer), alternatives(std::move(o.alternatives)), env(o.env), 43 45 targetType(o.targetType) {} 44 46 45 47 AlternativeFinder& operator= ( const AlternativeFinder& o ) { 46 48 if (&o == this) return *this; 47 49 48 50 // horrific nasty hack to rebind references... 49 51 alternatives.~AltList(); … … 54 56 AlternativeFinder& operator= ( AlternativeFinder&& o ) { 55 57 if (&o == this) return *this; 56 58 57 59 // horrific nasty hack to rebind references... 58 60 alternatives.~AltList(); … … 126 128 /// Adds alternatives for offsetof expressions, given the base type and name of the member 127 129 template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name ); 130 /// Takes a final result and checks if its assertions can be satisfied 131 template<typename OutputIterator> 132 void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out ); 133 /// Finds matching alternatives for a function, given a set of arguments 128 134 template<typename OutputIterator> 129 135 void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const std::vector< AlternativeFinder >& args, OutputIterator out ); 136 /// Checks if assertion parameters match for a new alternative 130 137 template< typename OutputIterator > 131 138 void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ); -
src/ResolvExpr/Resolver.cc
r4d5e57b r1ba5803 18 18 #include <memory> // for allocator, allocator_traits<... 19 19 #include <tuple> // for get 20 #include <vector> 20 21 21 22 #include "Alternative.h" // for Alternative, AltList … … 411 412 412 413 // Find all alternatives for all arguments in canonical form 413 std:: list< AlternativeFinder > argAlternatives;414 std::vector< AlternativeFinder > argAlternatives; 414 415 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) ); 415 416 416 417 // List all combinations of arguments 417 std:: list< AltList > possibilities;418 std::vector< AltList > possibilities; 418 419 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) ); 419 420 -
src/ResolvExpr/TypeEnvironment.cc
r4d5e57b r1ba5803 212 212 } 213 213 214 std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) { 215 env.print( out ); 216 return out; 217 } 214 218 } // namespace ResolvExpr 215 219 -
src/ResolvExpr/TypeEnvironment.h
r4d5e57b r1ba5803 86 86 TypeEnvironment *clone() const { return new TypeEnvironment( *this ); } 87 87 88 /// Iteratively adds the environment of a new actual (with allowWidening = false), 88 /// Iteratively adds the environment of a new actual (with allowWidening = false), 89 89 /// and extracts open variables. 90 90 void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ); … … 114 114 return sub.applyFree( type ); 115 115 } 116 117 std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ); 116 118 } // namespace ResolvExpr 117 119 -
src/ResolvExpr/typeops.h
r4d5e57b r1ba5803 16 16 #pragma once 17 17 18 #include <vector> 19 18 20 #include "SynTree/SynTree.h" 19 21 #include "SynTree/Type.h" … … 28 30 void combos( InputIterator begin, InputIterator end, OutputIterator out ) { 29 31 typedef typename InputIterator::value_type SetType; 30 typedef typename std:: list< typename SetType::value_type > ListType;32 typedef typename std::vector< typename SetType::value_type > ListType; 31 33 32 34 if ( begin == end ) { … … 38 40 begin++; 39 41 40 std:: list< ListType > recursiveResult;42 std::vector< ListType > recursiveResult; 41 43 combos( begin, end, back_inserter( recursiveResult ) ); 42 44 43 for ( typename std::list< ListType >::const_iterator i = recursiveResult.begin(); i != recursiveResult.end(); ++i ) { 44 for ( typename ListType::const_iterator j = current->begin(); j != current->end(); ++j ) { 45 ListType result; 46 std::back_insert_iterator< ListType > inserter = back_inserter( result ); 47 *inserter++ = *j; 48 std::copy( i->begin(), i->end(), inserter ); 49 *out++ = result; 50 } // for 51 } // for 45 for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) { 46 ListType result; 47 std::back_insert_iterator< ListType > inserter = back_inserter( result ); 48 *inserter++ = j; 49 std::copy( i.begin(), i.end(), inserter ); 50 *out++ = result; 51 } 52 52 } 53 53 -
src/SymTab/Autogen.cc
r4d5e57b r1ba5803 62 62 void previsit( FunctionDecl * functionDecl ); 63 63 64 void previsit( FunctionType * ftype );65 void previsit( PointerType * ptype );66 67 64 void previsit( CompoundStmt * compoundStmt ); 68 65 … … 72 69 unsigned int functionNesting = 0; // current level of nested functions 73 70 74 InitTweak::ManagedTypes managedTypes;75 71 std::vector< FuncData > data; 76 72 }; … … 622 618 // generate ctor/dtors/assign for typedecls, e.g., otype T = int *; 623 619 void AutogenerateRoutines::previsit( TypeDecl * typeDecl ) { 624 visit_children = false;625 620 if ( ! typeDecl->base ) return; 626 621 … … 628 623 TypeFuncGenerator gen( typeDecl, &refType, data, functionNesting, indexer ); 629 624 generateFunctions( gen, declsToAddAfter ); 630 } 631 632 void AutogenerateRoutines::previsit( FunctionType *) { 633 // ensure that we don't add assignment ops for types defined as part of the function 634 visit_children = false; 635 } 636 637 void AutogenerateRoutines::previsit( PointerType *) { 638 // ensure that we don't add assignment ops for types defined as part of the pointer 639 visit_children = false; 625 640 626 } 641 627 … … 645 631 } 646 632 647 void AutogenerateRoutines::previsit( FunctionDecl * functionDecl ) { 648 visit_children = false; 649 // record the existence of this function as appropriate 650 managedTypes.handleDWT( functionDecl ); 651 652 maybeAccept( functionDecl->type, *visitor ); 633 void AutogenerateRoutines::previsit( FunctionDecl * ) { 634 // Track whether we're currently in a function. 635 // Can ignore function type idiosyncrasies, because function type can never 636 // declare a new type. 653 637 functionNesting += 1; 654 maybeAccept( functionDecl->statements, *visitor ); 655 functionNesting -= 1; 638 GuardAction( [this]() { functionNesting -= 1; } ); 656 639 } 657 640 658 641 void AutogenerateRoutines::previsit( CompoundStmt * ) { 659 GuardScope( managedTypes );660 642 GuardScope( structsDone ); 661 643 } -
src/SymTab/Autogen.h
r4d5e57b r1ba5803 56 56 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. 57 57 template< typename OutputIterator > 58 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false, bool forward = true );58 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true ); 59 59 60 60 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types. 61 61 /// optionally returns a statement which must be inserted prior to the containing loop, if there is one 62 62 template< typename OutputIterator > 63 Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, bool addCast = false) {63 Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) { 64 64 bool isReferenceCtorDtor = false; 65 65 if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) { … … 68 68 fname = "?=?"; 69 69 dstParam = new AddressExpr( dstParam ); 70 addCast = false;70 addCast = nullptr; 71 71 isReferenceCtorDtor = true; 72 72 } … … 83 83 // remove lvalue as a qualifier, this can change to 84 84 // type->get_qualifiers() = Type::Qualifiers(); 85 assert( type ); 86 Type * castType = type->clone(); 85 Type * castType = addCast->clone(); 87 86 castType->get_qualifiers() -= Type::Qualifiers( Type::Lvalue | Type::Const | Type::Volatile | Type::Restrict | Type::Atomic ); 88 87 // castType->set_lvalue( true ); // xxx - might not need this … … 115 114 /// If forward is true, loop goes from 0 to N-1, else N-1 to 0 116 115 template< typename OutputIterator > 117 void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, bool addCast = false, bool forward = true ) {116 void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) { 118 117 static UniqueName indexName( "_index" ); 119 118 120 119 // for a flexible array member nothing is done -- user must define own assignment 121 if ( ! array->get_dimension() ) return ; 120 if ( ! array->get_dimension() ) return; 121 122 if ( addCast ) { 123 // peel off array layer from cast 124 ArrayType * at = strict_dynamic_cast< ArrayType * >( addCast ); 125 addCast = at->base; 126 } 122 127 123 128 Expression * begin, * end, * update, * cmp; … … 171 176 172 177 template< typename OutputIterator > 173 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, booladdCast, bool forward ) {178 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) { 174 179 if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { 175 180 genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward ); … … 191 196 if ( isUnnamedBitfield( obj ) ) return; 192 197 193 bool addCast = (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ); 198 Type * addCast = nullptr; 199 if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ) ) { 200 assert( dstParam->result ); 201 addCast = dstParam->result; 202 } 194 203 std::list< Statement * > stmts; 195 204 genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->type, addCast, forward ); -
src/SymTab/Indexer.cc
r4d5e57b r1ba5803 567 567 } 568 568 569 void Indexer::addIds( const std::list< DeclarationWithType * > & decls ) { 570 for ( auto d : decls ) { 571 addId( d ); 572 } 573 } 574 575 void Indexer::addTypes( const std::list< TypeDecl * > & tds ) { 576 for ( auto td : tds ) { 577 addType( td ); 578 addIds( td->assertions ); 579 } 580 } 581 582 void Indexer::addFunctionType( FunctionType * ftype ) { 583 addTypes( ftype->forall ); 584 addIds( ftype->returnVals ); 585 addIds( ftype->parameters ); 586 } 587 569 588 void Indexer::enterScope() { 570 589 ++scope; -
src/SymTab/Indexer.h
r4d5e57b r1ba5803 76 76 void addTrait( TraitDecl *decl ); 77 77 78 /// convenience function for adding a list of Ids to the indexer 79 void addIds( const std::list< DeclarationWithType * > & decls ); 80 81 /// convenience function for adding a list of forall parameters to the indexer 82 void addTypes( const std::list< TypeDecl * > & tds ); 83 84 /// convenience function for adding all of the declarations in a function type to the indexer 85 void addFunctionType( FunctionType * ftype ); 86 78 87 bool doDebug = false; ///< Display debugging trace? 79 88 private: -
src/SymTab/Validate.cc
r4d5e57b r1ba5803 124 124 125 125 /// Associates forward declarations of aggregates with their definitions 126 struct LinkReferenceToTypes final : public WithIndexer {126 struct LinkReferenceToTypes final : public WithIndexer, public WithGuards { 127 127 LinkReferenceToTypes( const Indexer *indexer ); 128 128 void postvisit( TypeInstType *typeInst ); … … 137 137 void postvisit( UnionDecl *unionDecl ); 138 138 void postvisit( TraitDecl * traitDecl ); 139 140 void previsit( StructDecl *structDecl ); 141 void previsit( UnionDecl *unionDecl ); 142 143 void renameGenericParams( std::list< TypeDecl * > & params ); 139 144 140 145 private: … … 147 152 ForwardStructsType forwardStructs; 148 153 ForwardUnionsType forwardUnions; 154 /// true if currently in a generic type body, so that type parameter instances can be renamed appropriately 155 bool inGeneric = false; 149 156 }; 150 157 … … 423 430 } 424 431 432 void checkGenericParameters( ReferenceToType * inst ) { 433 for ( Expression * param : inst->parameters ) { 434 if ( ! dynamic_cast< TypeExpr * >( param ) ) { 435 throw SemanticError( "Expression parameters for generic types are currently unsupported: ", inst ); 436 } 437 } 438 } 439 425 440 void LinkReferenceToTypes::postvisit( StructInstType *structInst ) { 426 441 StructDecl *st = local_indexer->lookupStruct( structInst->get_name() ); … … 434 449 forwardStructs[ structInst->get_name() ].push_back( structInst ); 435 450 } // if 451 checkGenericParameters( structInst ); 436 452 } 437 453 … … 446 462 forwardUnions[ unionInst->get_name() ].push_back( unionInst ); 447 463 } // if 464 checkGenericParameters( unionInst ); 448 465 } 449 466 … … 525 542 // need to carry over the 'sized' status of each decl in the instance 526 543 for ( auto p : group_iterate( traitDecl->get_parameters(), traitInst->get_parameters() ) ) { 527 TypeExpr * expr = strict_dynamic_cast< TypeExpr * >( std::get<1>(p) ); 544 TypeExpr * expr = dynamic_cast< TypeExpr * >( std::get<1>(p) ); 545 if ( ! expr ) { 546 throw SemanticError( "Expression parameters for trait instances are currently unsupported: ", std::get<1>(p) ); 547 } 528 548 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( expr->get_type() ) ) { 529 549 TypeDecl * formalDecl = std::get<0>(p); … … 546 566 } // if 547 567 } // if 568 } 569 570 void LinkReferenceToTypes::renameGenericParams( std::list< TypeDecl * > & params ) { 571 // rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g. 572 // forall(otype T) 573 // struct Box { 574 // T x; 575 // }; 576 // forall(otype T) 577 // void f(Box(T) b) { 578 // ... 579 // } 580 // The T in Box and the T in f are different, so internally the naming must reflect that. 581 GuardValue( inGeneric ); 582 inGeneric = ! params.empty(); 583 for ( TypeDecl * td : params ) { 584 td->name = "__" + td->name + "_generic_"; 585 } 586 } 587 588 void LinkReferenceToTypes::previsit( StructDecl * structDecl ) { 589 renameGenericParams( structDecl->parameters ); 590 } 591 592 void LinkReferenceToTypes::previsit( UnionDecl * unionDecl ) { 593 renameGenericParams( unionDecl->parameters ); 548 594 } 549 595 … … 575 621 576 622 void LinkReferenceToTypes::postvisit( TypeInstType *typeInst ) { 623 // ensure generic parameter instances are renamed like the base type 624 if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name; 577 625 if ( NamedTypeDecl *namedTypeDecl = local_indexer->lookupType( typeInst->get_name() ) ) { 578 626 if ( TypeDecl *typeDecl = dynamic_cast< TypeDecl * >( namedTypeDecl ) ) { -
src/SynTree/Expression.cc
r4d5e57b r1ba5803 324 324 return makeSub( refType->get_base() ); 325 325 } else if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) { 326 return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst-> get_parameters().begin() );326 return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() ); 327 327 } else if ( UnionInstType * aggInst = dynamic_cast< UnionInstType * >( t ) ) { 328 return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst-> get_parameters().begin() );328 return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() ); 329 329 } else { 330 330 assertf( false, "makeSub expects struct or union type for aggregate, but got: %s", toString( t ).c_str() ); -
src/Tuples/TupleAssignment.cc
r4d5e57b r1ba5803 251 251 // combine assignment environments into combined expression environment 252 252 simpleCombineEnvironments( current.begin(), current.end(), matcher->compositeEnv ); 253 currentFinder.get_alternatives().push_front( ResolvExpr::Alternative( 253 // xxx -- was push_front 254 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative( 254 255 new TupleAssignExpr(solved_assigns, matcher->tmpDecls), matcher->compositeEnv, 255 256 ResolvExpr::sumCost( current ) + matcher->baseCost ) ); -
src/benchmark/Makefile.am
r4d5e57b r1ba5803 24 24 repeats = 30 25 25 TIME_FORMAT = "%E" 26 PRINT_FORMAT = '%20s\t'26 PRINT_FORMAT = %20s: #Comments needed for spacing 27 27 28 28 .NOTPARALLEL: … … 217 217 218 218 compile-array$(EXEEXT): 219 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c 219 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 220 220 221 221 compile-attributes$(EXEEXT): 222 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c 222 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 223 223 224 224 compile-empty$(EXEEXT): 225 @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c 225 @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 226 226 227 227 compile-expression$(EXEEXT): 228 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c 228 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 229 229 230 230 compile-io$(EXEEXT): 231 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c 231 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 232 232 233 233 compile-monitor$(EXEEXT): 234 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/monitor.c 234 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 235 235 236 236 compile-operators$(EXEEXT): 237 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c 237 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 238 238 239 239 compile-thread$(EXEEXT): 240 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/thread.c 240 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/thread.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 241 241 242 242 compile-typeof$(EXEEXT): 243 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c 244 243 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 244 -
src/benchmark/Makefile.in
r4d5e57b r1ba5803 254 254 repeats = 30 255 255 TIME_FORMAT = "%E" 256 PRINT_FORMAT = '%20s\t'256 PRINT_FORMAT = %20s: #Comments needed for spacing 257 257 all: all-am 258 258 … … 623 623 624 624 compile-array$(EXEEXT): 625 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c 625 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 626 626 627 627 compile-attributes$(EXEEXT): 628 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c 628 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 629 629 630 630 compile-empty$(EXEEXT): 631 @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c 631 @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 632 632 633 633 compile-expression$(EXEEXT): 634 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c 634 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 635 635 636 636 compile-io$(EXEEXT): 637 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c 637 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 638 638 639 639 compile-monitor$(EXEEXT): 640 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/monitor.c 640 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 641 641 642 642 compile-operators$(EXEEXT): 643 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c 643 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 644 644 645 645 compile-thread$(EXEEXT): 646 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/thread.c 646 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/thread.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 647 647 648 648 compile-typeof$(EXEEXT): 649 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c 649 @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 650 650 651 651 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
src/tests/.expect/castError.txt
r4d5e57b r1ba5803 5 5 charAlternatives are: 6 6 Cost ( 1, 0, 0, 0 ): Cast of: 7 Variable Expression: f: signed int 7 Variable Expression: f: function 8 accepting unspecified arguments 9 ... returning nothing 10 8 11 ... to: 9 12 char … … 23 26 24 27 Cost ( 1, 0, 0, 0 ): Cast of: 25 Variable Expression: f: function 26 accepting unspecified arguments 27 ... returning nothing 28 28 Variable Expression: f: signed int 29 29 ... to: 30 30 char
Note: See TracChangeset
for help on using the changeset viewer.