Changeset f80e0218 for src/ResolvExpr
- Timestamp:
- Jun 30, 2016, 4:32:56 PM (10 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, gc_noraii, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, stuck-waitfor-destruct, with_gc
- Children:
- ea29e73
- Parents:
- 1b5c81ed (diff), 84d4d6f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- src/ResolvExpr
- Files:
-
- 8 edited
-
AlternativeFinder.cc (modified) (14 diffs)
-
AlternativeFinder.h (modified) (3 diffs)
-
CommonType.cc (modified) (3 diffs)
-
ConversionCost.cc (modified) (2 diffs)
-
RenameVars.cc (modified) (4 diffs)
-
Resolver.cc (modified) (18 diffs)
-
Resolver.h (modified) (2 diffs)
-
typeops.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/AlternativeFinder.cc
r1b5c81ed rf80e0218 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sat May 16 23:52:08 2015 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Wed Feb 10 17:00:04 201613 // Update Count : 2 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jun 13 16:13:54 2016 13 // Update Count : 25 14 14 // 15 15 … … 19 19 #include <functional> 20 20 #include <cassert> 21 #include <unordered_map> 22 #include <utility> 23 #include <vector> 21 24 22 25 #include "AlternativeFinder.h" … … 39 42 #include "Tuples/NameMatcher.h" 40 43 #include "Common/utility.h" 44 #include "InitTweak/InitTweak.h" 41 45 42 46 extern bool resolvep; … … 407 411 } 408 412 409 static const int recursionLimit = 10; 413 // /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included 414 //typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet; 415 416 static const int recursionLimit = /*10*/ 4; ///< Limit to depth of recursion satisfaction 417 //static const unsigned recursionParentLimit = 1; ///< Limit to the number of times an assertion can recursively use itself 410 418 411 419 void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) { … … 416 424 } 417 425 } 418 426 419 427 template< typename ForwardIterator, typename OutputIterator > 420 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, int level, const SymTab::Indexer &indexer, OutputIterator out ) { 428 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/ 429 int level, const SymTab::Indexer &indexer, OutputIterator out ) { 421 430 if ( begin == end ) { 422 431 if ( newNeed.empty() ) { … … 431 440 printAssertionSet( newNeed, std::cerr, 8 ); 432 441 ) 433 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );442 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, /*needParents,*/ level+1, indexer, out ); 434 443 return; 435 444 } … … 438 447 ForwardIterator cur = begin++; 439 448 if ( ! cur->second ) { 440 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );449 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out ); 441 450 } 442 451 DeclarationWithType *curDecl = cur->first; … … 455 464 std::cerr << std::endl; 456 465 ) 466 457 467 AssertionSet newHave, newerNeed( newNeed ); 458 468 TypeEnvironment newEnv( newAlt.env ); … … 477 487 newerAlt.env = newEnv; 478 488 assert( (*candidate)->get_uniqueId() ); 479 Expression *varExpr = new VariableExpr( static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) ) ); 489 DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) ); 490 //AssertionParentSet newNeedParents( needParents ); 491 // skip repeatingly-self-recursive assertion satisfaction 492 // DOESN'T WORK: grandchild nodes conflict with their cousins 493 //if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue; 494 Expression *varExpr = new VariableExpr( candDecl ); 480 495 deleteAll( varExpr->get_results() ); 481 496 varExpr->get_results().clear(); … … 491 506 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions 492 507 appExpr->get_inferParams()[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr ); 493 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );508 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out ); 494 509 } else { 495 510 delete adjType; … … 513 528 addToIndexer( have, decls ); 514 529 AssertionSet newNeed; 515 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out ); 530 //AssertionParentSet needParents; 531 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out ); 516 532 // PRINT( 517 533 // std::cerr << "declaration 14 is "; … … 546 562 547 563 { 548 NameExpr *fname = 0;; 549 if ( ( fname = dynamic_cast<NameExpr *>( untypedExpr->get_function())) 550 && ( fname->get_name() == std::string("&&")) ) { 564 std::string fname = InitTweak::getFunctionName( untypedExpr ); 565 if ( fname == "&&" ) { 551 566 VoidType v = Type::Qualifiers(); // resolve to type void * 552 567 PointerType pt( Type::Qualifiers(), v.clone() ); … … 757 772 for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) { 758 773 VariableExpr newExpr( *i, nameExpr->get_argName() ); 774 newExpr.set_extension( nameExpr->get_extension() ); 759 775 alternatives.push_back( Alternative( newExpr.clone(), env, Cost() ) ); 760 776 PRINT( … … 982 998 } // for 983 999 } 1000 1001 void AlternativeFinder::visit( ImplicitCopyCtorExpr * impCpCtorExpr ) { 1002 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) ); 1003 } 984 1004 } // namespace ResolvExpr 985 1005 -
src/ResolvExpr/AlternativeFinder.h
r1b5c81ed rf80e0218 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // AlternativeFinder.h -- 7 // AlternativeFinder.h -- 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sat May 16 23:56:12 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat May 16 23:58:43 201511 // Last Modified By : Rob Schluntz 12 // Last Modified On : Tue Apr 19 11:44:53 2016 13 13 // Update Count : 2 14 // 14 // 15 15 16 16 #ifndef ALTERNATIVEFINDER_H … … 54 54 virtual void visit( NameExpr *variableExpr ); 55 55 virtual void visit( VariableExpr *variableExpr ); 56 virtual void visit( ConstantExpr *constantExpr ); 56 virtual void visit( ConstantExpr *constantExpr ); 57 57 virtual void visit( SizeofExpr *sizeofExpr ); 58 58 virtual void visit( AlignofExpr *alignofExpr ); … … 65 65 virtual void visit( CommaExpr *commaExpr ); 66 66 virtual void visit( TupleExpr *tupleExpr ); 67 virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ); 67 68 public: // xxx - temporary hack - should make Tuples::TupleAssignment a friend 68 69 template< typename InputIterator, typename OutputIterator > -
src/ResolvExpr/CommonType.cc
r1b5c81ed rf80e0218 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // CommonType.cc -- 7 // CommonType.cc -- 8 8 // 9 9 // Author : Richard C. Bilson … … 134 134 result = new BasicType( basicType->get_qualifiers() + otherBasic->get_qualifiers(), newType ); 135 135 } // if 136 } else if ( EnumInstType *enumInstType = dynamic_cast< EnumInstType * > ( type2 ) ) { 137 // use signed int in lieu of the enum type 138 BasicType::Kind newType = combinedType[ basicType->get_kind() ][ BasicType::SignedInt ]; 139 if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= enumInstType->get_qualifiers() ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->get_qualifiers() <= enumInstType->get_qualifiers() ) || widenSecond ) ) { 140 result = new BasicType( basicType->get_qualifiers() + enumInstType->get_qualifiers(), newType ); 141 } // if 136 142 } // if 137 143 } … … 183 189 } 184 190 185 void CommonType::visit( EnumInstType *aggregateUseType ) { 191 void CommonType::visit( EnumInstType *enumInstType ) { 192 if ( dynamic_cast< BasicType * >( type2 ) ) { 193 // reuse BasicType, EnumInstType code by swapping type2 with enumInstType 194 Type * temp = type2; 195 type2 = enumInstType; 196 temp->accept( *this ); 197 type2 = temp; 198 } // if 186 199 } 187 200 -
src/ResolvExpr/ConversionCost.cc
r1b5c81ed rf80e0218 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // ConversionCost.cc -- 7 // ConversionCost.cc -- 8 8 // 9 9 // Author : Richard C. Bilson … … 157 157 cost = Cost( 0, 0, tableResult ); 158 158 } // if 159 } // if 159 } else if ( dynamic_cast< EnumInstType *>( dest ) ) { 160 // xxx - not positive this is correct, but appears to allow casting int => enum 161 cost = Cost( 1, 0, 0 ); 162 } // if 160 163 } 161 164 -
src/ResolvExpr/RenameVars.cc
r1b5c81ed rf80e0218 45 45 void RenameVars::visit( PointerType *pointerType ) { 46 46 typeBefore( pointerType ); 47 /// std::cout << "do pointer" << std::endl;48 47 maybeAccept( pointerType->get_base(), *this ); 49 /// std::cout << "done pointer" << std::endl;50 48 typeAfter( pointerType ); 51 49 } … … 60 58 void RenameVars::visit( FunctionType *functionType ) { 61 59 typeBefore( functionType ); 62 /// std::cout << "return vals" << std::endl;63 60 acceptAll( functionType->get_returnVals(), *this ); 64 /// std::cout << functionType->get_parameters().size() << " parameters" << std::endl;65 61 acceptAll( functionType->get_parameters(), *this ); 66 /// std::cout << "done function" << std::endl;67 62 typeAfter( functionType ); 68 63 } … … 95 90 void RenameVars::visit( TypeInstType *instType ) { 96 91 typeBefore( instType ); 97 /// std::cout << "instance of type " << instType->get_name() << std::endl;98 92 std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->get_name() ); 99 93 if ( i != mapStack.front().end() ) { 100 /// std::cout << "found name " << i->second << std::endl;101 94 instType->set_name( i->second ); 102 95 } else { 103 /// std::cout << "no name found" << std::endl;104 96 } // if 105 97 acceptAll( instType->get_parameters(), *this ); … … 120 112 void RenameVars::typeBefore( Type *type ) { 121 113 if ( ! type->get_forall().empty() ) { 122 /// std::cout << "type with forall: ";123 /// type->print( std::cout );124 /// std::cout << std::endl;125 114 // copies current name mapping into new mapping 126 115 mapStack.push_front( mapStack.front() ); -
src/ResolvExpr/Resolver.cc
r1b5c81ed rf80e0218 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Resolver.cc -- 7 // Resolver.cc -- 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:17:01 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Mar 24 16:43:11201613 // Update Count : 18111 // Last Modified By : Rob Schluntz 12 // Last Modified On : Fri May 13 11:36:40 2016 13 // Update Count : 203 14 14 // 15 15 … … 25 25 #include "SymTab/Indexer.h" 26 26 #include "Common/utility.h" 27 #include "InitTweak/InitTweak.h" 27 28 28 29 #include <iostream> … … 33 34 public: 34 35 Resolver() : SymTab::Indexer( false ), switchType( 0 ) {} 35 36 36 37 virtual void visit( FunctionDecl *functionDecl ); 37 38 virtual void visit( ObjectDecl *functionDecl ); 38 39 virtual void visit( TypeDecl *typeDecl ); 40 virtual void visit( EnumDecl * enumDecl ); 39 41 40 42 virtual void visit( ArrayType * at ); … … 51 53 virtual void visit( BranchStmt *branchStmt ); 52 54 virtual void visit( ReturnStmt *returnStmt ); 55 virtual void visit( ImplicitCtorDtorStmt * impCtorDtorStmt ); 53 56 54 57 virtual void visit( SingleInit *singleInit ); 55 58 virtual void visit( ListInit *listInit ); 59 virtual void visit( ConstructorInit *ctorInit ); 56 60 private: 57 61 typedef std::list< Initializer * >::iterator InitIterator; … … 59 63 void resolveAggrInit( AggregateDecl *, InitIterator &, InitIterator & ); 60 64 void resolveSingleAggrInit( Declaration *, InitIterator &, InitIterator & ); 61 65 void fallbackInit( ConstructorInit * ctorInit ); 62 66 std::list< Type * > functionReturn; 63 67 Type *initContext; 64 68 Type *switchType; 69 bool inEnumDecl = false; 65 70 }; 66 71 … … 82 87 } 83 88 89 84 90 namespace { 85 91 void finishExpr( Expression *expr, const TypeEnvironment &env ) { … … 87 93 env.makeSubstitution( *expr->get_env() ); 88 94 } 89 90 Expression *findVoidExpression( Expression *untyped, const SymTab::Indexer &indexer ) { 91 global_renamer.reset(); 92 TypeEnvironment env; 93 Expression *newExpr = resolveInVoidContext( untyped, indexer, env ); 94 finishExpr( newExpr, env ); 95 return newExpr; 96 } 97 95 } // namespace 96 97 Expression *findVoidExpression( Expression *untyped, const SymTab::Indexer &indexer ) { 98 global_renamer.reset(); 99 TypeEnvironment env; 100 Expression *newExpr = resolveInVoidContext( untyped, indexer, env ); 101 finishExpr( newExpr, env ); 102 return newExpr; 103 } 104 105 namespace { 98 106 Expression *findSingleExpression( Expression *untyped, const SymTab::Indexer &indexer ) { 99 107 TypeEnvironment env; … … 126 134 } // if 127 135 } 128 136 129 137 Expression *findIntegralExpression( Expression *untyped, const SymTab::Indexer &indexer ) { 130 138 TypeEnvironment env; … … 159 167 return newExpr; 160 168 } 161 162 } 163 169 170 } 171 164 172 void Resolver::visit( ObjectDecl *objectDecl ) { 165 173 Type *new_type = resolveTypeof( objectDecl->get_type(), *this ); … … 172 180 Type *temp = initContext; 173 181 initContext = new_type; 182 if ( inEnumDecl && dynamic_cast< EnumInstType * >( initContext ) ) { 183 // enumerator initializers should not use the enum type to initialize, since 184 // the enum type is still incomplete at this point. Use signed int instead. 185 initContext = new BasicType( Type::Qualifiers(), BasicType::SignedInt ); 186 } 174 187 SymTab::Indexer::visit( objectDecl ); 188 if ( inEnumDecl && dynamic_cast< EnumInstType * >( initContext ) ) { 189 // delete newly created signed int type 190 delete initContext; 191 } 175 192 initContext = temp; 176 193 } … … 212 229 } 213 230 231 void Resolver::visit( EnumDecl * enumDecl ) { 232 // in case we decide to allow nested enums 233 bool oldInEnumDecl = inEnumDecl; 234 inEnumDecl = true; 235 SymTab::Indexer::visit( enumDecl ); 236 inEnumDecl = oldInEnumDecl; 237 } 238 214 239 void Resolver::visit( ExprStmt *exprStmt ) { 215 240 if ( exprStmt->get_expr() ) { … … 258 283 forStmt->set_condition( newExpr ); 259 284 } // if 260 285 261 286 if ( forStmt->get_increment() ) { 262 287 Expression * newExpr = findVoidExpression( forStmt->get_increment(), *this ); … … 272 297 delete switchStmt->get_condition(); 273 298 switchStmt->set_condition( newExpr ); 274 299 275 300 visitor.Visitor::visit( switchStmt ); 276 301 } … … 314 339 bool isCharType( T t ) { 315 340 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) { 316 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar || 341 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar || 317 342 bt->get_kind() == BasicType::UnsignedChar; 318 343 } … … 326 351 string n = ne->get_name(); 327 352 if (n == "0") { 328 initContext = new BasicType(Type::Qualifiers(), 353 initContext = new BasicType(Type::Qualifiers(), 329 354 BasicType::SignedInt); 330 355 } else { … … 332 357 initContext = decl->get_type(); 333 358 } 334 } else if (ConstantExpr * e = 359 } else if (ConstantExpr * e = 335 360 dynamic_cast<ConstantExpr*>(singleInit->get_value())) { 336 361 Constant *c = e->get_constant(); … … 355 380 singleInit->set_value( ce->get_arg() ); 356 381 ce->set_arg( NULL ); 357 delete ce; 382 delete ce; 358 383 } 359 384 } … … 471 496 #endif 472 497 } 498 499 // ConstructorInit - fall back on C-style initializer 500 void Resolver::fallbackInit( ConstructorInit * ctorInit ) { 501 // could not find valid constructor, or found an intrinsic constructor 502 // fall back on C-style initializer 503 delete ctorInit->get_ctor(); 504 ctorInit->set_ctor( NULL ); 505 delete ctorInit->get_dtor(); 506 ctorInit->set_dtor( NULL ); 507 maybeAccept( ctorInit->get_init(), *this ); 508 } 509 510 void Resolver::visit( ConstructorInit *ctorInit ) { 511 try { 512 maybeAccept( ctorInit->get_ctor(), *this ); 513 maybeAccept( ctorInit->get_dtor(), *this ); 514 } catch ( SemanticError ) { 515 // no alternatives for the constructor initializer - fallback on C-style initializer 516 // xxx - not sure if this makes a ton of sense - should maybe never be able to have this situation? 517 fallbackInit( ctorInit ); 518 return; 519 } 520 521 // found a constructor - can get rid of C-style initializer 522 delete ctorInit->get_init(); 523 ctorInit->set_init( NULL ); 524 525 // intrinsic single parameter constructors and destructors do nothing. Since this was 526 // implicitly generated, there's no way for it to have side effects, so get rid of it 527 // to clean up generated code. 528 if ( InitTweak::isInstrinsicSingleArgCallStmt( ctorInit->get_ctor() ) ) { 529 delete ctorInit->get_ctor(); 530 ctorInit->set_ctor( NULL ); 531 } 532 if ( InitTweak::isInstrinsicSingleArgCallStmt( ctorInit->get_ctor() ) ) { 533 delete ctorInit->get_dtor(); 534 ctorInit->set_dtor( NULL ); 535 } 536 } 537 538 void Resolver::visit( ImplicitCtorDtorStmt * impCtorDtorStmt ) { 539 // before resolving ctor/dtor, need to remove type qualifiers from the first argument (the object being constructed). 540 // Do this through a cast expression to greatly simplify the code. 541 Expression * callExpr = InitTweak::getCtorDtorCall( impCtorDtorStmt ); 542 assert( callExpr ); 543 Expression *& constructee = InitTweak::getCallArg( callExpr, 0 ); 544 Type * type = 0; 545 546 // need to find the type of the first argument, which is unfortunately not uniform since array construction 547 // includes an untyped '+' expression. 548 if ( UntypedExpr * plusExpr = dynamic_cast< UntypedExpr * >( constructee ) ) { 549 // constructee is <array>+<index> 550 // get Variable <array>, then get the base type of the VariableExpr - this is the type that needs to be fixed 551 Expression * arr = InitTweak::getCallArg( plusExpr, 0 ); 552 assert( dynamic_cast< VariableExpr * >( arr ) ); 553 assert( arr && arr->get_results().size() == 1 ); 554 type = arr->get_results().front()->clone(); 555 } else { 556 // otherwise, constructing a plain object, which means the object's address is being taken. 557 // Need to get the type of the VariableExpr object, because the AddressExpr is rebuilt and uses the 558 // type of the VariableExpr to do so. 559 assert( constructee->get_results().size() == 1 ); 560 AddressExpr * addrExpr = dynamic_cast< AddressExpr * > ( constructee ); 561 assert( addrExpr && addrExpr->get_results().size() == 1); 562 type = addrExpr->get_results().front()->clone(); 563 } 564 // cast to T* with qualifiers removed. 565 // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument 566 // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever 567 // remove lvalue as a qualifier, this can change to 568 // type->get_qualifiers() = Type::Qualifiers(); 569 Type * base = InitTweak::getPointerBase( type ); 570 assert( base ); 571 base->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true); 572 // if pointer has lvalue qualifier, cast won't appear in output 573 type->set_isLvalue( false ); 574 constructee = new CastExpr( constructee, type ); 575 576 // finally, resolve the ctor/dtor 577 impCtorDtorStmt->get_callStmt()->accept( *this ); 578 } 473 579 } // namespace ResolvExpr 474 580 -
src/ResolvExpr/Resolver.h
r1b5c81ed rf80e0218 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Resolver.h -- 7 // Resolver.h -- 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:18:34 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun May 17 12:19:32 201511 // Last Modified By : Rob Schluntz 12 // Last Modified On : Thu Apr 14 15:06:53 2016 13 13 // Update Count : 2 14 14 // … … 24 24 void resolve( std::list< Declaration * > translationUnit ); 25 25 Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer ); 26 Expression *findVoidExpression( Expression *untyped, const SymTab::Indexer &indexer ); 26 27 } // namespace ResolvExpr 27 28 -
src/ResolvExpr/typeops.h
r1b5c81ed rf80e0218 54 54 55 55 // in AdjustExprType.cc 56 /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function 56 57 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ); 57 58
Note:
See TracChangeset
for help on using the changeset viewer.