Changeset 90152a4 for src/SymTab/Indexer.cc
- Timestamp:
- Aug 27, 2018, 4:40:34 PM (7 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- b7c89aa
- Parents:
- f9feab8 (diff), 305581d (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. - File:
-
- 1 edited
-
src/SymTab/Indexer.cc (modified) (25 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/SymTab/Indexer.cc
rf9feab8 r90152a4 26 26 #include "Common/SemanticError.h" // for SemanticError 27 27 #include "Common/utility.h" // for cloneAll 28 #include "GenPoly/GenPoly.h" 28 29 #include "InitTweak/InitTweak.h" // for isConstructor, isCopyFunction, isC... 29 30 #include "Mangler.h" // for Mangler … … 105 106 if ( ! CodeGen::isCtorDtorAssign( id ) ) return; 106 107 107 // helpful data structure 108 // helpful data structure to organize properties for a type 108 109 struct ValueType { 109 struct DeclBall { 110 struct DeclBall { // properties for this particular decl 110 111 IdData decl; 111 bool isUserDefinedFunc; // properties for this particular decl 112 bool isDefaultCtor; 113 bool isDtor; 112 bool isUserDefinedFunc; 114 113 bool isCopyFunc; 115 114 }; 116 115 // properties for this type 117 bool existsUserDefinedFunc = false; // any user-defined function found118 bool existsUserDefinedCtor = false; // any user-defined constructor found119 bool existsUserDefinedDtor = false; // any user-defined destructor found120 116 bool existsUserDefinedCopyFunc = false; // user-defined copy ctor found 121 bool existsUserDefinedDefaultCtor = false; // user-defined default ctorfound117 BaseSyntaxNode * deleteStmt = nullptr; // non-null if a user-defined function is found 122 118 std::list< DeclBall > decls; 123 119 … … 126 122 ValueType & operator+=( IdData data ) { 127 123 DeclarationWithType * function = data.id; 128 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->get_linkage() ); 129 bool isDefaultCtor = InitTweak::isDefaultConstructor( function ); 130 bool isDtor = InitTweak::isDestructor( function ); 131 bool isCopyFunc = InitTweak::isCopyFunction( function, function->get_name() ); 132 decls.push_back( DeclBall{ data, isUserDefinedFunc, isDefaultCtor, isDtor, isCopyFunc } ); 133 existsUserDefinedFunc = existsUserDefinedFunc || isUserDefinedFunc; 134 existsUserDefinedCtor = existsUserDefinedCtor || (isUserDefinedFunc && CodeGen::isConstructor( function->get_name() ) ); 135 existsUserDefinedDtor = existsUserDefinedDtor || (isUserDefinedFunc && isDtor); 124 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage ); 125 bool isCopyFunc = InitTweak::isCopyFunction( function, function->name ); 126 decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } ); 136 127 existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc); 137 existsUserDefinedDefaultCtor = existsUserDefinedDefaultCtor || (isUserDefinedFunc && isDefaultCtor); 128 if ( isUserDefinedFunc && ! deleteStmt ) { 129 // any user-defined function can act as an implicit delete statement for generated constructors. 130 // a delete stmt should not act as an implicit delete statement. 131 deleteStmt = data.id; 132 } 138 133 return *this; 139 134 } … … 147 142 for ( auto decl : copy ) { 148 143 if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) { 149 std::list< DeclarationWithType * > & params = function-> get_functionType()->get_parameters();144 std::list< DeclarationWithType * > & params = function->type->parameters; 150 145 assert( ! params.empty() ); 151 146 // use base type of pointer, so that qualifiers on the pointer type aren't considered. … … 159 154 160 155 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine 161 // the set of ctor/dtor/assign that are seen by the requester. In particular, if the user defines 162 // a default ctor, then the generated default ctor should never be seen, likewise for copy ctor 163 // and dtor. If the user defines any ctor/dtor, then no generated field ctors should be seen. 164 // If the user defines any ctor then the generated default ctor should not be seen (intrinsic default 165 // ctor must be overridden exactly). 156 // the set of ctor/dtor/assign that can be used by the requester. In particular, if the user defines 157 // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor 158 // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available. 159 // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default 160 // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor, 161 // then the generated copy constructor is unavailable, and likewise for the assignment operator. 166 162 for ( std::pair< const std::string, ValueType > & pair : funcMap ) { 167 163 ValueType & val = pair.second; 168 164 for ( ValueType::DeclBall ball : val.decls ) { 169 bool noUserDefinedFunc = ! val.existsUserDefinedFunc; 170 bool isUserDefinedFunc = ball.isUserDefinedFunc; 171 bool isAcceptableDefaultCtor = (! val.existsUserDefinedCtor || (! val.existsUserDefinedDefaultCtor && ball.decl.id->get_linkage() == LinkageSpec::Intrinsic)) && ball.isDefaultCtor; // allow default constructors only when no user-defined constructors exist, except in the case of intrinsics, which require exact overrides 172 bool isAcceptableCopyFunc = ! val.existsUserDefinedCopyFunc && ball.isCopyFunc; // handles copy ctor and assignment operator 173 bool isAcceptableDtor = ! val.existsUserDefinedDtor && ball.isDtor; 174 if ( noUserDefinedFunc || isUserDefinedFunc || isAcceptableDefaultCtor || isAcceptableCopyFunc || isAcceptableDtor ) { 175 // decl conforms to the rules described above, so it should be seen by the requester 176 out.push_back( ball.decl ); 165 bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic; 166 bool isCopyFunc = ball.isCopyFunc; 167 bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc; 168 169 // only implicitly delete non-user defined functions that are not intrinsic, and are 170 // not copy functions (assignment or copy constructor). If a user-defined copy function exists, 171 // do not pass along the non-user-defined copy functions since signatures do not have to match, 172 // and the generated functions will often be cheaper. 173 if ( isNotUserDefinedFunc ) { 174 if ( isCopyFunc ) { 175 // Skip over non-user-defined copy functions when there is a user-defined copy function. 176 // Since their signatures do not have to be exact, deleting them is the wrong choice. 177 if ( existsUserDefinedCopyFunc ) continue; 178 } else { 179 // delete non-user-defined non-copy functions if applicable. 180 // deleteStmt will be non-null only if a user-defined function is found. 181 ball.decl.deleteStmt = val.deleteStmt; 182 } 177 183 } 184 out.push_back( ball.decl ); 178 185 } 179 186 } … … 265 272 } 266 273 274 NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const { 275 return lookupTypeAtScope( id, 0 ); 276 } 277 278 StructDecl *Indexer::globalLookupStruct( const std::string &id ) const { 279 return lookupStructAtScope( id, 0 ); 280 } 281 282 UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const { 283 return lookupUnionAtScope( id, 0 ); 284 } 285 286 EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const { 287 return lookupEnumAtScope( id, 0 ); 288 } 289 267 290 EnumDecl *Indexer::lookupEnum( const std::string &id ) const { 268 291 if ( ! tables ) return 0; … … 286 309 } 287 310 288 DeclarationWithType *Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {289 if ( ! tables ) return 0;290 if ( tables->scope < scope ) return 0;311 const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const { 312 if ( ! tables ) return nullptr; 313 if ( tables->scope < scope ) return nullptr; 291 314 292 315 IdTable::const_iterator decls = tables->idTable.find( id ); … … 294 317 const MangleTable &mangleTable = decls->second; 295 318 MangleTable::const_iterator decl = mangleTable.find( mangleName ); 296 if ( decl != mangleTable.end() ) return decl->second.id;319 if ( decl != mangleTable.end() ) return &decl->second; 297 320 } 298 321 299 322 return tables->base.lookupIdAtScope( id, mangleName, scope ); 323 } 324 325 Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) { 326 return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope )); 300 327 } 301 328 … … 336 363 if ( ! tables ) return 0; 337 364 if ( tables->scope < scope ) return 0; 365 if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope ); 338 366 339 367 TypeTable::const_iterator ret = tables->typeTable.find( id ); … … 344 372 if ( ! tables ) return 0; 345 373 if ( tables->scope < scope ) return 0; 374 if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope ); 346 375 347 376 StructTable::const_iterator ret = tables->structTable.find( id ); … … 352 381 if ( ! tables ) return 0; 353 382 if ( tables->scope < scope ) return 0; 383 if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope ); 354 384 355 385 EnumTable::const_iterator ret = tables->enumTable.find( id ); … … 360 390 if ( ! tables ) return 0; 361 391 if ( tables->scope < scope ) return 0; 392 if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope ); 362 393 363 394 UnionTable::const_iterator ret = tables->unionTable.find( id ); … … 368 399 if ( ! tables ) return 0; 369 400 if ( tables->scope < scope ) return 0; 401 if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope ); 370 402 371 403 TraitTable::const_iterator ret = tables->traitTable.find( id ); … … 373 405 } 374 406 375 bool addedIdConflicts( DeclarationWithType *existing, DeclarationWithType *added ) { 407 bool isFunction( DeclarationWithType * decl ) { 408 return GenPoly::getFunctionType( decl->get_type() ); 409 } 410 411 bool isObject( DeclarationWithType * decl ) { 412 return ! isFunction( decl ); 413 } 414 415 bool isDefinition( DeclarationWithType * decl ) { 416 if ( FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ) ) { 417 // a function is a definition if it has a body 418 return func->statements; 419 } else { 420 // an object is a definition if it is not marked extern. 421 // both objects must be marked extern 422 return ! decl->get_storageClasses().is_extern; 423 } 424 } 425 426 bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) { 376 427 // if we're giving the same name mangling to things of different types then there is something wrong 377 assert( ( dynamic_cast<ObjectDecl*>( added ) && dynamic_cast<ObjectDecl*>( existing) )378 || ( dynamic_cast<FunctionDecl*>( added ) && dynamic_cast<FunctionDecl*>( existing) ) );379 380 if ( LinkageSpec::isOverridable( existing ->get_linkage() ) ) {428 assert( (isObject( added ) && isObject( existing.id ) ) 429 || ( isFunction( added ) && isFunction( existing.id ) ) ); 430 431 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) { 381 432 // new definition shadows the autogenerated one, even at the same scope 382 433 return false; 383 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing->get_type(), Indexer() ) ) { 384 // typesCompatible doesn't really do the right thing here. When checking compatibility of function types, 385 // we should ignore outermost pointer qualifiers, except _Atomic? 386 FunctionDecl *newentry = dynamic_cast< FunctionDecl* >( added ); 387 FunctionDecl *oldentry = dynamic_cast< FunctionDecl* >( existing ); 388 if ( newentry && oldentry ) { 389 if ( newentry->get_statements() && oldentry->get_statements() ) { 390 throw SemanticError( "duplicate function definition for ", added ); 391 } // if 392 } else { 393 // two objects with the same mangled name defined in the same scope. 394 // both objects must be marked extern or both must be intrinsic for this to be okay 395 // xxx - perhaps it's actually if either is intrinsic then this is okay? 396 // might also need to be same storage class? 397 ObjectDecl *newobj = dynamic_cast< ObjectDecl* >( added ); 398 ObjectDecl *oldobj = dynamic_cast< ObjectDecl* >( existing ); 399 if ( ! newobj->get_storageClasses().is_extern && ! oldobj->get_storageClasses().is_extern ) { 400 throw SemanticError( "duplicate object definition for ", added ); 434 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) { 435 436 // it is a conflict if one declaration is deleted and the other is not 437 if ( deleteStmt && ! existing.deleteStmt ) { 438 return handleConflicts( existing, "deletion of defined identifier " ); 439 } else if ( ! deleteStmt && existing.deleteStmt ) { 440 return handleConflicts( existing, "definition of deleted identifier " ); 441 } 442 443 if ( isDefinition( added ) && isDefinition( existing.id ) ) { 444 if ( isFunction( added ) ) { 445 return handleConflicts( existing, "duplicate function definition for " ); 446 } else { 447 return handleConflicts( existing, "duplicate object definition for " ); 401 448 } // if 402 449 } // if 403 450 } else { 404 throw SemanticError( "duplicate definition for ", added);451 return handleConflicts( existing, "duplicate definition for " ); 405 452 } // if 406 453 … … 408 455 } 409 456 410 void Indexer::addId( DeclarationWithType *decl, Expression * baseExpr ) { 457 void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) { 458 if ( decl->name == "" ) return; 411 459 debugPrint( "Adding Id " << decl->name << std::endl ); 412 460 makeWritable(); … … 430 478 // isomorphic to C type-compatibility, which it may not be. 431 479 if ( hasIncompatibleCDecl( name, mangleName, scope ) ) { 432 throw SemanticError( "conflicting overload of C function ", decl);433 } 434 } else { 435 // Check that a Cforall declaration doesn't over loadany C declaration480 SemanticError( decl, "conflicting overload of C function " ); 481 } 482 } else { 483 // Check that a Cforall declaration doesn't override any C declaration 436 484 if ( hasCompatibleCDecl( name, mangleName, scope ) ) { 437 throw SemanticError( "Cforall declaration hides C function ", decl);485 SemanticError( decl, "Cforall declaration hides C function " ); 438 486 } 439 487 } 440 488 441 489 // Skip repeat declarations of the same identifier 442 DeclarationWithType *existing = lookupIdAtScope( name, mangleName, scope );443 if ( existing && addedIdConflicts( existing, decl) ) return;490 IdData * existing = lookupIdAtScope( name, mangleName, scope ); 491 if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return; 444 492 445 493 // add to indexer 446 tables->idTable[ name ][ mangleName ] = { decl, baseExpr};494 tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt }; 447 495 ++tables->size; 448 496 } 449 497 498 void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) { 499 // default handling of conflicts is to raise an error 500 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr ); 501 } 502 503 void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) { 504 // default handling of conflicts is to raise an error 505 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt ); 506 } 507 450 508 bool addedTypeConflicts( NamedTypeDecl *existing, NamedTypeDecl *added ) { 451 if ( existing-> get_base() == 0) {509 if ( existing->base == nullptr ) { 452 510 return false; 453 } else if ( added-> get_base() == 0) {511 } else if ( added->base == nullptr ) { 454 512 return true; 455 513 } else { 456 throw SemanticError( "redeclaration of ", added ); 457 } 514 assert( existing->base && added->base ); 515 // typedef redeclarations are errors only if types are different 516 if ( ! ResolvExpr::typesCompatible( existing->base, added->base, Indexer() ) ) { 517 SemanticError( added->location, "redeclaration of " + added->name ); 518 } 519 } 520 // does not need to be added to the table if both existing and added have a base that are the same 521 return true; 458 522 } 459 523 … … 462 526 makeWritable(); 463 527 464 const std::string &id = decl-> get_name();528 const std::string &id = decl->name; 465 529 TypeTable::iterator existing = tables->typeTable.find( id ); 466 530 if ( existing == tables->typeTable.end() ) { … … 478 542 479 543 bool addedDeclConflicts( AggregateDecl *existing, AggregateDecl *added ) { 480 if ( existing->get_members().empty()) {544 if ( ! existing->body ) { 481 545 return false; 482 } else if ( ! added->get_members().empty()) {483 throw SemanticError( "redeclaration of ", added);546 } else if ( added->body ) { 547 SemanticError( added, "redeclaration of " ); 484 548 } // if 485 549 return true; … … 495 559 makeWritable(); 496 560 497 const std::string &id = decl-> get_name();561 const std::string &id = decl->name; 498 562 StructTable::iterator existing = tables->structTable.find( id ); 499 563 if ( existing == tables->structTable.end() ) { … … 514 578 makeWritable(); 515 579 516 const std::string &id = decl-> get_name();580 const std::string &id = decl->name; 517 581 EnumTable::iterator existing = tables->enumTable.find( id ); 518 582 if ( existing == tables->enumTable.end() ) { … … 538 602 makeWritable(); 539 603 540 const std::string &id = decl-> get_name();604 const std::string &id = decl->name; 541 605 UnionTable::iterator existing = tables->unionTable.find( id ); 542 606 if ( existing == tables->unionTable.end() ) { … … 557 621 makeWritable(); 558 622 559 const std::string &id = decl-> get_name();623 const std::string &id = decl->name; 560 624 TraitTable::iterator existing = tables->traitTable.find( id ); 561 625 if ( existing == tables->traitTable.end() ) { … … 572 636 } 573 637 574 void Indexer::addWith( WithStmt * stmt ) { 575 for ( Expression * expr : stmt->exprs ) { 638 void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) { 639 for ( Declaration * decl : aggr->members ) { 640 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) { 641 addId( dwt, handleConflicts, expr ); 642 if ( dwt->name == "" ) { 643 Type * t = dwt->get_type()->stripReferences(); 644 if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) { 645 Expression * base = expr->clone(); 646 ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost? 647 ResolvExpr::referenceToRvalueConversion( base, cost ); 648 addMembers( t->getAggr(), new MemberExpr( dwt, base ), handleConflicts ); 649 } 650 } 651 } 652 } 653 } 654 655 void Indexer::addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ) { 656 for ( Expression * expr : withExprs ) { 576 657 if ( expr->result ) { 577 658 AggregateDecl * aggr = expr->result->stripReferences()->getAggr(); 578 659 assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() ); 579 660 580 for ( Declaration * decl : aggr->members) {581 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {582 addId( dwt, expr );583 }584 } 661 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) { 662 // on conflict, delete the identifier 663 existing.deleteStmt = withStmt; 664 return true; 665 }); 585 666 } 586 667 } … … 641 722 642 723 void Indexer::print( std::ostream &os, int indent ) const { 643 using std::cerr;724 using std::cerr; 644 725 645 726 if ( tables ) { … … 666 747 } 667 748 668 Expression * Indexer::IdData::combine() const { 749 Expression * Indexer::IdData::combine( ResolvExpr::Cost & cost ) const { 750 Expression * ret = nullptr; 669 751 if ( baseExpr ) { 670 752 Expression * base = baseExpr->clone(); 671 ResolvExpr::referenceToRvalueConversion( base );672 Expression *ret = new MemberExpr( id, base );753 ResolvExpr::referenceToRvalueConversion( base, cost ); 754 ret = new MemberExpr( id, base ); 673 755 // xxx - this introduces hidden environments, for now remove them. 674 756 // std::swap( base->env, ret->env ); 675 757 delete base->env; 676 758 base->env = nullptr; 677 return ret; 678 } else { 679 return new VariableExpr( id ); 680 } 759 } else { 760 ret = new VariableExpr( id ); 761 } 762 if ( deleteStmt ) ret = new DeletedExpr( ret, deleteStmt ); 763 return ret; 681 764 } 682 765 } // namespace SymTab
Note:
See TracChangeset
for help on using the changeset viewer.