- Timestamp:
- Nov 14, 2023, 12:19:09 PM (2 years ago)
- Branches:
- master
- Children:
- 1ccae59, 89a8bab
- Parents:
- df8ba61a (diff), 5625427 (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
- Files:
-
- 114 deleted
- 97 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Decl.cpp
rdf8ba61a r8d182b1 20 20 #include <unordered_map> 21 21 22 #include "CodeGen/FixMain.h" // for FixMain23 22 #include "Common/Eval.h" // for eval 24 23 … … 76 75 } 77 76 this->type = ftype; 78 // Hack forcing the function "main" to have Cforall linkage to replace79 // main even if it is inside an extern "C", and also makes sure the80 // replacing function is always a C function.81 if ( name == "main" ) {82 this->linkage = CodeGen::FixMain::getMainLinkage();83 }84 77 } 85 78 … … 108 101 } 109 102 this->type = type; 110 // See note above about this hack.111 if ( name == "main" ) {112 this->linkage = CodeGen::FixMain::getMainLinkage();113 }114 103 } 115 104 -
src/AST/SymbolTable.cpp
rdf8ba61a r8d182b1 39 39 static inline auto stats() { 40 40 using namespace Stats::Counters; 41 static auto group = build<CounterGroup>(" Indexers");41 static auto group = build<CounterGroup>("Symbol Tables"); 42 42 static struct { 43 43 SimpleCounter * count; -
src/AST/SymbolTable.hpp
rdf8ba61a r8d182b1 88 88 using Ptr = std::shared_ptr<const SymbolTable>; 89 89 90 Ptr prevScope; ///< Indexerfor parent scope90 Ptr prevScope; ///< Symbol Table for parent scope 91 91 unsigned long scope; ///< Scope index of this indexer 92 92 unsigned long repScope; ///< Scope index of currently represented scope -
src/AST/Type.hpp
rdf8ba61a r8d182b1 34 34 35 35 namespace ast { 36 37 template< typename T > class Pass;38 36 39 37 class Type : public Node { -
src/AST/module.mk
rdf8ba61a r8d182b1 20 20 AST/Bitfield.hpp \ 21 21 AST/Chain.hpp \ 22 AST/Convert.cpp \23 AST/Convert.hpp \24 22 AST/Copy.cpp \ 25 23 AST/Copy.hpp \ -
src/BasicTypes-gen.cc
rdf8ba61a r8d182b1 272 272 size_t start, end; 273 273 274 275 #define TypeH TOP_SRCDIR "src/SynTree/Type.h"276 resetInput( file, TypeH, buffer, code, str );277 278 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH );279 start += sizeof( STARTMK ); // includes newline280 code << str.substr( 0, start );281 282 code << "\t" << BYMK << endl;283 code << "\tenum Kind {" << endl;284 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {285 code << "\t\t" << graph[r].name << "," << endl;286 } // for287 code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;288 code << "\t} kind;" << endl;289 code << "\t"; // indentation for end marker290 291 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );292 code << str.substr( start );293 294 output( file, TypeH, code );295 // cout << code.str();296 297 298 #define TypeC TOP_SRCDIR "src/SynTree/Type.cc"299 resetInput( file, TypeC, buffer, code, str );300 301 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC );302 start += sizeof( STARTMK ); // includes newline303 code << str.substr( 0, start );304 305 code << BYMK << endl;306 code << "const char * BasicType::typeNames[] = {" << endl;307 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {308 code << "\t\"" << graph[r].type << "\"," << endl;309 } // for310 code << "};" << endl;311 312 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC );313 code << str.substr( start );314 315 output( file, TypeC, code );316 // cout << code.str();317 318 319 // TEMPORARY DURING CHANGE OVER320 274 #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp" 321 275 resetInput( file, TypeH_AST, buffer, code, str ); -
src/CodeGen/CodeGeneratorNew.cpp
rdf8ba61a r8d182b1 24 24 namespace CodeGen { 25 25 26 int CodeGenerator _new::tabsize = 4;26 int CodeGenerator::tabsize = 4; 27 27 28 28 // The kinds of statements that should be followed by whitespace. … … 35 35 } 36 36 37 void CodeGenerator _new::extension( ast::Expr const * expr ) {37 void CodeGenerator::extension( ast::Expr const * expr ) { 38 38 if ( expr->extension ) output << "__extension__ "; 39 39 } 40 40 41 void CodeGenerator _new::extension( ast::Decl const * decl ) {41 void CodeGenerator::extension( ast::Decl const * decl ) { 42 42 if ( decl->extension ) output << "__extension__ "; 43 43 } 44 44 45 void CodeGenerator _new::asmName( ast::DeclWithType const * decl ) {45 void CodeGenerator::asmName( ast::DeclWithType const * decl ) { 46 46 if ( auto asmName = decl->asmName.as<ast::ConstantExpr>() ) { 47 47 output << " asm ( " << asmName->rep << " )"; … … 49 49 } 50 50 51 CodeGenerator _new::LabelPrinter & CodeGenerator_new::LabelPrinter::operator()(51 CodeGenerator::LabelPrinter & CodeGenerator::LabelPrinter::operator()( 52 52 std::vector<ast::Label> const & l ) { 53 53 labels = &l; … … 55 55 } 56 56 57 std::ostream & CodeGenerator _new::LabelPrinter::operator()( std::ostream & output ) const {57 std::ostream & CodeGenerator::LabelPrinter::operator()( std::ostream & output ) const { 58 58 const std::vector<ast::Label> & labels = *this->labels; 59 59 for ( const ast::Label & label : labels ) { … … 66 66 // Using updateLocation at the beginning of a node and endl within a node 67 67 // should become the method of formating. 68 void CodeGenerator _new::updateLocation( CodeLocation const & to ) {68 void CodeGenerator::updateLocation( CodeLocation const & to ) { 69 69 // Skip if linemarks shouldn't appear or if location is unset. 70 70 if ( !options.lineMarks || to.isUnset() ) return; … … 86 86 } 87 87 88 void CodeGenerator _new::updateLocation( ast::ParseNode const * to ) {88 void CodeGenerator::updateLocation( ast::ParseNode const * to ) { 89 89 updateLocation( to->location ); 90 90 } 91 91 92 std::ostream & CodeGenerator _new::LineEnder::operator()( std::ostream & os ) const {92 std::ostream & CodeGenerator::LineEnder::operator()( std::ostream & os ) const { 93 93 os << "\n" << std::flush; 94 94 cg.currentLocation.first_line++; … … 96 96 } 97 97 98 CodeGenerator _new::CodeGenerator_new( std::ostream & os, const Options & options ) :99 indent( 0, CodeGenerator _new::tabsize ), output( os ),98 CodeGenerator::CodeGenerator( std::ostream & os, const Options & options ) : 99 indent( 0, CodeGenerator::tabsize ), output( os ), 100 100 options( options ), printLabels( *this ), endl( *this ) 101 101 {} 102 102 103 std::string CodeGenerator _new::mangleName( ast::DeclWithType const * decl ) {103 std::string CodeGenerator::mangleName( ast::DeclWithType const * decl ) { 104 104 // GCC builtins should always be printed unmangled. 105 105 if ( options.pretty || decl->linkage.is_gcc_builtin ) { … … 112 112 } 113 113 114 void CodeGenerator _new::genAttributes(114 void CodeGenerator::genAttributes( 115 115 const std::vector<ast::ptr<ast::Attribute>> & attributes ) { 116 116 if ( attributes.empty() ) return; … … 129 129 } 130 130 131 void CodeGenerator _new::previsit( ast::Node const * ) {131 void CodeGenerator::previsit( ast::Node const * ) { 132 132 // All traversal is manual. 133 133 // TODO: Which means the ast::Pass is just providing a default no visit? … … 135 135 } 136 136 137 void CodeGenerator _new::previsit( ast::ParseNode const * node ) {137 void CodeGenerator::previsit( ast::ParseNode const * node ) { 138 138 previsit( (ast::Node const *)node ); 139 139 updateLocation( node ); 140 140 } 141 141 142 void CodeGenerator _new::postvisit( ast::Node const * node ) {142 void CodeGenerator::postvisit( ast::Node const * node ) { 143 143 std::stringstream ss; 144 144 ast::print( ss, node ); … … 146 146 } 147 147 148 void CodeGenerator _new::previsit( ast::Expr const * expr ) {148 void CodeGenerator::previsit( ast::Expr const * expr ) { 149 149 previsit( (ast::ParseNode const *)expr ); 150 150 GuardAction( [this, expr](){ … … 155 155 } 156 156 157 void CodeGenerator _new::postvisit( ast::FunctionDecl const * decl ) {157 void CodeGenerator::postvisit( ast::FunctionDecl const * decl ) { 158 158 // Deleted decls should never be used, so don't print them in C. 159 159 if ( decl->isDeleted && options.genC ) return; … … 168 168 169 169 std::ostringstream acc; 170 ast::Pass<CodeGenerator _new> subCG( acc, subOptions );170 ast::Pass<CodeGenerator> subCG( acc, subOptions ); 171 171 // Add the forall clause. 172 172 // TODO: These probably should be removed by now and the assert used. … … 213 213 } 214 214 215 //void CodeGenerator_new::postvisit( ast::ObjectDecl const * decl_ ) { 216 ast::ObjectDecl const * CodeGenerator_new::postvisit( 215 ast::ObjectDecl const * CodeGenerator::postvisit( 217 216 ast::ObjectDecl const * decl ) { 218 217 // Deleted decls should never be used, so don't print them in C. … … 262 261 } 263 262 264 void CodeGenerator _new::handleStorageClass( ast::DeclWithType const * decl ) {263 void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) { 265 264 if ( decl->storage.any() ) { 266 265 ast::print( output, decl->storage ); … … 268 267 } 269 268 270 void CodeGenerator _new::handleAggregate(269 void CodeGenerator::handleAggregate( 271 270 ast::AggregateDecl const * decl, std::string const & kind ) { 272 271 if ( !decl->params.empty() && !options.genC ) { … … 296 295 } 297 296 298 void CodeGenerator _new::postvisit( ast::StructDecl const * decl ) {297 void CodeGenerator::postvisit( ast::StructDecl const * decl ) { 299 298 extension( decl ); 300 299 handleAggregate( decl, "struct " ); 301 300 } 302 301 303 void CodeGenerator _new::postvisit( ast::UnionDecl const * decl ) {302 void CodeGenerator::postvisit( ast::UnionDecl const * decl ) { 304 303 extension( decl ); 305 304 handleAggregate( decl, "union " ); … … 332 331 } 333 332 334 void CodeGenerator _new::postvisit( ast::EnumDecl const * decl ) {333 void CodeGenerator::postvisit( ast::EnumDecl const * decl ) { 335 334 extension( decl ); 336 335 auto members = decl->members; … … 370 369 } 371 370 372 void CodeGenerator _new::postvisit( ast::TraitDecl const * decl ) {371 void CodeGenerator::postvisit( ast::TraitDecl const * decl ) { 373 372 assertf( !options.genC, "TraitDecls should not reach code generation." ); 374 373 extension( decl ); … … 376 375 } 377 376 378 void CodeGenerator _new::postvisit( ast::TypedefDecl const * decl ) {377 void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) { 379 378 assertf( !options.genC, "Typedefs should not reach code generation." ); 380 379 output << "typedef " << genType( decl->base, decl->name, options ) << endl; 381 380 } 382 381 383 void CodeGenerator _new::postvisit( ast::TypeDecl const * decl ) {382 void CodeGenerator::postvisit( ast::TypeDecl const * decl ) { 384 383 assertf( !options.genC, "TypeDecls should not reach code generation." ); 385 384 output << decl->genTypeString() << " " << decl->name; … … 397 396 } 398 397 399 void CodeGenerator _new::postvisit( ast::StaticAssertDecl const * decl ) {398 void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) { 400 399 output << "_Static_assert("; 401 400 decl->cond->accept( *visitor ); … … 405 404 } 406 405 407 void CodeGenerator _new::postvisit( ast::Designation const * designation ) {406 void CodeGenerator::postvisit( ast::Designation const * designation ) { 408 407 auto designators = designation->designators; 409 408 if ( 0 == designators.size() ) return; … … 423 422 } 424 423 425 void CodeGenerator _new::postvisit( ast::SingleInit const * init ) {424 void CodeGenerator::postvisit( ast::SingleInit const * init ) { 426 425 init->value->accept( *visitor ); 427 426 } 428 427 429 void CodeGenerator _new::postvisit( ast::ListInit const * init ) {428 void CodeGenerator::postvisit( ast::ListInit const * init ) { 430 429 auto initBegin = init->initializers.begin(); 431 430 auto initEnd = init->initializers.end(); … … 446 445 } 447 446 448 void CodeGenerator _new::postvisit( ast::ConstructorInit const * init ) {447 void CodeGenerator::postvisit( ast::ConstructorInit const * init ) { 449 448 assertf( !options.genC, "ConstructorInit nodes should not reach code generation." ); 450 449 // This isn't actual code, but labels the constructor/destructor pairs. … … 456 455 } 457 456 458 void CodeGenerator _new::postvisit( ast::ApplicationExpr const * expr ) {457 void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) { 459 458 extension( expr ); 460 459 if ( auto var = expr->func.as<ast::VariableExpr>() ) { … … 550 549 } 551 550 552 void CodeGenerator _new::postvisit( ast::UntypedExpr const * expr ) {551 void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) { 553 552 extension( expr ); 554 553 if ( auto name = expr->func.as<ast::NameExpr>() ) { … … 638 637 } 639 638 640 void CodeGenerator _new::postvisit( ast::RangeExpr const * expr ) {639 void CodeGenerator::postvisit( ast::RangeExpr const * expr ) { 641 640 expr->low->accept( *visitor ); 642 641 output << " ... "; … … 644 643 } 645 644 646 void CodeGenerator _new::postvisit( ast::NameExpr const * expr ) {645 void CodeGenerator::postvisit( ast::NameExpr const * expr ) { 647 646 extension( expr ); 648 647 if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) { … … 657 656 } 658 657 659 void CodeGenerator _new::postvisit( ast::DimensionExpr const * expr ) {658 void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) { 660 659 extension( expr ); 661 660 output << "/*non-type*/" << expr->name; 662 661 } 663 662 664 void CodeGenerator _new::postvisit( ast::AddressExpr const * expr ) {663 void CodeGenerator::postvisit( ast::AddressExpr const * expr ) { 665 664 extension( expr ); 666 665 output << "(&"; … … 669 668 } 670 669 671 void CodeGenerator _new::postvisit( ast::LabelAddressExpr const * expr ) {670 void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) { 672 671 extension( expr ); 673 672 output << "(&&" << expr->arg << ")"; 674 673 } 675 674 676 void CodeGenerator _new::postvisit( ast::CastExpr const * expr ) {675 void CodeGenerator::postvisit( ast::CastExpr const * expr ) { 677 676 extension( expr ); 678 677 output << "("; … … 688 687 } 689 688 690 void CodeGenerator _new::postvisit( ast::KeywordCastExpr const * expr ) {689 void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) { 691 690 assertf( !options.genC, "KeywordCastExpr should not reach code generation." ); 692 691 extension( expr ); … … 696 695 } 697 696 698 void CodeGenerator _new::postvisit( ast::VirtualCastExpr const * expr ) {697 void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) { 699 698 assertf( !options.genC, "VirtualCastExpr should not reach code generation." ); 700 699 extension( expr ); … … 705 704 } 706 705 707 void CodeGenerator _new::postvisit( ast::UntypedMemberExpr const * expr ) {706 void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) { 708 707 assertf( !options.genC, "UntypedMemberExpr should not reach code generation." ); 709 708 extension( expr ); … … 713 712 } 714 713 715 void CodeGenerator _new::postvisit( ast::MemberExpr const * expr ) {714 void CodeGenerator::postvisit( ast::MemberExpr const * expr ) { 716 715 extension( expr ); 717 716 expr->aggregate->accept( *visitor ); … … 719 718 } 720 719 721 void CodeGenerator _new::postvisit( ast::VariableExpr const * expr ) {720 void CodeGenerator::postvisit( ast::VariableExpr const * expr ) { 722 721 extension( expr ); 723 722 const OperatorInfo * opInfo; … … 733 732 } 734 733 735 void CodeGenerator _new::postvisit( ast::ConstantExpr const * expr ) {734 void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) { 736 735 extension( expr ); 737 736 output << expr->rep; 738 737 } 739 738 740 void CodeGenerator _new::postvisit( ast::SizeofExpr const * expr ) {739 void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) { 741 740 extension( expr ); 742 741 output << "sizeof("; … … 749 748 } 750 749 751 void CodeGenerator _new::postvisit( ast::AlignofExpr const * expr ) {750 void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) { 752 751 // Using the GCC extension to avoid changing the std to C11. 753 752 extension( expr ); … … 761 760 } 762 761 763 void CodeGenerator _new::postvisit( ast::UntypedOffsetofExpr const * expr ) {762 void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) { 764 763 assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." ); 765 764 output << "offsetof("; … … 769 768 } 770 769 771 void CodeGenerator _new::postvisit( ast::OffsetofExpr const * expr ) {770 void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) { 772 771 // Use GCC builtin 773 772 output << "__builtin_offsetof("; … … 777 776 } 778 777 779 void CodeGenerator _new::postvisit( ast::OffsetPackExpr const * expr ) {778 void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) { 780 779 assertf( !options.genC, "OffsetPackExpr should not reach code generation." ); 781 780 output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")"; 782 781 } 783 782 784 void CodeGenerator _new::postvisit( ast::LogicalExpr const * expr ) {783 void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) { 785 784 extension( expr ); 786 785 output << "("; … … 791 790 } 792 791 793 void CodeGenerator _new::postvisit( ast::ConditionalExpr const * expr ) {792 void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) { 794 793 extension( expr ); 795 794 output << "("; … … 802 801 } 803 802 804 void CodeGenerator _new::postvisit( ast::CommaExpr const * expr ) {803 void CodeGenerator::postvisit( ast::CommaExpr const * expr ) { 805 804 extension( expr ); 806 805 output << "("; … … 818 817 } 819 818 820 void CodeGenerator _new::postvisit( ast::TupleAssignExpr const * expr ) {819 void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) { 821 820 assertf( !options.genC, "TupleAssignExpr should not reach code generation." ); 822 821 expr->stmtExpr->accept( *visitor ); 823 822 } 824 823 825 void CodeGenerator _new::postvisit( ast::UntypedTupleExpr const * expr ) {824 void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) { 826 825 assertf( !options.genC, "UntypedTupleExpr should not reach code generation." ); 827 826 extension( expr ); … … 831 830 } 832 831 833 void CodeGenerator _new::postvisit( ast::TupleExpr const * expr ) {832 void CodeGenerator::postvisit( ast::TupleExpr const * expr ) { 834 833 assertf( !options.genC, "TupleExpr should not reach code generation." ); 835 834 extension( expr ); … … 839 838 } 840 839 841 void CodeGenerator _new::postvisit( ast::TupleIndexExpr const * expr ) {840 void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) { 842 841 assertf( !options.genC, "TupleIndexExpr should not reach code generation." ); 843 842 extension( expr ); … … 846 845 } 847 846 848 void CodeGenerator _new::postvisit( ast::TypeExpr const * expr ) {847 void CodeGenerator::postvisit( ast::TypeExpr const * expr ) { 849 848 // TODO: Should there be an assertion there? 850 849 if ( !options.genC ) { … … 853 852 } 854 853 855 void CodeGenerator _new::postvisit( ast::AsmExpr const * expr ) {854 void CodeGenerator::postvisit( ast::AsmExpr const * expr ) { 856 855 if ( !expr->inout.empty() ) { 857 856 output << "[ " << expr->inout << " ] "; … … 863 862 } 864 863 865 void CodeGenerator _new::postvisit( ast::CompoundLiteralExpr const * expr ) {864 void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) { 866 865 //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) ); 867 866 assert( expr->result && expr->init.as<ast::ListInit>() ); … … 870 869 } 871 870 872 void CodeGenerator _new::postvisit( ast::UniqueExpr const * expr ) {871 void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) { 873 872 assertf( !options.genC, "UniqueExpr should not reach code generation." ); 874 873 output << "unq<" << expr->id << ">{ "; … … 877 876 } 878 877 879 void CodeGenerator _new::postvisit( ast::StmtExpr const * expr ) {878 void CodeGenerator::postvisit( ast::StmtExpr const * expr ) { 880 879 auto stmts = expr->stmts->kids; 881 880 output << "({" << endl; … … 905 904 } 906 905 907 void CodeGenerator _new::postvisit( ast::ConstructorExpr const * expr ) {906 void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) { 908 907 assertf( !options.genC, "ConstructorExpr should not reach code generation." ); 909 908 expr->callExpr->accept( *visitor ); 910 909 } 911 910 912 void CodeGenerator _new::postvisit( ast::DeletedExpr const * expr ) {911 void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) { 913 912 assertf( !options.genC, "DeletedExpr should not reach code generation." ); 914 913 expr->expr->accept( *visitor ); 915 914 } 916 915 917 void CodeGenerator _new::postvisit( ast::DefaultArgExpr const * expr ) {916 void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) { 918 917 assertf( !options.genC, "DefaultArgExpr should not reach code generation." ); 919 918 expr->expr->accept( *visitor ); 920 919 } 921 920 922 void CodeGenerator _new::postvisit( ast::GenericExpr const * expr ) {921 void CodeGenerator::postvisit( ast::GenericExpr const * expr ) { 923 922 assertf( !options.genC, "GenericExpr should not reach code generation." ); 924 923 output << "_Generic("; … … 940 939 } 941 940 942 void CodeGenerator _new::postvisit( ast::CompoundStmt const * stmt ) {941 void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) { 943 942 output << "{" << endl; 944 943 … … 955 954 } 956 955 957 void CodeGenerator _new::postvisit( ast::ExprStmt const * stmt ) {956 void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) { 958 957 assert( stmt ); 959 958 // Cast the top-level expression to void to reduce gcc warnings. … … 967 966 } 968 967 969 void CodeGenerator _new::postvisit( ast::AsmStmt const * stmt ) {968 void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) { 970 969 output << "asm "; 971 970 if ( stmt->isVolatile ) output << "volatile "; … … 991 990 } 992 991 993 void CodeGenerator _new::postvisit( ast::AsmDecl const * decl ) {992 void CodeGenerator::postvisit( ast::AsmDecl const * decl ) { 994 993 output << "asm "; 995 994 ast::AsmStmt const * stmt = decl->stmt; … … 999 998 } 1000 999 1001 void CodeGenerator _new::postvisit( ast::DirectiveDecl const * decl ) {1000 void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) { 1002 1001 // endl prevents spaces before the directive. 1003 1002 output << endl << decl->stmt->directive; 1004 1003 } 1005 1004 1006 void CodeGenerator _new::postvisit( ast::DirectiveStmt const * stmt ) {1005 void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) { 1007 1006 // endl prevents spaces before the directive. 1008 1007 output << endl << stmt->directive; 1009 1008 } 1010 1009 1011 void CodeGenerator _new::postvisit( ast::IfStmt const * stmt ) {1010 void CodeGenerator::postvisit( ast::IfStmt const * stmt ) { 1012 1011 output << "if ( "; 1013 1012 stmt->cond->accept( *visitor ); … … 1022 1021 } 1023 1022 1024 void CodeGenerator _new::postvisit( ast::SwitchStmt const * stmt ) {1023 void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) { 1025 1024 output << "switch ( "; 1026 1025 stmt->cond->accept( *visitor ); … … 1036 1035 } 1037 1036 1038 void CodeGenerator _new::postvisit( ast::CaseClause const * clause ) {1037 void CodeGenerator::postvisit( ast::CaseClause const * clause ) { 1039 1038 updateLocation( clause ); 1040 1039 output << indent; … … 1056 1055 } 1057 1056 1058 void CodeGenerator _new::postvisit( ast::BranchStmt const * stmt ) {1057 void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) { 1059 1058 switch ( stmt->kind ) { 1060 1059 case ast::BranchStmt::Goto: … … 1091 1090 } 1092 1091 1093 void CodeGenerator _new::postvisit( ast::ReturnStmt const * stmt ) {1092 void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) { 1094 1093 output << "return "; 1095 1094 if ( stmt->expr ) stmt->expr->accept( *visitor ); … … 1097 1096 } 1098 1097 1099 void CodeGenerator _new::postvisit( ast::ThrowStmt const * stmt ) {1098 void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) { 1100 1099 assertf( !options.genC, "ThrowStmt should not reach code generation." ); 1101 1100 … … 1112 1111 } 1113 1112 1114 void CodeGenerator _new::postvisit( ast::CatchClause const * stmt ) {1113 void CodeGenerator::postvisit( ast::CatchClause const * stmt ) { 1115 1114 assertf( !options.genC, "CatchClause should not reach code generation." ); 1116 1115 … … 1126 1125 } 1127 1126 1128 void CodeGenerator _new::postvisit( ast::WaitForStmt const * stmt ) {1127 void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) { 1129 1128 assertf( !options.genC, "WaitforStmt should not reach code generation." ); 1130 1129 … … 1172 1171 } 1173 1172 1174 void CodeGenerator _new::postvisit( ast::WithStmt const * stmt ) {1173 void CodeGenerator::postvisit( ast::WithStmt const * stmt ) { 1175 1174 assertf( !options.genC, "WithStmt should not reach code generation." ); 1176 1175 … … 1181 1180 } 1182 1181 1183 void CodeGenerator _new::postvisit( ast::WhileDoStmt const * stmt ) {1182 void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) { 1184 1183 if ( stmt->isDoWhile ) { 1185 1184 output << "do"; … … 1191 1190 output << " "; 1192 1191 1193 output << CodeGenerator _new::printLabels( stmt->body->labels );1192 output << CodeGenerator::printLabels( stmt->body->labels ); 1194 1193 stmt->body->accept( *visitor ); 1195 1194 … … 1203 1202 } 1204 1203 1205 void CodeGenerator _new::postvisit( ast::ForStmt const * stmt ) {1204 void CodeGenerator::postvisit( ast::ForStmt const * stmt ) { 1206 1205 // Initializer is always hoised so don't generate it. 1207 1206 // TODO: Do an assertion check? … … 1226 1225 } 1227 1226 1228 void CodeGenerator _new::postvisit( ast::NullStmt const * ) {1227 void CodeGenerator::postvisit( ast::NullStmt const * ) { 1229 1228 output << "/* null statement */ ;"; 1230 1229 } 1231 1230 1232 void CodeGenerator _new::postvisit( ast::DeclStmt const * stmt ) {1231 void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) { 1233 1232 stmt->decl->accept( *visitor ); 1234 1233 … … 1236 1235 } 1237 1236 1238 void CodeGenerator _new::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {1237 void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) { 1239 1238 assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." ); 1240 1239 stmt->callStmt->accept( *visitor ); 1241 1240 } 1242 1241 1243 void CodeGenerator _new::postvisit( ast::MutexStmt const * stmt ) {1242 void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) { 1244 1243 assertf( !options.genC, "MutexStmt should not reach code generation." ); 1245 1244 // TODO: But this isn't what a mutex statement looks like. -
src/CodeGen/CodeGeneratorNew.hpp
rdf8ba61a r8d182b1 25 25 namespace CodeGen { 26 26 27 #warning Remove the _new when old version is removed. 28 struct CodeGenerator_new : 27 struct CodeGenerator final : 29 28 public ast::WithGuards, 30 29 public ast::WithShortCircuiting, 31 public ast::WithVisitorRef<CodeGenerator _new> {32 CodeGenerator _new( std::ostream & out, Options const & options );30 public ast::WithVisitorRef<CodeGenerator> { 31 CodeGenerator( std::ostream & out, Options const & options ); 33 32 34 33 // Turn off visit_children for all nodes. … … 119 118 /// Custom local implementation of endl that updates print location. 120 119 struct LineEnder { 121 CodeGenerator _new& cg;122 LineEnder( CodeGenerator _new& cg ) : cg( cg ) {}120 CodeGenerator & cg; 121 LineEnder( CodeGenerator & cg ) : cg( cg ) {} 123 122 std::ostream & operator()( std::ostream & ) const; 124 123 }; … … 129 128 /// Wrapper class to help print vectors of Labels. 130 129 struct LabelPrinter { 131 LabelPrinter( CodeGenerator _new& cg ) : cg( cg ), labels( nullptr ) {}130 LabelPrinter( CodeGenerator & cg ) : cg( cg ), labels( nullptr ) {} 132 131 LabelPrinter & operator()( std::vector<ast::Label> const & l ); 133 132 std::ostream & operator()( std::ostream & ) const; 134 CodeGenerator _new& cg;133 CodeGenerator & cg; 135 134 std::vector<ast::Label> const * labels; 136 135 }; -
src/CodeGen/FixMain.cc
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.cc -- 7 // FixMain.cc -- Tools to change a Cforall main into a C main. 8 8 // 9 9 // Author : Thierry Delisle … … 25 25 #include "AST/Type.hpp" 26 26 #include "AST/Vector.hpp" 27 #include "Common/PassVisitor.h"28 27 #include "Common/SemanticError.h" // for SemanticError 29 28 #include "CodeGen/GenType.h" // for GenType 30 #include "SynTree/Declaration.h" // for FunctionDecl, operator<<31 #include "SynTree/Type.h" // for FunctionType32 29 #include "SymTab/Mangler.h" 33 30 … … 36 33 namespace { 37 34 38 struct FindMainCore { 39 FunctionDecl * main_signature = nullptr; 40 41 void previsit( FunctionDecl * decl ) { 42 if ( FixMain::isMain( decl ) ) { 43 if ( main_signature ) { 44 SemanticError( decl, "Multiple definition of main routine\n" ); 45 } 46 main_signature = decl; 47 } 48 } 49 }; 50 51 struct FindMainCore_new { 35 struct FindMainCore final { 52 36 ast::FunctionDecl const * main_declaration = nullptr; 53 37 54 38 void previsit( ast::FunctionDecl const * decl ) { 55 if ( FixMain::isMain( decl ) ) {39 if ( isMain( decl ) ) { 56 40 if ( main_declaration ) { 57 41 SemanticError( decl, "Multiple definition of main routine\n" ); … … 65 49 return genType( types[at], "", Options( false, false, false, false ) ); 66 50 } 67 68 }69 70 template<typename container>71 std::string genTypeAt(const container& p, size_t idx) {72 return genType((*std::next(p.begin(), idx))->get_type(), "");73 }74 75 void FixMain::fix( std::list< Declaration * > & translationUnit,76 std::ostream &os, const char* bootloader_filename ) {77 PassVisitor< FindMainCore > main_finder;78 acceptAll( translationUnit, main_finder );79 FunctionDecl * main_signature = main_finder.pass.main_signature;80 81 if( main_signature ) {82 os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";83 main_signature->mangleName = SymTab::Mangler::mangle(main_signature);84 85 os << main_signature->get_scopedMangleName() << "(";86 const auto& params = main_signature->get_functionType()->get_parameters();87 switch(params.size()) {88 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;89 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;90 case 0: break;91 default : assert(false);92 }93 os << "); }\n";94 95 std::ifstream bootloader(bootloader_filename, std::ios::in);96 assertf( bootloader.is_open(), "cannot open bootloader.c\n" );97 os << bootloader.rdbuf();98 }99 }100 101 namespace {102 51 103 52 ast::ObjectDecl * makeIntObj(){ … … 157 106 } 158 107 108 struct FixLinkageCore final { 109 ast::Linkage::Spec const spec; 110 FixLinkageCore( ast::Linkage::Spec spec ) : spec( spec ) {} 111 112 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ) { 113 if ( decl->name != "main" ) return decl; 114 return ast::mutate_field( decl, &ast::FunctionDecl::linkage, spec ); 115 } 116 }; 117 159 118 } // namespace 160 119 161 bool FixMain::isMain( FunctionDecl * decl ) { 162 if ( std::string("main") != decl->name ) { 163 return false; 164 } 165 return is_main( SymTab::Mangler::mangle( decl, true, true ) ); 166 } 167 168 bool FixMain::isMain( const ast::FunctionDecl * decl ) { 120 bool isMain( const ast::FunctionDecl * decl ) { 169 121 if ( std::string("main") != decl->name ) { 170 122 return false; … … 173 125 } 174 126 175 void FixMain::fix( ast::TranslationUnit & translationUnit, 127 void fixMainLinkage( ast::TranslationUnit & translationUnit, 128 bool replace_main ) { 129 ast::Linkage::Spec const spec = 130 ( replace_main ) ? ast::Linkage::Cforall : ast::Linkage::C; 131 ast::Pass<FixLinkageCore>::run( translationUnit, spec ); 132 } 133 134 void fixMainInvoke( ast::TranslationUnit & translationUnit, 176 135 std::ostream &os, const char * bootloader_filename ) { 177 136 178 ast::Pass<FindMainCore _new> main_finder;137 ast::Pass<FindMainCore> main_finder; 179 138 ast::accept_all( translationUnit, main_finder ); 180 139 if ( nullptr == main_finder.core.main_declaration ) return; -
src/CodeGen/FixMain.h
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.h -- 7 // FixMain.h -- Tools to change a Cforall main into a C main. 8 8 // 9 9 // Author : Thierry Delisle … … 17 17 18 18 #include <iosfwd> 19 #include <memory>20 #include <list>21 19 22 #include "AST/LinkageSpec.hpp"23 #include "SynTree/LinkageSpec.h"24 25 class Declaration;26 class FunctionDecl;27 20 namespace ast { 28 21 class FunctionDecl; … … 32 25 namespace CodeGen { 33 26 34 class FixMain { 35 public : 36 static inline LinkageSpec::Spec mainLinkage() { 37 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C; 38 } 39 static inline ast::Linkage::Spec getMainLinkage() { 40 return replace_main ? ast::Linkage::Cforall : ast::Linkage::C; 41 } 27 /// Is this function a program main function? 28 bool isMain( const ast::FunctionDecl * decl ); 42 29 43 static inline void setReplaceMain(bool val) { 44 replace_main = val; 45 } 30 /// Adjust the linkage of main functions. 31 void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain ); 46 32 47 static bool isMain(FunctionDecl* decl); 48 static bool isMain(const ast::FunctionDecl * decl); 49 50 static void fix( std::list< Declaration * > & decls, 51 std::ostream &os, const char* bootloader_filename ); 52 static void fix( ast::TranslationUnit & translationUnit, 53 std::ostream &os, const char * bootloader_filename ); 54 55 private: 56 static bool replace_main; 57 }; 33 /// Add a wrapper around to run the Cforall main. 34 void fixMainInvoke( ast::TranslationUnit & transUnit, 35 std::ostream & os, const char * bootloaderFilename ); 58 36 59 37 } // namespace CodeGen -
src/CodeGen/FixNames.cc
rdf8ba61a r8d182b1 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h"25 24 #include "Common/SemanticError.h" // for SemanticError 26 25 #include "FixMain.h" // for FixMain 27 26 #include "SymTab/Mangler.h" // for Mangler 28 #include "SynTree/LinkageSpec.h" // for Cforall, isMangled29 #include "SynTree/Constant.h" // for Constant30 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarat...31 #include "SynTree/Expression.h" // for ConstantExpr32 #include "SynTree/Label.h" // for Label, noLabels33 #include "SynTree/Statement.h" // for ReturnStmt, CompoundStmt34 #include "SynTree/Type.h" // for Type, BasicType, Type::Qualifiers35 #include "SynTree/Visitor.h" // for Visitor, acceptAll36 27 #include "CompilationState.h" 37 28 38 29 namespace CodeGen { 39 class FixNames : public WithGuards {40 public:41 void postvisit( ObjectDecl *objectDecl );42 void postvisit( FunctionDecl *functionDecl );43 30 44 void previsit( CompoundStmt *compoundStmt ); 45 private: 46 int scopeLevel = 1; 47 48 void fixDWT( DeclarationWithType *dwt ); 49 }; 50 51 void fixNames( std::list< Declaration* > & translationUnit ) { 52 PassVisitor<FixNames> fixer; 53 acceptAll( translationUnit, fixer ); 54 } 55 56 void FixNames::fixDWT( DeclarationWithType * dwt ) { 57 if ( dwt->get_name() != "" ) { 58 if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) { 59 if (!useNewAST) { 60 dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) ); 61 } 62 dwt->set_scopeLevel( scopeLevel ); 63 } // if 64 } // if 65 } 66 67 void FixNames::postvisit( ObjectDecl * objectDecl ) { 68 fixDWT( objectDecl ); 69 } 70 71 void FixNames::postvisit( FunctionDecl * functionDecl ) { 72 fixDWT( functionDecl ); 73 74 if ( FixMain::isMain( functionDecl ) ) { 75 int nargs = functionDecl->get_functionType()->get_parameters().size(); 76 if( !(nargs == 0 || nargs == 2 || nargs == 3) ) { 77 SemanticError(functionDecl, "Main expected to have 0, 2 or 3 arguments\n"); 78 } 79 functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) ); 80 } 81 } 82 83 void FixNames::previsit( CompoundStmt * ) { 84 scopeLevel++; 85 GuardAction( [this](){ scopeLevel--; } ); 86 } 31 namespace { 87 32 88 33 /// Does work with the main function and scopeLevels. 89 class FixNames _newfinal {34 class FixNames final { 90 35 int scopeLevel = 1; 91 36 … … 103 48 104 49 const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) { 105 if ( FixMain::isMain( functionDecl ) ) {50 if ( isMain( functionDecl ) ) { 106 51 auto mutDecl = ast::mutate( functionDecl ); 107 52 … … 138 83 }; 139 84 85 } // namespace 86 140 87 void fixNames( ast::TranslationUnit & translationUnit ) { 141 ast::Pass<FixNames _new>::run( translationUnit );88 ast::Pass<FixNames>::run( translationUnit ); 142 89 } 143 90 -
src/CodeGen/FixNames.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 class Declaration;21 18 namespace ast { 22 19 class TranslationUnit; … … 24 21 25 22 namespace CodeGen { 26 /// mangles object and function names 27 void fixNames( std::list< Declaration* > & translationUnit ); 23 28 24 /// Sets scope levels and fills in main's default return. 29 25 void fixNames( ast::TranslationUnit & translationUnit ); 26 30 27 } // namespace CodeGen 31 28 -
src/CodeGen/GenType.cc
rdf8ba61a r8d182b1 21 21 #include "AST/Print.hpp" // for print 22 22 #include "AST/Vector.hpp" // for vector 23 #include "CodeGenerator.h" // for CodeGenerator 24 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new 25 #include "SynTree/Declaration.h" // for DeclarationWithType 26 #include "SynTree/Expression.h" // for Expression 27 #include "SynTree/Type.h" // for PointerType, Type, FunctionType 28 #include "SynTree/Visitor.h" // for Visitor 23 #include "CodeGeneratorNew.hpp" // for CodeGenerator 24 #include "Common/UniqueName.h" // for UniqueName 29 25 30 26 namespace CodeGen { 31 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {32 std::string typeString;33 GenType( const std::string &typeString, const Options &options );34 35 void previsit( BaseSyntaxNode * );36 void postvisit( BaseSyntaxNode * );37 38 void postvisit( FunctionType * funcType );39 void postvisit( VoidType * voidType );40 void postvisit( BasicType * basicType );41 void postvisit( PointerType * pointerType );42 void postvisit( ArrayType * arrayType );43 void postvisit( ReferenceType * refType );44 void postvisit( StructInstType * structInst );45 void postvisit( UnionInstType * unionInst );46 void postvisit( EnumInstType * enumInst );47 void postvisit( TypeInstType * typeInst );48 void postvisit( TupleType * tupleType );49 void postvisit( VarArgsType * varArgsType );50 void postvisit( ZeroType * zeroType );51 void postvisit( OneType * oneType );52 void postvisit( GlobalScopeType * globalType );53 void postvisit( TraitInstType * inst );54 void postvisit( TypeofType * typeof );55 void postvisit( VTableType * vtable );56 void postvisit( QualifiedType * qualType );57 58 private:59 void handleQualifiers( Type *type );60 std::string handleGeneric( ReferenceToType * refType );61 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );62 63 Options options;64 };65 66 std::string genType( Type *type, const std::string &baseString, const Options &options ) {67 PassVisitor<GenType> gt( baseString, options );68 std::ostringstream os;69 70 if ( ! type->get_attributes().empty() ) {71 PassVisitor<CodeGenerator> cg( os, options );72 cg.pass.genAttributes( type->get_attributes() );73 } // if74 75 type->accept( gt );76 return os.str() + gt.pass.typeString;77 }78 79 std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {80 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) );81 }82 83 std::string genPrettyType( Type * type, const std::string & baseString ) {84 return genType( type, baseString, true, false );85 }86 87 GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {}88 89 // *** BaseSyntaxNode90 void GenType::previsit( BaseSyntaxNode * ) {91 // turn off automatic recursion for all nodes, to allow each visitor to92 // precisely control the order in which its children are visited.93 visit_children = false;94 }95 96 void GenType::postvisit( BaseSyntaxNode * node ) {97 std::stringstream ss;98 node->print( ss );99 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );100 }101 102 void GenType::postvisit( VoidType * voidType ) {103 typeString = "void " + typeString;104 handleQualifiers( voidType );105 }106 107 void GenType::postvisit( BasicType * basicType ) {108 BasicType::Kind kind = basicType->kind;109 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );110 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;111 handleQualifiers( basicType );112 }113 114 void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {115 std::ostringstream os;116 if ( typeString != "" ) {117 if ( typeString[ 0 ] == '*' ) {118 os << "(" << typeString << ")";119 } else {120 os << typeString;121 } // if122 } // if123 os << "[";124 125 if ( isStatic ) {126 os << "static ";127 } // if128 if ( qualifiers.is_const ) {129 os << "const ";130 } // if131 if ( qualifiers.is_volatile ) {132 os << "volatile ";133 } // if134 if ( qualifiers.is_restrict ) {135 os << "__restrict ";136 } // if137 if ( qualifiers.is_atomic ) {138 os << "_Atomic ";139 } // if140 if ( dimension != 0 ) {141 PassVisitor<CodeGenerator> cg( os, options );142 dimension->accept( cg );143 } else if ( isVarLen ) {144 // no dimension expression on a VLA means it came in with the * token145 os << "*";146 } // if147 os << "]";148 149 typeString = os.str();150 151 base->accept( *visitor );152 }153 154 void GenType::postvisit( PointerType * pointerType ) {155 assert( pointerType->base != 0);156 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {157 genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );158 } else {159 handleQualifiers( pointerType );160 if ( typeString[ 0 ] == '?' ) {161 typeString = "* " + typeString;162 } else {163 typeString = "*" + typeString;164 } // if165 pointerType->base->accept( *visitor );166 } // if167 }168 169 void GenType::postvisit( ArrayType * arrayType ) {170 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );171 }172 173 void GenType::postvisit( ReferenceType * refType ) {174 assert( 0 != refType->base );175 assertf( ! options.genC, "Reference types should not reach code generation." );176 handleQualifiers( refType );177 typeString = "&" + typeString;178 refType->base->accept( *visitor );179 }180 181 void GenType::postvisit( FunctionType * funcType ) {182 std::ostringstream os;183 184 if ( typeString != "" ) {185 if ( typeString[ 0 ] == '*' ) {186 os << "(" << typeString << ")";187 } else {188 os << typeString;189 } // if190 } // if191 192 /************* parameters ***************/193 194 const std::list<DeclarationWithType *> &pars = funcType->parameters;195 196 if ( pars.empty() ) {197 if ( funcType->get_isVarArgs() ) {198 os << "()";199 } else {200 os << "(void)";201 } // if202 } else {203 PassVisitor<CodeGenerator> cg( os, options );204 os << "(" ;205 206 cg.pass.genCommaList( pars.begin(), pars.end() );207 208 if ( funcType->get_isVarArgs() ) {209 os << ", ...";210 } // if211 os << ")";212 } // if213 214 typeString = os.str();215 216 if ( funcType->returnVals.size() == 0 ) {217 typeString = "void " + typeString;218 } else {219 funcType->returnVals.front()->get_type()->accept( *visitor );220 } // if221 222 // add forall223 if( ! funcType->forall.empty() && ! options.genC ) {224 // assertf( ! genC, "Aggregate type parameters should not reach code generation." );225 std::ostringstream os;226 PassVisitor<CodeGenerator> cg( os, options );227 os << "forall(";228 cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );229 os << ")" << std::endl;230 typeString = os.str() + typeString;231 }232 }233 234 std::string GenType::handleGeneric( ReferenceToType * refType ) {235 if ( ! refType->parameters.empty() ) {236 std::ostringstream os;237 PassVisitor<CodeGenerator> cg( os, options );238 os << "(";239 cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );240 os << ") ";241 return os.str();242 }243 return "";244 }245 246 void GenType::postvisit( StructInstType * structInst ) {247 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;248 if ( options.genC ) typeString = "struct " + typeString;249 handleQualifiers( structInst );250 }251 252 void GenType::postvisit( UnionInstType * unionInst ) {253 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;254 if ( options.genC ) typeString = "union " + typeString;255 handleQualifiers( unionInst );256 }257 258 void GenType::postvisit( EnumInstType * enumInst ) {259 if ( enumInst->baseEnum && enumInst->baseEnum->base ) {260 typeString = genType(enumInst->baseEnum->base, typeString, options);261 } else {262 typeString = enumInst->name + " " + typeString;263 if ( options.genC ) {264 typeString = "enum " + typeString;265 }266 }267 handleQualifiers( enumInst );268 }269 270 void GenType::postvisit( TypeInstType * typeInst ) {271 assertf( ! options.genC, "Type instance types should not reach code generation." );272 typeString = typeInst->name + " " + typeString;273 handleQualifiers( typeInst );274 }275 276 void GenType::postvisit( TupleType * tupleType ) {277 assertf( ! options.genC, "Tuple types should not reach code generation." );278 unsigned int i = 0;279 std::ostringstream os;280 os << "[";281 for ( Type * t : *tupleType ) {282 i++;283 os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");284 }285 os << "] ";286 typeString = os.str() + typeString;287 }288 289 void GenType::postvisit( VarArgsType * varArgsType ) {290 typeString = "__builtin_va_list " + typeString;291 handleQualifiers( varArgsType );292 }293 294 void GenType::postvisit( ZeroType * zeroType ) {295 // ideally these wouldn't hit codegen at all, but should be safe to make them ints296 typeString = (options.pretty ? "zero_t " : "long int ") + typeString;297 handleQualifiers( zeroType );298 }299 300 void GenType::postvisit( OneType * oneType ) {301 // ideally these wouldn't hit codegen at all, but should be safe to make them ints302 typeString = (options.pretty ? "one_t " : "long int ") + typeString;303 handleQualifiers( oneType );304 }305 306 void GenType::postvisit( GlobalScopeType * globalType ) {307 assertf( ! options.genC, "Global scope type should not reach code generation." );308 handleQualifiers( globalType );309 }310 311 void GenType::postvisit( TraitInstType * inst ) {312 assertf( ! options.genC, "Trait types should not reach code generation." );313 typeString = inst->name + " " + typeString;314 handleQualifiers( inst );315 }316 317 void GenType::postvisit( TypeofType * typeof ) {318 std::ostringstream os;319 PassVisitor<CodeGenerator> cg( os, options );320 os << "typeof(";321 typeof->expr->accept( cg );322 os << ") " << typeString;323 typeString = os.str();324 handleQualifiers( typeof );325 }326 327 void GenType::postvisit( VTableType * vtable ) {328 assertf( ! options.genC, "Virtual table types should not reach code generation." );329 std::ostringstream os;330 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString;331 typeString = os.str();332 handleQualifiers( vtable );333 }334 335 void GenType::postvisit( QualifiedType * qualType ) {336 assertf( ! options.genC, "Qualified types should not reach code generation." );337 std::ostringstream os;338 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString;339 typeString = os.str();340 handleQualifiers( qualType );341 }342 343 void GenType::handleQualifiers( Type * type ) {344 if ( type->get_const() ) {345 typeString = "const " + typeString;346 } // if347 if ( type->get_volatile() ) {348 typeString = "volatile " + typeString;349 } // if350 if ( type->get_restrict() ) {351 typeString = "__restrict " + typeString;352 } // if353 if ( type->get_atomic() ) {354 typeString = "_Atomic " + typeString;355 } // if356 }357 27 358 28 namespace { 359 29 360 #warning Remove the _new when old version is removed. 361 struct GenType_new : 30 struct GenType final : 362 31 public ast::WithShortCircuiting, 363 public ast::WithVisitorRef<GenType _new> {32 public ast::WithVisitorRef<GenType> { 364 33 std::string result; 365 GenType _new( const std::string &typeString, const Options &options );34 GenType( const std::string &typeString, const Options &options ); 366 35 367 36 void previsit( ast::Node const * ); … … 397 66 }; 398 67 399 GenType _new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}400 401 void GenType _new::previsit( ast::Node const * ) {68 GenType::GenType( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {} 69 70 void GenType::previsit( ast::Node const * ) { 402 71 // Turn off automatic recursion for all nodes, to allow each visitor to 403 72 // precisely control the order in which its children are visited. … … 405 74 } 406 75 407 void GenType _new::postvisit( ast::Node const * node ) {76 void GenType::postvisit( ast::Node const * node ) { 408 77 std::stringstream ss; 409 78 ast::print( ss, node ); … … 411 80 } 412 81 413 void GenType _new::postvisit( ast::VoidType const * type ) {82 void GenType::postvisit( ast::VoidType const * type ) { 414 83 result = "void " + result; 415 84 handleQualifiers( type ); 416 85 } 417 86 418 void GenType _new::postvisit( ast::BasicType const * type ) {87 void GenType::postvisit( ast::BasicType const * type ) { 419 88 ast::BasicType::Kind kind = type->kind; 420 89 assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES ); … … 423 92 } 424 93 425 void GenType _new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {94 void GenType::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) { 426 95 std::ostringstream os; 427 96 if ( result != "" ) { … … 449 118 } 450 119 if ( dimension != 0 ) { 451 ast::Pass<CodeGenerator _new>::read( dimension, os, options );120 ast::Pass<CodeGenerator>::read( dimension, os, options ); 452 121 } else if ( isVarLen ) { 453 122 // no dimension expression on a VLA means it came in with the * token … … 461 130 } 462 131 463 void GenType _new::postvisit( ast::PointerType const * type ) {132 void GenType::postvisit( ast::PointerType const * type ) { 464 133 if ( type->isStatic || type->isVarLen || type->dimension ) { 465 134 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); … … 475 144 } 476 145 477 void GenType _new::postvisit( ast::ArrayType const * type ) {146 void GenType::postvisit( ast::ArrayType const * type ) { 478 147 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); 479 148 } 480 149 481 void GenType _new::postvisit( ast::ReferenceType const * type ) {150 void GenType::postvisit( ast::ReferenceType const * type ) { 482 151 assertf( !options.genC, "Reference types should not reach code generation." ); 483 152 handleQualifiers( type ); … … 486 155 } 487 156 488 void GenType _new::postvisit( ast::FunctionType const * type ) {157 void GenType::postvisit( ast::FunctionType const * type ) { 489 158 std::ostringstream os; 490 159 … … 526 195 //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." ); 527 196 std::ostringstream os; 528 ast::Pass<CodeGenerator _new> cg( os, options );197 ast::Pass<CodeGenerator> cg( os, options ); 529 198 os << "forall("; 530 199 cg.core.genCommaList( type->forall ); … … 534 203 } 535 204 536 std::string GenType _new::handleGeneric( ast::BaseInstType const * type ) {205 std::string GenType::handleGeneric( ast::BaseInstType const * type ) { 537 206 if ( !type->params.empty() ) { 538 207 std::ostringstream os; 539 ast::Pass<CodeGenerator _new> cg( os, options );208 ast::Pass<CodeGenerator> cg( os, options ); 540 209 os << "("; 541 210 cg.core.genCommaList( type->params ); … … 546 215 } 547 216 548 void GenType _new::postvisit( ast::StructInstType const * type ) {217 void GenType::postvisit( ast::StructInstType const * type ) { 549 218 result = type->name + handleGeneric( type ) + " " + result; 550 219 if ( options.genC ) result = "struct " + result; … … 552 221 } 553 222 554 void GenType _new::postvisit( ast::UnionInstType const * type ) {223 void GenType::postvisit( ast::UnionInstType const * type ) { 555 224 result = type->name + handleGeneric( type ) + " " + result; 556 225 if ( options.genC ) result = "union " + result; … … 558 227 } 559 228 560 void GenType _new::postvisit( ast::EnumInstType const * type ) {229 void GenType::postvisit( ast::EnumInstType const * type ) { 561 230 if ( type->base && type->base->base ) { 562 231 result = genType( type->base->base, result, options ); … … 570 239 } 571 240 572 void GenType _new::postvisit( ast::TypeInstType const * type ) {241 void GenType::postvisit( ast::TypeInstType const * type ) { 573 242 assertf( !options.genC, "TypeInstType should not reach code generation." ); 574 243 result = type->name + " " + result; … … 576 245 } 577 246 578 void GenType _new::postvisit( ast::TupleType const * type ) {247 void GenType::postvisit( ast::TupleType const * type ) { 579 248 assertf( !options.genC, "TupleType should not reach code generation." ); 580 249 unsigned int i = 0; … … 589 258 } 590 259 591 void GenType _new::postvisit( ast::VarArgsType const * type ) {260 void GenType::postvisit( ast::VarArgsType const * type ) { 592 261 result = "__builtin_va_list " + result; 593 262 handleQualifiers( type ); 594 263 } 595 264 596 void GenType _new::postvisit( ast::ZeroType const * type ) {265 void GenType::postvisit( ast::ZeroType const * type ) { 597 266 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 598 267 result = (options.pretty ? "zero_t " : "long int ") + result; … … 600 269 } 601 270 602 void GenType _new::postvisit( ast::OneType const * type ) {271 void GenType::postvisit( ast::OneType const * type ) { 603 272 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 604 273 result = (options.pretty ? "one_t " : "long int ") + result; … … 606 275 } 607 276 608 void GenType _new::postvisit( ast::GlobalScopeType const * type ) {277 void GenType::postvisit( ast::GlobalScopeType const * type ) { 609 278 assertf( !options.genC, "GlobalScopeType should not reach code generation." ); 610 279 handleQualifiers( type ); 611 280 } 612 281 613 void GenType _new::postvisit( ast::TraitInstType const * type ) {282 void GenType::postvisit( ast::TraitInstType const * type ) { 614 283 assertf( !options.genC, "TraitInstType should not reach code generation." ); 615 284 result = type->name + " " + result; … … 617 286 } 618 287 619 void GenType _new::postvisit( ast::TypeofType const * type ) {288 void GenType::postvisit( ast::TypeofType const * type ) { 620 289 std::ostringstream os; 621 290 os << "typeof("; 622 ast::Pass<CodeGenerator _new>::read( type, os, options );291 ast::Pass<CodeGenerator>::read( type, os, options ); 623 292 os << ") " << result; 624 293 result = os.str(); … … 626 295 } 627 296 628 void GenType _new::postvisit( ast::VTableType const * type ) {297 void GenType::postvisit( ast::VTableType const * type ) { 629 298 assertf( !options.genC, "Virtual table types should not reach code generation." ); 630 299 std::ostringstream os; … … 634 303 } 635 304 636 void GenType _new::postvisit( ast::QualifiedType const * type ) {305 void GenType::postvisit( ast::QualifiedType const * type ) { 637 306 assertf( !options.genC, "QualifiedType should not reach code generation." ); 638 307 std::ostringstream os; … … 642 311 } 643 312 644 void GenType _new::handleQualifiers( ast::Type const * type ) {313 void GenType::handleQualifiers( ast::Type const * type ) { 645 314 if ( type->is_const() ) { 646 315 result = "const " + result; … … 657 326 } 658 327 659 std::string GenType _new::genParamList( const ast::vector<ast::Type> & range ) {328 std::string GenType::genParamList( const ast::vector<ast::Type> & range ) { 660 329 auto cur = range.begin(); 661 330 auto end = range.end(); 662 331 if ( cur == end ) return ""; 663 332 std::ostringstream oss; 664 for ( unsigned int i = 0 ; ; ++i ) { 665 oss << genType( *cur++, "__param_" + std::to_string(i), options ); 333 UniqueName param( "__param_" ); 334 while ( true ) { 335 oss << genType( *cur++, options.genC ? param.newName() : "", options ); 666 336 if ( cur == end ) break; 667 337 oss << ", "; … … 675 345 std::ostringstream os; 676 346 if ( !type->attributes.empty() ) { 677 ast::Pass<CodeGenerator _new> cg( os, options );347 ast::Pass<CodeGenerator> cg( os, options ); 678 348 cg.core.genAttributes( type->attributes ); 679 349 } 680 350 681 return os.str() + ast::Pass<GenType _new>::read( type, base, options );351 return os.str() + ast::Pass<GenType>::read( type, base, options ); 682 352 } 683 353 684 354 std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) { 685 return ast::Pass<GenType _new>::read( type, base, options );355 return ast::Pass<GenType>::read( type, base, options ); 686 356 } 687 357 -
src/CodeGen/Generate.cc
rdf8ba61a r8d182b1 19 19 #include <string> // for operator<< 20 20 21 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new, doSemicolon, ... 22 #include "CodeGenerator.h" // for CodeGenerator, doSemicolon, oper... 21 #include "CodeGeneratorNew.hpp" // for CodeGenerator, doSemicolon, ... 23 22 #include "GenType.h" // for genPrettyType 24 #include "Common/PassVisitor.h" // for PassVisitor25 #include "SynTree/LinkageSpec.h" // for isBuiltin, isGeneratable26 #include "SynTree/BaseSyntaxNode.h" // for BaseSyntaxNode27 #include "SynTree/Declaration.h" // for Declaration28 #include "SynTree/Type.h" // for Type29 23 30 24 using namespace std; 31 25 32 26 namespace CodeGen { 33 namespace {34 /// Removes misc. nodes that should not exist in CodeGen35 struct TreeCleaner {36 void premutate( CompoundStmt * stmt );37 Statement * postmutate( ImplicitCtorDtorStmt * stmt );38 39 static bool shouldClean( Declaration * );40 };41 42 void cleanTree( std::list< Declaration * > & translationUnit ) {43 PassVisitor<TreeCleaner> cleaner;44 filter( translationUnit, [](Declaration * decl) { return TreeCleaner::shouldClean(decl); }, false );45 mutateAll( translationUnit, cleaner );46 } // cleanTree47 } // namespace48 49 void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {50 cleanTree( translationUnit );51 52 PassVisitor<CodeGenerator> cgv( os, pretty, generateC, lineMarks, printExprTypes );53 for ( auto & dcl : translationUnit ) {54 if ( LinkageSpec::isGeneratable( dcl->get_linkage() ) && (doIntrinsics || ! LinkageSpec::isBuiltin( dcl->get_linkage() ) ) ) {55 cgv.pass.updateLocation( dcl );56 dcl->accept(cgv);57 if ( doSemicolon( dcl ) ) {58 os << ";";59 } // if60 os << cgv.pass.endl;61 } // if62 } // for63 }64 65 void generate( BaseSyntaxNode * node, std::ostream & os ) {66 if ( Type * type = dynamic_cast< Type * >( node ) ) {67 os << genPrettyType( type, "" );68 } else {69 PassVisitor<CodeGenerator> cgv( os, true, false, false, false );70 node->accept( cgv );71 }72 os << std::endl;73 }74 75 namespace {76 void TreeCleaner::premutate( CompoundStmt * cstmt ) {77 filter( cstmt->kids, [](Statement * stmt) {78 if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( stmt ) ) {79 return shouldClean( declStmt->decl );80 }81 return false;82 }, false );83 }84 85 Statement * TreeCleaner::postmutate( ImplicitCtorDtorStmt * stmt ) {86 Statement * callStmt = nullptr;87 std::swap( stmt->callStmt, callStmt );88 delete stmt;89 return callStmt;90 }91 92 bool TreeCleaner::shouldClean( Declaration * decl ) {93 return dynamic_cast< TraitDecl * >( decl );94 }95 } // namespace96 27 97 28 namespace { … … 101 32 102 33 /// Removes various nodes that should not exist in CodeGen. 103 struct TreeCleaner _new{34 struct TreeCleaner final { 104 35 ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) { 105 36 auto mutStmt = ast::mutate( stmt ); … … 120 51 bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) { 121 52 erase_if( translationUnit.decls, shouldClean ); 122 ast::Pass<TreeCleaner _new>::run( translationUnit );53 ast::Pass<TreeCleaner>::run( translationUnit ); 123 54 124 ast::Pass<CodeGenerator _new> cgv( os,55 ast::Pass<CodeGenerator> cgv( os, 125 56 Options( pretty, generateC, lineMarks, printExprTypes ) ); 126 57 for ( auto & decl : translationUnit.decls ) { -
src/CodeGen/Generate.h
rdf8ba61a r8d182b1 17 17 18 18 #include <iostream> // for ostream 19 #include <list> // for list20 21 class BaseSyntaxNode;22 class Declaration;23 19 24 20 namespace ast { … … 27 23 28 24 namespace CodeGen { 29 /// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.)30 void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC = false , bool lineMarks = false, bool printTypeExpr = false );31 32 /// Generate code for a single node -- helpful for debugging in gdb33 void generate( BaseSyntaxNode * node, std::ostream & os );34 25 35 26 /// Generates all code in transUnit and writing it to the os. -
src/CodeGen/LinkOnce.cc
rdf8ba61a r8d182b1 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h" // for PassVisitor, WithShortCircuiting25 24 26 25 namespace CodeGen { 27 26 28 27 namespace { 29 30 bool is_cfa_linkonce_old( Attribute const * attr ) {31 return std::string("cfa_linkonce") == attr->name;32 }33 34 bool is_section_attribute_old( Attribute const * attr ) {35 return std::string("section") == attr->name;36 }37 38 class LinkOnceVisitorCore : public WithShortCircuiting {39 public:40 void previsit( Declaration * ) {41 visit_children = false;42 }43 44 void previsit( DeclarationWithType * decl ) {45 std::list< Attribute * > & attributes = decl->attributes;46 // See if we can find the element:47 auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce_old );48 if ( attributes.end() != found ) {49 // Remove any other sections:50 attributes.remove_if( is_section_attribute_old );51 // Iterator to the cfa_linkonce attribute should still be valid.52 Attribute * attribute = *found;53 assert( attribute->parameters.empty() );54 assert( !decl->mangleName.empty() );55 // Overwrite the attribute in place.56 const std::string section_name = ".gnu.linkonce." + decl->mangleName;57 attribute->name = "section";58 attribute->parameters.push_back(59 new ConstantExpr( Constant::from_string( section_name ) )60 );61 62 // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce63 // visibility is a mess otherwise64 attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));65 66 }67 visit_children = false;68 }69 };70 28 71 29 bool is_cfa_linkonce( ast::Attribute const * attr ) { … … 122 80 } // namespace 123 81 124 void translateLinkOnce( std::list< Declaration *> & translationUnit ) {125 PassVisitor<LinkOnceVisitorCore> translator;126 acceptAll( translationUnit, translator );127 }128 129 82 void translateLinkOnce( ast::TranslationUnit & translationUnit ) { 130 83 ast::Pass<LinkOnceCore>::run( translationUnit ); -
src/CodeGen/LinkOnce.h
rdf8ba61a r8d182b1 20 20 // for now its almost the only attribute we handle. 21 21 22 #include <list> // for list23 22 24 class Declaration;25 23 namespace ast { 26 24 class TranslationUnit; … … 29 27 namespace CodeGen { 30 28 31 void translateLinkOnce( std::list< Declaration *> & translationUnit );32 29 void translateLinkOnce( ast::TranslationUnit & translationUnit ); 33 30 /* Convert the cfa_linkonce attribute on top level declaration into -
src/CodeGen/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC_CODEGEN = \ 18 CodeGen/FixMain2.cc \ 19 CodeGen/FixMain.h \ 18 CodeGen/CodeGeneratorNew.cpp \ 19 CodeGen/CodeGeneratorNew.hpp \ 20 CodeGen/GenType.cc \ 21 CodeGen/GenType.h \ 20 22 CodeGen/OperatorTable.cc \ 21 23 CodeGen/OperatorTable.h 22 24 23 25 SRC += $(SRC_CODEGEN) \ 24 CodeGen/CodeGenerator.cc \25 CodeGen/CodeGenerator.h \26 CodeGen/CodeGeneratorNew.cpp \27 CodeGen/CodeGeneratorNew.hpp \28 26 CodeGen/Generate.cc \ 29 27 CodeGen/Generate.h \ 30 28 CodeGen/FixMain.cc \ 29 CodeGen/FixMain.h \ 31 30 CodeGen/FixNames.cc \ 32 31 CodeGen/FixNames.h \ 33 CodeGen/GenType.cc \34 CodeGen/GenType.h \35 32 CodeGen/LinkOnce.cc \ 36 33 CodeGen/LinkOnce.h \ -
src/Common/Eval.cc
rdf8ba61a r8d182b1 19 19 20 20 #include "AST/Inspect.hpp" 21 #include "Common/PassVisitor.h"22 21 #include "CodeGen/OperatorTable.h" // access: OperatorInfo 23 22 #include "AST/Pass.hpp" 24 23 #include "InitTweak/InitTweak.h" 25 #include "SynTree/Expression.h" 26 27 //------------------------------------------------------------- 28 // Old AST 29 struct EvalOld : public WithShortCircuiting { 30 long long int value = 0; // compose the result of the constant expression 31 bool valid = true; // true => constant expression and value is the result 32 // false => not constant expression, e.g., ++i 33 bool cfavalid = true; // true => constant expression and value computable 34 // false => constant expression but value not computable, e.g., sizeof(int) 35 36 void previsit( const BaseSyntaxNode * ) { visit_children = false; } 37 void postvisit( const BaseSyntaxNode * ) { valid = false; } 38 39 void postvisit( const SizeofExpr * ) { 40 } 41 42 void postvisit( const ConstantExpr * expr ) { 43 value = expr->intValue(); 44 } 45 46 void postvisit( const CastExpr * expr ) { 47 auto arg = eval(expr->arg); 48 valid = arg.second; 49 value = arg.first; 50 // TODO: perform type conversion on value if valid 51 } 52 53 void postvisit( const VariableExpr * const expr ) { 54 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) { 55 if ( EnumDecl * decl = inst->baseEnum ) { 56 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf 57 return; 58 } 59 } 60 } 61 valid = false; 62 } 63 64 void postvisit( const ApplicationExpr * expr ) { 65 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr)); 66 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; } 67 const std::string & fname = function->name; 68 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() ); 69 std::pair<long long int, bool> arg1, arg2; 70 arg1 = eval(expr->args.front()); 71 valid = valid && arg1.second; 72 if ( ! valid ) return; 73 if ( expr->args.size() == 2 ) { 74 arg2 = eval(expr->args.back()); 75 valid = valid && arg2.second; 76 if ( ! valid ) return; 77 } 78 if (fname == "?+?") { 79 value = arg1.first + arg2.first; 80 } else if (fname == "?-?") { 81 value = arg1.first - arg2.first; 82 } else if (fname == "?*?") { 83 value = arg1.first * arg2.first; 84 } else if (fname == "?/?") { 85 value = arg1.first / arg2.first; 86 } else if (fname == "?%?") { 87 value = arg1.first % arg2.first; 88 } else { 89 valid = false; 90 } 91 // TODO: implement other intrinsic functions 92 } 93 }; 94 95 //------------------------------------------------------------- 96 // New AST 24 97 25 struct EvalNew : public ast::WithShortCircuiting { 98 26 Evaluation result = { 0, true, true }; … … 270 198 }; 271 199 272 std::pair<long long int, bool> eval( const Expression * expr ) {273 PassVisitor<EvalOld> ev;274 if ( expr ) {275 expr->accept( ev );276 return std::make_pair( ev.pass.value, ev.pass.valid );277 } else {278 return std::make_pair( 0, false );279 }280 }281 282 200 Evaluation eval( const ast::Expr * expr ) { 283 201 if ( expr ) { -
src/Common/Eval.h
rdf8ba61a r8d182b1 30 30 31 31 /// Evaluates expr as a long long int. 32 /// If second is false, expr could not be evaluated.33 std::pair<long long int, bool> eval(const Expression * expr);34 32 Evaluation eval(const ast::Expr * expr); 35 33 -
src/Common/Examine.cc
rdf8ba61a r8d182b1 19 19 #include "CodeGen/OperatorTable.h" 20 20 #include "InitTweak/InitTweak.h" 21 22 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {23 if (func->name != "main") return nullptr;24 if (func->type->parameters.size() != 1) return nullptr;25 26 auto param = func->type->parameters.front();27 28 auto type = dynamic_cast<ReferenceType * >(param->get_type());29 if (!type) return nullptr;30 31 auto obj = dynamic_cast<StructInstType *>(type->base);32 if (!obj) return nullptr;33 34 if (kind != obj->baseStruct->kind) return nullptr;35 36 return param;37 }38 21 39 22 namespace { … … 69 52 70 53 namespace { 71 Type * getDestructorParam( FunctionDecl * func ) {72 if ( !CodeGen::isDestructor( func->name ) ) return nullptr;73 74 auto params = func->type->parameters;75 if ( 1 != params.size() ) return nullptr;76 77 auto ref = dynamic_cast<ReferenceType *>( params.front()->get_type() );78 if ( ref ) {79 return ref->base;80 }81 return nullptr;82 }83 54 84 55 const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) { … … 88 59 } 89 60 90 }91 92 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ) {93 if ( Type * type = getDestructorParam( func ) ) {94 auto stype = dynamic_cast<StructInstType *>( type );95 return stype && stype->baseStruct == type_decl;96 }97 return false;98 61 } 99 62 -
src/Common/Examine.h
rdf8ba61a r8d182b1 15 15 16 16 #include "AST/Decl.hpp" 17 #include "SynTree/Declaration.h"18 17 19 18 /// Check if this is a main function for a type of an aggregate kind. 20 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );21 19 const ast::DeclWithType * isMainFor( 22 20 const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ); … … 24 22 25 23 /// Check if this function is a destructor for the given structure. 26 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );27 24 bool isDestructorFor( 28 25 const ast::FunctionDecl * func, const ast::StructDecl * type ); -
src/Common/UniqueName.cc
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.cc -- 7 // UniqueName.cc -- Create a unique variants of a base name with a counter. 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jun 8 14:47:49 201513 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Nov 7 15:04:00 2023 13 // Update Count : 4 14 14 // 15 15 16 #include <string> 17 #include <sstream> 16 #include "UniqueName.h" 18 17 19 #include " UniqueName.h"18 #include "Common/ToString.hpp" 20 19 21 20 UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) { … … 23 22 24 23 std::string UniqueName::newName( const std::string &additional ) { 25 std::ostringstream os; 26 os << base << additional << count++; 27 return os.str(); 24 return toString( base, additional, count++ ); 28 25 } 29 26 -
src/Common/UniqueName.h
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.h -- 7 // UniqueName.h -- Create a unique variants of a base name with a counter. 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 21 22:18:45 201713 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Nov 7 15:00:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 19 19 20 20 class UniqueName { 21 22 UniqueName( const std::string &base = "");21 public: 22 UniqueName( const std::string &base ); 23 23 std::string newName( const std::string &additional = "" ); 24 24 private: 25 25 std::string base; 26 26 int count; -
src/Common/module.mk
rdf8ba61a r8d182b1 31 31 Common/Indenter.cc \ 32 32 Common/Iterate.hpp \ 33 Common/PassVisitor.cc \34 Common/PassVisitor.h \35 Common/PassVisitor.impl.h \36 Common/PassVisitor.proto.h \37 33 Common/PersistentMap.h \ 38 34 Common/ResolvProtoDump.hpp \ -
src/Concurrency/module.mk
rdf8ba61a r8d182b1 21 21 Concurrency/Corun.hpp \ 22 22 Concurrency/KeywordsNew.cpp \ 23 Concurrency/Keywords.cc \24 23 Concurrency/Keywords.h \ 25 24 Concurrency/WaitforNew.cpp \ 26 Concurrency/Waitfor.cc \27 25 Concurrency/Waitfor.h \ 28 26 Concurrency/Waituntil.cpp \ -
src/ControlStruct/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC += \ 18 ControlStruct/ExceptDecl.cc \19 18 ControlStruct/ExceptDeclNew.cpp \ 20 19 ControlStruct/ExceptDecl.h \ 21 20 ControlStruct/ExceptTranslateNew.cpp \ 22 ControlStruct/ExceptTranslate.cc \23 21 ControlStruct/ExceptTranslate.h \ 24 22 ControlStruct/FixLabels.cpp \ 25 23 ControlStruct/FixLabels.hpp \ 26 ControlStruct/ForExprMutator.cc \27 ControlStruct/ForExprMutator.h \28 24 ControlStruct/HoistControlDecls.cpp \ 29 25 ControlStruct/HoistControlDecls.hpp \ 30 ControlStruct/LabelFixer.cc \31 ControlStruct/LabelFixer.h \32 ControlStruct/LabelGenerator.cc \33 ControlStruct/LabelGenerator.h \34 26 ControlStruct/LabelGeneratorNew.cpp \ 35 27 ControlStruct/LabelGeneratorNew.hpp \ 36 ControlStruct/MLEMutator.cc \37 ControlStruct/MLEMutator.h \38 28 ControlStruct/MultiLevelExit.cpp \ 39 ControlStruct/MultiLevelExit.hpp \ 40 ControlStruct/Mutate.cc \ 41 ControlStruct/Mutate.h 29 ControlStruct/MultiLevelExit.hpp 42 30 -
src/GenPoly/FindFunction.cc
rdf8ba61a r8d182b1 20 20 #include "AST/Pass.hpp" // for Pass 21 21 #include "AST/Type.hpp" 22 #include "Common/PassVisitor.h" // for PassVisitor23 22 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::iterator 24 23 #include "GenPoly/GenPoly.h" // for TyVarMap 25 24 #include "ScrubTyVars.h" // for ScrubTyVars 26 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl27 #include "SynTree/Mutator.h" // for Mutator, mutateAll28 #include "SynTree/Type.h" // for FunctionType, Type, Type::For...29 25 30 26 namespace GenPoly { 31 class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting {32 public:33 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );34 35 void premutate( FunctionType * functionType );36 Type * postmutate( FunctionType * functionType );37 void premutate( PointerType * pointerType );38 private:39 void handleForall( const Type::ForallList &forall );40 41 std::list< FunctionType const * > & functions;42 TyVarMap tyVars;43 bool replaceMode;44 FindFunctionPredicate predicate;45 };46 47 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {48 PassVisitor<FindFunction> finder( functions, tyVars, false, predicate );49 type->acceptMutator( finder );50 }51 52 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {53 PassVisitor<FindFunction> finder( functions, tyVars, true, predicate );54 type = type->acceptMutator( finder );55 }56 57 FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )58 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) {59 }60 61 void FindFunction::handleForall( const Type::ForallList &forall ) {62 for ( const Declaration * td : forall ) {63 TyVarMap::iterator var = tyVars.find( td->name );64 if ( var != tyVars.end() ) {65 tyVars.erase( var->first );66 } // if67 } // for68 }69 70 void FindFunction::premutate( FunctionType * functionType ) {71 visit_children = false;72 GuardScope( tyVars );73 handleForall( functionType->get_forall() );74 mutateAll( functionType->get_returnVals(), *visitor );75 }76 77 Type * FindFunction::postmutate( FunctionType * functionType ) {78 Type *ret = functionType;79 if ( predicate( functionType, tyVars ) ) {80 functions.push_back( functionType );81 if ( replaceMode ) {82 // replace type parameters in function type with void*83 ret = ScrubTyVars::scrub( functionType->clone(), tyVars );84 } // if85 } // if86 return ret;87 }88 89 void FindFunction::premutate( PointerType * pointerType ) {90 GuardScope( tyVars );91 handleForall( pointerType->get_forall() );92 }93 27 94 28 namespace { … … 154 88 void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) { 155 89 GuardScope( typeVars ); 156 //handleForall( type->forall );157 90 } 158 91 … … 164 97 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false ); 165 98 type->accept( pass ); 166 //(void)type;167 //(void)functions;168 //(void)typeVars;169 //(void)predicate;170 99 } 171 100 … … 175 104 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true ); 176 105 return type->accept( pass ); 177 //(void)functions;178 //(void)typeVars;179 //(void)predicate;180 //return type;181 106 } 182 107 -
src/GenPoly/FindFunction.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 18 #include "GenPoly.h" // for TyVarMap 21 19 22 class FunctionType;23 class Type;24 25 20 namespace GenPoly { 26 typedef bool (*FindFunctionPredicate)( FunctionType*, const TyVarMap& );27 28 /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions`29 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );30 /// like `findFunction`, but also replaces the function type with void ()(void)31 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );32 21 33 22 typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & ); -
src/GenPoly/GenPoly.cc
rdf8ba61a r8d182b1 29 29 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::const_it... 30 30 #include "ResolvExpr/typeops.h" // for flatten 31 #include "SynTree/Constant.h" // for Constant32 #include "SynTree/Expression.h" // for Expression, TypeExpr, Constan...33 #include "SynTree/Type.h" // for Type, StructInstType, UnionIn...34 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution35 31 36 32 using namespace std; … … 39 35 namespace { 40 36 /// Checks a parameter list for polymorphic parameters; will substitute according to env if present 41 bool hasPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {42 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {43 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );44 assertf(paramType, "Aggregate parameters should be type expressions");45 if ( isPolyType( paramType->get_type(), env ) ) return true;46 }47 return false;48 }49 50 37 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) { 51 38 for ( auto ¶m : params ) { … … 58 45 59 46 /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present 60 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {61 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {62 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );63 assertf(paramType, "Aggregate parameters should be type expressions");64 if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true;65 }66 return false;67 }68 69 47 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) { 70 48 for ( auto & param : params ) { … … 77 55 78 56 /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present 79 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {80 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {81 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );82 assertf(paramType, "Aggregate parameters should be type expressions");83 if ( isDynType( paramType->get_type(), tyVars, env ) ) return true;84 }85 return false;86 }87 88 57 bool hasDynParams( 89 58 const std::vector<ast::ptr<ast::Expr>> & params, … … 99 68 return false; 100 69 } 101 102 /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present103 bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {104 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {105 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );106 assertf(paramType, "Aggregate parameters should be type expressions");107 if ( includesPolyType( paramType->get_type(), env ) ) return true;108 }109 return false;110 }111 112 /// Checks a parameter list for inclusion of polymorphic parameters from tyVars; will substitute according to env if present113 bool includesPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {114 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {115 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );116 assertf(paramType, "Aggregate parameters should be type expressions");117 if ( includesPolyType( paramType->get_type(), tyVars, env ) ) return true;118 }119 return false;120 }121 }122 123 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ) {124 if ( ! env ) return type;125 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {126 Type *newType = env->lookup( typeInst->get_name() );127 if ( newType ) return newType;128 }129 return type;130 }131 132 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) {133 if ( ! env ) return type;134 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) {135 Type *newType = env->lookup( typeInst->get_name() );136 if ( newType ) return newType;137 }138 return type;139 70 } 140 71 … … 146 77 } 147 78 return type; 148 }149 150 Type *isPolyType( Type *type, const TypeSubstitution *env ) {151 type = replaceTypeInst( type, env );152 153 if ( dynamic_cast< TypeInstType * >( type ) ) {154 return type;155 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {156 return isPolyType( arrayType->base, env );157 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {158 if ( hasPolyParams( structType->get_parameters(), env ) ) return type;159 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {160 if ( hasPolyParams( unionType->get_parameters(), env ) ) return type;161 }162 return 0;163 79 } 164 80 … … 178 94 } 179 95 180 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {181 type = replaceTypeInst( type, env );182 183 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {184 if ( tyVars.contains( typeInst->get_name() ) ) {185 return type;186 }187 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {188 return isPolyType( arrayType->base, tyVars, env );189 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {190 if ( hasPolyParams( structType->get_parameters(), tyVars, env ) ) return type;191 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {192 if ( hasPolyParams( unionType->get_parameters(), tyVars, env ) ) return type;193 }194 return 0;195 }196 197 96 const ast::Type * isPolyType( const ast::Type * type, 198 97 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 211 110 } 212 111 213 ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {214 type = replaceTypeInst( type, env );215 216 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {217 auto var = tyVars.find( typeInst->get_name() );218 if ( var != tyVars.end() && var->second.isComplete ) {219 return typeInst;220 }221 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {222 if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType;223 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {224 if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType;225 }226 return 0;227 }228 229 112 const ast::BaseInstType * isDynType( 230 113 const ast::Type * type, const TypeVarMap & typeVars, … … 249 132 } 250 133 251 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) {252 if ( function->get_returnVals().empty() ) return 0;253 254 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );255 }256 257 134 const ast::BaseInstType *isDynRet( 258 135 const ast::FunctionType * type, const TypeVarMap & typeVars ) { … … 262 139 } 263 140 264 ReferenceToType *isDynRet( FunctionType *function ) {265 if ( function->get_returnVals().empty() ) return 0;266 267 TyVarMap forallTypes( TypeDecl::Data{} );268 makeTyVarMap( function, forallTypes );269 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );270 }271 272 141 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) { 273 142 if ( func->returns.empty() ) return nullptr; … … 278 147 } 279 148 280 bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {281 // if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {282 // return true;283 // } // if284 if ( isDynRet( adaptee, tyVars ) ) return true;285 286 for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) {287 // if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) {288 if ( isDynType( (*innerArg)->get_type(), tyVars ) ) {289 return true;290 } // if291 } // for292 return false;293 }294 295 149 bool needsAdapter( 296 150 ast::FunctionType const * adaptee, const TypeVarMap & typeVars ) { … … 304 158 return false; 305 159 } 306 307 Type *isPolyPtr( Type *type, const TypeSubstitution *env ) {308 type = replaceTypeInst( type, env );309 310 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {311 return isPolyType( ptr->get_base(), env );312 }313 return 0;314 }315 316 Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {317 type = replaceTypeInst( type, env );318 319 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {320 return isPolyType( ptr->get_base(), tyVars, env );321 }322 return 0;323 }324 160 325 161 const ast::Type * isPolyPtr( … … 333 169 return nullptr; 334 170 } 335 336 Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {337 int dummy;338 if ( ! levels ) { levels = &dummy; }339 *levels = 0;340 341 while ( true ) {342 type = replaceTypeInst( type, env );343 344 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {345 type = ptr->get_base();346 ++(*levels);347 } else break;348 }349 350 return isPolyType( type, env );351 }352 353 Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) {354 int dummy;355 if ( ! levels ) { levels = &dummy; }356 *levels = 0;357 358 while ( true ) {359 type = replaceTypeInst( type, env );360 361 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {362 type = ptr->get_base();363 ++(*levels);364 } else break;365 }366 367 return isPolyType( type, tyVars, env );368 }369 171 370 172 ast::Type const * hasPolyBase( … … 388 190 } 389 191 390 bool includesPolyType( Type *type, const TypeSubstitution *env ) {391 type = replaceTypeInst( type, env );392 393 if ( dynamic_cast< TypeInstType * >( type ) ) {394 return true;395 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {396 if ( includesPolyType( pointerType->get_base(), env ) ) return true;397 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {398 if ( includesPolyParams( structType->get_parameters(), env ) ) return true;399 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {400 if ( includesPolyParams( unionType->get_parameters(), env ) ) return true;401 }402 return false;403 }404 405 bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {406 type = replaceTypeInst( type, env );407 408 if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) {409 if ( tyVars.contains( typeInstType->get_name() ) ) {410 return true;411 }412 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {413 if ( includesPolyType( pointerType->get_base(), tyVars, env ) ) return true;414 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {415 if ( includesPolyParams( structType->get_parameters(), tyVars, env ) ) return true;416 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {417 if ( includesPolyParams( unionType->get_parameters(), tyVars, env ) ) return true;418 }419 return false;420 }421 422 FunctionType * getFunctionType( Type *ty ) {423 PointerType *ptrType;424 if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) {425 return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise426 } else {427 return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise428 }429 }430 431 192 const ast::FunctionType * getFunctionType( const ast::Type * ty ) { 432 193 if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) { … … 437 198 } 438 199 439 VariableExpr * getBaseVar( Expression *expr, int *levels ) {440 int dummy;441 if ( ! levels ) { levels = &dummy; }442 *levels = 0;443 444 while ( true ) {445 if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) {446 return varExpr;447 } else if ( MemberExpr *memberExpr = dynamic_cast< MemberExpr* >( expr ) ) {448 expr = memberExpr->get_aggregate();449 } else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) {450 expr = addressExpr->get_arg();451 } else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) {452 // look for compiler-inserted dereference operator453 NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() );454 if ( ! fn || fn->get_name() != std::string("*?") ) return 0;455 expr = *untypedExpr->begin_args();456 } else if ( CommaExpr *commaExpr = dynamic_cast< CommaExpr* >( expr ) ) {457 // copy constructors insert comma exprs, look at second argument which contains the variable458 expr = commaExpr->get_arg2();459 continue;460 } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( expr ) ) {461 int lvl1;462 int lvl2;463 VariableExpr * var1 = getBaseVar( condExpr->get_arg2(), &lvl1 );464 VariableExpr * var2 = getBaseVar( condExpr->get_arg3(), &lvl2 );465 if ( lvl1 == lvl2 && var1 && var2 && var1->get_var() == var2->get_var() ) {466 *levels = lvl1;467 return var1;468 }469 break;470 } else break;471 472 ++(*levels);473 }474 475 return 0;476 }477 478 200 namespace { 479 201 /// Checks if is a pointer to D … … 488 210 inline D const * as( B const * p ) { 489 211 return reinterpret_cast<D const *>( p ); 490 }491 492 /// Flattens a declaration list493 template<typename Output>494 void flattenList( list< DeclarationWithType* > src, Output out ) {495 for ( DeclarationWithType* decl : src ) {496 ResolvExpr::flatten( decl->get_type(), out );497 }498 }499 500 /// Flattens a list of types501 template<typename Output>502 void flattenList( list< Type* > src, Output out ) {503 for ( Type* ty : src ) {504 ResolvExpr::flatten( ty, out );505 }506 212 } 507 213 … … 515 221 } 516 222 517 /// Checks if two lists of parameters are equal up to polymorphic substitution.518 bool paramListsPolyCompatible( const list< Expression* >& aparams, const list< Expression* >& bparams ) {519 if ( aparams.size() != bparams.size() ) return false;520 521 for ( list< Expression* >::const_iterator at = aparams.begin(), bt = bparams.begin();522 at != aparams.end(); ++at, ++bt ) {523 TypeExpr *aparam = dynamic_cast< TypeExpr* >(*at);524 assertf(aparam, "Aggregate parameters should be type expressions");525 TypeExpr *bparam = dynamic_cast< TypeExpr* >(*bt);526 assertf(bparam, "Aggregate parameters should be type expressions");527 528 // xxx - might need to let VoidType be a wildcard here too; could have some voids529 // stuffed in for dtype-statics.530 // if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue;531 if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false;532 }533 534 return true;535 }536 537 223 bool paramListsPolyCompatible( 538 224 std::vector<ast::ptr<ast::Expr>> const & lparams, … … 559 245 return true; 560 246 } 561 }562 563 bool typesPolyCompatible( Type *a, Type *b ) {564 type_index aid{ typeid(*a) };565 // polymorphic types always match566 if ( aid == type_index{typeid(TypeInstType)} ) return true;567 568 type_index bid{ typeid(*b) };569 // polymorphic types always match570 if ( bid == type_index{typeid(TypeInstType)} ) return true;571 572 // can't match otherwise if different types573 if ( aid != bid ) return false;574 575 // recurse through type structure (conditions borrowed from Unify.cc)576 if ( aid == type_index{typeid(BasicType)} ) {577 return as<BasicType>(a)->get_kind() == as<BasicType>(b)->get_kind();578 } else if ( aid == type_index{typeid(PointerType)} ) {579 PointerType *ap = as<PointerType>(a), *bp = as<PointerType>(b);580 581 // void pointers should match any other pointer type582 return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )583 || typesPolyCompatible( ap->get_base(), bp->get_base() );584 } else if ( aid == type_index{typeid(ReferenceType)} ) {585 ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b);586 return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )587 || typesPolyCompatible( ap->get_base(), bp->get_base() );588 } else if ( aid == type_index{typeid(ArrayType)} ) {589 ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b);590 591 if ( aa->get_isVarLen() ) {592 if ( ! ba->get_isVarLen() ) return false;593 } else {594 if ( ba->get_isVarLen() ) return false;595 596 ConstantExpr *ad = dynamic_cast<ConstantExpr*>( aa->get_dimension() );597 ConstantExpr *bd = dynamic_cast<ConstantExpr*>( ba->get_dimension() );598 if ( ad && bd599 && ad->get_constant()->get_value() != bd->get_constant()->get_value() )600 return false;601 }602 603 return typesPolyCompatible( aa->get_base(), ba->get_base() );604 } else if ( aid == type_index{typeid(FunctionType)} ) {605 FunctionType *af = as<FunctionType>(a), *bf = as<FunctionType>(b);606 607 vector<Type*> aparams, bparams;608 flattenList( af->get_parameters(), back_inserter( aparams ) );609 flattenList( bf->get_parameters(), back_inserter( bparams ) );610 if ( aparams.size() != bparams.size() ) return false;611 612 vector<Type*> areturns, breturns;613 flattenList( af->get_returnVals(), back_inserter( areturns ) );614 flattenList( bf->get_returnVals(), back_inserter( breturns ) );615 if ( areturns.size() != breturns.size() ) return false;616 617 for ( unsigned i = 0; i < aparams.size(); ++i ) {618 if ( ! typesPolyCompatible( aparams[i], bparams[i] ) ) return false;619 }620 for ( unsigned i = 0; i < areturns.size(); ++i ) {621 if ( ! typesPolyCompatible( areturns[i], breturns[i] ) ) return false;622 }623 return true;624 } else if ( aid == type_index{typeid(StructInstType)} ) {625 StructInstType *aa = as<StructInstType>(a), *ba = as<StructInstType>(b);626 627 if ( aa->get_name() != ba->get_name() ) return false;628 return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );629 } else if ( aid == type_index{typeid(UnionInstType)} ) {630 UnionInstType *aa = as<UnionInstType>(a), *ba = as<UnionInstType>(b);631 632 if ( aa->get_name() != ba->get_name() ) return false;633 return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );634 } else if ( aid == type_index{typeid(EnumInstType)} ) {635 return as<EnumInstType>(a)->get_name() == as<EnumInstType>(b)->get_name();636 } else if ( aid == type_index{typeid(TraitInstType)} ) {637 return as<TraitInstType>(a)->get_name() == as<TraitInstType>(b)->get_name();638 } else if ( aid == type_index{typeid(TupleType)} ) {639 TupleType *at = as<TupleType>(a), *bt = as<TupleType>(b);640 641 vector<Type*> atypes, btypes;642 flattenList( at->get_types(), back_inserter( atypes ) );643 flattenList( bt->get_types(), back_inserter( btypes ) );644 if ( atypes.size() != btypes.size() ) return false;645 646 for ( unsigned i = 0; i < atypes.size(); ++i ) {647 if ( ! typesPolyCompatible( atypes[i], btypes[i] ) ) return false;648 }649 return true;650 } else return true; // VoidType, VarArgsType, ZeroType & OneType just need the same type651 247 } 652 248 … … 763 359 } 764 360 765 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {766 // is parameter is not polymorphic, don't need to box767 if ( ! isPolyType( param, exprTyVars ) ) return false;768 Type * newType = arg->clone();769 if ( env ) env->apply( newType );770 std::unique_ptr<Type> manager( newType );771 // if the argument's type is polymorphic, we don't need to box again!772 return ! isPolyType( newType );773 }774 775 361 bool needsBoxing( const ast::Type * param, const ast::Type * arg, 776 362 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 786 372 return !isPolyType( newType ); 787 373 } 788 789 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {790 FunctionType * function = getFunctionType( appExpr->function->result );791 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );792 TyVarMap exprTyVars( TypeDecl::Data{} );793 makeTyVarMap( function, exprTyVars );794 return needsBoxing( param, arg, exprTyVars, env );795 }796 374 797 375 bool needsBoxing( … … 806 384 } 807 385 808 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {809 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );810 }811 812 386 void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) { 813 387 typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) ); … … 817 391 typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) ); 818 392 } 819 820 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {821 for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {822 assert( *tyVar );823 addToTyVarMap( *tyVar, tyVarMap );824 }825 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {826 makeTyVarMap( pointer->get_base(), tyVarMap );827 }828 }829 393 830 394 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) { … … 846 410 } 847 411 848 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {849 for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {850 os << i->first << " (" << i->second << ") ";851 } // for852 os << std::endl;853 }854 855 412 } // namespace GenPoly 856 413 -
src/GenPoly/GenPoly.h
rdf8ba61a r8d182b1 23 23 #include "AST/Fwd.hpp" // for ApplicationExpr, BaseInstType, Func... 24 24 #include "SymTab/Mangler.h" // for Mangler 25 #include "SynTree/Declaration.h" // for TypeDecl::Data, AggregateDecl, Type...26 #include "SynTree/SynTree.h" // for Visitor Nodes27 25 28 26 namespace ast { … … 32 30 namespace GenPoly { 33 31 34 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;35 32 struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> { 36 33 TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {} … … 38 35 39 36 /// Replaces a TypeInstType by its referrent in the environment, if applicable 40 Type* replaceTypeInst( Type* type, const TypeSubstitution* env );41 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env );42 37 const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * ); 43 38 44 39 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided 45 Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );46 40 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr); 47 41 48 42 /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 49 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );50 43 const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr ); 51 44 52 45 /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided 53 ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );54 46 const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 ); 55 47 56 48 /// true iff function has dynamic-layout return type under the given type variable map 57 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );58 49 const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars ); 59 50 60 51 /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters 61 ReferenceToType *isDynRet( FunctionType *function );62 52 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ); 63 53 64 54 /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type 65 bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVarr );66 55 bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars ); 67 56 68 /// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided69 Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 );70 71 57 /// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 72 Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );73 58 const ast::Type * isPolyPtr( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * env = 0 ); 74 75 /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise;76 /// N will be stored in levels, if provided, will look up substitution in env if provided77 Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 );78 59 79 60 /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise; 80 61 /// N will be stored in levels, if provided, will look up substitution in env if provided 81 Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 );82 62 const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 ); 83 63 84 /// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one85 /// polymorphic parameter; will look up substitution in env if provided.86 bool includesPolyType( Type *type, const TypeSubstitution *env = 0 );87 88 /// true iff this type or some base of this type after dereferencing pointers is either polymorphic in tyVars, or a generic type with89 /// at least one polymorphic parameter in tyVars; will look up substitution in env if provided.90 bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );91 92 64 /// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise 93 FunctionType *getFunctionType( Type *ty );94 65 const ast::FunctionType * getFunctionType( const ast::Type * ty ); 95 66 96 /// If expr (after dereferencing N >= 0 pointers) is a variable expression, returns the variable expression, NULL otherwise;97 /// N will be stored in levels, if provided98 VariableExpr *getBaseVar( Expression *expr, int *levels = 0 );99 100 67 /// true iff types are structurally identical, where TypeInstType's match any type. 101 bool typesPolyCompatible( Type *aty, Type *bty );102 68 bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ); 103 69 104 70 /// true if arg requires boxing given exprTyVars 105 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );106 71 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ); 107 72 108 73 /// true if arg requires boxing in the call to appExpr 109 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );110 74 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst ); 111 75 112 76 /// Adds the type variable `tyVar` to `tyVarMap` 113 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );114 77 void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars ); 115 78 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ); 116 79 117 80 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 118 void makeTyVarMap( Type *type, TyVarMap &tyVarMap );119 81 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ); 120 82 void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ); 121 122 /// Prints type variable map123 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );124 125 /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().126 inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); }127 83 128 84 /// Gets the name of the sizeof parameter for the type, given its mangled name … … 136 92 137 93 /// Gets the name of the layout function for a given aggregate type, given its declaration 138 inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }139 94 inline std::string layoutofName( ast::AggregateDecl const * decl ) { 140 95 return std::string( "_layoutof_" ) + decl->name; -
src/GenPoly/ScrubTyVars.cc
rdf8ba61a r8d182b1 21 21 #include "ScrubTyVars.h" 22 22 #include "SymTab/Mangler.h" // for mangleType 23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Typ...24 #include "SynTree/Expression.h" // for Expression (ptr only), NameExpr25 #include "SynTree/Mutator.h" // for Mutator26 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type27 23 28 24 namespace GenPoly { 29 Type * ScrubTyVars::postmutate( TypeInstType * typeInst ) {30 if ( ! tyVars ) {31 if ( typeInst->get_isFtype() ) {32 delete typeInst;33 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );34 } else {35 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );36 delete typeInst;37 return ret;38 }39 }40 41 TyVarMap::const_iterator tyVar = tyVars->find( typeInst->name );42 if ( tyVar != tyVars->end() ) {43 switch ( tyVar->second.kind ) {44 case TypeDecl::Dtype:45 case TypeDecl::Ttype:46 {47 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );48 delete typeInst;49 return ret;50 }51 case TypeDecl::Ftype:52 delete typeInst;53 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );54 default:55 assertf(false, "Unhandled tyvar kind: %d", tyVar->second.kind);56 } // switch57 } // if58 return typeInst;59 }60 61 Type * ScrubTyVars::mutateAggregateType( Type * ty ) {62 if ( shouldScrub( ty ) ) {63 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );64 delete ty;65 return ret;66 }67 return ty;68 }69 70 Type * ScrubTyVars::postmutate( StructInstType * structInst ) {71 return mutateAggregateType( structInst );72 }73 74 Type * ScrubTyVars::postmutate( UnionInstType * unionInst ) {75 return mutateAggregateType( unionInst );76 }77 78 void ScrubTyVars::primeBaseScrub( Type * type ) {79 // need to determine whether type needs to be scrubbed to determine whether80 // automatic recursion is necessary81 if ( Type * t = shouldScrub( type ) ) {82 visit_children = false;83 GuardValue( dynType );84 dynType = t;85 }86 }87 88 Expression * ScrubTyVars::postmutate( SizeofExpr * szeof ) {89 // sizeof( T ) => _sizeof_T parameter, which is the size of T90 if ( dynType ) {91 Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );92 return expr;93 } // if94 return szeof;95 }96 97 Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) {98 // alignof( T ) => _alignof_T parameter, which is the alignment of T99 if ( dynType ) {100 Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );101 return expr;102 } // if103 return algnof;104 }105 106 Type * ScrubTyVars::postmutate( PointerType * pointer ) {107 if ( dynType ) {108 Type * ret = dynType->acceptMutator( *visitor );109 ret->get_qualifiers() |= pointer->get_qualifiers();110 pointer->base = nullptr;111 delete pointer;112 return ret;113 }114 return pointer;115 }116 25 117 26 namespace { -
src/GenPoly/ScrubTyVars.h
rdf8ba61a r8d182b1 19 19 20 20 #include "AST/Fwd.hpp" // for Node 21 #include "Common/PassVisitor.h"22 21 #include "GenPoly.h" // for TyVarMap, isPolyType, isDynType 23 #include "SynTree/Mutator.h" // for Mutator24 #include "SynTree/Type.h" // for Type (ptr only), PointerType (ptr only)25 26 class AlignofExpr;27 class Expression;28 class SizeofExpr;29 22 30 23 namespace GenPoly { 31 struct ScrubTyVars : public WithVisitorRef<ScrubTyVars>, public WithShortCircuiting, public WithGuards {32 /// Whether to scrub all type variables from the provided map, dynamic type variables from the provided map, or all type variables33 enum ScrubMode { FromMap, DynamicFromMap, All };34 35 ScrubTyVars() : tyVars(nullptr), mode( All ) {}36 37 ScrubTyVars( const TyVarMap &tyVars, ScrubMode mode = FromMap ): tyVars( &tyVars ), mode( mode ) {}38 39 public:40 /// For all polymorphic types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,41 /// and sizeof/alignof expressions with the proper variable42 template< typename SynTreeClass >43 static SynTreeClass *scrub( SynTreeClass *target, const TyVarMap &tyVars );44 45 /// For all dynamic-layout types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,46 /// and sizeof/alignof expressions with the proper variable47 template< typename SynTreeClass >48 static SynTreeClass *scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars );49 50 /// For all polymorphic types, replaces generic types, dtypes, and ftypes with the appropriate void type,51 /// and sizeof/alignof expressions with the proper variable52 template< typename SynTreeClass >53 static SynTreeClass *scrubAll( SynTreeClass *target );54 55 /// determine if children should be visited based on whether base type should be scrubbed.56 void primeBaseScrub( Type * );57 58 void premutate( TypeInstType * ) { visit_children = false; }59 void premutate( StructInstType * ) { visit_children = false; }60 void premutate( UnionInstType * ) { visit_children = false; }61 void premutate( SizeofExpr * szeof ) { primeBaseScrub( szeof->type ); }62 void premutate( AlignofExpr * algnof ) { primeBaseScrub( algnof->type ); }63 void premutate( PointerType * pointer ) { primeBaseScrub( pointer->base ); }64 65 Type * postmutate( TypeInstType * typeInst );66 Type * postmutate( StructInstType * structInst );67 Type * postmutate( UnionInstType * unionInst );68 Expression * postmutate( SizeofExpr * szeof );69 Expression * postmutate( AlignofExpr * algnof );70 Type * postmutate( PointerType * pointer );71 72 private:73 /// Returns the type if it should be scrubbed, NULL otherwise.74 Type* shouldScrub( Type *ty ) {75 switch ( mode ) {76 case FromMap: return isPolyType( ty, *tyVars );77 case DynamicFromMap: return isDynType( ty, *tyVars );78 case All: return isPolyType( ty );79 }80 assert(false); return nullptr; // unreachable81 // return dynamicOnly ? isDynType( ty, tyVars ) : isPolyType( ty, tyVars );82 }83 84 /// Mutates (possibly generic) aggregate types appropriately85 Type* mutateAggregateType( Type *ty );86 87 const TyVarMap *tyVars; ///< Type variables to scrub88 ScrubMode mode; ///< which type variables to scrub? [FromMap]89 90 Type * dynType = nullptr; ///< result of shouldScrub91 };92 93 template< typename SynTreeClass >94 SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) {95 PassVisitor<ScrubTyVars> scrubber( tyVars );96 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );97 }98 99 template< typename SynTreeClass >100 SynTreeClass * ScrubTyVars::scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ) {101 PassVisitor<ScrubTyVars> scrubber( tyVars, ScrubTyVars::DynamicFromMap );102 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );103 }104 105 template< typename SynTreeClass >106 SynTreeClass * ScrubTyVars::scrubAll( SynTreeClass *target ) {107 PassVisitor<ScrubTyVars> scrubber;108 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );109 }110 24 111 25 // ScrubMode and scrubTypeVarsBase are internal. -
src/GenPoly/SpecializeNew.cpp
rdf8ba61a r8d182b1 23 23 #include "GenPoly/GenPoly.h" // for getFunctionType 24 24 #include "ResolvExpr/FindOpenVars.h" // for findOpenVars 25 #include "ResolvExpr/TypeEnvironment.h" // for FirstOpen, FirstClosed26 25 27 26 namespace GenPoly { -
src/GenPoly/module.mk
rdf8ba61a r8d182b1 23 23 SRC += $(SRC_GENPOLY) \ 24 24 GenPoly/BoxNew.cpp \ 25 GenPoly/Box.cc \26 25 GenPoly/Box.h \ 27 26 GenPoly/ErasableScopedMap.h \ … … 29 28 GenPoly/FindFunction.h \ 30 29 GenPoly/InstantiateGenericNew.cpp \ 31 GenPoly/InstantiateGeneric.cc \32 30 GenPoly/InstantiateGeneric.h \ 33 31 GenPoly/LvalueNew.cpp \ 34 GenPoly/Lvalue.cc \35 32 GenPoly/ScopedSet.h \ 36 33 GenPoly/ScrubTyVars.cc \ 37 34 GenPoly/ScrubTyVars.h \ 38 GenPoly/Specialize.cc \39 35 GenPoly/SpecializeNew.cpp \ 40 36 GenPoly/Specialize.h -
src/InitTweak/FixGlobalInit.cc
rdf8ba61a r8d182b1 20 20 #include <algorithm> // for replace_if 21 21 22 #include "Common/PassVisitor.h"23 #include "Common/UniqueName.h" // for UniqueName24 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt25 #include "SynTree/LinkageSpec.h" // for C26 #include "SynTree/Attribute.h" // for Attribute27 #include "SynTree/Constant.h" // for Constant28 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declaration29 #include "SynTree/Expression.h" // for ConstantExpr, Expression (ptr only)30 #include "SynTree/Initializer.h" // for ConstructorInit, Initializer31 #include "SynTree/Label.h" // for Label32 #include "SynTree/Statement.h" // for CompoundStmt, Statement (ptr only)33 #include "SynTree/Type.h" // for Type, Type::StorageClasses, Functi...34 #include "SynTree/Visitor.h" // for acceptAll, Visitor35 36 22 #include "AST/Expr.hpp" 37 23 #include "AST/Node.hpp" 38 24 #include "AST/Pass.hpp" 25 #include "Common/UniqueName.h" // for UniqueName 26 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt 39 27 40 28 namespace InitTweak { 41 class GlobalFixer : public WithShortCircuiting { 42 public: 43 GlobalFixer( bool inLibrary ); 44 45 void previsit( ObjectDecl *objDecl ); 46 void previsit( FunctionDecl *functionDecl ); 47 void previsit( StructDecl *aggregateDecl ); 48 void previsit( UnionDecl *aggregateDecl ); 49 void previsit( EnumDecl *aggregateDecl ); 50 void previsit( TraitDecl *aggregateDecl ); 51 void previsit( TypeDecl *typeDecl ); 52 53 UniqueName tempNamer; 54 FunctionDecl * initFunction; 55 FunctionDecl * destroyFunction; 56 }; 57 58 class GlobalFixer_new : public ast::WithShortCircuiting { 29 class GlobalFixer : public ast::WithShortCircuiting { 59 30 public: 60 31 void previsit (const ast::ObjectDecl *); … … 70 41 }; 71 42 72 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ) {73 PassVisitor<GlobalFixer> visitor( inLibrary );74 acceptAll( translationUnit, visitor );75 GlobalFixer & fixer = visitor.pass;76 // don't need to include function if it's empty77 if ( fixer.initFunction->get_statements()->get_kids().empty() ) {78 delete fixer.initFunction;79 } else {80 translationUnit.push_back( fixer.initFunction );81 } // if82 83 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) {84 delete fixer.destroyFunction;85 } else {86 translationUnit.push_back( fixer.destroyFunction );87 } // if88 }89 90 GlobalFixer::GlobalFixer( bool inLibrary ) : tempNamer( "_global_init" ) {91 std::list< Expression * > ctorParameters;92 std::list< Expression * > dtorParameters;93 if ( inLibrary ) {94 // Constructor/destructor attributes take a single parameter which95 // is the priority, with lower numbers meaning higher priority.96 // Functions specified with priority are guaranteed to run before97 // functions without a priority. To ensure that constructors and destructors98 // for library code are run before constructors and destructors for user code,99 // specify a priority when building the library. Priorities 0-100 are reserved by gcc.100 // Priorities 101-200 are reserved by cfa, so use priority 200 for CFA library globals,101 // allowing room for overriding with a higher priority.102 ctorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );103 dtorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );104 }105 initFunction = new FunctionDecl( "__global_init__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );106 initFunction->get_attributes().push_back( new Attribute( "constructor", ctorParameters ) );107 destroyFunction = new FunctionDecl( "__global_destroy__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );108 destroyFunction->get_attributes().push_back( new Attribute( "destructor", dtorParameters ) );109 }110 111 43 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 112 ast::Pass<GlobalFixer _new> fixer;44 ast::Pass<GlobalFixer> fixer; 113 45 accept_all(translationUnit, fixer); 114 46 … … 141 73 } 142 74 143 void GlobalFixer::previsit( ObjectDecl *objDecl ) { 144 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids(); 145 std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids(); 146 147 // C allows you to initialize objects with constant expressions 148 // xxx - this is an optimization. Need to first resolve constructors before we decide 149 // to keep C-style initializer. 150 // if ( isConstExpr( objDecl->get_init() ) ) return; 151 152 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 153 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 154 assert( ! ctorInit->ctor || ! ctorInit->init ); 155 156 Statement * dtor = ctorInit->dtor; 157 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 158 // don't need to call intrinsic dtor, because it does nothing, but 159 // non-intrinsic dtors must be called 160 destroyStatements.push_front( dtor ); 161 ctorInit->dtor = nullptr; 162 } // if 163 if ( Statement * ctor = ctorInit->ctor ) { 164 addDataSectionAttribute( objDecl ); 165 initStatements.push_back( ctor ); 166 objDecl->init = nullptr; 167 ctorInit->ctor = nullptr; 168 } else if ( Initializer * init = ctorInit->init ) { 169 objDecl->init = init; 170 ctorInit->init = nullptr; 171 } else { 172 // no constructor and no initializer, which is okay 173 objDecl->init = nullptr; 174 } // if 175 delete ctorInit; 176 } // if 177 } 178 179 void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) { 75 void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) { 180 76 auto mutDecl = mutate(objDecl); 181 77 assertf(mutDecl == objDecl, "Global object decl must be unique"); … … 207 103 } 208 104 209 // only modify global variables210 void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }211 void GlobalFixer::previsit( StructDecl * ) { visit_children = false; }212 void GlobalFixer::previsit( UnionDecl * ) { visit_children = false; }213 void GlobalFixer::previsit( EnumDecl * ) { visit_children = false; }214 void GlobalFixer::previsit( TraitDecl * ) { visit_children = false; }215 void GlobalFixer::previsit( TypeDecl * ) { visit_children = false; }216 217 105 } // namespace InitTweak 218 106 -
src/InitTweak/FixInitNew.cpp
rdf8ba61a r8d182b1 178 178 /// (currently by FixInit) 179 179 struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> { 180 typedef std::list< ObjectDecl * > OrderedDecls;181 typedef std::list< OrderedDecls > OrderedDeclsStack;182 183 180 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {} 184 181 … … 194 191 ast::Pass<LabelFinder> & finder; 195 192 LabelFinder::LabelMap & labelVars; 196 OrderedDeclsStack reverseDeclOrder;197 193 }; 198 194 … … 921 917 // static variables with the same name in different functions. 922 918 // Note: it isn't sufficient to modify only the mangleName, because 923 // then subsequent Indexerpasses can choke on seeing the object's name919 // then subsequent SymbolTable passes can choke on seeing the object's name 924 920 // if another object has the same name and type. An unfortunate side-effect 925 921 // of renaming the object is that subsequent NameExprs may fail to resolve, … … 1173 1169 arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) ); 1174 1170 } 1175 InitExpander _newsrcParam( arg2 );1171 InitExpander srcParam( arg2 ); 1176 1172 // cast away reference type and construct field. 1177 1173 ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences()); -
src/InitTweak/GenInit.cc
rdf8ba61a r8d182b1 29 29 #include "CompilationState.h" 30 30 #include "CodeGen/OperatorTable.h" 31 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort...32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/ToString.hpp" // for toCString … … 38 37 #include "InitTweak.h" // for isConstExpr, InitExpander, checkIn... 39 38 #include "ResolvExpr/Resolver.h" 40 #include "SymTab/Autogen.h" // for genImplicitCall41 39 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 42 40 #include "SymTab/Mangler.h" // for Mangler 43 #include "SynTree/LinkageSpec.h" // for isOverridable, C44 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType45 #include "SynTree/Expression.h" // for VariableExpr, UntypedExpr, Address...46 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit, Initi...47 #include "SynTree/Label.h" // for Label48 #include "SynTree/Mutator.h" // for mutateAll49 #include "SynTree/Statement.h" // for CompoundStmt, ImplicitCtorDtorStmt50 #include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers51 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept52 41 #include "Tuples/Tuples.h" // for maybeImpure 53 42 #include "Validate/FindSpecialDecls.h" // for SizeType 54 43 55 44 namespace InitTweak { 56 namespace {57 const std::list<Label> noLabels;58 const std::list<Expression *> noDesignators;59 }60 61 struct ReturnFixer : public WithStmtsToAdd, public WithGuards {62 /// consistently allocates a temporary variable for the return value63 /// of a function so that anything which the resolver decides can be constructed64 /// into the return type of a function can be returned.65 static void makeReturnTemp( std::list< Declaration * > &translationUnit );66 67 void premutate( FunctionDecl *functionDecl );68 void premutate( ReturnStmt * returnStmt );69 70 protected:71 FunctionType * ftype = nullptr;72 std::string funcName;73 };74 75 struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor> {76 /// create constructor and destructor statements for object declarations.77 /// the actual call statements will be added in after the resolver has run78 /// so that the initializer expression is only removed if a constructor is found79 /// and the same destructor call is inserted in all of the appropriate locations.80 static void generateCtorDtor( std::list< Declaration * > &translationUnit );81 82 void previsit( ObjectDecl * );83 void previsit( FunctionDecl *functionDecl );84 85 // should not traverse into any of these declarations to find objects86 // that need to be constructed or destructed87 void previsit( StructDecl *aggregateDecl );88 void previsit( AggregateDecl * ) { visit_children = false; }89 void previsit( NamedTypeDecl * ) { visit_children = false; }90 void previsit( FunctionType * ) { visit_children = false; }91 92 void previsit( CompoundStmt * compoundStmt );93 94 private:95 // set of mangled type names for which a constructor or destructor exists in the current scope.96 // these types require a ConstructorInit node to be generated, anything else is a POD type and thus97 // should not have a ConstructorInit generated.98 99 ManagedTypes managedTypes;100 bool inFunction = false;101 };102 103 struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {104 /// hoist dimension from array types in object declaration so that it uses a single105 /// const variable of type size_t, so that side effecting array dimensions are only106 /// computed once.107 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );108 109 void premutate( ObjectDecl * objectDecl );110 DeclarationWithType * postmutate( ObjectDecl * objectDecl );111 void premutate( FunctionDecl *functionDecl );112 // should not traverse into any of these declarations to find objects113 // that need to be constructed or destructed114 void premutate( AggregateDecl * ) { visit_children = false; }115 void premutate( NamedTypeDecl * ) { visit_children = false; }116 void premutate( FunctionType * ) { visit_children = false; }117 118 // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)119 void premutate( EnumDecl * ) {}120 121 void hoist( Type * type );122 123 Type::StorageClasses storageClasses;124 bool inFunction = false;125 };126 127 struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {128 /// hoist dimension from array types in object declaration so that it uses a single129 /// const variable of type size_t, so that side effecting array dimensions are only130 /// computed once.131 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );132 133 void premutate( ObjectDecl * objectDecl );134 DeclarationWithType * postmutate( ObjectDecl * objectDecl );135 void premutate( FunctionDecl *functionDecl );136 // should not traverse into any of these declarations to find objects137 // that need to be constructed or destructed138 void premutate( AggregateDecl * ) { visit_children = false; }139 void premutate( NamedTypeDecl * ) { visit_children = false; }140 void premutate( FunctionType * ) { visit_children = false; }141 142 void hoist( Type * type );143 144 Type::StorageClasses storageClasses;145 bool inFunction = false;146 };147 148 void genInit( std::list< Declaration * > & translationUnit ) {149 if (!useNewAST) {150 HoistArrayDimension::hoistArrayDimension( translationUnit );151 }152 else {153 HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );154 }155 fixReturnStatements( translationUnit );156 157 if (!useNewAST) {158 CtorDtor::generateCtorDtor( translationUnit );159 }160 }161 162 void fixReturnStatements( std::list< Declaration * > & translationUnit ) {163 PassVisitor<ReturnFixer> fixer;164 mutateAll( translationUnit, fixer );165 }166 167 void ReturnFixer::premutate( ReturnStmt *returnStmt ) {168 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();169 assert( returnVals.size() == 0 || returnVals.size() == 1 );170 // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address171 // is being returned172 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {173 // explicitly construct the return value using the return expression and the retVal object174 assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() );175 176 ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() );177 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) {178 // return statement has already been mutated - don't need to do it again179 if ( varExpr->var == retVal ) return;180 }181 Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );182 assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );183 stmtsToAddBefore.push_back( stmt );184 185 // return the retVal object186 returnStmt->expr = new VariableExpr( returnVals.front() );187 } // if188 }189 190 void ReturnFixer::premutate( FunctionDecl *functionDecl ) {191 GuardValue( ftype );192 GuardValue( funcName );193 194 ftype = functionDecl->type;195 funcName = functionDecl->name;196 }197 198 // precompute array dimension expression, because constructor generation may duplicate it,199 // which would be incorrect if it is a side-effecting computation.200 void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {201 PassVisitor<HoistArrayDimension> hoister;202 mutateAll( translationUnit, hoister );203 }204 205 void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) {206 GuardValue( storageClasses );207 storageClasses = objectDecl->get_storageClasses();208 }209 210 DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) {211 hoist( objectDecl->get_type() );212 return objectDecl;213 }214 215 void HoistArrayDimension::hoist( Type * type ) {216 // if in function, generate const size_t var217 static UniqueName dimensionName( "_array_dim" );218 219 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.220 if ( ! inFunction ) return;221 if ( storageClasses.is_static ) return;222 223 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {224 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?225 226 // need to resolve array dimensions in order to accurately determine if constexpr227 ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );228 // array is variable-length when the dimension is not constexpr229 arrayType->isVarLen = ! isConstExpr( arrayType->dimension );230 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.231 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve232 // still try to detect constant expressions233 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;234 235 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );236 arrayDimension->get_type()->set_const( true );237 238 arrayType->set_dimension( new VariableExpr( arrayDimension ) );239 declsToAddBefore.push_back( arrayDimension );240 241 hoist( arrayType->get_base() );242 return;243 }244 }245 246 void HoistArrayDimension::premutate( FunctionDecl * ) {247 GuardValue( inFunction );248 inFunction = true;249 }250 251 // precompute array dimension expression, because constructor generation may duplicate it,252 // which would be incorrect if it is a side-effecting computation.253 void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {254 PassVisitor<HoistArrayDimension_NoResolve> hoister;255 mutateAll( translationUnit, hoister );256 }257 258 void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {259 GuardValue( storageClasses );260 storageClasses = objectDecl->get_storageClasses();261 }262 263 DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {264 hoist( objectDecl->get_type() );265 return objectDecl;266 }267 268 void HoistArrayDimension_NoResolve::hoist( Type * type ) {269 // if in function, generate const size_t var270 static UniqueName dimensionName( "_array_dim" );271 272 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.273 if ( ! inFunction ) return;274 if ( storageClasses.is_static ) return;275 276 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {277 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?278 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.279 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve280 // still try to detect constant expressions281 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;282 283 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );284 arrayDimension->get_type()->set_const( true );285 286 arrayType->set_dimension( new VariableExpr( arrayDimension ) );287 declsToAddBefore.push_back( arrayDimension );288 289 hoist( arrayType->get_base() );290 return;291 }292 }293 294 void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {295 GuardValue( inFunction );296 inFunction = true;297 }298 45 299 46 namespace { 300 47 301 # warning Remove the _New suffix after the conversion is complete.302 303 48 // Outer pass finds declarations, for their type could wrap a type that needs hoisting 304 struct HoistArrayDimension_NoResolve _Newfinal :49 struct HoistArrayDimension_NoResolve final : 305 50 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting, 306 51 public ast::WithGuards, public ast::WithConstTranslationUnit, 307 public ast::WithVisitorRef<HoistArrayDimension_NoResolve _New>,52 public ast::WithVisitorRef<HoistArrayDimension_NoResolve>, 308 53 public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> { 309 54 … … 312 57 public ast::WithShortCircuiting, public ast::WithGuards { 313 58 314 HoistArrayDimension_NoResolve _New* outer;315 HoistDimsFromTypes( HoistArrayDimension_NoResolve _New* outer ) : outer(outer) {}59 HoistArrayDimension_NoResolve * outer; 60 HoistDimsFromTypes( HoistArrayDimension_NoResolve * outer ) : outer(outer) {} 316 61 317 62 // Only intended for visiting through types. … … 464 209 465 210 466 struct ReturnFixer _Newfinal :211 struct ReturnFixer final : 467 212 public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting { 468 213 void previsit( const ast::FunctionDecl * decl ); … … 472 217 }; 473 218 474 void ReturnFixer _New::previsit( const ast::FunctionDecl * decl ) {219 void ReturnFixer::previsit( const ast::FunctionDecl * decl ) { 475 220 if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false; 476 221 GuardValue( funcDecl ) = decl; 477 222 } 478 223 479 const ast::ReturnStmt * ReturnFixer _New::previsit(224 const ast::ReturnStmt * ReturnFixer::previsit( 480 225 const ast::ReturnStmt * stmt ) { 481 226 auto & returns = funcDecl->returns; … … 518 263 519 264 void genInit( ast::TranslationUnit & transUnit ) { 520 ast::Pass<HoistArrayDimension_NoResolve _New>::run( transUnit );521 ast::Pass<ReturnFixer _New>::run( transUnit );265 ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit ); 266 ast::Pass<ReturnFixer>::run( transUnit ); 522 267 } 523 268 524 269 void fixReturnStatements( ast::TranslationUnit & transUnit ) { 525 ast::Pass<ReturnFixer_New>::run( transUnit ); 526 } 527 528 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { 529 PassVisitor<CtorDtor> ctordtor; 530 acceptAll( translationUnit, ctordtor ); 531 } 532 533 bool ManagedTypes::isManaged( Type * type ) const { 534 // references are never constructed 535 if ( dynamic_cast< ReferenceType * >( type ) ) return false; 536 // need to clear and reset qualifiers when determining if a type is managed 537 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() ); 538 type->get_qualifiers() = Type::Qualifiers(); 539 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) { 540 // tuple is also managed if any of its components are managed 541 if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) { 542 return true; 543 } 544 } 545 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable) 546 return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type ); 547 } 548 549 bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const { 550 Type * type = objDecl->get_type(); 551 while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { 552 // must always construct VLAs with an initializer, since this is an error in C 553 if ( at->isVarLen && objDecl->init ) return true; 554 type = at->get_base(); 555 } 556 return isManaged( type ); 557 } 558 559 // why is this not just on FunctionDecl? 560 void ManagedTypes::handleDWT( DeclarationWithType * dwt ) { 561 // if this function is a user-defined constructor or destructor, mark down the type as "managed" 562 if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) { 563 std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters(); 564 assert( ! params.empty() ); 565 Type * type = InitTweak::getPointerBase( params.front()->get_type() ); 566 assert( type ); 567 managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) ); 568 } 569 } 570 571 void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) { 572 // don't construct members, but need to take note if there is a managed member, 573 // because that means that this type is also managed 574 for ( Declaration * member : aggregateDecl->get_members() ) { 575 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) { 576 if ( isManaged( field ) ) { 577 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that 578 // polymorphic constructors make generic types managed types 579 StructInstType inst( Type::Qualifiers(), aggregateDecl ); 580 managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) ); 581 break; 582 } 583 } 584 } 585 } 586 587 void ManagedTypes::beginScope() { managedTypes.beginScope(); } 588 void ManagedTypes::endScope() { managedTypes.endScope(); } 589 590 bool ManagedTypes_new::isManaged( const ast::Type * type ) const { 270 ast::Pass<ReturnFixer>::run( transUnit ); 271 } 272 273 bool ManagedTypes::isManaged( const ast::Type * type ) const { 591 274 // references are never constructed 592 275 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false; … … 607 290 } 608 291 609 bool ManagedTypes _new::isManaged( const ast::ObjectDecl * objDecl ) const {292 bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const { 610 293 const ast::Type * type = objDecl->type; 611 294 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { … … 617 300 } 618 301 619 void ManagedTypes _new::handleDWT( const ast::DeclWithType * dwt ) {302 void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) { 620 303 // if this function is a user-defined constructor or destructor, mark down the type as "managed" 621 304 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) { … … 628 311 } 629 312 630 void ManagedTypes _new::handleStruct( const ast::StructDecl * aggregateDecl ) {313 void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) { 631 314 // don't construct members, but need to take note if there is a managed member, 632 315 // because that means that this type is also managed … … 644 327 } 645 328 646 void ManagedTypes_new::beginScope() { managedTypes.beginScope(); } 647 void ManagedTypes_new::endScope() { managedTypes.endScope(); } 648 649 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) { 650 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 651 assertf( objDecl, "genCtorDtor passed null objDecl" ); 652 std::list< Statement * > stmts; 653 InitExpander_old srcParam( maybeClone( arg ) ); 654 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl ); 655 assert( stmts.size() <= 1 ); 656 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr; 657 658 } 329 void ManagedTypes::beginScope() { managedTypes.beginScope(); } 330 void ManagedTypes::endScope() { managedTypes.endScope(); } 659 331 660 332 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 661 333 assertf(objDecl, "genCtorDtor passed null objDecl"); 662 InitExpander _newsrcParam(arg);334 InitExpander srcParam(arg); 663 335 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 664 }665 666 ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {667 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor668 // for each constructable object669 std::list< Statement * > ctor;670 std::list< Statement * > dtor;671 672 InitExpander_old srcParam( objDecl->get_init() );673 InitExpander_old nullParam( (Initializer *)NULL );674 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );675 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );676 677 // Currently genImplicitCall produces a single Statement - a CompoundStmt678 // which wraps everything that needs to happen. As such, it's technically679 // possible to use a Statement ** in the above calls, but this is inherently680 // unsafe, so instead we take the slightly less efficient route, but will be681 // immediately informed if somehow the above assumption is broken. In this case,682 // we could always wrap the list of statements at this point with a CompoundStmt,683 // but it seems reasonable at the moment for this to be done by genImplicitCall684 // itself. It is possible that genImplicitCall produces no statements (e.g. if685 // an array type does not have a dimension). In this case, it's fine to ignore686 // the object for the purposes of construction.687 assert( ctor.size() == dtor.size() && ctor.size() <= 1 );688 if ( ctor.size() == 1 ) {689 // need to remember init expression, in case no ctors exist690 // if ctor does exist, want to use ctor expression instead of init691 // push this decision to the resolver692 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );693 return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );694 }695 return nullptr;696 }697 698 void CtorDtor::previsit( ObjectDecl * objDecl ) {699 managedTypes.handleDWT( objDecl );700 // hands off if @=, extern, builtin, etc.701 // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C702 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {703 // constructed objects cannot be designated704 if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );705 // constructed objects should not have initializers nested too deeply706 if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " );707 708 objDecl->set_init( genCtorInit( objDecl ) );709 }710 }711 712 void CtorDtor::previsit( FunctionDecl *functionDecl ) {713 visit_children = false; // do not try and construct parameters or forall parameters714 GuardValue( inFunction );715 inFunction = true;716 717 managedTypes.handleDWT( functionDecl );718 719 GuardScope( managedTypes );720 // go through assertions and recursively add seen ctor/dtors721 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {722 for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {723 managedTypes.handleDWT( assertion );724 }725 }726 727 maybeAccept( functionDecl->get_statements(), *visitor );728 }729 730 void CtorDtor::previsit( StructDecl *aggregateDecl ) {731 visit_children = false; // do not try to construct and destruct aggregate members732 733 managedTypes.handleStruct( aggregateDecl );734 }735 736 void CtorDtor::previsit( CompoundStmt * ) {737 GuardScope( managedTypes );738 336 } 739 337 … … 741 339 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each 742 340 // constructable object 743 InitExpander _newsrcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };341 InitExpander srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr }; 744 342 ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl); 745 343 -
src/InitTweak/GenInit.h
rdf8ba61a r8d182b1 22 22 #include "Common/CodeLocation.h" 23 23 #include "GenPoly/ScopedSet.h" // for ScopedSet 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 namespace InitTweak { 27 26 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 void genInit( std::list< Declaration * > & translationUnit );29 27 void genInit( ast::TranslationUnit & translationUnit ); 30 28 31 29 /// Converts return statements into copy constructor calls on the hidden return variable. 32 30 /// This pass must happen before auto-gen. 33 void fixReturnStatements( std::list< Declaration * > & translationUnit );34 31 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 35 32 36 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 37 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );38 34 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 39 35 40 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 41 ConstructorInit * genCtorInit( ObjectDecl * objDecl );42 37 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ); 43 38 44 class ManagedTypes { 45 public: 46 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed 47 bool isManaged( Type * type ) const; // determine if type is managed 48 49 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor 50 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed 51 52 void beginScope(); 53 void endScope(); 54 private: 55 GenPoly::ScopedSet< std::string > managedTypes; 56 }; 57 58 class ManagedTypes_new { 39 class ManagedTypes final { 59 40 public: 60 41 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed -
src/InitTweak/InitTweak.cc
rdf8ba61a r8d182b1 29 29 #include "AST/Type.hpp" 30 30 #include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto... 31 #include "Common/PassVisitor.h"32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/UniqueName.h" // for UniqueName … … 36 35 #include "InitTweak.h" 37 36 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 38 #include "SymTab/Autogen.h"39 #include "SymTab/Indexer.h" // for Indexer40 #include "SynTree/LinkageSpec.h" // for Spec, isBuiltin, Intrinsic41 #include "SynTree/Attribute.h" // for Attribute42 #include "SynTree/Constant.h" // for Constant43 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType44 #include "SynTree/Expression.h" // for Expression, UntypedExpr, Applicati...45 #include "SynTree/Initializer.h" // for Initializer, ListInit, Designation46 #include "SynTree/Label.h" // for Label47 #include "SynTree/Statement.h" // for CompoundStmt, ExprStmt, BranchStmt48 #include "SynTree/Type.h" // for FunctionType, ArrayType, PointerType49 #include "SynTree/Visitor.h" // for Visitor, maybeAccept50 37 #include "Tuples/Tuples.h" // for Tuples::isTtype 51 38 52 39 namespace InitTweak { 53 40 namespace { 54 struct HasDesignations : public WithShortCircuiting { 55 bool hasDesignations = false; 56 57 void previsit( BaseSyntaxNode * ) { 58 // short circuit if we already know there are designations 59 if ( hasDesignations ) visit_children = false; 60 } 61 62 void previsit( Designation * des ) { 63 // short circuit if we already know there are designations 64 if ( hasDesignations ) visit_children = false; 65 else if ( ! des->get_designators().empty() ) { 66 hasDesignations = true; 67 visit_children = false; 68 } 69 } 70 }; 71 72 struct InitDepthChecker : public WithGuards { 73 bool depthOkay = true; 74 Type * type; 75 int curDepth = 0, maxDepth = 0; 76 InitDepthChecker( Type * type ) : type( type ) { 77 Type * t = type; 78 while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) { 79 maxDepth++; 80 t = at->get_base(); 81 } 82 maxDepth++; 83 } 84 void previsit( ListInit * ) { 85 curDepth++; 86 GuardAction( [this]() { curDepth--; } ); 87 if ( curDepth > maxDepth ) depthOkay = false; 88 } 89 }; 90 91 struct HasDesignations_new : public ast::WithShortCircuiting { 41 struct HasDesignations : public ast::WithShortCircuiting { 92 42 bool result = false; 93 43 … … 107 57 }; 108 58 109 struct InitDepthChecker _new{59 struct InitDepthChecker { 110 60 bool result = true; 111 61 const ast::Type * type; 112 62 int curDepth = 0, maxDepth = 0; 113 InitDepthChecker _new( const ast::Type * type ) : type( type ) {63 InitDepthChecker( const ast::Type * type ) : type( type ) { 114 64 const ast::Type * t = type; 115 65 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) { … … 128 78 }; 129 79 130 struct InitFlattener_old : public WithShortCircuiting { 131 void previsit( SingleInit * singleInit ) { 132 visit_children = false; 133 argList.push_back( singleInit->value->clone() ); 134 } 135 std::list< Expression * > argList; 136 }; 137 138 struct InitFlattener_new : public ast::WithShortCircuiting { 80 struct InitFlattener : public ast::WithShortCircuiting { 139 81 std::vector< ast::ptr< ast::Expr > > argList; 140 82 … … 147 89 } // anonymous namespace 148 90 149 std::list< Expression * > makeInitList( Initializer * init ) {150 PassVisitor<InitFlattener_old> flattener;151 maybeAccept( init, flattener );152 return flattener.pass.argList;153 }154 155 bool isDesignated( Initializer * init ) {156 PassVisitor<HasDesignations> finder;157 maybeAccept( init, finder );158 return finder.pass.hasDesignations;159 }160 161 bool checkInitDepth( ObjectDecl * objDecl ) {162 PassVisitor<InitDepthChecker> checker( objDecl->type );163 maybeAccept( objDecl->init, checker );164 return checker.pass.depthOkay;165 }166 167 91 bool isDesignated( const ast::Init * init ) { 168 ast::Pass<HasDesignations _new> finder;92 ast::Pass<HasDesignations> finder; 169 93 maybe_accept( init, finder ); 170 94 return finder.core.result; … … 172 96 173 97 bool checkInitDepth( const ast::ObjectDecl * objDecl ) { 174 ast::Pass<InitDepthChecker _new> checker( objDecl->type );98 ast::Pass<InitDepthChecker> checker( objDecl->type ); 175 99 maybe_accept( objDecl->init.get(), checker ); 176 100 return checker.core.result; … … 178 102 179 103 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 180 ast::Pass< InitFlattener _new> flattener;104 ast::Pass< InitFlattener > flattener; 181 105 maybe_accept( init, flattener ); 182 106 return std::move( flattener.core.argList ); 183 107 } 184 108 185 class InitExpander_old::ExpanderImpl { 186 public: 187 virtual ~ExpanderImpl() = default; 188 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0; 189 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0; 190 }; 191 192 class InitImpl_old : public InitExpander_old::ExpanderImpl { 193 public: 194 InitImpl_old( Initializer * init ) : init( init ) {} 195 virtual ~InitImpl_old() = default; 196 197 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) { 198 // this is wrong, but just a placeholder for now 199 // if ( ! flattened ) flatten( indices ); 200 // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >(); 201 return makeInitList( init ); 202 } 203 204 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); 205 private: 206 Initializer * init; 207 }; 208 209 class ExprImpl_old : public InitExpander_old::ExpanderImpl { 210 public: 211 ExprImpl_old( Expression * expr ) : arg( expr ) {} 212 virtual ~ExprImpl_old() { delete arg; } 213 214 virtual std::list< Expression * > next( std::list< Expression * > & indices ) { 215 std::list< Expression * > ret; 216 Expression * expr = maybeClone( arg ); 217 if ( expr ) { 218 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) { 219 // go through indices and layer on subscript exprs ?[?] 220 ++it; 221 UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") ); 222 subscriptExpr->get_args().push_back( expr ); 223 subscriptExpr->get_args().push_back( (*it)->clone() ); 224 expr = subscriptExpr; 225 } 226 ret.push_back( expr ); 227 } 228 return ret; 229 } 230 231 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); 232 private: 233 Expression * arg; 234 }; 235 236 InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {} 237 238 InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {} 239 240 std::list< Expression * > InitExpander_old::operator*() { 241 return cur; 242 } 243 244 InitExpander_old & InitExpander_old::operator++() { 245 cur = expander->next( indices ); 246 return *this; 247 } 248 249 // use array indices list to build switch statement 250 void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) { 251 indices.push_back( index ); 252 indices.push_back( dimension ); 253 } 254 255 void InitExpander_old::clearArrayIndices() { 256 deleteAll( indices ); 257 indices.clear(); 258 } 259 260 bool InitExpander_old::addReference() { 261 bool added = false; 262 for ( Expression *& expr : cur ) { 263 expr = new AddressExpr( expr ); 264 added = true; 265 } 266 return added; 267 } 268 269 namespace { 270 /// given index i, dimension d, initializer init, and callExpr f, generates 271 /// if (i < d) f(..., init) 272 /// ++i; 273 /// so that only elements within the range of the array are constructed 274 template< typename OutIterator > 275 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) { 276 UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") ); 277 cond->get_args().push_back( index->clone() ); 278 cond->get_args().push_back( dimension->clone() ); 279 280 std::list< Expression * > args = makeInitList( init ); 281 callExpr->get_args().splice( callExpr->get_args().end(), args ); 282 283 *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr ); 284 285 UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) ); 286 increment->get_args().push_back( index->clone() ); 287 *out++ = new ExprStmt( increment ); 288 } 289 290 template< typename OutIterator > 291 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) { 292 if ( idx == idxEnd ) return; 293 Expression * index = *idx++; 294 assert( idx != idxEnd ); 295 Expression * dimension = *idx++; 296 297 // xxx - may want to eventually issue a warning here if we can detect 298 // that the number of elements exceeds to dimension of the array 299 if ( idx == idxEnd ) { 300 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) { 301 for ( Initializer * init : *listInit ) { 302 buildCallExpr( callExpr->clone(), index, dimension, init, out ); 303 } 304 } else { 305 buildCallExpr( callExpr->clone(), index, dimension, init, out ); 306 } 307 } else { 308 std::list< Statement * > branches; 309 310 unsigned long cond = 0; 311 ListInit * listInit = dynamic_cast< ListInit * >( init ); 312 if ( ! listInit ) { 313 // xxx - this shouldn't be an error, but need a way to 314 // terminate without creating output, so should catch this error 315 SemanticError( init->location, "unbalanced list initializers" ); 316 } 317 318 static UniqueName targetLabel( "L__autogen__" ); 319 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } ); 320 for ( Initializer * init : *listInit ) { 321 Expression * condition; 322 // check for designations 323 // if ( init-> ) { 324 condition = new ConstantExpr( Constant::from_ulong( cond ) ); 325 ++cond; 326 // } else { 327 // condition = // ... take designation 328 // cond = // ... take designation+1 329 // } 330 std::list< Statement * > stmts; 331 build( callExpr, idx, idxEnd, init, back_inserter( stmts ) ); 332 stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) ); 333 CaseStmt * caseStmt = new CaseStmt( condition, stmts ); 334 branches.push_back( caseStmt ); 335 } 336 *out++ = new SwitchStmt( index->clone(), branches ); 337 *out++ = new NullStmt( { switchLabel } ); 338 } 339 } 340 } 341 342 // if array came with an initializer list: initialize each element 343 // may have more initializers than elements in the array - need to check at each index that 344 // we haven't exceeded size. 345 // may have fewer initializers than elements in the array - need to default construct 346 // remaining elements. 347 // To accomplish this, generate switch statement, consuming all of expander's elements 348 Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) { 349 if ( ! init ) return nullptr; 350 CompoundStmt * block = new CompoundStmt(); 351 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) ); 352 if ( block->get_kids().empty() ) { 353 delete block; 354 return nullptr; 355 } else { 356 init = nullptr; // init was consumed in creating the list init 357 return block; 358 } 359 } 360 361 Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) { 362 return nullptr; 363 } 364 365 Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) { 366 return expander->buildListInit( dst, indices ); 367 } 368 369 class InitExpander_new::ExpanderImpl { 109 class InitExpander::ExpanderImpl { 370 110 public: 371 111 virtual ~ExpanderImpl() = default; … … 397 137 template< typename Out > 398 138 void build( 399 ast::UntypedExpr * callExpr, const InitExpander _new::IndexList & indices,139 ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices, 400 140 const ast::Init * init, Out & out 401 141 ) { … … 443 183 } 444 184 445 class InitImpl _new final : public InitExpander_new::ExpanderImpl {185 class InitImpl final : public InitExpander::ExpanderImpl { 446 186 ast::ptr< ast::Init > init; 447 187 public: 448 InitImpl _new( const ast::Init * i ) : init( i ) {}449 450 std::vector< ast::ptr< ast::Expr > > next( InitExpander _new::IndexList & ) override {188 InitImpl( const ast::Init * i ) : init( i ) {} 189 190 std::vector< ast::ptr< ast::Expr > > next( InitExpander::IndexList & ) override { 451 191 return makeInitList( init ); 452 192 } 453 193 454 194 ast::ptr< ast::Stmt > buildListInit( 455 ast::UntypedExpr * callExpr, InitExpander _new::IndexList & indices195 ast::UntypedExpr * callExpr, InitExpander::IndexList & indices 456 196 ) override { 457 197 // If array came with an initializer list, initialize each element. We may have more … … 475 215 }; 476 216 477 class ExprImpl _new final : public InitExpander_new::ExpanderImpl {217 class ExprImpl final : public InitExpander::ExpanderImpl { 478 218 ast::ptr< ast::Expr > arg; 479 219 public: 480 ExprImpl _new( const ast::Expr * a ) : arg( a ) {}220 ExprImpl( const ast::Expr * a ) : arg( a ) {} 481 221 482 222 std::vector< ast::ptr< ast::Expr > > next( 483 InitExpander _new::IndexList & indices223 InitExpander::IndexList & indices 484 224 ) override { 485 225 if ( ! arg ) return {}; … … 497 237 498 238 ast::ptr< ast::Stmt > buildListInit( 499 ast::UntypedExpr *, InitExpander _new::IndexList &239 ast::UntypedExpr *, InitExpander::IndexList & 500 240 ) override { 501 241 return {}; … … 504 244 } // anonymous namespace 505 245 506 InitExpander _new::InitExpander_new( const ast::Init * init )507 : expander( new InitImpl _new{ init } ), crnt(), indices() {}508 509 InitExpander _new::InitExpander_new( const ast::Expr * expr )510 : expander( new ExprImpl _new{ expr } ), crnt(), indices() {}511 512 std::vector< ast::ptr< ast::Expr > > InitExpander _new::operator* () { return crnt; }513 514 InitExpander _new & InitExpander_new::operator++ () {246 InitExpander::InitExpander( const ast::Init * init ) 247 : expander( new InitImpl{ init } ), crnt(), indices() {} 248 249 InitExpander::InitExpander( const ast::Expr * expr ) 250 : expander( new ExprImpl{ expr } ), crnt(), indices() {} 251 252 std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; } 253 254 InitExpander & InitExpander::operator++ () { 515 255 crnt = expander->next( indices ); 516 256 return *this; … … 519 259 /// builds statement which has the same semantics as a C-style list initializer (for array 520 260 /// initializers) using callExpr as the base expression to perform initialization 521 ast::ptr< ast::Stmt > InitExpander _new::buildListInit( ast::UntypedExpr * callExpr ) {261 ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) { 522 262 return expander->buildListInit( callExpr, indices ); 523 263 } 524 264 525 void InitExpander _new::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {265 void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) { 526 266 indices.emplace_back( index ); 527 267 indices.emplace_back( dimension ); 528 268 } 529 269 530 void InitExpander _new::clearArrayIndices() { indices.clear(); }531 532 bool InitExpander _new::addReference() {270 void InitExpander::clearArrayIndices() { indices.clear(); } 271 272 bool InitExpander::addReference() { 533 273 for ( ast::ptr< ast::Expr > & expr : crnt ) { 534 274 expr = new ast::AddressExpr{ expr }; … … 536 276 return ! crnt.empty(); 537 277 } 538 539 Type * getTypeofThis( FunctionType * ftype ) {540 assertf( ftype, "getTypeofThis: nullptr ftype" );541 ObjectDecl * thisParam = getParamThis( ftype );542 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );543 return refType->base;544 }545 278 546 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { … … 554 287 } 555 288 556 ObjectDecl * getParamThis( FunctionType * ftype ) {557 assertf( ftype, "getParamThis: nullptr ftype" );558 auto & params = ftype->parameters;559 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );560 return strict_dynamic_cast< ObjectDecl * >( params.front() );561 }562 563 289 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 564 290 assertf( func, "getParamThis: nullptr ftype" ); … … 566 292 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 567 293 return params.front().strict_as<ast::ObjectDecl>(); 568 }569 570 bool tryConstruct( DeclarationWithType * dwt ) {571 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );572 if ( ! objDecl ) return false;573 return (objDecl->get_init() == nullptr ||574 ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() ))575 && ! objDecl->get_storageClasses().is_extern576 && isConstructable( objDecl->type );577 }578 579 bool isConstructable( Type * type ) {580 return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type );581 294 } 582 295 … … 595 308 } 596 309 597 struct CallFinder_old { 598 CallFinder_old( const std::list< std::string > & names ) : names( names ) {} 599 600 void postvisit( ApplicationExpr * appExpr ) { 601 handleCallExpr( appExpr ); 602 } 603 604 void postvisit( UntypedExpr * untypedExpr ) { 605 handleCallExpr( untypedExpr ); 606 } 607 608 std::list< Expression * > * matches; 609 private: 610 const std::list< std::string > names; 611 612 template< typename CallExpr > 613 void handleCallExpr( CallExpr * expr ) { 614 std::string fname = getFunctionName( expr ); 615 if ( std::find( names.begin(), names.end(), fname ) != names.end() ) { 616 matches->push_back( expr ); 617 } 618 } 619 }; 620 621 struct CallFinder_new final { 310 struct CallFinder final { 622 311 std::vector< const ast::Expr * > matches; 623 312 const std::vector< std::string > names; 624 313 625 CallFinder _new( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}314 CallFinder( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {} 626 315 627 316 void handleCallExpr( const ast::Expr * expr ) { … … 636 325 }; 637 326 638 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {639 static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );640 finder.pass.matches = &matches;641 maybeAccept( stmt, finder );642 }643 644 327 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 645 ast::Pass< CallFinder _new> finder{ std::vector< std::string >{ "?{}", "^?{}" } };328 ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 646 329 maybe_accept( stmt, finder ); 647 330 return std::move( finder.core.matches ); 648 331 } 649 332 650 Expression * getCtorDtorCall( Statement * stmt ) {651 std::list< Expression * > matches;652 collectCtorDtorCalls( stmt, matches );653 assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() );654 return matches.size() == 1 ? matches.front() : nullptr;655 }656 657 333 namespace { 658 DeclarationWithType * getCalledFunction( Expression * expr );659 660 template<typename CallExpr>661 DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) {662 // (*f)(x) => should get "f"663 std::string name = getFunctionName( expr );664 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );665 assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" );666 return getCalledFunction( expr->get_args().front() );667 }668 669 DeclarationWithType * getCalledFunction( Expression * expr ) {670 assert( expr );671 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {672 return varExpr->var;673 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {674 return memberExpr->member;675 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {676 return getCalledFunction( castExpr->arg );677 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) {678 return handleDerefCalledFunction( untypedExpr );679 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {680 return handleDerefCalledFunction( appExpr );681 } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {682 return getCalledFunction( addrExpr->arg );683 } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) {684 return getCalledFunction( commaExpr->arg2 );685 }686 return nullptr;687 }688 689 DeclarationWithType * getFunctionCore( const Expression * expr ) {690 if ( const auto * appExpr = dynamic_cast< const ApplicationExpr * >( expr ) ) {691 return getCalledFunction( appExpr->function );692 } else if ( const auto * untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {693 return getCalledFunction( untyped->function );694 }695 assertf( false, "getFunction with unknown expression: %s", toString( expr ).c_str() );696 }697 }698 699 DeclarationWithType * getFunction( Expression * expr ) {700 return getFunctionCore( expr );701 }702 703 const DeclarationWithType * getFunction( const Expression * expr ) {704 return getFunctionCore( expr );705 }706 707 ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {708 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );709 if ( ! appExpr ) return nullptr;710 DeclarationWithType * function = getCalledFunction( appExpr->get_function() );711 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );712 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor713 // will call all member dtors, and some members may have a user defined dtor.714 return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr;715 }716 717 namespace {718 template <typename Predicate>719 bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {720 std::list< Expression * > callExprs;721 collectCtorDtorCalls( stmt, callExprs );722 return std::all_of( callExprs.begin(), callExprs.end(), pred);723 }724 725 334 template <typename Predicate> 726 335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { … … 728 337 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 729 338 } 730 }731 732 bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {733 return allofCtorDtor( stmt, []( Expression * callExpr ){734 if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {735 FunctionType *funcType = GenPoly::getFunctionType( appExpr->function->result );736 assert( funcType );737 return funcType->get_parameters().size() == 1;738 }739 return false;740 });741 339 } 742 340 … … 751 349 return false; 752 350 }); 753 }754 755 bool isIntrinsicCallStmt( Statement * stmt ) {756 return allofCtorDtor( stmt, []( Expression * callExpr ) {757 return isIntrinsicCallExpr( callExpr );758 });759 }760 761 namespace {762 template<typename CallExpr>763 Expression *& callArg( CallExpr * callExpr, unsigned int pos ) {764 if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() );765 for ( Expression *& arg : callExpr->get_args() ) {766 if ( pos == 0 ) return arg;767 pos--;768 }769 assert( false );770 }771 }772 773 Expression *& getCallArg( Expression * callExpr, unsigned int pos ) {774 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) {775 return callArg( appExpr, pos );776 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {777 return callArg( untypedExpr, pos );778 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {779 std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();780 assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );781 ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() );782 TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() );783 assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );784 return getCallArg( tuple->get_exprs().front(), pos );785 } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) {786 return getCallArg( copyCtor->callExpr, pos );787 } else {788 assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );789 }790 }791 792 namespace {793 std::string funcName( Expression * func );794 795 template<typename CallExpr>796 std::string handleDerefName( CallExpr * expr ) {797 // (*f)(x) => should get name "f"798 std::string name = getFunctionName( expr );799 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );800 assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );801 return funcName( expr->get_args().front() );802 }803 804 std::string funcName( Expression * func ) {805 if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) {806 return nameExpr->get_name();807 } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {808 return varExpr->get_var()->get_name();809 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {810 return funcName( castExpr->get_arg() );811 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {812 return memberExpr->get_member()->get_name();813 } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {814 return funcName( memberExpr->get_member() );815 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) {816 return handleDerefName( untypedExpr );817 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) {818 return handleDerefName( appExpr );819 } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) {820 return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) );821 } else {822 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );823 }824 }825 }826 827 std::string getFunctionName( Expression * expr ) {828 // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and829 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction830 // can't possibly do anything reasonable.831 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {832 return funcName( appExpr->get_function() );833 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {834 return funcName( untypedExpr->get_function() );835 } else {836 std::cerr << expr << std::endl;837 assertf( false, "Unexpected expression type passed to getFunctionName" );838 }839 }840 841 Type * getPointerBase( Type * type ) {842 if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {843 return ptrType->get_base();844 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {845 return arrayType->get_base();846 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {847 return refType->get_base();848 } else {849 return nullptr;850 }851 }852 853 Type * isPointerType( Type * type ) {854 return getPointerBase( type ) ? type : nullptr;855 }856 857 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {858 static FunctionDecl * assign = nullptr;859 if ( ! assign ) {860 // temporary? Generate a fake assignment operator to represent bitwise assignments.861 // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.862 TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );863 assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );864 }865 if ( dynamic_cast< ReferenceType * >( dst->result ) ) {866 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {867 dst = new AddressExpr( dst );868 }869 } else {870 dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );871 }872 if ( dynamic_cast< ReferenceType * >( src->result ) ) {873 for (int depth = src->result->referenceDepth(); depth > 0; depth--) {874 src = new AddressExpr( src );875 }876 }877 return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );878 351 } 879 352 … … 908 381 } 909 382 910 struct ConstExprChecker : public WithShortCircuiting { 911 // most expressions are not const expr 912 void previsit( Expression * ) { isConstExpr = false; visit_children = false; } 913 914 void previsit( AddressExpr *addressExpr ) { 915 visit_children = false; 916 917 // address of a variable or member expression is constexpr 918 Expression * arg = addressExpr->get_arg(); 919 if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false; 920 } 921 922 // these expressions may be const expr, depending on their children 923 void previsit( SizeofExpr * ) {} 924 void previsit( AlignofExpr * ) {} 925 void previsit( UntypedOffsetofExpr * ) {} 926 void previsit( OffsetofExpr * ) {} 927 void previsit( OffsetPackExpr * ) {} 928 void previsit( CommaExpr * ) {} 929 void previsit( LogicalExpr * ) {} 930 void previsit( ConditionalExpr * ) {} 931 void previsit( CastExpr * ) {} 932 void previsit( ConstantExpr * ) {} 933 934 void previsit( VariableExpr * varExpr ) { 935 visit_children = false; 936 937 if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) { 938 long long int value; 939 if ( inst->baseEnum->valueOf( varExpr->var, value ) ) { 940 // enumerators are const expr 941 return; 942 } 943 } 944 isConstExpr = false; 945 } 946 947 bool isConstExpr = true; 948 }; 949 950 struct ConstExprChecker_new : public ast::WithShortCircuiting { 383 struct ConstExprChecker : public ast::WithShortCircuiting { 951 384 // most expressions are not const expr 952 385 void previsit( const ast::Expr * ) { result = false; visit_children = false; } … … 991 424 }; 992 425 993 bool isConstExpr( Expression * expr ) {994 if ( expr ) {995 PassVisitor<ConstExprChecker> checker;996 expr->accept( checker );997 return checker.pass.isConstExpr;998 }999 return true;1000 }1001 1002 bool isConstExpr( Initializer * init ) {1003 if ( init ) {1004 PassVisitor<ConstExprChecker> checker;1005 init->accept( checker );1006 return checker.pass.isConstExpr;1007 } // if1008 // for all intents and purposes, no initializer means const expr1009 return true;1010 }1011 1012 426 bool isConstExpr( const ast::Expr * expr ) { 1013 427 if ( expr ) { 1014 ast::Pass<ConstExprChecker _new> checker;428 ast::Pass<ConstExprChecker> checker; 1015 429 expr->accept( checker ); 1016 430 return checker.core.result; … … 1021 435 bool isConstExpr( const ast::Init * init ) { 1022 436 if ( init ) { 1023 ast::Pass<ConstExprChecker _new> checker;437 ast::Pass<ConstExprChecker> checker; 1024 438 init->accept( checker ); 1025 439 return checker.core.result; … … 1029 443 } 1030 444 1031 const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) {1032 const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl );1033 if ( ! function ) return nullptr;1034 if ( function->name != fname ) return nullptr;1035 FunctionType * ftype = function->type;1036 if ( ftype->parameters.size() != 2 ) return nullptr;1037 1038 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() );1039 Type * t2 = ftype->parameters.back()->get_type();1040 assert( t1 );1041 1042 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) {1043 return function;1044 } else {1045 return nullptr;1046 }1047 }1048 1049 445 bool isAssignment( const ast::FunctionDecl * decl ) { 1050 446 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl ); … … 1073 469 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 ); 1074 470 } 1075 1076 1077 const FunctionDecl * isAssignment( const Declaration * decl ) {1078 return isCopyFunction( decl, "?=?" );1079 }1080 const FunctionDecl * isDestructor( const Declaration * decl ) {1081 if ( CodeGen::isDestructor( decl->name ) ) {1082 return dynamic_cast< const FunctionDecl * >( decl );1083 }1084 return nullptr;1085 }1086 const FunctionDecl * isDefaultConstructor( const Declaration * decl ) {1087 if ( CodeGen::isConstructor( decl->name ) ) {1088 if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {1089 if ( func->type->parameters.size() == 1 ) {1090 return func;1091 }1092 }1093 }1094 return nullptr;1095 }1096 const FunctionDecl * isCopyConstructor( const Declaration * decl ) {1097 return isCopyFunction( decl, "?{}" );1098 }1099 471 1100 472 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message … … 1105 477 static const char * const data_section = ".data" ASM_COMMENT; 1106 478 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 1107 void addDataSectionAttribute( ObjectDecl * objDecl ) {1108 const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any();1109 const char * section = is_tls ? tlsd_section : data_section;1110 objDecl->attributes.push_back(new Attribute("section", {1111 new ConstantExpr( Constant::from_string( section ) )1112 }));1113 }1114 479 1115 480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { … … 1121 486 } 1122 487 1123 } 488 } // namespace InitTweak -
src/InitTweak/InitTweak.h
rdf8ba61a r8d182b1 22 22 23 23 #include "AST/Fwd.hpp" // for AST nodes 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 // helper functions for initialization 27 26 namespace InitTweak { 28 const FunctionDecl * isAssignment( const Declaration * decl );29 const FunctionDecl * isDestructor( const Declaration * decl );30 const FunctionDecl * isDefaultConstructor( const Declaration * decl );31 const FunctionDecl * isCopyConstructor( const Declaration * decl );32 const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname );33 27 bool isAssignment( const ast::FunctionDecl * decl ); 34 28 bool isDestructor( const ast::FunctionDecl * decl ); … … 38 32 39 33 /// returns the base type of the first parameter to a constructor/destructor/assignment function 40 Type * getTypeofThis( FunctionType * ftype );41 34 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 42 35 43 36 /// returns the first parameter of a constructor/destructor/assignment function 44 ObjectDecl * getParamThis( FunctionType * ftype );45 37 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 46 38 47 39 /// generate a bitwise assignment operation. 48 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );49 50 40 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 51 41 52 42 /// transform Initializer into an argument list that can be passed to a call expression 53 std::list< Expression * > makeInitList( Initializer * init );54 43 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 55 44 56 45 /// True if the resolver should try to construct dwt 57 bool tryConstruct( DeclarationWithType * dwt );58 46 bool tryConstruct( const ast::DeclWithType * dwt ); 59 47 60 48 /// True if the type can have a user-defined constructor 61 bool isConstructable( Type * t );62 49 bool isConstructable( const ast::Type * t ); 63 50 64 51 /// True if the Initializer contains designations 65 bool isDesignated( Initializer * init );66 52 bool isDesignated( const ast::Init * init ); 67 53 68 54 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 69 55 /// type, where the depth of its type is the number of nested ArrayTypes + 1 70 bool checkInitDepth( ObjectDecl * objDecl );71 56 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 72 73 /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)74 DeclarationWithType * getFunction( Expression * expr );75 const DeclarationWithType * getFunction( const Expression * expr );76 77 /// Non-Null if expr is a call expression whose target function is intrinsic78 ApplicationExpr * isIntrinsicCallExpr( Expression * expr );79 57 80 58 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 81 59 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 82 60 /// Currently has assertions that make it less than fully general. 83 bool isIntrinsicSingleArgCallStmt( Statement * stmt );84 61 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 85 62 86 /// True if stmt is a call statement where the function called is intrinsic.87 bool isIntrinsicCallStmt( Statement * stmt );88 89 63 /// get all Ctor/Dtor call expressions from a Statement 90 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );91 64 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 92 65 93 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call94 Expression * getCtorDtorCall( Statement * stmt );95 96 /// returns the name of the function being called97 std::string getFunctionName( Expression * expr );98 99 /// returns the argument to a call expression in position N indexed from 0100 Expression *& getCallArg( Expression * callExpr, unsigned int pos );101 102 /// returns the base type of a PointerType or ArrayType, else returns NULL103 Type * getPointerBase( Type * );104 105 /// returns the argument if it is a PointerType or ArrayType, else returns NULL106 Type * isPointerType( Type * );107 108 66 /// returns true if expr is trivially a compile-time constant 109 bool isConstExpr( Expression * expr );110 bool isConstExpr( Initializer * init );111 112 67 bool isConstExpr( const ast::Expr * expr ); 113 68 bool isConstExpr( const ast::Init * init ); … … 122 77 /// .section .data#,"a" 123 78 /// to avoid assembler warning "ignoring changed section attributes for .data" 124 void addDataSectionAttribute( ObjectDecl * objDecl );125 126 79 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 127 80 128 class InitExpander_old { 129 public: 130 // expand by stepping through init to get each list of arguments 131 InitExpander_old( Initializer * init ); 132 133 // always expand to expr 134 InitExpander_old( Expression * expr ); 135 136 // iterator-like interface 137 std::list< Expression * > operator*(); 138 InitExpander_old & operator++(); 139 140 // builds statement which has the same semantics as a C-style list initializer 141 // (for array initializers) using callExpr as the base expression to perform initialization 142 Statement * buildListInit( UntypedExpr * callExpr ); 143 void addArrayIndex( Expression * index, Expression * dimension ); 144 void clearArrayIndices(); 145 bool addReference(); 146 147 class ExpanderImpl; 148 149 typedef std::list< Expression * > IndexList; 150 private: 151 std::shared_ptr< ExpanderImpl > expander; 152 std::list< Expression * > cur; 153 154 // invariant: list of size 2N (elements come in pairs [index, dimension]) 155 IndexList indices; 156 }; 157 158 class InitExpander_new { 81 class InitExpander final { 159 82 public: 160 83 using IndexList = std::vector< ast::ptr< ast::Expr > >; … … 169 92 public: 170 93 /// Expand by stepping through init to get each list of arguments 171 InitExpander _new( const ast::Init * init );94 InitExpander( const ast::Init * init ); 172 95 173 96 /// Always expand to expression 174 InitExpander _new( const ast::Expr * expr );97 InitExpander( const ast::Expr * expr ); 175 98 176 99 std::vector< ast::ptr< ast::Expr > > operator* (); 177 InitExpander _new& operator++ ();100 InitExpander & operator++ (); 178 101 179 102 /// builds statement which has the same semantics as a C-style list initializer (for array … … 188 111 bool addReference(); 189 112 }; 190 } // namespace 113 } // namespace InitTweak 191 114 192 115 // Local Variables: // -
src/InitTweak/module.mk
rdf8ba61a r8d182b1 24 24 InitTweak/FixGlobalInit.cc \ 25 25 InitTweak/FixGlobalInit.h \ 26 InitTweak/FixInit.cc \27 26 InitTweak/FixInit.h \ 28 27 InitTweak/FixInitNew.cpp -
src/MakeLibCfa.h
rdf8ba61a r8d182b1 24 24 25 25 namespace LibCfa { 26 void makeLibCfa( std::list< Declaration* > &prelude );27 26 void makeLibCfa( ast::TranslationUnit & translationUnit ); 28 27 } // namespace LibCfa -
src/Makefile.am
rdf8ba61a r8d182b1 22 22 CompilationState.cc \ 23 23 CompilationState.h \ 24 MakeLibCfa.cc \25 24 MakeLibCfaNew.cpp \ 26 25 MakeLibCfa.h … … 42 41 include AST/module.mk 43 42 include CodeGen/module.mk 44 include CodeTools/module.mk45 43 include Concurrency/module.mk 46 44 include Common/module.mk … … 51 49 include ResolvExpr/module.mk 52 50 include SymTab/module.mk 53 include SynTree/module.mk54 51 include Tuples/module.mk 55 52 include Validate/module.mk 56 53 include Virtual/module.mk 57 54 58 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/ SynTree/Type.h55 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/AST/Type.hpp 59 56 60 57 $(srcdir)/AST/Type.hpp : BasicTypes-gen.cc -
src/Parser/RunParser.cpp
rdf8ba61a r8d182b1 16 16 #include "RunParser.hpp" 17 17 18 #include "AST/Convert.hpp" // for convert19 18 #include "AST/TranslationUnit.hpp" // for TranslationUnit 20 #include "CodeTools/TrackLoc.h" // for fillLocations21 19 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 22 20 #include "Parser/DeclarationNode.h" // for DeclarationNode, buildList -
src/Parser/parser.yy
rdf8ba61a r8d182b1 57 57 #include "Common/SemanticError.h" // error_str 58 58 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... 59 60 #include "SynTree/Attribute.h" // for Attribute61 59 62 60 // lex uses __null in a boolean context, it's fine. -
src/ResolvExpr/AdjustExprType.cc
rdf8ba61a r8d182b1 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "SymTab/Indexer.h" // for Indexer23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype24 #include "SynTree/Mutator.h" // for Mutator25 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type26 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment27 21 28 22 namespace ResolvExpr { 29 23 30 24 namespace { 31 class AdjustExprType_old final : public WithShortCircuiting { 32 public: 33 AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer ); 34 void premutate( VoidType * ) { visit_children = false; } 35 void premutate( BasicType * ) { visit_children = false; } 36 void premutate( PointerType * ) { visit_children = false; } 37 void premutate( ArrayType * ) { visit_children = false; } 38 void premutate( FunctionType * ) { visit_children = false; } 39 void premutate( StructInstType * ) { visit_children = false; } 40 void premutate( UnionInstType * ) { visit_children = false; } 41 void premutate( EnumInstType * ) { visit_children = false; } 42 void premutate( TraitInstType * ) { visit_children = false; } 43 void premutate( TypeInstType * ) { visit_children = false; } 44 void premutate( TupleType * ) { visit_children = false; } 45 void premutate( VarArgsType * ) { visit_children = false; } 46 void premutate( ZeroType * ) { visit_children = false; } 47 void premutate( OneType * ) { visit_children = false; } 48 49 Type * postmutate( ArrayType * arrayType ); 50 Type * postmutate( FunctionType * functionType ); 51 Type * postmutate( TypeInstType * aggregateUseType ); 52 53 private: 54 const TypeEnvironment & env; 55 const SymTab::Indexer & indexer; 56 }; 57 58 AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer ) 59 : env( env ), indexer( indexer ) { 60 } 61 62 Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) { 63 PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base }; 64 arrayType->base = nullptr; 65 delete arrayType; 66 return pointerType; 67 } 68 69 Type * AdjustExprType_old::postmutate( FunctionType * functionType ) { 70 return new PointerType{ Type::Qualifiers(), functionType }; 71 } 72 73 Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) { 74 if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) { 75 if ( eqvClass->data.kind == TypeDecl::Ftype ) { 76 return new PointerType{ Type::Qualifiers(), typeInst }; 77 } 78 } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) { 79 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) { 80 if ( tyDecl->get_kind() == TypeDecl::Ftype ) { 81 return new PointerType{ Type::Qualifiers(), typeInst }; 82 } // if 83 } // if 84 } // if 85 return typeInst; 86 } 87 } // anonymous namespace 88 89 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) { 90 PassVisitor<AdjustExprType_old> adjuster( env, indexer ); 91 Type * newType = type->acceptMutator( adjuster ); 92 type = newType; 93 } 94 95 void adjustExprType( Type *& type ) { 96 TypeEnvironment env; 97 SymTab::Indexer indexer; 98 adjustExprType( type, env, indexer ); 99 } 100 101 namespace { 102 class AdjustExprType_new final : public ast::WithShortCircuiting { 25 class AdjustExprType final : public ast::WithShortCircuiting { 103 26 const ast::SymbolTable & symtab; 104 27 public: 105 28 const ast::TypeEnvironment & tenv; 106 29 107 AdjustExprType _new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )30 AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 108 31 : symtab( syms ), tenv( e ) {} 109 32 … … 152 75 const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab 153 76 ) { 154 ast::Pass<AdjustExprType _new> adjuster{ env, symtab };77 ast::Pass<AdjustExprType> adjuster{ env, symtab }; 155 78 return type->accept( adjuster ); 156 79 } -
src/ResolvExpr/AdjustExprType.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 }22 18 namespace ast { 23 19 class SymbolTable; … … 27 23 28 24 namespace ResolvExpr { 29 30 class TypeEnvironment;31 32 /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function33 void adjustExprType( Type *& type, const TypeEnvironment & env, const SymTab::Indexer & indexer );34 35 /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function using empty TypeEnvironment and Indexer.36 void adjustExprType( Type *& type );37 38 template< typename ForwardIterator >39 void adjustExprTypeList( ForwardIterator begin, ForwardIterator end, const TypeEnvironment & env, const SymTab::Indexer & indexer ) {40 while ( begin != end ) {41 adjustExprType( *begin++, env, indexer );42 } // while43 }44 25 45 26 /// Replaces array types with equivalent pointer, -
src/ResolvExpr/CandidateFinder.cpp
rdf8ba61a r8d182b1 61 61 namespace { 62 62 /// First index is which argument, second is which alternative, third is which exploded element 63 using ExplodedArgs _new= std::deque< std::vector< ExplodedArg > >;63 using ExplodedArgs = std::deque< std::vector< ExplodedArg > >; 64 64 65 65 /// Returns a list of alternatives with the minimum cost in the given list … … 255 255 256 256 /// Gets the list of exploded candidates for this pack 257 const ExplodedArg & getExpl( const ExplodedArgs _new& args ) const {257 const ExplodedArg & getExpl( const ExplodedArgs & args ) const { 258 258 return args[ nextArg-1 ][ explAlt ]; 259 259 } … … 281 281 bool instantiateArgument( 282 282 const CodeLocation & location, 283 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs _new& args,283 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs & args, 284 284 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 285 285 unsigned nTuples = 0 … … 618 618 const CodeLocation & location, 619 619 const CandidateRef & func, const ast::FunctionType * funcType, 620 const ExplodedArgs _new& args, CandidateList & out );620 const ExplodedArgs & args, CandidateList & out ); 621 621 622 622 /// Adds implicit struct-conversions to the alternative list … … 737 737 const CodeLocation & location, 738 738 const CandidateRef & func, const ast::FunctionType * funcType, 739 const ExplodedArgs _new& args, CandidateList & out739 const ExplodedArgs & args, CandidateList & out 740 740 ) { 741 741 ast::OpenVarSet funcOpen; … … 997 997 998 998 // pre-explode arguments 999 ExplodedArgs _newargExpansions;999 ExplodedArgs argExpansions; 1000 1000 for ( const CandidateFinder & args : argCandidates ) { 1001 1001 argExpansions.emplace_back(); -
src/ResolvExpr/CastCost.cc
rdf8ba61a r8d182b1 26 26 #include "ResolvExpr/ConversionCost.h" // for conversionCost 27 27 #include "ResolvExpr/PtrsCastable.hpp" // for ptrsCastable 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass29 #include "ResolvExpr/typeops.h" // for ptrsCastable30 28 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 31 #include "SymTab/Indexer.h" // for Indexer32 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl33 #include "SynTree/Type.h" // for PointerType, Type, TypeInstType34 29 35 30 #if 0 … … 40 35 41 36 namespace ResolvExpr { 42 struct CastCost_old : public ConversionCost {43 public:44 CastCost_old( const Type * dest, bool srcIsLvalue,45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );46 37 38 namespace { 39 struct CastCost : public ConversionCost { 47 40 using ConversionCost::previsit; 48 41 using ConversionCost::postvisit; 49 void postvisit( const BasicType * basicType );50 void postvisit( const PointerType * pointerType );51 };52 42 53 Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue, 54 const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 55 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) { 56 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) { 57 if ( eqvClass->type ) { 58 return castCost( src, eqvClass->type, srcIsLvalue, indexer, env ); 59 } else { 60 return Cost::infinity; 61 } 62 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) { 63 // all typedefs should be gone by this point 64 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType ); 65 if ( type->base ) { 66 return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe; 67 } // if 68 } // if 69 } // if 70 71 PRINT( 72 std::cerr << "castCost ::: src is "; 73 src->print( std::cerr ); 74 std::cerr << std::endl << "dest is "; 75 dest->print( std::cerr ); 76 std::cerr << std::endl << "env is" << std::endl; 77 env.print( std::cerr, 8 ); 78 ) 79 80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) { 81 PRINT( std::cerr << "compatible!" << std::endl; ) 82 return Cost::zero; 83 } else if ( dynamic_cast< const VoidType * >( dest ) ) { 84 return Cost::safe; 85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) { 86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; ) 87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) { 88 return ptrsCastable( t1, t2, env, indexer ); 89 }); 90 } else { 91 PassVisitor<CastCost_old> converter( 92 dest, srcIsLvalue, indexer, env, 93 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & )) 94 castCost ); 95 src->accept( converter ); 96 if ( converter.pass.get_cost() == Cost::infinity ) { 97 return Cost::infinity; 98 } else { 99 // xxx - why are we adding cost 0 here? 100 return converter.pass.get_cost() + Cost::zero; 101 } // if 102 } // if 103 } 104 105 CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue, 106 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc ) 107 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) { 108 } 109 110 void CastCost_old::postvisit( const BasicType * basicType ) { 111 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest ); 112 if ( destAsPointer && basicType->isInteger() ) { 113 // necessary for, e.g. unsigned long => void * 114 cost = Cost::unsafe; 115 } else { 116 cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env ); 117 } // if 118 } 119 120 void CastCost_old::postvisit( const PointerType * pointerType ) { 121 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) { 122 if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) { 123 cost = Cost::safe; 124 } else { 125 TypeEnvironment newEnv( env ); 126 newEnv.add( pointerType->forall ); 127 newEnv.add( pointerType->base->forall ); 128 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer ); 129 if ( castResult > 0 ) { 130 cost = Cost::safe; 131 } else if ( castResult < 0 ) { 132 cost = Cost::infinity; 133 } // if 134 } // if 135 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 136 if ( destAsBasic->isInteger() ) { 137 // necessary for, e.g. void * => unsigned long 138 cost = Cost::unsafe; 139 } // if 140 } 141 } 142 143 namespace { 144 struct CastCost_new : public ConversionCost_new { 145 using ConversionCost_new::previsit; 146 using ConversionCost_new::postvisit; 147 148 CastCost_new( 43 CastCost( 149 44 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 150 45 const ast::TypeEnvironment & env, CostCalculation costFunc ) 151 : ConversionCost _new( dst, srcIsLvalue, symtab, env, costFunc ) {}46 : ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {} 152 47 153 48 void postvisit( const ast::BasicType * basicType ) { … … 189 84 }; 190 85 191 #warning For overload resolution between the two versions.192 int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,193 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {194 return ptrsCastable( t1, t2, symtab, env );195 }196 Cost localCastCost(197 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,198 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env199 ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }200 86 } // anonymous namespace 201 202 203 87 204 88 Cost castCost( … … 242 126 } else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) { 243 127 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; ) 244 #warning cast on ptrsCastable artifact of having two functions, remove when port done245 128 return convertToReferenceCost( 246 src, refType, srcIsLvalue, symtab, env, localPtrsCastable );129 src, refType, srcIsLvalue, symtab, env, ptrsCastable ); 247 130 } else { 248 #warning cast on castCost artifact of having two functions, remove when port done 249 ast::Pass< CastCost_new > converter( 250 dst, srcIsLvalue, symtab, env, localCastCost ); 131 ast::Pass< CastCost > converter( 132 dst, srcIsLvalue, symtab, env, castCost ); 251 133 src->accept( converter ); 252 134 return converter.core.cost; -
src/ResolvExpr/CastCost.hpp
rdf8ba61a r8d182b1 18 18 #include "ResolvExpr/Cost.h" // for Cost 19 19 20 class Type;21 namespace SymTab {22 class Indexer;23 }24 20 namespace ast { 25 21 class SymbolTable; … … 30 26 namespace ResolvExpr { 31 27 32 class TypeEnvironment;33 34 Cost castCost(35 const Type * src, const Type * dest, bool srcIsLvalue,36 const SymTab::Indexer & indexer, const TypeEnvironment & env );37 28 Cost castCost( 38 29 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, -
src/ResolvExpr/CommonType.cc
rdf8ba61a r8d182b1 23 23 #include "AST/Pass.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h"26 #include "ResolvExpr/TypeEnvironment.h" // for OpenVarSet, AssertionSet27 #include "SymTab/Indexer.h" // for Indexer28 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl (ptr...29 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::...30 #include "SynTree/Visitor.h" // for Visitor31 25 #include "Unify.h" // for unifyExact, WidenMode 32 26 #include "typeops.h" // for isFtype … … 41 35 42 36 namespace ResolvExpr { 43 struct CommonType_old : public WithShortCircuiting {44 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );45 Type * get_result() const { return result; }46 47 void previsit( BaseSyntaxNode * ) { visit_children = false; }48 49 void postvisit( VoidType * voidType );50 void postvisit( BasicType * basicType );51 void postvisit( PointerType * pointerType );52 void postvisit( ArrayType * arrayType );53 void postvisit( ReferenceType * refType );54 void postvisit( FunctionType * functionType );55 void postvisit( StructInstType * aggregateUseType );56 void postvisit( UnionInstType * aggregateUseType );57 void postvisit( EnumInstType * aggregateUseType );58 void postvisit( TraitInstType * aggregateUseType );59 void postvisit( TypeInstType * aggregateUseType );60 void postvisit( TupleType * tupleType );61 void postvisit( VarArgsType * varArgsType );62 void postvisit( ZeroType * zeroType );63 void postvisit( OneType * oneType );64 65 private:66 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );67 template< typename RefType > void handleRefType( RefType * inst, Type * other );68 69 Type * result;70 Type * type2; // inherited71 bool widenFirst, widenSecond;72 const SymTab::Indexer &indexer;73 TypeEnvironment &env;74 const OpenVarSet &openVars;75 };76 77 Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {78 Type * common = nullptr;79 AssertionSet have, need;80 OpenVarSet newOpen( openVars );81 // need unify to bind type variables82 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) {83 PRINT(84 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;85 )86 if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {87 PRINT(88 std::cerr << "widen okay" << std::endl;89 )90 common->tq |= t1->tq;91 common->tq |= t2->tq;92 return common;93 }94 }95 PRINT(96 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;97 )98 return nullptr;99 }100 101 Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {102 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );103 104 int depth1 = type1->referenceDepth();105 int depth2 = type2->referenceDepth();106 if ( depth1 > 0 || depth2 > 0 ) {107 int diff = depth1-depth2;108 // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.109 // if ( diff > 1 || diff < -1 ) return nullptr;110 111 // special case where one type has a reference depth of 1 larger than the other112 if ( diff > 0 || diff < 0 ) {113 PRINT(114 std::cerr << "reference depth diff: " << diff << std::endl;115 )116 Type * result = nullptr;117 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );118 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );119 if ( diff > 0 ) {120 // deeper on the left121 assert( ref1 );122 result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );123 } else {124 // deeper on the right125 assert( ref2 );126 result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );127 }128 if ( result && ref1 ) {129 // formal is reference, so result should be reference130 PRINT(131 std::cerr << "formal is reference; result should be reference" << std::endl;132 )133 result = new ReferenceType( ref1->tq, result );134 }135 PRINT(136 std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;137 )138 return result;139 }140 // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.141 }142 143 type1->accept( visitor );144 Type * result = visitor.pass.get_result();145 if ( ! result ) {146 // this appears to be handling for opaque type declarations147 if ( widenSecond ) {148 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {149 if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {150 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );151 if ( type->get_base() ) {152 Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;153 AssertionSet have, need;154 OpenVarSet newOpen( openVars );155 type1->tq = Type::Qualifiers();156 type->get_base()->tq = tq1;157 if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {158 result = type1->clone();159 result->tq = tq1 | tq2;160 } // if161 type1->tq = tq1;162 type->get_base()->tq = Type::Qualifiers();163 } // if164 } // if165 } // if166 } // if167 } // if168 #ifdef DEBUG169 std::cerr << "============= commonType" << std::endl << "type1 is ";170 type1->print( std::cerr );171 std::cerr << " type2 is ";172 type2->print( std::cerr );173 if ( result ) {174 std::cerr << " common type is ";175 result->print( std::cerr );176 } else {177 std::cerr << " no common type";178 } // if179 std::cerr << std::endl;180 #endif181 return result;182 }183 37 184 38 // GENERATED START, DO NOT EDIT … … 489 343 ); 490 344 491 CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) 492 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) { 493 } 494 495 void CommonType_old::postvisit( VoidType * ) {} 496 497 void CommonType_old::postvisit( BasicType * basicType ) { 498 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) { 499 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ (ast::BasicType::Kind)(int)otherBasic->get_kind() ]; 500 if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) { 501 result = new BasicType( basicType->tq | otherBasic->tq, newType ); 502 } // if 503 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) { 504 // use signed int in lieu of the enum/zero/one type 505 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ]; 506 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) { 507 result = new BasicType( basicType->tq | type2->tq, newType ); 508 } // if 509 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) { 510 const EnumDecl* enumDecl = enumInst->baseEnum; 511 if ( const Type* baseType = enumDecl->base ) { 512 result = baseType->clone(); 513 } else { 514 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ]; 515 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) { 516 result = new BasicType( basicType->tq | type2->tq, newType ); 517 } // if 518 } 519 } 520 } 521 522 template< typename Pointer > 523 void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) { 524 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) { 525 OpenVarSet::const_iterator entry = openVars.find( var->get_name() ); 526 if ( entry != openVars.end() ) { 527 AssertionSet need, have; 528 WidenMode widen( widenFirst, widenSecond ); 529 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return; 530 } 531 } 532 result = voidPointer->clone(); 533 result->tq |= otherPointer->tq; 534 } 535 536 void CommonType_old::postvisit( PointerType * pointerType ) { 537 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) { 538 // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl; 539 if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) { 540 getCommonWithVoidPointer( otherPointer, pointerType ); 541 } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) { 542 getCommonWithVoidPointer( pointerType, otherPointer ); 543 } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst ) 544 && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) { 545 // std::cerr << "middle case" << std::endl; 546 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq; 547 pointerType->get_base()->tq = Type::Qualifiers(); 548 otherPointer->get_base()->tq = Type::Qualifiers(); 549 AssertionSet have, need; 550 OpenVarSet newOpen( openVars ); 551 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) { 552 // std::cerr << "unifyExact success" << std::endl; 553 if ( tq1 < tq2 ) { 554 result = pointerType->clone(); 555 } else { 556 result = otherPointer->clone(); 557 } // if 558 strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2; 559 } else { 560 /// std::cerr << "place for ptr-to-type" << std::endl; 561 } // if 562 pointerType->get_base()->tq = tq1; 563 otherPointer->get_base()->tq = tq2; 564 } // if 565 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 566 result = pointerType->clone(); 567 result->tq |= type2->tq; 568 } // if 569 } 570 571 void CommonType_old::postvisit( ArrayType * ) {} 572 573 void CommonType_old::postvisit( ReferenceType * refType ) { 574 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) { 575 // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl; 576 // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl; 577 if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) { 578 getCommonWithVoidPointer( otherRef, refType ); 579 } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) { 580 getCommonWithVoidPointer( refType, otherRef ); 581 } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) 582 && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) { 583 // std::cerr << "middle case" << std::endl; 584 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq; 585 refType->get_base()->tq = Type::Qualifiers(); 586 otherRef->get_base()->tq = Type::Qualifiers(); 587 AssertionSet have, need; 588 OpenVarSet newOpen( openVars ); 589 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) { 590 if ( tq1 < tq2 ) { 591 result = refType->clone(); 592 } else { 593 result = otherRef->clone(); 594 } // if 595 strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2; 596 } else { 597 /// std::cerr << "place for ptr-to-type" << std::endl; 598 } // if 599 refType->get_base()->tq = tq1; 600 otherRef->get_base()->tq = tq2; 601 } // if 602 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 603 result = refType->clone(); 604 result->tq |= type2->tq; 605 } // if 606 } 607 608 void CommonType_old::postvisit( FunctionType * ) {} 609 void CommonType_old::postvisit( StructInstType * ) {} 610 void CommonType_old::postvisit( UnionInstType * ) {} 611 612 void CommonType_old::postvisit( EnumInstType * enumInstType ) { 613 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) { 614 // reuse BasicType, EnumInstType code by swapping type2 with enumInstType 615 result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars ); 616 } // if 617 } 618 619 void CommonType_old::postvisit( TraitInstType * ) { 620 } 621 622 void CommonType_old::postvisit( TypeInstType * inst ) { 623 if ( widenFirst ) { 624 const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ); 625 if ( nt ) { 626 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt ); 627 if ( type->get_base() ) { 628 Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq; 629 AssertionSet have, need; 630 OpenVarSet newOpen( openVars ); 631 type2->tq = Type::Qualifiers(); 632 type->get_base()->tq = tq1; 633 if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) { 634 result = type2->clone(); 635 result->tq = tq1 | tq2; 636 } // if 637 type2->tq = tq2; 638 type->get_base()->tq = Type::Qualifiers(); 639 } // if 640 } // if 641 } // if 642 } 643 644 void CommonType_old::postvisit( TupleType * ) {} 645 void CommonType_old::postvisit( VarArgsType * ) {} 646 647 void CommonType_old::postvisit( ZeroType * zeroType ) { 648 if ( widenFirst ) { 649 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) { 650 if ( widenSecond || zeroType->tq <= type2->tq ) { 651 result = type2->clone(); 652 result->tq |= zeroType->tq; 653 } 654 } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) { 655 result = new BasicType( zeroType->tq, BasicType::SignedInt ); 656 result->tq |= type2->tq; 657 } 658 } 659 } 660 661 void CommonType_old::postvisit( OneType * oneType ) { 662 if ( widenFirst ) { 663 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) { 664 if ( widenSecond || oneType->tq <= type2->tq ) { 665 result = type2->clone(); 666 result->tq |= oneType->tq; 667 } 668 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 669 result = new BasicType( oneType->tq, BasicType::SignedInt ); 670 result->tq |= type2->tq; 671 } 672 } 673 } 674 675 class CommonType_new final : public ast::WithShortCircuiting { 345 class CommonType final : public ast::WithShortCircuiting { 676 346 const ast::Type * type2; 677 347 WidenMode widen; … … 684 354 ast::ptr< ast::Type > result; 685 355 686 CommonType _new(356 CommonType( 687 357 const ast::Type * t2, WidenMode w, 688 358 ast::TypeEnvironment & env, const ast::OpenVarSet & o, … … 718 388 result = enumDecl->base.get(); 719 389 } else { 720 #warning remove casts when `commonTypes` moved to new AST721 390 ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ]; 722 391 if ( … … 1069 738 }; 1070 739 1071 // size_t CommonType _new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");740 // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType"); 1072 741 namespace { 1073 742 ast::ptr< ast::Type > handleReference( … … 1141 810 } 1142 811 // otherwise both are reference types of the same depth and this is handled by the visitor 1143 ast::Pass<CommonType _new> visitor{ type2, widen, env, open, need, have };812 ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have }; 1144 813 type1->accept( visitor ); 1145 814 // ast::ptr< ast::Type > result = visitor.core.result; -
src/ResolvExpr/CommonType.hpp
rdf8ba61a r8d182b1 18 18 #include "AST/Fwd.hpp" 19 19 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 20 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet21 20 #include "WidenMode.h" // for WidenMode 22 23 class Type;24 namespace SymTab {25 class Indexer;26 }27 21 28 22 namespace ResolvExpr { 29 23 30 Type * commonType(31 Type * type1, Type * type2, bool widenFirst, bool widenSecond,32 const SymTab::Indexer & indexer, TypeEnvironment & env,33 const OpenVarSet & openVars );34 24 ast::ptr< ast::Type > commonType( 35 25 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, -
src/ResolvExpr/ConversionCost.cc
rdf8ba61a r8d182b1 21 21 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment24 23 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 25 24 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 26 #include "SymTab/Indexer.h" // for Indexer27 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl28 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType29 30 25 31 26 namespace ResolvExpr { 32 #if 033 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0, 0 };34 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, -1, 1, -1 };35 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0, 0 };36 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0, 0 };37 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0, 0 };38 const Cost Cost::sign = Cost{ 0, 0, 0, 1, 0, 0, 0 };39 const Cost Cost::var = Cost{ 0, 0, 0, 0, 1, 0, 0 };40 const Cost Cost::spec = Cost{ 0, 0, 0, 0, 0, -1, 0 };41 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 0, 1 };42 #endif43 27 44 28 #if 0 … … 47 31 #define PRINT(x) 48 32 #endif 49 50 Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,51 const SymTab::Indexer &indexer, const TypeEnvironment &env ) {52 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {53 PRINT( std::cerr << "type inst " << destAsTypeInst->name; )54 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {55 if ( eqvClass->type ) {56 return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );57 } else {58 return Cost::infinity;59 }60 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {61 PRINT( std::cerr << " found" << std::endl; )62 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );63 // all typedefs should be gone by this point64 assert( type );65 if ( type->base ) {66 return conversionCost( src, type->base, srcIsLvalue, indexer, env )67 + Cost::safe;68 } // if69 } // if70 PRINT( std::cerr << " not found" << std::endl; )71 } // if72 PRINT(73 std::cerr << "src is ";74 src->print( std::cerr );75 std::cerr << std::endl << "dest is ";76 dest->print( std::cerr );77 std::cerr << std::endl << "env is" << std::endl;78 env.print( std::cerr, 8 );79 )80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {81 PRINT( std::cerr << "compatible!" << std::endl; )82 return Cost::zero;83 } else if ( dynamic_cast< const VoidType * >( dest ) ) {84 return Cost::safe;85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){88 return ptrsAssignable( t1, t2, env );89 });90 } else {91 PassVisitor<ConversionCost> converter(92 dest, srcIsLvalue, indexer, env,93 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))94 conversionCost );95 src->accept( converter );96 if ( converter.pass.get_cost() == Cost::infinity ) {97 return Cost::infinity;98 } else {99 return converter.pass.get_cost() + Cost::zero;100 } // if101 } // if102 }103 104 static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,105 int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {106 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )107 if ( diff > 0 ) {108 // TODO: document this109 Cost cost = convertToReferenceCost(110 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,111 diff-1, indexer, env, func );112 cost.incReference();113 return cost;114 } else if ( diff < -1 ) {115 // TODO: document this116 Cost cost = convertToReferenceCost(117 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,118 diff+1, indexer, env, func );119 cost.incReference();120 return cost;121 } else if ( diff == 0 ) {122 const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );123 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );124 if ( srcAsRef && destAsRef ) { // pointer-like conversions between references125 PRINT( std::cerr << "converting between references" << std::endl; )126 Type::Qualifiers tq1 = srcAsRef->base->tq;127 Type::Qualifiers tq2 = destAsRef->base->tq;128 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {129 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )130 if ( tq1 == tq2 ) {131 // types are the same132 return Cost::zero;133 } else {134 // types are the same, except otherPointer has more qualifiers135 return Cost::safe;136 }137 } else { // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?138 int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );139 PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )140 if ( assignResult > 0 ) {141 return Cost::safe;142 } else if ( assignResult < 0 ) {143 return Cost::unsafe;144 } // if145 } // if146 } else {147 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )148 PassVisitor<ConversionCost> converter(149 dest, srcIsLvalue, indexer, env,150 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))151 conversionCost );152 src->accept( converter );153 return converter.pass.get_cost();154 } // if155 } else {156 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );157 assert( diff == -1 && destAsRef );158 PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )159 if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {160 PRINT( std::cerr << "converting compatible base type" << std::endl; )161 if ( srcIsLvalue ) {162 PRINT(163 std::cerr << "lvalue to reference conversion" << std::endl;164 std::cerr << src << " => " << destAsRef << std::endl;165 )166 // lvalue-to-reference conversion: cv lvalue T => cv T &167 if ( src->tq == destAsRef->base->tq ) {168 return Cost::reference; // cost needs to be non-zero to add cast169 } if ( src->tq < destAsRef->base->tq ) {170 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same171 } else {172 return Cost::unsafe;173 } // if174 } else if ( destAsRef->base->get_const() ) {175 PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )176 // rvalue-to-const-reference conversion: T => const T &177 return Cost::safe;178 } else {179 PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )180 // rvalue-to-reference conversion: T => T &181 return Cost::unsafe;182 } // if183 } // if184 PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )185 }186 return Cost::infinity;187 }188 189 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,190 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {191 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();192 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );193 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )194 return cost;195 }196 197 ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )198 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {199 }200 33 201 34 // GENERATED START, DO NOT EDIT … … 319 152 ); 320 153 321 void ConversionCost::postvisit( const VoidType * ) {322 cost = Cost::infinity;323 }324 325 // refactor for code resue326 void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {327 int tableResult = costMatrix[ src->kind ][ dest->kind ];328 if ( tableResult == -1 ) {329 cost = Cost::unsafe;330 } else {331 cost = Cost::zero;332 cost.incSafe( tableResult );333 cost.incSign( signMatrix[ src->kind ][ dest->kind ] );334 } // if335 } // ConversionCost::conversionCostFromBasicToBasic336 337 void ConversionCost::postvisit(const BasicType * basicType) {338 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {339 conversionCostFromBasicToBasic(basicType, destAsBasic);340 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {341 const EnumDecl * base_enum = enumInst->baseEnum;342 if ( const Type * base = base_enum->base ) {343 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {344 conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);345 } else {346 cost = Cost::infinity;347 } // if348 } else {349 cost = Cost::unsafe;350 } // if351 } // if352 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.353 }354 355 void ConversionCost::postvisit( const PointerType * pointerType ) {356 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {357 PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )358 Type::Qualifiers tq1 = pointerType->base->tq;359 Type::Qualifiers tq2 = destAsPtr->base->tq;360 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {361 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )362 if ( tq1 == tq2 ) {363 // types are the same364 cost = Cost::zero;365 } else {366 // types are the same, except otherPointer has more qualifiers367 cost = Cost::safe;368 } // if369 } else {370 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );371 PRINT( std::cerr << " :: " << assignResult << std::endl; )372 if ( assignResult > 0 && tq1 <= tq2 ) {373 // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?374 if ( tq1 == tq2 ) {375 cost = Cost::safe;376 } else if ( tq1 < tq2 ) {377 cost = Cost::safe+Cost::safe;378 }379 } else if ( assignResult < 0 ) {380 cost = Cost::unsafe;381 } // if382 // assignResult == 0 means Cost::Infinity383 } // if384 // case case for zero_t because it should not be possible to convert pointers to zero_t.385 } // if386 }387 388 void ConversionCost::postvisit( const ArrayType * ) {}389 390 void ConversionCost::postvisit( const ReferenceType * refType ) {391 // Note: dest can never be a reference, since it would have been caught in an earlier check392 assert( ! dynamic_cast< const ReferenceType * >( dest ) );393 // convert reference to rvalue: cv T1 & => T2394 // recursively compute conversion cost from T1 to T2.395 // cv can be safely dropped because of 'implicit dereference' behavior.396 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );397 if ( refType->base->tq == dest->tq ) {398 cost.incReference(); // prefer exact qualifiers399 } else if ( refType->base->tq < dest->tq ) {400 cost.incSafe(); // then gaining qualifiers401 } else {402 cost.incUnsafe(); // lose qualifiers as last resort403 }404 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )405 }406 407 void ConversionCost::postvisit( const FunctionType * ) {}408 409 void ConversionCost::postvisit( const EnumInstType * enumInst) {410 const EnumDecl * enumDecl = enumInst -> baseEnum;411 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum412 cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );413 } else {414 static Type::Qualifiers q;415 static BasicType integer( q, BasicType::SignedInt );416 cost = costFunc( &integer, dest, srcIsLvalue, indexer, env ); // safe if dest >= int417 } // if418 if ( cost < Cost::unsafe ) {419 cost.incSafe();420 } // if421 }422 423 void ConversionCost::postvisit( const TraitInstType * ) {}424 425 void ConversionCost::postvisit( const TypeInstType * inst ) {426 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {427 cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );428 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {429 if ( inst->name == destAsInst->name ) {430 cost = Cost::zero;431 }432 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {433 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );434 // all typedefs should be gone by this point435 assert( type );436 if ( type->base ) {437 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;438 } // if439 } // if440 }441 442 void ConversionCost::postvisit( const TupleType * tupleType ) {443 Cost c = Cost::zero;444 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {445 std::list< Type * >::const_iterator srcIt = tupleType->types.begin();446 std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();447 while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {448 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );449 if ( newCost == Cost::infinity ) {450 return;451 } // if452 c += newCost;453 } // while454 if ( destIt != destAsTuple->types.end() ) {455 cost = Cost::infinity;456 } else {457 cost = c;458 } // if459 } // if460 }461 462 void ConversionCost::postvisit( const VarArgsType * ) {463 if ( dynamic_cast< const VarArgsType * >( dest ) ) {464 cost = Cost::zero;465 }466 }467 468 void ConversionCost::postvisit( const ZeroType * ) {469 if ( dynamic_cast< const ZeroType * >( dest ) ) {470 cost = Cost::zero;471 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {472 // copied from visit(BasicType *) for signed int, but +1 for safe conversions473 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];474 if ( tableResult == -1 ) {475 cost = Cost::unsafe;476 } else {477 cost = Cost::zero;478 cost.incSafe( tableResult + 1 );479 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );480 } // if481 } else if ( dynamic_cast< const PointerType * >( dest ) ) {482 cost = Cost::zero;483 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation484 } // if485 }486 487 void ConversionCost::postvisit( const OneType * ) {488 if ( dynamic_cast< const OneType * >( dest ) ) {489 cost = Cost::zero;490 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {491 // copied from visit(BasicType *) for signed int, but +1 for safe conversions492 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];493 if ( tableResult == -1 ) {494 cost = Cost::unsafe;495 } else {496 cost = Cost::zero;497 cost.incSafe( tableResult + 1 );498 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );499 } // if500 } // if501 }502 503 154 namespace { 504 # warning For overload resolution between the two versions.505 155 int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 506 156 const ast::SymbolTable &, const ast::TypeEnvironment & env ) { 507 157 return ptrsAssignable( t1, t2, env ); 508 158 } 509 Cost localConversionCost(510 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,511 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env512 ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }513 159 } 514 160 … … 540 186 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable ); 541 187 } else { 542 return ast::Pass<ConversionCost _new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );188 return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost ); 543 189 } 544 190 } … … 581 227 } 582 228 } else { 583 return ast::Pass<ConversionCost _new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );229 return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost ); 584 230 } 585 231 } else { … … 613 259 } 614 260 615 void ConversionCost _new::postvisit( const ast::VoidType * voidType ) {261 void ConversionCost::postvisit( const ast::VoidType * voidType ) { 616 262 (void)voidType; 617 263 cost = Cost::infinity; 618 264 } 619 265 620 void ConversionCost _new::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) {266 void ConversionCost::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) { 621 267 int tableResult = costMatrix[ src->kind ][ dest->kind ]; 622 268 if ( tableResult == -1 ) { … … 629 275 } 630 276 631 void ConversionCost _new::postvisit( const ast::BasicType * basicType ) {277 void ConversionCost::postvisit( const ast::BasicType * basicType ) { 632 278 if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) { 633 279 conversionCostFromBasicToBasic( basicType, dstAsBasic ); … … 635 281 const ast::EnumDecl * enumDecl = enumInst->base.get(); 636 282 if ( enumDecl->isTyped && !enumDecl->base.get() ) { 637 cost = Cost::infinity; 283 cost = Cost::infinity; 638 284 } else if ( const ast::Type * enumType = enumDecl->base.get() ) { 639 285 if ( const ast::BasicType * enumTypeAsBasic = dynamic_cast<const ast::BasicType *>(enumType) ) { … … 648 294 } 649 295 650 void ConversionCost _new::postvisit( const ast::PointerType * pointerType ) {296 void ConversionCost::postvisit( const ast::PointerType * pointerType ) { 651 297 if ( const ast::PointerType * dstAsPtr = dynamic_cast< const ast::PointerType * >( dst ) ) { 652 298 ast::CV::Qualifiers tq1 = pointerType->base->qualifiers; … … 694 340 } 695 341 696 void ConversionCost _new::postvisit( const ast::ArrayType * arrayType ) {342 void ConversionCost::postvisit( const ast::ArrayType * arrayType ) { 697 343 (void)arrayType; 698 344 } 699 345 700 void ConversionCost _new::postvisit( const ast::ReferenceType * refType ) {346 void ConversionCost::postvisit( const ast::ReferenceType * refType ) { 701 347 assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) ); 702 348 … … 716 362 } 717 363 718 void ConversionCost _new::postvisit( const ast::FunctionType * functionType ) {364 void ConversionCost::postvisit( const ast::FunctionType * functionType ) { 719 365 (void)functionType; 720 366 } 721 367 722 void ConversionCost _new::postvisit( const ast::EnumInstType * enumInstType ) {368 void ConversionCost::postvisit( const ast::EnumInstType * enumInstType ) { 723 369 const ast::EnumDecl * baseEnum = enumInstType->base; 724 370 if ( const ast::Type * baseType = baseEnum->base ) { … … 733 379 } 734 380 735 void ConversionCost _new::postvisit( const ast::TraitInstType * traitInstType ) {381 void ConversionCost::postvisit( const ast::TraitInstType * traitInstType ) { 736 382 (void)traitInstType; 737 383 } 738 384 739 void ConversionCost _new::postvisit( const ast::TypeInstType * typeInstType ) {385 void ConversionCost::postvisit( const ast::TypeInstType * typeInstType ) { 740 386 if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) { 741 387 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env ); … … 754 400 } 755 401 756 void ConversionCost _new::postvisit( const ast::TupleType * tupleType ) {402 void ConversionCost::postvisit( const ast::TupleType * tupleType ) { 757 403 Cost c = Cost::zero; 758 404 if ( const ast::TupleType * dstAsTuple = dynamic_cast< const ast::TupleType * >( dst ) ) { … … 776 422 } 777 423 778 void ConversionCost _new::postvisit( const ast::VarArgsType * varArgsType ) {424 void ConversionCost::postvisit( const ast::VarArgsType * varArgsType ) { 779 425 (void)varArgsType; 780 426 if ( dynamic_cast< const ast::VarArgsType * >( dst ) ) { … … 783 429 } 784 430 785 void ConversionCost _new::postvisit( const ast::ZeroType * zeroType ) {431 void ConversionCost::postvisit( const ast::ZeroType * zeroType ) { 786 432 (void)zeroType; 787 433 if ( dynamic_cast< const ast::ZeroType * >( dst ) ) { … … 810 456 } 811 457 812 void ConversionCost _new::postvisit( const ast::OneType * oneType ) {458 void ConversionCost::postvisit( const ast::OneType * oneType ) { 813 459 (void)oneType; 814 460 if ( dynamic_cast< const ast::OneType * >( dst ) ) { 815 461 cost = Cost::zero; 816 462 } else if ( const ast::BasicType * dstAsBasic = 817 dynamic_cast< const ast::BasicType * >( dst ) ) { 463 dynamic_cast< const ast::BasicType * >( dst ) ) { 818 464 int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ]; 819 465 if ( -1 == tableResult ) { … … 824 470 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 825 471 } 826 827 // cost = Cost::zero; 828 } 829 } 830 // size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost"); 472 } 473 } 474 475 // size_t ConversionCost::traceId = Stats::Heap::new_stacktrace_id("ConversionCost"); 831 476 832 477 } // namespace ResolvExpr -
src/ResolvExpr/ConversionCost.h
rdf8ba61a r8d182b1 22 22 #include "AST/Fwd.hpp" 23 23 #include "AST/Pass.hpp" // for WithShortCircuiting 24 #include "Common/PassVisitor.h"25 #include "SynTree/Visitor.h" // for Visitor26 #include "SynTree/SynTree.h" // for Visitor Nodes27 28 namespace SymTab {29 class Indexer;30 } // namespace SymTab31 24 32 25 namespace ResolvExpr { 33 class TypeEnvironment;34 35 Cost conversionCost(36 const Type * src, const Type * dest, bool srcIsLvalue,37 const SymTab::Indexer & indexer, const TypeEnvironment & env );38 39 typedef std::function<Cost(const Type *, const Type *, bool,40 const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;41 42 struct ConversionCost : public WithShortCircuiting {43 public:44 ConversionCost( const Type * dest, bool srcIsLvalue,45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );46 47 Cost get_cost() const { return cost; }48 49 void previsit( const BaseSyntaxNode * ) { visit_children = false; }50 51 void postvisit( const VoidType * voidType );52 void postvisit( const BasicType * basicType );53 void postvisit( const PointerType * pointerType );54 void postvisit( const ArrayType * arrayType );55 void postvisit( const ReferenceType * refType );56 void postvisit( const FunctionType * functionType );57 void postvisit( const EnumInstType * aggregateUseType );58 void postvisit( const TraitInstType * aggregateUseType );59 void postvisit( const TypeInstType * aggregateUseType );60 void postvisit( const TupleType * tupleType );61 void postvisit( const VarArgsType * varArgsType );62 void postvisit( const ZeroType * zeroType );63 void postvisit( const OneType * oneType );64 protected:65 const Type * dest;66 bool srcIsLvalue;67 const SymTab::Indexer &indexer;68 Cost cost;69 const TypeEnvironment &env;70 CostFunction costFunc;71 private:72 // refactor for code resue73 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest );74 };75 76 typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;77 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,78 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );79 26 80 27 // Some function pointer types, differ in return type. … … 92 39 PtrsCalculation func ); 93 40 94 #warning when the old ConversionCost is removed, get ride of the _new suffix. 95 class ConversionCost_new : public ast::WithShortCircuiting { 41 class ConversionCost : public ast::WithShortCircuiting { 96 42 protected: 97 43 const ast::Type * dst; … … 105 51 Cost result() { return cost; } 106 52 107 ConversionCost _new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,53 ConversionCost( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 108 54 const ast::TypeEnvironment & env, CostCalculation costCalc ) : 109 55 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ), -
src/ResolvExpr/CurrentObject.cc
rdf8ba61a r8d182b1 33 33 #include "Common/utility.h" // for toString 34 34 #include "CurrentObject.h" 35 #include "SynTree/Constant.h" // for Constant36 #include "SynTree/Declaration.h" // for ObjectDecl, Declaration, Struc...37 #include "SynTree/Expression.h" // for InitAlternative, VariableExpr38 #include "SynTree/Initializer.h" // for Designation, operator<<39 #include "SynTree/Type.h" // for Type, StructInstType, UnionIns...40 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution41 35 42 36 #if 0 … … 45 39 #define PRINT(x) 46 40 #endif 47 48 namespace ResolvExpr {49 template< typename AggrInst >50 TypeSubstitution makeGenericSubstitution( AggrInst * inst ) {51 assert( inst );52 assert( inst->get_baseParameters() );53 std::list< TypeDecl * > baseParams = *inst->get_baseParameters();54 std::list< Expression * > typeSubs = inst->get_parameters();55 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );56 return subs;57 }58 59 TypeSubstitution makeGenericSubstitution( Type * type ) {60 if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) {61 return makeGenericSubstitution( inst );62 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) {63 return makeGenericSubstitution( inst );64 } else {65 return TypeSubstitution();66 }67 }68 69 class MemberIterator {70 public:71 virtual ~MemberIterator() {}72 73 /// walks the current object using the given designators as a guide74 virtual void setPosition( std::list< Expression * > & designators ) = 0;75 76 /// retrieve the list of possible Type/Designation pairs for the current position in the currect object77 virtual std::list<InitAlternative> operator*() const = 0;78 79 /// true if the iterator is not currently at the end80 virtual operator bool() const = 0;81 82 /// moves the iterator by one member in the current object83 virtual MemberIterator & bigStep() = 0;84 85 /// moves the iterator by one member in the current subobject86 virtual MemberIterator & smallStep() = 0;87 88 /// the type of the current object89 virtual Type * getType() = 0;90 91 /// the type of the current subobject92 virtual Type * getNext() = 0;93 94 /// printing for debug95 virtual void print( std::ostream & out, Indenter indent ) const = 0;96 97 /// helper for operator*; aggregates must add designator to each init alternative, but98 /// adding designators in operator* creates duplicates.99 virtual std::list<InitAlternative> first() const = 0; // should be protected100 };101 102 std::ostream & operator<<(std::ostream & out, const MemberIterator & it) {103 Indenter indenter;104 it.print( out, indenter );105 return out;106 }107 108 /// create a new MemberIterator that traverses a type correctly109 MemberIterator * createMemberIterator( Type * type );110 111 /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry112 class SimpleIterator : public MemberIterator {113 public:114 SimpleIterator( Type * type ) : type( type ) {}115 116 virtual void setPosition( std::list< Expression * > & designators ) {117 assertf( designators.empty(), "simple iterator given non-empty designator..." ); // xxx - might be semantic error118 }119 120 virtual std::list<InitAlternative> operator*() const { return first(); }121 virtual operator bool() const { return type; }122 123 // big step is the same as small step124 virtual MemberIterator & bigStep() { return smallStep(); }125 virtual MemberIterator & smallStep() {126 type = nullptr; // type is nullified on increment since SimpleIterators do not have members127 return *this;128 }129 130 virtual void print( std::ostream & out, __attribute__((unused)) Indenter indent ) const {131 out << "SimpleIterator(" << type << ")";132 }133 134 virtual Type * getType() { return type; }135 virtual Type * getNext() { return type; }136 137 protected:138 virtual std::list<InitAlternative> first() const {139 if ( type ) return std::list<InitAlternative>{ { type->clone(), new Designation( {} ) } };140 else return std::list<InitAlternative>{};141 }142 private:143 Type * type = nullptr;144 };145 146 class ArrayIterator : public MemberIterator {147 public:148 ArrayIterator( ArrayType * at ) : array( at ) {149 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )150 base = at->base;151 memberIter = createMemberIterator( base );152 if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " );153 setSize( at->dimension );154 }155 156 ~ArrayIterator() {157 delete memberIter;158 }159 160 private:161 void setSize( Expression * expr ) {162 auto res = eval( expr );163 if (res.second) {164 size = res.first;165 } else {166 SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) );167 }168 }169 170 public:171 void setPosition( Expression * expr ) {172 // need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions173 auto arg = eval( expr );174 index = arg.first;175 return;176 177 // if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {178 // try {179 // index = constExpr->intValue();180 // } catch( SemanticErrorException & ) {181 // SemanticError( expr, "Constant expression of non-integral type in array designator: " );182 // }183 // } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {184 // setPosition( castExpr->get_arg() );185 // } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {186 // EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );187 // assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );188 // long long int value;189 // if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {190 // index = value;191 // }192 // } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {193 // index = 0; // xxx - get actual sizeof/alignof value?194 // } else {195 // assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );196 // }197 }198 199 virtual void setPosition( std::list< Expression * > & designators ) {200 if ( ! designators.empty() ) {201 setPosition( designators.front() );202 designators.pop_front();203 memberIter->setPosition( designators );204 }205 }206 207 virtual std::list<InitAlternative> operator*() const {208 return first();209 }210 211 virtual operator bool() const { return index < size; }212 213 virtual MemberIterator & bigStep() {214 PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )215 ++index;216 delete memberIter;217 if ( index < size ) memberIter = createMemberIterator( base );218 else memberIter = nullptr;219 return *this;220 }221 222 virtual MemberIterator & smallStep() {223 PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )224 if ( memberIter ) {225 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )226 memberIter->smallStep();227 if ( *memberIter ) {228 PRINT( std::cerr << "has valid member iter" << std::endl; )229 return *this;230 }231 }232 return bigStep();233 }234 235 virtual Type * getType() { return array; }236 virtual Type * getNext() { return base; }237 238 virtual std::list<InitAlternative> first() const {239 PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )240 if ( memberIter && *memberIter ) {241 std::list<InitAlternative> ret = memberIter->first();242 for ( InitAlternative & alt : ret ) {243 alt.designation->get_designators().push_front( new ConstantExpr( Constant::from_ulong( index ) ) );244 }245 return ret;246 }247 return std::list<InitAlternative>();248 }249 250 virtual void print( std::ostream & out, Indenter indent ) const {251 out << "ArrayIterator(Array of " << base << ")";252 if ( memberIter ) {253 Indenter childIndent = indent+1;254 out << std::endl << childIndent;255 memberIter->print( out, childIndent );256 }257 }258 259 private:260 ArrayType * array = nullptr;261 Type * base = nullptr;262 size_t index = 0;263 size_t size = 0;264 MemberIterator * memberIter = nullptr;265 };266 267 class AggregateIterator : public MemberIterator {268 public:269 typedef std::list<Declaration *> MemberList;270 typedef MemberList::const_iterator iterator;271 std::string kind = ""; // for debug272 std::string name;273 Type * inst = nullptr;274 const MemberList & members;275 iterator curMember;276 bool atbegin = true; // false at first {small,big}Step -- this aggr type is only added to the possibilities at the beginning277 Type * curType = nullptr;278 MemberIterator * memberIter = nullptr;279 mutable TypeSubstitution sub;280 281 AggregateIterator( const std::string & kind, const std::string & name, Type * inst, const MemberList & members ) : kind( kind ), name( name ), inst( inst ), members( members ), curMember( members.begin() ), sub( makeGenericSubstitution( inst ) ) {282 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )283 init();284 }285 286 virtual ~AggregateIterator() {287 delete memberIter;288 }289 290 bool init() {291 PRINT( std::cerr << "--init()--" << members.size() << std::endl; )292 if ( curMember != members.end() ) {293 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( *curMember ) ) {294 PRINT( std::cerr << "incremented to field: " << field << std::endl; )295 curType = field->get_type();296 memberIter = createMemberIterator( curType );297 return true;298 }299 }300 return false;301 }302 303 virtual std::list<InitAlternative> operator*() const {304 if (memberIter && *memberIter) {305 std::list<InitAlternative> ret = memberIter->first();306 PRINT( std::cerr << "sub: " << sub << std::endl; )307 for ( InitAlternative & alt : ret ) {308 PRINT( std::cerr << "iterating and adding designators" << std::endl; )309 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );310 // need to substitute for generic types, so that casts are to concrete types311 PRINT( std::cerr << " type is: " << alt.type; )312 sub.apply( alt.type ); // also apply to designation??313 PRINT( std::cerr << " ==> " << alt.type << std::endl; )314 }315 return ret;316 }317 return std::list<InitAlternative>();318 }319 320 virtual void setPosition( std::list< Expression * > & designators ) {321 if ( ! designators.empty() ) {322 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( designators.front() ) ) {323 for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {324 if ( *curMember == varExpr->get_var() ) {325 designators.pop_front();326 delete memberIter;327 memberIter = createMemberIterator( varExpr->get_result() );328 curType = varExpr->get_result();329 atbegin = curMember == members.begin() && designators.empty(); // xxx - is this the right condition for atbegin??330 memberIter->setPosition( designators );331 return;332 } // if333 } // for334 assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );335 } else {336 assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );337 } // if338 } // if339 }340 341 virtual MemberIterator & smallStep() {342 PRINT( std::cerr << "smallStep in " << kind << std::endl; )343 atbegin = false;344 if ( memberIter ) {345 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )346 memberIter->smallStep();347 if ( *memberIter ) {348 PRINT( std::cerr << "success!" << std::endl; )349 return *this;350 }351 }352 return bigStep();353 }354 355 virtual Type * getType() { return inst; }356 virtual Type * getNext() {357 if ( memberIter && *memberIter ) return memberIter->getType(); // xxx - ??? recursive call???358 return nullptr;359 }360 361 virtual std::list<InitAlternative> first() const {362 std::list<InitAlternative> ret;363 PRINT( std::cerr << "first " << kind << std::endl; )364 if ( memberIter && *memberIter ) { // might not need *memberIter??365 PRINT( std::cerr << "adding children" << std::endl; )366 ret = memberIter->first();367 for ( InitAlternative & alt : ret ) {368 PRINT( std::cerr << "iterating and adding designators" << std::endl; )369 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );370 }371 }372 if ( atbegin ) {373 // xxx - what about case of empty struct??374 // only add self if at the very beginning of the structure375 PRINT( std::cerr << "adding self" << std::endl; )376 ret.push_front( { inst->clone(), new Designation( {} ) } );377 }378 return ret;379 }380 381 virtual void print( std::ostream & out, Indenter indent ) const {382 out << kind << "(" << name << ")";383 if ( memberIter ) {384 Indenter childIndent = indent+1;385 out << std::endl << childIndent;386 memberIter->print( out, childIndent );387 }388 }389 };390 391 class UnionIterator : public AggregateIterator {392 public:393 UnionIterator( UnionInstType * inst ) : AggregateIterator( "UnionIterator", inst->get_name(), inst, inst->get_baseUnion()->get_members() ) {}394 395 virtual operator bool() const { return (memberIter && *memberIter); }396 virtual MemberIterator & bigStep() {397 // unions only initialize one member398 PRINT( std::cerr << "bigStep in " << kind << std::endl; )399 atbegin = false;400 delete memberIter;401 memberIter = nullptr;402 curType = nullptr;403 curMember = members.end();404 return *this;405 }406 };407 408 class StructIterator : public AggregateIterator {409 public:410 StructIterator( StructInstType * inst ) : AggregateIterator( "StructIterator", inst->get_name(), inst, inst->get_baseStruct()->get_members() ) {}411 412 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }413 414 virtual MemberIterator & bigStep() {415 PRINT( std::cerr << "bigStep in " << kind << std::endl; )416 atbegin = false;417 delete memberIter;418 memberIter = nullptr;419 curType = nullptr;420 for ( ; curMember != members.end(); ) {421 ++curMember;422 if ( init() ) {423 return *this;424 }425 }426 return *this;427 }428 };429 430 class TupleIterator : public AggregateIterator {431 public:432 TupleIterator( TupleType * inst ) : AggregateIterator( "TupleIterator", toString("Tuple", inst->size()), inst, inst->get_members() ) {}433 434 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }435 436 virtual MemberIterator & bigStep() {437 PRINT( std::cerr << "bigStep in " << kind << std::endl; )438 atbegin = false;439 delete memberIter;440 memberIter = nullptr;441 curType = nullptr;442 for ( ; curMember != members.end(); ) {443 ++curMember;444 if ( init() ) {445 return *this;446 }447 }448 return *this;449 }450 };451 452 MemberIterator * createMemberIterator( Type * type ) {453 if ( ReferenceToType * aggr = dynamic_cast< ReferenceToType * >( type ) ) {454 if ( StructInstType * sit = dynamic_cast< StructInstType * >( aggr ) ) {455 return new StructIterator( sit );456 } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( aggr ) ) {457 return new UnionIterator( uit );458 } else {459 assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );460 return new SimpleIterator( type );461 }462 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {463 return new ArrayIterator( at );464 } else if ( TupleType * tt = dynamic_cast< TupleType * >( type ) ) {465 return new TupleIterator( tt );466 } else {467 return new SimpleIterator( type );468 }469 }470 471 CurrentObject::CurrentObject() {}472 CurrentObject::CurrentObject( Type * type ) {473 objStack.push( new SimpleIterator( type ) );474 }475 476 477 void CurrentObject::setNext( Designation * designation ) {478 assertf( ! objStack.empty(), "obj stack empty in setNext" );479 PRINT( std::cerr << "____setNext" << designation << std::endl; )480 objStack.top()->setPosition( designation->get_designators() );481 }482 483 Designation * CurrentObject::findNext( Designation * designation ) {484 typedef std::list< Expression * > DesignatorChain;485 PRINT( std::cerr << "___findNext" << std::endl; )486 // find all the d's487 std::list<DesignatorChain> desigAlts{ { } }, newDesigAlts;488 std::list<Type *> curTypes { (objStack.top())->getType() }, newTypes;489 for ( Expression * expr : designation->get_designators() ) {490 PRINT( std::cerr << "____untyped: " << expr << std::endl; )491 std::list<DesignatorChain>::iterator dit = desigAlts.begin();492 if ( NameExpr * nexpr = dynamic_cast<NameExpr *>(expr) ) {493 for ( Type * t : curTypes ) {494 assert( dit != desigAlts.end() );495 DesignatorChain & d = *dit;496 PRINT( std::cerr << "____actual: " << t << std::endl; )497 ReferenceToType * refType = dynamic_cast<ReferenceToType *>(t);498 std::list<Declaration *> members;499 if ( refType ) {500 refType->lookup( nexpr->get_name(), members ); // concatenate identical field name501 // xxx - need to also include anonymous members in this somehow...502 for ( Declaration * mem: members ) {503 if ( ObjectDecl * field = dynamic_cast<ObjectDecl *>(mem) ) {504 PRINT( std::cerr << "____alt: " << field->get_type() << std::endl; )505 DesignatorChain newD = d;506 newD.push_back( new VariableExpr( field ) );507 newDesigAlts.push_back( newD );508 newTypes.push_back( field->get_type() );509 } // if510 } // for511 } // if512 ++dit;513 } // for514 } else {515 for ( Type * t : curTypes ) {516 assert( dit != desigAlts.end() );517 DesignatorChain & d = *dit;518 if ( ArrayType * at = dynamic_cast< ArrayType * > ( t ) ) {519 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )520 d.push_back( expr );521 newDesigAlts.push_back( d );522 newTypes.push_back( at->get_base() );523 }524 ++dit;525 } // for526 } // if527 desigAlts = newDesigAlts;528 newDesigAlts.clear();529 curTypes = newTypes;530 newTypes.clear();531 assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );532 } // for533 if ( desigAlts.size() > 1 ) {534 SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );535 } else if ( desigAlts.size() == 0 ) {536 SemanticError( designation, "No reasonable alternatives for designation: " );537 }538 DesignatorChain & d = desigAlts.back();539 PRINT( for ( Expression * expr : d ) {540 std::cerr << "____desig: " << expr << std::endl;541 } ) // for542 assertf( ! curTypes.empty(), "empty designator chosen");543 544 // set new designators545 assertf( ! objStack.empty(), "empty object stack when setting designation" );546 Designation * actualDesignation = new Designation( d );547 objStack.top()->setPosition( d ); // destroys d548 return actualDesignation;549 }550 551 void CurrentObject::increment() {552 PRINT( std::cerr << "____increment" << std::endl; )553 if ( ! objStack.empty() ) {554 PRINT( std::cerr << *objStack.top() << std::endl; )555 objStack.top()->smallStep();556 }557 }558 559 void CurrentObject::enterListInit() {560 PRINT( std::cerr << "____entering list init" << std::endl; )561 assertf( ! objStack.empty(), "empty obj stack entering list init" );562 Type * type = objStack.top()->getNext();563 if ( type ) {564 objStack.push( createMemberIterator( type ) );565 } else {566 assertf( false, "not sure about this case..." );567 }568 }569 570 void CurrentObject::exitListInit() {571 PRINT( std::cerr << "____exiting list init" << std::endl; )572 assertf( ! objStack.empty(), "objstack empty" );573 delete objStack.top();574 objStack.pop();575 if ( ! objStack.empty() ) {576 PRINT( std::cerr << *objStack.top() << std::endl; )577 objStack.top()->bigStep();578 }579 }580 581 std::list< InitAlternative > CurrentObject::getOptions() {582 PRINT( std::cerr << "____getting current options" << std::endl; )583 assertf( ! objStack.empty(), "objstack empty in getOptions" );584 return **objStack.top();585 }586 587 Type * CurrentObject::getCurrentType() {588 PRINT( std::cerr << "____getting current type" << std::endl; )589 assertf( ! objStack.empty(), "objstack empty in getCurrentType" );590 return objStack.top()->getNext();591 }592 } // namespace ResolvExpr593 41 594 42 namespace ast { -
src/ResolvExpr/FindOpenVars.cc
rdf8ba61a r8d182b1 16 16 #include "FindOpenVars.h" 17 17 18 #include <list> // for _List_const_iterator, list<>::const...19 #include <map> // for map<>::mapped_type20 21 18 #include "AST/Pass.hpp" 22 19 #include "AST/Type.hpp" 23 20 #include "AST/TypeEnvironment.hpp" 24 #include "Common/PassVisitor.h"25 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType (ptr ...26 #include "SynTree/Type.h" // for Type, Type::ForallList, ArrayType27 21 28 22 #include <iostream> 29 23 30 24 namespace ResolvExpr { 31 struct FindOpenVars_old : public WithGuards {32 FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );33 34 void previsit( const PointerType * pointerType );35 void previsit( const ArrayType * arrayType );36 void previsit( const FunctionType * functionType );37 void previsit( const TupleType * tupleType );38 39 void common_action( const Type *type );40 41 OpenVarSet &openVars, &closedVars;42 AssertionSet &needAssertions, &haveAssertions;43 bool nextIsOpen;44 };45 46 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {47 PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );48 type->accept( finder );49 }50 51 FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )52 : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) {53 }54 55 void FindOpenVars_old::common_action( const Type * type ) {56 if ( nextIsOpen ) {57 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {58 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };59 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {60 needAssertions[ *assert ].isUsed = false;61 }62 /// cloneAll( (*i)->get_assertions(), needAssertions );63 /// needAssertions.insert( needAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );64 }65 } else {66 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {67 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };68 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {69 haveAssertions[ *assert ].isUsed = false;70 }71 /// cloneAll( (*i)->get_assertions(), haveAssertions );72 /// haveAssertions.insert( haveAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );73 } // for74 } // if75 /// std::cerr << "type is ";76 /// type->print( std::cerr );77 /// std::cerr << std::endl << "need is" << std::endl;78 /// printAssertionSet( needAssertions, std::cerr );79 /// std::cerr << std::endl << "have is" << std::endl;80 /// printAssertionSet( haveAssertions, std::cerr );81 }82 83 void FindOpenVars_old::previsit(const PointerType * pointerType) {84 common_action( pointerType );85 }86 87 void FindOpenVars_old::previsit(const ArrayType * arrayType) {88 common_action( arrayType );89 }90 91 void FindOpenVars_old::previsit(const FunctionType * functionType) {92 common_action( functionType );93 nextIsOpen = ! nextIsOpen;94 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );95 }96 97 void FindOpenVars_old::previsit(const TupleType * tupleType) {98 common_action( tupleType );99 }100 25 101 26 namespace { 102 struct FindOpenVars _newfinal : public ast::WithGuards {27 struct FindOpenVars final : public ast::WithGuards { 103 28 ast::OpenVarSet & open; 104 29 ast::OpenVarSet & closed; … … 108 33 bool nextIsOpen; 109 34 110 FindOpenVars _new(35 FindOpenVars( 111 36 ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n, 112 37 ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen ) … … 148 73 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 149 74 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) { 150 ast::Pass< FindOpenVars _new> finder{ open, closed, need, have, env, firstIsOpen };75 ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen }; 151 76 type->accept( finder ); 152 77 -
src/ResolvExpr/FindOpenVars.h
rdf8ba61a r8d182b1 17 17 18 18 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 19 #include "ResolvExpr/TypeEnvironment.h" // for AssertionSet, OpenVarSet20 19 21 class Type;22 20 namespace ast { 23 21 class Type; … … 25 23 26 24 namespace ResolvExpr { 27 // Updates open and closed variables and their associated assertions28 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );29 30 25 enum FirstMode { FirstClosed, FirstOpen }; 31 26 -
src/ResolvExpr/PolyCost.cc
rdf8ba61a r8d182b1 18 18 #include "AST/Type.hpp" 19 19 #include "AST/TypeEnvironment.hpp" 20 #include "Common/PassVisitor.h"21 #include "SymTab/Indexer.h" // for Indexer22 #include "SynTree/Type.h" // for TypeInstType, Type23 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment24 20 25 21 namespace ResolvExpr { 26 struct PolyCost {27 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );28 22 29 void previsit( TypeInstType * aggregateUseType ); 30 int result; 31 const TypeEnvironment &tenv; 32 const SymTab::Indexer &indexer; 33 }; 34 35 int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) { 36 PassVisitor<PolyCost> coster( env, indexer ); 37 type->accept( coster ); 38 return (coster.pass.result > 0) ? 1 : 0; 39 } 40 41 PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) { 42 } 43 44 void PolyCost::previsit(TypeInstType * typeInst) { 45 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) { 46 if ( eqvClass->type ) { 47 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) { 48 if ( indexer.lookupType( otherTypeInst->name ) ) { 49 // bound to opaque type 50 result += 1; 51 } // if 52 } else { 53 // bound to concrete type 54 result += 1; 55 } // if 56 } // if 57 } // if 58 } 59 60 // TODO: When the old PolyCost is torn out get rid of the _new suffix. 61 class PolyCost_new { 23 class PolyCost { 62 24 const ast::SymbolTable &symtab; 63 25 public: … … 65 27 const ast::TypeEnvironment &env_; 66 28 67 PolyCost _new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )29 PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 68 30 : symtab( symtab ), result( 0 ), env_( env ) {} 69 31 … … 86 48 const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 87 49 ) { 88 ast::Pass<PolyCost _new> costing( symtab, env );50 ast::Pass<PolyCost> costing( symtab, env ); 89 51 type->accept( costing ); 90 52 return (costing.core.result > 0) ? 1 : 0; -
src/ResolvExpr/PolyCost.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 }22 18 namespace ast { 23 19 class SymbolTable; … … 28 24 namespace ResolvExpr { 29 25 30 class TypeEnvironment;31 32 int polyCost( Type * type,33 const TypeEnvironment & env, const SymTab::Indexer & indexer );34 26 int polyCost( const ast::Type * type, 35 27 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); -
src/ResolvExpr/PtrsAssignable.cc
rdf8ba61a r8d182b1 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment23 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType24 #include "SynTree/Visitor.h" // for Visitor25 26 21 27 22 namespace ResolvExpr { 28 struct PtrsAssignable : public WithShortCircuiting {29 PtrsAssignable( const Type * dest, const TypeEnvironment &env );30 23 31 int get_result() const { return result; } 32 33 void previsit( const Type * ) { visit_children = false; } 34 35 void postvisit( const VoidType * voidType ); 36 void postvisit( const BasicType * basicType ); 37 void postvisit( const PointerType * pointerType ); 38 void postvisit( const ArrayType * arrayType ); 39 void postvisit( const FunctionType * functionType ); 40 void postvisit( const StructInstType * inst ); 41 void postvisit( const UnionInstType * inst ); 42 void postvisit( const EnumInstType * inst ); 43 void postvisit( const TraitInstType * inst ); 44 void postvisit( const TypeInstType * inst ); 45 void postvisit( const TupleType * tupleType ); 46 void postvisit( const VarArgsType * varArgsType ); 47 void postvisit( const ZeroType * zeroType ); 48 void postvisit( const OneType * oneType ); 49 private: 50 const Type * dest; 51 int result; 52 const TypeEnvironment &env; 53 }; 54 55 int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) { 56 // std::cerr << "assignable: " << src << " | " << dest << std::endl; 57 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) { 58 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 59 return ptrsAssignable( src, eqvClass->type, env ); 60 } // if 61 } // if 62 if ( dynamic_cast< const VoidType* >( dest ) ) { 63 // void * = T * for any T is unsafe 64 // xxx - this should be safe, but that currently breaks the build 65 return -1; 66 } else { 67 PassVisitor<PtrsAssignable> ptrs( dest, env ); 68 src->accept( ptrs ); 69 return ptrs.pass.get_result(); 70 } // if 71 } 72 73 PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {} 74 75 void PtrsAssignable::postvisit( const VoidType * ) { 76 // T * = void * is disallowed - this is a change from C, where any 77 // void * can be assigned or passed to a non-void pointer without a cast. 78 } 79 80 void PtrsAssignable::postvisit( const BasicType * ) {} 81 void PtrsAssignable::postvisit( const PointerType * ) {} 82 void PtrsAssignable::postvisit( const ArrayType * ) {} 83 void PtrsAssignable::postvisit( const FunctionType * ) {} 84 85 void PtrsAssignable::postvisit( const StructInstType * ) {} 86 void PtrsAssignable::postvisit( const UnionInstType * ) {} 87 88 void PtrsAssignable::postvisit( const EnumInstType * ) { 89 if ( dynamic_cast< const BasicType* >( dest ) ) { 90 // int * = E *, etc. is safe. This isn't technically correct, as each 91 // enum has one basic type that it is compatible with, an that type can 92 // differ from enum to enum. Without replicating GCC's internal logic, 93 // there is no way to know which type this particular enum is compatible 94 // with, so punt on this for now. 95 result = 1; 96 } 97 } 98 99 void PtrsAssignable::postvisit( const TraitInstType * ) {} 100 void PtrsAssignable::postvisit( const TypeInstType * inst ) { 101 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) { 102 if ( eqvClass->type ) { 103 // T * = S * for any S depends on the type bound to T 104 result = ptrsAssignable( eqvClass->type, dest, env ); 105 } 106 } // if 107 } 108 109 void PtrsAssignable::postvisit( const TupleType * ) {} 110 void PtrsAssignable::postvisit( const VarArgsType * ) {} 111 void PtrsAssignable::postvisit( const ZeroType * ) {} 112 void PtrsAssignable::postvisit( const OneType * ) {} 113 114 // TODO: Get rid of the `_new` suffix when the old version is removed. 115 struct PtrsAssignable_new : public ast::WithShortCircuiting { 24 struct PtrsAssignable : public ast::WithShortCircuiting { 116 25 const ast::Type * dst; 117 26 const ast::TypeEnvironment & typeEnv; 118 27 int result; 119 28 120 PtrsAssignable _new( const ast::Type * dst, const ast::TypeEnvironment & env ) :29 PtrsAssignable( const ast::Type * dst, const ast::TypeEnvironment & env ) : 121 30 dst( dst ), typeEnv( env ), result( 0 ) {} 122 31 123 void previsit( Type * ) { visit_children = false; }32 void previsit( ast::Type * ) { visit_children = false; } 124 33 125 34 void postvisit( const ast::EnumInstType * ) { … … 153 62 return -1; 154 63 } else { 155 ast::Pass<PtrsAssignable _new> visitor( dst, env );64 ast::Pass<PtrsAssignable> visitor( dst, env ); 156 65 src->accept( visitor ); 157 66 return visitor.core.result; -
src/ResolvExpr/PtrsAssignable.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 18 namespace ast { 20 19 class Type; … … 24 23 namespace ResolvExpr { 25 24 26 class TypeEnvironment;27 28 int ptrsAssignable( const Type * src, const Type * dest,29 const TypeEnvironment & env );30 25 int ptrsAssignable( const ast::Type * src, const ast::Type * dst, 31 26 const ast::TypeEnvironment & env ); -
src/ResolvExpr/PtrsCastable.cc
rdf8ba61a r8d182b1 20 20 #include "AST/Type.hpp" 21 21 #include "AST/TypeEnvironment.hpp" 22 #include "Common/PassVisitor.h"23 22 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 24 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment25 #include "SymTab/Indexer.h" // for Indexer26 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype27 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType28 #include "SynTree/Visitor.h" // for Visitor29 23 30 24 namespace ResolvExpr { 31 struct PtrsCastable_old : public WithShortCircuiting {32 public:33 PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );34 35 int get_result() const { return result; }36 37 void previsit( const Type * ) { visit_children = false; }38 39 void postvisit( const VoidType * voidType );40 void postvisit( const BasicType * basicType );41 void postvisit( const PointerType * pointerType );42 void postvisit( const ArrayType * arrayType );43 void postvisit( const FunctionType * functionType );44 void postvisit( const StructInstType * inst );45 void postvisit( const UnionInstType * inst );46 void postvisit( const EnumInstType * inst );47 void postvisit( const TraitInstType * inst );48 void postvisit( const TypeInstType * inst );49 void postvisit( const TupleType * tupleType );50 void postvisit( const VarArgsType * varArgsType );51 void postvisit( const ZeroType * zeroType );52 void postvisit( const OneType * oneType );53 private:54 const Type * dest;55 int result;56 const TypeEnvironment &env;57 const SymTab::Indexer &indexer;58 };59 60 namespace {61 int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {62 if ( dynamic_cast< const FunctionType* >( src ) ) {63 return -1;64 } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) {65 if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) {66 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) {67 if ( tyDecl->kind == TypeDecl::Ftype ) {68 return -1;69 } // if70 } //if71 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {72 if ( eqvClass->data.kind == TypeDecl::Ftype ) {73 return -1;74 } // if75 } // if76 } //if77 return 1;78 }79 int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {80 return -1 * objectCast( src, env, indexer ); // reverse the sense of objectCast81 }82 }83 84 int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {85 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {86 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {87 // xxx - should this be ptrsCastable?88 return ptrsAssignable( src, eqvClass->type, env );89 } // if90 } // if91 if ( dynamic_cast< const VoidType* >( dest ) ) {92 return objectCast( src, env, indexer );93 } else {94 PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer );95 src->accept( ptrs );96 return ptrs.pass.get_result();97 } // if98 }99 100 PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )101 : dest( dest ), result( 0 ), env( env ), indexer( indexer ) {102 }103 104 void PtrsCastable_old::postvisit( const VoidType * ) {105 result = objectCast( dest, env, indexer );106 }107 108 void PtrsCastable_old::postvisit( const BasicType * ) {109 result = objectCast( dest, env, indexer );110 }111 112 void PtrsCastable_old::postvisit( const PointerType * ) {113 result = objectCast( dest, env, indexer );114 }115 116 void PtrsCastable_old::postvisit( const ArrayType * ) {117 result = objectCast( dest, env, indexer );118 }119 120 void PtrsCastable_old::postvisit( const FunctionType * ) {121 // result = -1;122 result = functionCast( dest, env, indexer );123 }124 125 void PtrsCastable_old::postvisit( const StructInstType * ) {126 result = objectCast( dest, env, indexer );127 }128 129 void PtrsCastable_old::postvisit( const UnionInstType * ) {130 result = objectCast( dest, env, indexer );131 }132 133 void PtrsCastable_old::postvisit( const EnumInstType * ) {134 if ( dynamic_cast< const EnumInstType * >( dest ) ) {135 result = 1;136 } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) {137 if ( bt->kind == BasicType::SignedInt ) {138 result = 0;139 } else {140 result = 1;141 }142 } else {143 result = objectCast( dest, env, indexer );144 }145 }146 147 void PtrsCastable_old::postvisit( const TraitInstType * ) {}148 149 void PtrsCastable_old::postvisit( const TypeInstType *inst ) {150 //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;151 result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;152 }153 154 void PtrsCastable_old::postvisit( const TupleType * ) {155 result = objectCast( dest, env, indexer );156 }157 158 void PtrsCastable_old::postvisit( const VarArgsType * ) {159 result = objectCast( dest, env, indexer );160 }161 162 void PtrsCastable_old::postvisit( const ZeroType * ) {163 result = objectCast( dest, env, indexer );164 }165 166 void PtrsCastable_old::postvisit( const OneType * ) {167 result = objectCast( dest, env, indexer );168 }169 25 170 26 namespace { … … 199 55 } 200 56 201 class PtrsCastable _new: public ast::WithShortCircuiting {57 class PtrsCastable : public ast::WithShortCircuiting { 202 58 const ast::Type * dst; 203 59 const ast::TypeEnvironment & env; … … 206 62 int result; 207 63 208 PtrsCastable _new(64 PtrsCastable( 209 65 const ast::Type * d, const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 210 66 : dst( d ), env( e ), symtab( syms ), result( 0 ) {} … … 293 149 return objectCast( src, env, symtab ); 294 150 } else { 295 return ast::Pass<PtrsCastable _new>::read( src, dst, env, symtab );151 return ast::Pass<PtrsCastable>::read( src, dst, env, symtab ); 296 152 } 297 153 } -
src/ResolvExpr/PtrsCastable.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 }22 18 namespace ast { 23 19 class SymbolTable; … … 28 24 namespace ResolvExpr { 29 25 30 class TypeEnvironment;31 32 int ptrsCastable(33 const Type * src, const Type * dst,34 const TypeEnvironment & env, const SymTab::Indexer & indexer );35 26 int ptrsCastable( 36 27 const ast::Type * src, const ast::Type * dst, -
src/ResolvExpr/RenameVars.cc
rdf8ba61a r8d182b1 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 23 #include "Common/ScopedMap.h" 25 24 #include "Common/SemanticError.h" // for SemanticError 26 25 #include "RenameVars.h" 27 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec...28 #include "SynTree/Expression.h" // for Expression29 #include "SynTree/Type.h" // for Type, TypeInstType, TraitInstType30 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept31 26 32 27 #include "AST/Copy.hpp" … … 49 44 } 50 45 51 void rename( TypeInstType * type ) {52 auto it = nameMap.find( type->name );53 if ( it != nameMap.end() ) {54 type->name = it->second;55 }56 }57 58 46 void nextUsage() { 59 47 ++next_usage_id; 60 }61 62 void openLevel( Type * type ) {63 if ( ! type->forall.empty() ) {64 nameMap.beginScope();65 // renames all "forall" type names to `_${level}_${name}'66 for ( auto td : type->forall ) {67 std::ostringstream output;68 output << "_" << resetCount << "_" << level << "_" << td->name;69 std::string newname( output.str() );70 nameMap[ td->get_name() ] = newname;71 td->name = newname;72 // ditto for assertion names, the next level in73 level++;74 }75 }76 }77 78 void closeLevel( Type * type ) {79 if ( !type->forall.empty() ) {80 nameMap.endScope();81 }82 48 } 83 49 … … 135 101 RenamingData renaming; 136 102 137 struct RenameVars_old { 138 void previsit( TypeInstType * instType ) { 139 renaming.openLevel( (Type*)instType ); 140 renaming.rename( instType ); 141 } 142 void previsit( Type * type ) { 143 renaming.openLevel( type ); 144 } 145 void postvisit( Type * type ) { 146 renaming.closeLevel( type ); 147 } 148 }; 149 150 struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 103 struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 151 104 RenameMode mode; 152 105 … … 178 131 } // namespace 179 132 180 void renameTyVars( Type * t ) {181 PassVisitor<RenameVars_old> renamer;182 t->accept( renamer );183 }184 185 133 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) { 186 ast::Pass<RenameVars _new> renamer;134 ast::Pass<RenameVars> renamer; 187 135 renamer.core.mode = mode; 188 136 if (mode == GEN_USAGE && reset) { -
src/ResolvExpr/RenameVars.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 #include <map> // for map20 #include <string> // for string21 22 #include "SynTree/SynTree.h" // for Visitor Nodes23 #include "SynTree/Visitor.h" // for Visitor24 25 18 namespace ast { 26 19 class Type; … … 28 21 29 22 namespace ResolvExpr { 30 /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID31 void renameTyVars( Type * );32 33 23 enum RenameMode { 34 24 GEN_USAGE, // for type in VariableExpr -
src/ResolvExpr/ResolveTypeof.cc
rdf8ba61a r8d182b1 24 24 #include "AST/Type.hpp" 25 25 #include "AST/TypeEnvironment.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/utility.h" // for copy 28 27 #include "InitTweak/InitTweak.h" // for isConstExpr … … 30 29 #include "Resolver.h" // for resolveInVoidContext 31 30 #include "SymTab/Mangler.h" 32 #include "SynTree/Expression.h" // for Expression33 #include "SynTree/Mutator.h" // for Mutator34 #include "SynTree/Type.h" // for TypeofType, Type35 36 namespace SymTab {37 class Indexer;38 } // namespace SymTab39 31 40 32 namespace ResolvExpr { 41 namespace {42 #if 043 void44 printAlts( const AltList &list, std::ostream &os, int indent = 0 )45 {46 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {47 i->print( os, indent );48 os << std::endl;49 }50 }51 #endif52 }53 54 class ResolveTypeof_old : public WithShortCircuiting {55 public:56 ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {}57 void premutate( TypeofType *typeofType );58 Type * postmutate( TypeofType *typeofType );59 60 private:61 const SymTab::Indexer &indexer;62 };63 64 Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {65 PassVisitor<ResolveTypeof_old> mutator( indexer );66 return type->acceptMutator( mutator );67 }68 69 void ResolveTypeof_old::premutate( TypeofType * ) {70 visit_children = false;71 }72 73 Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) {74 #if 075 std::cerr << "resolving typeof: ";76 typeofType->print( std::cerr );77 std::cerr << std::endl;78 #endif79 // pass on null expression80 if ( ! typeofType->expr ) return typeofType;81 82 bool isBasetypeof = typeofType->is_basetypeof;83 auto oldQuals = typeofType->get_qualifiers().val;84 85 Type* newType;86 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) {87 // typeof wrapping type88 newType = tyExpr->type;89 tyExpr->type = nullptr;90 delete tyExpr;91 } else {92 // typeof wrapping expression93 Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );94 assert( newExpr->result && ! newExpr->result->isVoid() );95 newType = newExpr->result;96 newExpr->result = nullptr;97 delete typeofType;98 delete newExpr;99 }100 101 // clear qualifiers for base, combine with typeoftype quals in any case102 if ( isBasetypeof ) {103 // replace basetypeof(<enum>) by int104 if ( dynamic_cast<EnumInstType*>(newType) ) {105 Type* newerType =106 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,107 newType->attributes };108 delete newType;109 newType = newerType;110 }111 newType->get_qualifiers().val112 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;113 } else {114 newType->get_qualifiers().val |= oldQuals;115 }116 117 return newType;118 }119 33 120 34 namespace { 121 struct ResolveTypeof _new: public ast::WithShortCircuiting {35 struct ResolveTypeof : public ast::WithShortCircuiting { 122 36 const ResolveContext & context; 123 37 124 ResolveTypeof _new( const ResolveContext & context ) :38 ResolveTypeof( const ResolveContext & context ) : 125 39 context( context ) {} 126 40 … … 164 78 165 79 const ast::Type * resolveTypeof( const ast::Type * type , const ResolveContext & context ) { 166 ast::Pass< ResolveTypeof _new> mutator( context );80 ast::Pass< ResolveTypeof > mutator( context ); 167 81 return type->accept( mutator ); 168 82 } -
src/ResolvExpr/ResolveTypeof.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 } // namespace SymTab22 18 namespace ast { 23 19 class Type; … … 28 24 struct ResolveContext; 29 25 30 Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );31 26 const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & ); 32 27 const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & ); 33 28 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & ); 34 const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & );29 const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & ); 35 30 } // namespace ResolvExpr 36 31 -
src/ResolvExpr/Resolver.cc
rdf8ba61a r8d182b1 19 19 #include <vector> // for vector 20 20 21 #include "Alternative.h" // for Alternative, AltList22 #include "AlternativeFinder.h" // for AlternativeFinder, resolveIn...23 21 #include "Candidate.hpp" 24 22 #include "CandidateFinder.hpp" … … 40 38 #include "Common/Eval.h" // for eval 41 39 #include "Common/Iterate.hpp" // for group_iterate 42 #include "Common/PassVisitor.h" // for PassVisitor43 40 #include "Common/SemanticError.h" // for SemanticError 44 41 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 45 42 #include "Common/ToString.hpp" // for toCString 43 #include "Common/UniqueName.h" // for UniqueName 46 44 #include "InitTweak/GenInit.h" 47 45 #include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt 48 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment49 #include "SymTab/Autogen.h" // for SizeType50 #include "SymTab/Indexer.h" // for Indexer51 46 #include "SymTab/Mangler.h" // for Mangler 52 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar...53 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr54 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit55 #include "SynTree/Statement.h" // for ForStmt, Statement, BranchStmt56 #include "SynTree/Type.h" // for Type, BasicType, PointerType57 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution58 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept59 47 #include "Tuples/Tuples.h" 60 48 #include "Validate/FindSpecialDecls.h" // for SizeType … … 63 51 64 52 namespace ResolvExpr { 65 struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {66 Resolver_old() {}67 Resolver_old( const SymTab::Indexer & other ) {68 indexer = other;69 }70 71 void previsit( FunctionDecl * functionDecl );72 void postvisit( FunctionDecl * functionDecl );73 void previsit( ObjectDecl * objectDecll );74 void previsit( EnumDecl * enumDecl );75 void previsit( StaticAssertDecl * assertDecl );76 77 void previsit( ArrayType * at );78 void previsit( PointerType * at );79 80 void previsit( ExprStmt * exprStmt );81 void previsit( AsmExpr * asmExpr );82 void previsit( AsmStmt * asmStmt );83 void previsit( IfStmt * ifStmt );84 void previsit( WhileDoStmt * whileDoStmt );85 void previsit( ForStmt * forStmt );86 void previsit( SwitchStmt * switchStmt );87 void previsit( CaseStmt * caseStmt );88 void previsit( BranchStmt * branchStmt );89 void previsit( ReturnStmt * returnStmt );90 void previsit( ThrowStmt * throwStmt );91 void previsit( CatchStmt * catchStmt );92 void postvisit( CatchStmt * catchStmt );93 void previsit( WaitForStmt * stmt );94 95 void previsit( SingleInit * singleInit );96 void previsit( ListInit * listInit );97 void previsit( ConstructorInit * ctorInit );98 private:99 typedef std::list< Initializer * >::iterator InitIterator;100 101 template< typename PtrType >102 void handlePtrType( PtrType * type );103 104 void fallbackInit( ConstructorInit * ctorInit );105 106 Type * functionReturn = nullptr;107 CurrentObject currentObject = nullptr;108 bool inEnumDecl = false;109 };110 111 struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {112 void previsit( FunctionDecl * );113 void previsit( WithStmt * );114 115 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );116 };117 118 void resolve( std::list< Declaration * > translationUnit ) {119 PassVisitor<Resolver_old> resolver;120 acceptAll( translationUnit, resolver );121 }122 123 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {124 PassVisitor<Resolver_old> resolver( indexer );125 maybeAccept( decl, resolver );126 }127 128 namespace {129 struct DeleteFinder_old : public WithShortCircuiting {130 DeletedExpr * delExpr = nullptr;131 void previsit( DeletedExpr * expr ) {132 if ( delExpr ) visit_children = false;133 else delExpr = expr;134 }135 136 void previsit( Expression * ) {137 if ( delExpr ) visit_children = false;138 }139 };140 }141 142 DeletedExpr * findDeletedExpr( Expression * expr ) {143 PassVisitor<DeleteFinder_old> finder;144 expr->accept( finder );145 return finder.pass.delExpr;146 }147 148 namespace {149 struct StripCasts_old {150 Expression * postmutate( CastExpr * castExpr ) {151 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {152 // generated cast is to the same type as its argument, so it's unnecessary -- remove it153 Expression * expr = castExpr->arg;154 castExpr->arg = nullptr;155 std::swap( expr->env, castExpr->env );156 return expr;157 }158 return castExpr;159 }160 161 static void strip( Expression *& expr ) {162 PassVisitor<StripCasts_old> stripper;163 expr = expr->acceptMutator( stripper );164 }165 };166 167 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {168 expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;169 env.makeSubstitution( *expr->env );170 StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression171 }172 173 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {174 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {175 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {176 // cast is to the same type as its argument, so it's unnecessary -- remove it177 expr = castExpr->arg;178 castExpr->arg = nullptr;179 std::swap( expr->env, castExpr->env );180 delete castExpr;181 }182 }183 }184 } // namespace185 186 namespace {187 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {188 assertf( untyped, "expected a non-null expression." );189 190 // xxx - this isn't thread-safe, but should work until we parallelize the resolver191 static unsigned recursion_level = 0;192 193 ++recursion_level;194 TypeEnvironment env;195 AlternativeFinder finder( indexer, env );196 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );197 --recursion_level;198 199 #if 0200 if ( finder.get_alternatives().size() != 1 ) {201 std::cerr << "untyped expr is ";202 untyped->print( std::cerr );203 std::cerr << std::endl << "alternatives are:";204 for ( const Alternative & alt : finder.get_alternatives() ) {205 alt.print( std::cerr );206 } // for207 } // if208 #endif209 210 // produce filtered list of alternatives211 AltList candidates;212 for ( Alternative & alt : finder.get_alternatives() ) {213 if ( pred( alt ) ) {214 candidates.push_back( std::move( alt ) );215 }216 }217 218 // produce invalid error if no candidates219 if ( candidates.empty() ) {220 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );221 }222 223 // search for cheapest candidate224 AltList winners;225 bool seen_undeleted = false;226 for ( unsigned i = 0; i < candidates.size(); ++i ) {227 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );228 229 if ( c > 0 ) continue; // skip more expensive than winner230 231 if ( c < 0 ) {232 // reset on new cheapest233 seen_undeleted = ! findDeletedExpr( candidates[i].expr );234 winners.clear();235 } else /* if ( c == 0 ) */ {236 if ( findDeletedExpr( candidates[i].expr ) ) {237 // skip deleted expression if already seen one equivalent-cost not238 if ( seen_undeleted ) continue;239 } else if ( ! seen_undeleted ) {240 // replace list of equivalent-cost deleted expressions with one non-deleted241 winners.clear();242 seen_undeleted = true;243 }244 }245 246 winners.emplace_back( std::move( candidates[i] ) );247 }248 249 // promote alternative.cvtCost to .cost250 // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost251 for ( Alternative& winner : winners ) {252 winner.cost = winner.cvtCost;253 }254 255 // produce ambiguous errors, if applicable256 if ( winners.size() != 1 ) {257 std::ostringstream stream;258 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";259 untyped->print( stream );260 stream << " Alternatives are:\n";261 printAlts( winners, stream, 1 );262 SemanticError( untyped->location, stream.str() );263 }264 265 // single selected choice266 Alternative& choice = winners.front();267 268 // fail on only expression deleted269 if ( ! seen_undeleted ) {270 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );271 }272 273 // xxx - check for ambiguous expressions274 275 // output selected choice276 alt = std::move( choice );277 }278 279 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages280 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {281 if ( ! untyped ) return;282 Alternative choice;283 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );284 finishExpr( choice.expr, choice.env, untyped->env );285 delete untyped;286 untyped = choice.expr;287 choice.expr = nullptr;288 }289 290 bool standardAlternativeFilter( const Alternative & ) {291 // currently don't need to filter, under normal circumstances.292 // in the future, this may be useful for removing deleted expressions293 return true;294 }295 } // namespace296 297 // used in resolveTypeof298 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {299 TypeEnvironment env;300 return resolveInVoidContext( expr, indexer, env );301 }302 303 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {304 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0305 // interpretations, an exception has already been thrown.306 assertf( expr, "expected a non-null expression." );307 308 CastExpr * untyped = new CastExpr( expr ); // cast to void309 untyped->location = expr->location;310 311 // set up and resolve expression cast to void312 Alternative choice;313 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );314 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );315 assert( castExpr );316 env = std::move( choice.env );317 318 // clean up resolved expression319 Expression * ret = castExpr->arg;320 castExpr->arg = nullptr;321 322 // unlink the arg so that it isn't deleted twice at the end of the program323 untyped->arg = nullptr;324 return ret;325 }326 327 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {328 resetTyVarRenaming();329 TypeEnvironment env;330 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );331 finishExpr( newExpr, env, untyped->env );332 delete untyped;333 untyped = newExpr;334 }335 336 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {337 findKindExpression( untyped, indexer, "", standardAlternativeFilter );338 }339 340 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {341 assert( untyped && type );342 // transfer location to generated cast for error purposes343 CodeLocation location = untyped->location;344 untyped = new CastExpr( untyped, type );345 untyped->location = location;346 findSingleExpression( untyped, indexer );347 removeExtraneousCast( untyped, indexer );348 }349 350 namespace {351 bool isIntegralType( const Alternative & alt ) {352 Type * type = alt.expr->result;353 if ( dynamic_cast< EnumInstType * >( type ) ) {354 return true;355 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {356 return bt->isInteger();357 } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {358 return true;359 } else {360 return false;361 } // if362 }363 364 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {365 findKindExpression( untyped, indexer, "condition", isIntegralType );366 }367 }368 369 370 bool isStructOrUnion( const Alternative & alt ) {371 Type * t = alt.expr->result->stripReferences();372 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );373 }374 375 void resolveWithExprs( std::list< Declaration * > & translationUnit ) {376 PassVisitor<ResolveWithExprs> resolver;377 acceptAll( translationUnit, resolver );378 }379 380 void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {381 for ( Expression *& expr : withExprs ) {382 // only struct- and union-typed expressions are viable candidates383 findKindExpression( expr, indexer, "with statement", isStructOrUnion );384 385 // if with expression might be impure, create a temporary so that it is evaluated once386 if ( Tuples::maybeImpure( expr ) ) {387 static UniqueName tmpNamer( "_with_tmp_" );388 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );389 expr = new VariableExpr( tmp );390 newStmts.push_back( new DeclStmt( tmp ) );391 if ( InitTweak::isConstructable( tmp->type ) ) {392 // generate ctor/dtor and resolve them393 tmp->init = InitTweak::genCtorInit( tmp );394 tmp->accept( *visitor );395 }396 }397 }398 }399 400 void ResolveWithExprs::previsit( WithStmt * withStmt ) {401 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );402 }403 404 void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {405 {406 // resolve with-exprs with parameters in scope and add any newly generated declarations to the407 // front of the function body.408 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );409 indexer.addFunctionType( functionDecl->type );410 std::list< Statement * > newStmts;411 resolveWithExprs( functionDecl->withExprs, newStmts );412 if ( functionDecl->statements ) {413 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );414 } else {415 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );416 }417 }418 }419 420 void Resolver_old::previsit( ObjectDecl * objectDecl ) {421 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that422 // class-variable initContext is changed multiple time because the LHS is analysed twice.423 // The second analysis changes initContext because of a function type can contain object424 // declarations in the return and parameter types. So each value of initContext is425 // retained, so the type on the first analysis is preserved and used for selecting the RHS.426 GuardValue( currentObject );427 currentObject = CurrentObject( objectDecl->get_type() );428 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {429 // enumerator initializers should not use the enum type to initialize, since430 // the enum type is still incomplete at this point. Use signed int instead.431 // TODO: BasicType::SignedInt may not longer be true432 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );433 }434 }435 436 template< typename PtrType >437 void Resolver_old::handlePtrType( PtrType * type ) {438 if ( type->get_dimension() ) {439 findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );440 }441 }442 443 void Resolver_old::previsit( ArrayType * at ) {444 handlePtrType( at );445 }446 447 void Resolver_old::previsit( PointerType * pt ) {448 handlePtrType( pt );449 }450 451 void Resolver_old::previsit( FunctionDecl * functionDecl ) {452 #if 0453 std::cerr << "resolver visiting functiondecl ";454 functionDecl->print( std::cerr );455 std::cerr << std::endl;456 #endif457 GuardValue( functionReturn );458 functionReturn = ResolvExpr::extractResultType( functionDecl->type );459 }460 461 void Resolver_old::postvisit( FunctionDecl * functionDecl ) {462 // default value expressions have an environment which shouldn't be there and trips up463 // later passes.464 // xxx - it might be necessary to somehow keep the information from this environment, but I465 // can't currently see how it's useful.466 for ( Declaration * d : functionDecl->type->parameters ) {467 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {468 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {469 delete init->value->env;470 init->value->env = nullptr;471 }472 }473 }474 }475 476 void Resolver_old::previsit( EnumDecl * ) {477 // in case we decide to allow nested enums478 GuardValue( inEnumDecl );479 inEnumDecl = true;480 }481 482 void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {483 findIntegralExpression( assertDecl->condition, indexer );484 }485 486 void Resolver_old::previsit( ExprStmt * exprStmt ) {487 visit_children = false;488 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );489 findVoidExpression( exprStmt->expr, indexer );490 }491 492 void Resolver_old::previsit( AsmExpr * asmExpr ) {493 visit_children = false;494 findVoidExpression( asmExpr->operand, indexer );495 }496 497 void Resolver_old::previsit( AsmStmt * asmStmt ) {498 visit_children = false;499 acceptAll( asmStmt->get_input(), *visitor );500 acceptAll( asmStmt->get_output(), *visitor );501 }502 503 void Resolver_old::previsit( IfStmt * ifStmt ) {504 findIntegralExpression( ifStmt->condition, indexer );505 }506 507 void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {508 findIntegralExpression( whileDoStmt->condition, indexer );509 }510 511 void Resolver_old::previsit( ForStmt * forStmt ) {512 if ( forStmt->condition ) {513 findIntegralExpression( forStmt->condition, indexer );514 } // if515 516 if ( forStmt->increment ) {517 findVoidExpression( forStmt->increment, indexer );518 } // if519 }520 521 void Resolver_old::previsit( SwitchStmt * switchStmt ) {522 GuardValue( currentObject );523 findIntegralExpression( switchStmt->condition, indexer );524 525 currentObject = CurrentObject( switchStmt->condition->result );526 }527 528 void Resolver_old::previsit( CaseStmt * caseStmt ) {529 if ( caseStmt->condition ) {530 std::list< InitAlternative > initAlts = currentObject.getOptions();531 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );532 // must remove cast from case statement because RangeExpr cannot be cast.533 Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );534 findSingleExpression( newExpr, indexer );535 // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.536 // Ideally we would perform the conversion internally here.537 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {538 newExpr = castExpr->arg;539 castExpr->arg = nullptr;540 std::swap( newExpr->env, castExpr->env );541 delete castExpr;542 }543 caseStmt->condition = newExpr;544 }545 }546 547 void Resolver_old::previsit( BranchStmt * branchStmt ) {548 visit_children = false;549 // must resolve the argument for a computed goto550 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement551 if ( branchStmt->computedTarget ) {552 // computed goto argument is void *553 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );554 } // if555 } // if556 }557 558 void Resolver_old::previsit( ReturnStmt * returnStmt ) {559 visit_children = false;560 if ( returnStmt->expr ) {561 findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );562 } // if563 }564 565 void Resolver_old::previsit( ThrowStmt * throwStmt ) {566 visit_children = false;567 // TODO: Replace *exception type with &exception type.568 if ( throwStmt->get_expr() ) {569 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );570 assert( exception_decl );571 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );572 findSingleExpression( throwStmt->expr, exceptType, indexer );573 }574 }575 576 void Resolver_old::previsit( CatchStmt * catchStmt ) {577 // Until we are very sure this invarent (ifs that move between passes have then)578 // holds, check it. This allows a check for when to decode the mangling.579 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {580 assert( ifStmt->then );581 }582 // Encode the catchStmt so the condition can see the declaration.583 if ( catchStmt->cond ) {584 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );585 catchStmt->cond = nullptr;586 catchStmt->body = ifStmt;587 }588 }589 590 void Resolver_old::postvisit( CatchStmt * catchStmt ) {591 // Decode the catchStmt so everything is stored properly.592 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );593 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {594 assert( ifStmt->condition );595 assert( ifStmt->else_ );596 catchStmt->cond = ifStmt->condition;597 catchStmt->body = ifStmt->else_;598 ifStmt->condition = nullptr;599 ifStmt->else_ = nullptr;600 delete ifStmt;601 }602 }603 604 53 template< typename iterator_t > 605 54 inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) { … … 611 60 } 612 61 613 void Resolver_old::previsit( WaitForStmt * stmt ) {614 visit_children = false;615 616 // Resolve all clauses first617 for( auto& clause : stmt->clauses ) {618 619 TypeEnvironment env;620 AlternativeFinder funcFinder( indexer, env );621 622 // Find all alternatives for a function in canonical form623 funcFinder.findWithAdjustment( clause.target.function );624 625 if ( funcFinder.get_alternatives().empty() ) {626 stringstream ss;627 ss << "Use of undeclared indentifier '";628 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;629 ss << "' in call to waitfor";630 SemanticError( stmt->location, ss.str() );631 }632 633 if(clause.target.arguments.empty()) {634 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");635 }636 637 // Find all alternatives for all arguments in canonical form638 std::vector< AlternativeFinder > argAlternatives;639 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );640 641 // List all combinations of arguments642 std::vector< AltList > possibilities;643 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );644 645 AltList func_candidates;646 std::vector< AltList > args_candidates;647 648 // For every possible function :649 // try matching the arguments to the parameters650 // not the other way around because we have more arguments than parameters651 SemanticErrorException errors;652 for ( Alternative & func : funcFinder.get_alternatives() ) {653 try {654 PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );655 if( !pointer ) {656 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );657 }658 659 FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );660 if( !function ) {661 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );662 }663 664 665 {666 auto param = function->parameters.begin();667 auto param_end = function->parameters.end();668 669 if( !advance_to_mutex( param, param_end ) ) {670 SemanticError(function, "candidate function not viable: no mutex parameters\n");671 }672 }673 674 Alternative newFunc( func );675 // Strip reference from function676 referenceToRvalueConversion( newFunc.expr, newFunc.cost );677 678 // For all the set of arguments we have try to match it with the parameter of the current function alternative679 for ( auto & argsList : possibilities ) {680 681 try {682 // Declare data structures need for resolution683 OpenVarSet openVars;684 AssertionSet resultNeed, resultHave;685 TypeEnvironment resultEnv( func.env );686 makeUnifiableVars( function, openVars, resultNeed );687 // add all type variables as open variables now so that those not used in the parameter688 // list are still considered open.689 resultEnv.add( function->forall );690 691 // Load type variables from arguemnts into one shared space692 simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );693 694 // Make sure we don't widen any existing bindings695 resultEnv.forbidWidening();696 697 // Find any unbound type variables698 resultEnv.extractOpenVars( openVars );699 700 auto param = function->parameters.begin();701 auto param_end = function->parameters.end();702 703 int n_mutex_param = 0;704 705 // For every arguments of its set, check if it matches one of the parameter706 // The order is important707 for( auto & arg : argsList ) {708 709 // Ignore non-mutex arguments710 if( !advance_to_mutex( param, param_end ) ) {711 // We ran out of parameters but still have arguments712 // this function doesn't match713 SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));714 }715 716 n_mutex_param++;717 718 // Check if the argument matches the parameter type in the current scope719 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {720 // Type doesn't match721 stringstream ss;722 ss << "candidate function not viable: no known convertion from '";723 (*param)->get_type()->print( ss );724 ss << "' to '";725 arg.expr->get_result()->print( ss );726 ss << "' with env '";727 resultEnv.print(ss);728 ss << "'\n";729 SemanticError( function, ss.str() );730 }731 732 param++;733 }734 735 // All arguments match !736 737 // Check if parameters are missing738 if( advance_to_mutex( param, param_end ) ) {739 do {740 n_mutex_param++;741 param++;742 } while( advance_to_mutex( param, param_end ) );743 744 // We ran out of arguments but still have parameters left745 // this function doesn't match746 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));747 }748 749 // All parameters match !750 751 // Finish the expressions to tie in the proper environments752 finishExpr( newFunc.expr, resultEnv );753 for( Alternative & alt : argsList ) {754 finishExpr( alt.expr, resultEnv );755 }756 757 // This is a match store it and save it for later758 func_candidates.push_back( newFunc );759 args_candidates.push_back( argsList );760 761 }762 catch( SemanticErrorException & e ) {763 errors.append( e );764 }765 }766 }767 catch( SemanticErrorException & e ) {768 errors.append( e );769 }770 }771 772 // Make sure we got the right number of arguments773 if( func_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor" ); top.append( errors ); throw top; }774 if( args_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }775 if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor" ); top.append( errors ); throw top; }776 if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor" ); top.append( errors ); throw top; }777 // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.778 779 // Swap the results from the alternative with the unresolved values.780 // Alternatives will handle deletion on destruction781 std::swap( clause.target.function, func_candidates.front().expr );782 for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {783 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );784 }785 786 // Resolve the conditions as if it were an IfStmt787 // Resolve the statments normally788 findSingleExpression( clause.condition, this->indexer );789 clause.statement->accept( *visitor );790 }791 792 793 if( stmt->timeout.statement ) {794 // Resolve the timeout as an size_t for now795 // Resolve the conditions as if it were an IfStmt796 // Resolve the statments normally797 findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );798 findSingleExpression( stmt->timeout.condition, this->indexer );799 stmt->timeout.statement->accept( *visitor );800 }801 802 if( stmt->orelse.statement ) {803 // Resolve the conditions as if it were an IfStmt804 // Resolve the statments normally805 findSingleExpression( stmt->orelse.condition, this->indexer );806 stmt->orelse.statement->accept( *visitor );807 }808 }809 810 bool isCharType( Type * t ) {811 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {812 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||813 bt->get_kind() == BasicType::UnsignedChar;814 }815 return false;816 }817 818 void Resolver_old::previsit( SingleInit * singleInit ) {819 visit_children = false;820 // resolve initialization using the possibilities as determined by the currentObject cursor821 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );822 findSingleExpression( newExpr, indexer );823 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );824 825 // move cursor to the object that is actually initialized826 currentObject.setNext( initExpr->get_designation() );827 828 // discard InitExpr wrapper and retain relevant pieces829 newExpr = initExpr->expr;830 initExpr->expr = nullptr;831 std::swap( initExpr->env, newExpr->env );832 // InitExpr may have inferParams in the case where the expression specializes a function833 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not834 // sufficient.835 newExpr->spliceInferParams( initExpr );836 delete initExpr;837 838 // get the actual object's type (may not exactly match what comes back from the resolver839 // due to conversions)840 Type * initContext = currentObject.getCurrentType();841 842 removeExtraneousCast( newExpr, indexer );843 844 // check if actual object's type is char[]845 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {846 if ( isCharType( at->get_base() ) ) {847 // check if the resolved type is char *848 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {849 if ( isCharType( pt->get_base() ) ) {850 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {851 // strip cast if we're initializing a char[] with a char *,852 // e.g. char x[] = "hello";853 newExpr = ce->get_arg();854 ce->set_arg( nullptr );855 std::swap( ce->env, newExpr->env );856 delete ce;857 }858 }859 }860 }861 }862 863 // set initializer expr to resolved express864 singleInit->value = newExpr;865 866 // move cursor to next object in preparation for next initializer867 currentObject.increment();868 }869 870 void Resolver_old::previsit( ListInit * listInit ) {871 visit_children = false;872 // move cursor into brace-enclosed initializer-list873 currentObject.enterListInit();874 // xxx - fix this so that the list isn't copied, iterator should be used to change current875 // element876 std::list<Designation *> newDesignations;877 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {878 // iterate designations and initializers in pairs, moving the cursor to the current879 // designated object and resolving the initializer against that object.880 Designation * des = std::get<0>(p);881 Initializer * init = std::get<1>(p);882 newDesignations.push_back( currentObject.findNext( des ) );883 init->accept( *visitor );884 }885 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list886 listInit->get_designations() = newDesignations; // xxx - memory management887 currentObject.exitListInit();888 889 // xxx - this part has not be folded into CurrentObject yet890 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {891 // Type * base = tt->get_baseType()->get_base();892 // if ( base ) {893 // // know the implementation type, so try using that as the initContext894 // ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );895 // currentObject = &tmpObj;896 // visit( listInit );897 // } else {898 // // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context899 // Parent::visit( listInit );900 // }901 // } else {902 }903 904 // ConstructorInit - fall back on C-style initializer905 void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {906 // could not find valid constructor, or found an intrinsic constructor907 // fall back on C-style initializer908 delete ctorInit->get_ctor();909 ctorInit->set_ctor( nullptr );910 delete ctorInit->get_dtor();911 ctorInit->set_dtor( nullptr );912 maybeAccept( ctorInit->get_init(), *visitor );913 }914 915 // needs to be callable from outside the resolver, so this is a standalone function916 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {917 assert( ctorInit );918 PassVisitor<Resolver_old> resolver( indexer );919 ctorInit->accept( resolver );920 }921 922 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {923 assert( stmtExpr );924 PassVisitor<Resolver_old> resolver( indexer );925 stmtExpr->accept( resolver );926 stmtExpr->computeResult();927 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?928 }929 930 void Resolver_old::previsit( ConstructorInit * ctorInit ) {931 visit_children = false;932 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit933 maybeAccept( ctorInit->ctor, *visitor );934 maybeAccept( ctorInit->dtor, *visitor );935 936 // found a constructor - can get rid of C-style initializer937 delete ctorInit->init;938 ctorInit->init = nullptr;939 940 // intrinsic single parameter constructors and destructors do nothing. Since this was941 // implicitly generated, there's no way for it to have side effects, so get rid of it942 // to clean up generated code.943 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {944 delete ctorInit->ctor;945 ctorInit->ctor = nullptr;946 }947 948 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {949 delete ctorInit->dtor;950 ctorInit->dtor = nullptr;951 }952 953 // xxx - todo -- what about arrays?954 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {955 // // can reduce the constructor down to a SingleInit using the956 // // second argument from the ctor call, since957 // delete ctorInit->get_ctor();958 // ctorInit->set_ctor( nullptr );959 960 // Expression * arg =961 // ctorInit->set_init( new SingleInit( arg ) );962 // }963 }964 965 ///////////////////////////////////////////////////////////////////////////966 //967 // *** NEW RESOLVER ***968 //969 ///////////////////////////////////////////////////////////////////////////970 971 62 namespace { 972 63 /// Finds deleted expressions in an expression tree 973 struct DeleteFinder _new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> {64 struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> { 974 65 const ast::DeletedExpr * result = nullptr; 975 66 … … 989 80 }; 990 81 991 struct ResolveDesignators _newfinal : public ast::WithShortCircuiting {82 struct ResolveDesignators final : public ast::WithShortCircuiting { 992 83 ResolveContext& context; 993 84 bool result = false; 994 85 995 ResolveDesignators _new( ResolveContext& _context ): context{_context} {};86 ResolveDesignators( ResolveContext& _context ): context{_context} {}; 996 87 997 88 void previsit( const ast::Node * ) { … … 1022 113 /// Check if this expression is or includes a deleted expression 1023 114 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) { 1024 return ast::Pass<DeleteFinder _new>::read( expr );115 return ast::Pass<DeleteFinder>::read( expr ); 1025 116 } 1026 117 … … 1112 203 1113 204 /// Strips extraneous casts out of an expression 1114 struct StripCasts _newfinal {205 struct StripCasts final { 1115 206 const ast::Expr * postvisit( const ast::CastExpr * castExpr ) { 1116 207 if ( … … 1126 217 1127 218 static void strip( ast::ptr< ast::Expr > & expr ) { 1128 ast::Pass< StripCasts _new> stripper;219 ast::Pass< StripCasts > stripper; 1129 220 expr = expr->accept( stripper ); 1130 221 } … … 1160 251 expr.get_and_mutate()->env = std::move( newenv ); 1161 252 // remove unncecessary casts 1162 StripCasts _new::strip( expr );253 StripCasts::strip( expr ); 1163 254 } 1164 255 … … 1277 368 } 1278 369 1279 class Resolver _newfinal370 class Resolver final 1280 371 : public ast::WithSymbolTable, public ast::WithGuards, 1281 public ast::WithVisitorRef<Resolver _new>, public ast::WithShortCircuiting,372 public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting, 1282 373 public ast::WithStmtsToAdd<> { 1283 374 … … 1285 376 ast::CurrentObject currentObject; 1286 377 // for work previously in GenInit 1287 static InitTweak::ManagedTypes _newmanagedTypes;378 static InitTweak::ManagedTypes managedTypes; 1288 379 ResolveContext context; 1289 380 … … 1292 383 public: 1293 384 static size_t traceId; 1294 Resolver _new( const ast::TranslationGlobal & global ) :385 Resolver( const ast::TranslationGlobal & global ) : 1295 386 ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd), 1296 387 context{ symtab, global } {} 1297 Resolver _new( const ResolveContext & context ) :388 Resolver( const ResolveContext & context ) : 1298 389 ast::WithSymbolTable{ context.symtab }, 1299 390 context{ symtab, context.global } {} … … 1336 427 bool on_error(ast::ptr<ast::Decl> & decl); 1337 428 }; 1338 // size_t Resolver _new::traceId = Stats::Heap::new_stacktrace_id("Resolver");1339 1340 InitTweak::ManagedTypes _new Resolver_new::managedTypes;429 // size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver"); 430 431 InitTweak::ManagedTypes Resolver::managedTypes; 1341 432 1342 433 void resolve( ast::TranslationUnit& translationUnit ) { 1343 ast::Pass< Resolver _new>::run( translationUnit, translationUnit.global );434 ast::Pass< Resolver >::run( translationUnit, translationUnit.global ); 1344 435 } 1345 436 … … 1348 439 ) { 1349 440 assert( ctorInit ); 1350 ast::Pass< Resolver _new> resolver( context );441 ast::Pass< Resolver > resolver( context ); 1351 442 return ctorInit->accept( resolver ); 1352 443 } … … 1356 447 ) { 1357 448 assert( stmtExpr ); 1358 ast::Pass< Resolver _new> resolver( context );449 ast::Pass< Resolver > resolver( context ); 1359 450 auto ret = mutate(stmtExpr->accept(resolver)); 1360 451 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult(); … … 1398 489 } 1399 490 1400 const ast::FunctionDecl * Resolver _new::previsit( const ast::FunctionDecl * functionDecl ) {491 const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) { 1401 492 GuardValue( functionReturn ); 1402 493 … … 1472 563 } 1473 564 1474 const ast::FunctionDecl * Resolver _new::postvisit( const ast::FunctionDecl * functionDecl ) {565 const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) { 1475 566 // default value expressions have an environment which shouldn't be there and trips up 1476 567 // later passes. … … 1500 591 } 1501 592 1502 const ast::ObjectDecl * Resolver _new::previsit( const ast::ObjectDecl * objectDecl ) {593 const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) { 1503 594 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()], 1504 595 // class-variable `initContext` is changed multiple times because the LHS is analyzed … … 1539 630 // constructed objects cannot be designated 1540 631 if ( InitTweak::isDesignated( mutDecl->init ) ) { 1541 ast::Pass<ResolveDesignators _new> res( context );632 ast::Pass<ResolveDesignators> res( context ); 1542 633 maybe_accept( mutDecl->init.get(), res ); 1543 634 if ( !res.core.result ) { … … 1559 650 } 1560 651 1561 void Resolver _new::previsit( const ast::AggregateDecl * _aggDecl ) {652 void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) { 1562 653 auto aggDecl = mutate(_aggDecl); 1563 654 assertf(aggDecl == _aggDecl, "type declarations must be unique"); … … 1571 662 } 1572 663 1573 void Resolver _new::previsit( const ast::StructDecl * structDecl ) {664 void Resolver::previsit( const ast::StructDecl * structDecl ) { 1574 665 previsit(static_cast<const ast::AggregateDecl *>(structDecl)); 1575 666 managedTypes.handleStruct(structDecl); 1576 667 } 1577 668 1578 void Resolver _new::previsit( const ast::EnumDecl * ) {669 void Resolver::previsit( const ast::EnumDecl * ) { 1579 670 // in case we decide to allow nested enums 1580 671 GuardValue( inEnumDecl ); … … 1583 674 } 1584 675 1585 const ast::StaticAssertDecl * Resolver _new::previsit(676 const ast::StaticAssertDecl * Resolver::previsit( 1586 677 const ast::StaticAssertDecl * assertDecl 1587 678 ) { … … 1603 694 } 1604 695 1605 const ast::ArrayType * Resolver _new::previsit( const ast::ArrayType * at ) {696 const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) { 1606 697 return handlePtrType( at, context ); 1607 698 } 1608 699 1609 const ast::PointerType * Resolver _new::previsit( const ast::PointerType * pt ) {700 const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) { 1610 701 return handlePtrType( pt, context ); 1611 702 } 1612 703 1613 const ast::ExprStmt * Resolver _new::previsit( const ast::ExprStmt * exprStmt ) {704 const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) { 1614 705 visit_children = false; 1615 706 assertf( exprStmt->expr, "ExprStmt has null expression in resolver" ); … … 1619 710 } 1620 711 1621 const ast::AsmExpr * Resolver _new::previsit( const ast::AsmExpr * asmExpr ) {712 const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) { 1622 713 visit_children = false; 1623 714 … … 1628 719 } 1629 720 1630 const ast::AsmStmt * Resolver _new::previsit( const ast::AsmStmt * asmStmt ) {721 const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) { 1631 722 visitor->maybe_accept( asmStmt, &ast::AsmStmt::input ); 1632 723 visitor->maybe_accept( asmStmt, &ast::AsmStmt::output ); … … 1635 726 } 1636 727 1637 const ast::IfStmt * Resolver _new::previsit( const ast::IfStmt * ifStmt ) {728 const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) { 1638 729 return ast::mutate_field( 1639 730 ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) ); 1640 731 } 1641 732 1642 const ast::WhileDoStmt * Resolver _new::previsit( const ast::WhileDoStmt * whileDoStmt ) {733 const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) { 1643 734 return ast::mutate_field( 1644 735 whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) ); 1645 736 } 1646 737 1647 const ast::ForStmt * Resolver _new::previsit( const ast::ForStmt * forStmt ) {738 const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) { 1648 739 if ( forStmt->cond ) { 1649 740 forStmt = ast::mutate_field( … … 1659 750 } 1660 751 1661 const ast::SwitchStmt * Resolver _new::previsit( const ast::SwitchStmt * switchStmt ) {752 const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) { 1662 753 GuardValue( currentObject ); 1663 754 switchStmt = ast::mutate_field( … … 1668 759 } 1669 760 1670 const ast::CaseClause * Resolver _new::previsit( const ast::CaseClause * caseStmt ) {761 const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) { 1671 762 if ( caseStmt->cond ) { 1672 763 std::deque< ast::InitAlternative > initAlts = currentObject.getOptions(); … … 1689 780 } 1690 781 1691 const ast::BranchStmt * Resolver _new::previsit( const ast::BranchStmt * branchStmt ) {782 const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) { 1692 783 visit_children = false; 1693 784 // must resolve the argument of a computed goto … … 1702 793 } 1703 794 1704 const ast::ReturnStmt * Resolver _new::previsit( const ast::ReturnStmt * returnStmt ) {795 const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) { 1705 796 visit_children = false; 1706 797 if ( returnStmt->expr ) { … … 1712 803 } 1713 804 1714 const ast::ThrowStmt * Resolver _new::previsit( const ast::ThrowStmt * throwStmt ) {805 const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) { 1715 806 visit_children = false; 1716 807 if ( throwStmt->expr ) { … … 1727 818 } 1728 819 1729 const ast::CatchClause * Resolver _new::previsit( const ast::CatchClause * catchClause ) {820 const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) { 1730 821 // Until we are very sure this invarent (ifs that move between passes have then) 1731 822 // holds, check it. This allows a check for when to decode the mangling. … … 1743 834 } 1744 835 1745 const ast::CatchClause * Resolver _new::postvisit( const ast::CatchClause * catchClause ) {836 const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) { 1746 837 // Decode the catchStmt so everything is stored properly. 1747 838 const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>(); … … 1758 849 } 1759 850 1760 const ast::WaitForStmt * Resolver _new::previsit( const ast::WaitForStmt * stmt ) {851 const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) { 1761 852 visit_children = false; 1762 853 … … 2023 1114 } 2024 1115 2025 const ast::WithStmt * Resolver _new::previsit( const ast::WithStmt * withStmt ) {1116 const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) { 2026 1117 auto mutStmt = mutate(withStmt); 2027 1118 resolveWithExprs(mutStmt->exprs, stmtsToAddBefore); … … 2029 1120 } 2030 1121 2031 void Resolver _new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {1122 void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) { 2032 1123 for (auto & expr : exprs) { 2033 1124 // only struct- and union-typed expressions are viable candidates … … 2055 1146 2056 1147 2057 const ast::SingleInit * Resolver _new::previsit( const ast::SingleInit * singleInit ) {1148 const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) { 2058 1149 visit_children = false; 2059 1150 // resolve initialization using the possibilities as determined by the `currentObject` … … 2104 1195 } 2105 1196 2106 const ast::ListInit * Resolver _new::previsit( const ast::ListInit * listInit ) {1197 const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) { 2107 1198 // move cursor into brace-enclosed initializer-list 2108 1199 currentObject.enterListInit( listInit->location ); … … 2127 1218 } 2128 1219 2129 const ast::ConstructorInit * Resolver _new::previsit( const ast::ConstructorInit * ctorInit ) {1220 const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) { 2130 1221 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor ); 2131 1222 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor ); … … 2149 1240 2150 1241 // suppress error on autogen functions and mark invalid autogen as deleted. 2151 bool Resolver _new::on_error(ast::ptr<ast::Decl> & decl) {1242 bool Resolver::on_error(ast::ptr<ast::Decl> & decl) { 2152 1243 if (auto functionDecl = decl.as<ast::FunctionDecl>()) { 2153 1244 // xxx - can intrinsic gen ever fail? -
src/ResolvExpr/Resolver.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 18 #include "AST/Node.hpp" // for ptr 21 22 class ConstructorInit;23 class Declaration;24 class Expression;25 class DeletedExpr;26 class StmtExpr;27 class Type;28 namespace SymTab {29 class Indexer;30 } // namespace SymTab31 19 32 20 namespace ast { … … 45 33 46 34 namespace ResolvExpr { 47 /// Checks types and binds syntactic constructs to typed representations48 void resolve( std::list< Declaration * > translationUnit );49 void resolveDecl( Declaration *, const SymTab::Indexer & indexer );50 Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer );51 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer );52 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer );53 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer );54 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer );55 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer );56 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr57 DeletedExpr * findDeletedExpr( Expression * expr );58 /// Resolves with-stmts and with-clauses on functions59 void resolveWithExprs( std::list< Declaration * > & translationUnit );60 35 61 36 /// Helper Type: Passes around information between various sub-calls. -
src/ResolvExpr/SatisfyAssertions.cpp
rdf8ba61a r8d182b1 46 46 #include "SymTab/Mangler.h" 47 47 48 49 50 48 namespace ResolvExpr { 51 49 -
src/ResolvExpr/SpecCost.cc
rdf8ba61a r8d182b1 16 16 #include <cassert> 17 17 #include <limits> 18 #include <list>19 18 #include <type_traits> 20 19 21 20 #include "AST/Pass.hpp" 22 21 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 #include "SynTree/Declaration.h"25 #include "SynTree/Expression.h"26 #include "SynTree/Type.h"27 22 28 23 namespace ResolvExpr { 29 24 30 /// Counts specializations in a type 31 class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> { 32 int count = -1; ///< specialization count (-1 for none) 25 namespace { 33 26 34 public: 35 int get_count() const { return count >= 0 ? count : 0; } 27 const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) { 28 return expr->result.get(); 29 } 36 30 37 // mark specialization of base type 38 void postvisit(PointerType*) { if ( count >= 0 ) ++count; } 31 const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) { 32 return type.get(); 33 } 39 34 40 // mark specialization of base type41 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }42 43 // mark specialization of base type44 void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }45 46 void postvisit(StructInstType*) { if ( count >= 0 ) ++count; }47 void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; }48 49 private:50 // takes minimum non-negative count over parameter/return list51 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {52 for ( DeclarationWithType* dwt : dwts ) {53 count = -1;54 maybeAccept( dwt->get_type(), *visitor );55 if ( count != -1 && count < mincount ) mincount = count;56 }57 }58 59 public:60 // take minimal specialization value over ->returnVals and ->parameters61 void previsit(FunctionType* fty) {62 int mincount = std::numeric_limits<int>::max();63 takeminover( mincount, fty->parameters );64 takeminover( mincount, fty->returnVals );65 // add another level to mincount if set66 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;67 // already visited children68 visit_children = false;69 }70 71 private:72 // returns minimum non-negative count + 1 over type parameters (-1 if none such)73 int minover( std::list<Expression*>& parms ) {74 int mincount = std::numeric_limits<int>::max();75 for ( Expression* parm : parms ) {76 count = -1;77 maybeAccept( parm->result, *visitor );78 if ( count != -1 && count < mincount ) mincount = count;79 }80 return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;81 }82 83 public:84 // look for polymorphic parameters85 void previsit(StructInstType* sty) {86 count = minover( sty->parameters );87 }88 89 // look for polymorphic parameters90 void previsit(UnionInstType* uty) {91 count = minover( uty->parameters );92 }93 94 // note polymorphic type (which may be specialized)95 // xxx - maybe account for open/closed type variables96 void postvisit(TypeInstType*) { count = 0; }97 98 // take minimal specialization over elements99 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize100 void previsit(TupleType* tty) {101 int mincount = std::numeric_limits<int>::max();102 for ( Type* ty : tty->types ) {103 count = -1;104 maybeAccept( ty, *visitor );105 if ( count != -1 && count < mincount ) mincount = count;106 }107 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;108 visit_children = false;109 }110 };111 112 /// Returns the (negated) specialization cost for a given type113 int specCost( Type* ty ) {114 PassVisitor<CountSpecs> counter;115 maybeAccept( ty, *counter.pass.visitor );116 return counter.pass.get_count();117 }118 119 namespace {120 35 /// The specialization counter inner class. 121 36 class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> { … … 131 46 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 132 47 133 #warning Should use a standard maybe_accept134 void maybe_accept( ast::Type const * type ) {135 if ( type ) {136 auto node = type->accept( *visitor );137 assert( node == nullptr || node == type );138 }139 }140 141 48 // Update the minimum to the new lowest non-none value. 142 49 template<typename T> … … 144 51 for ( const auto & node : list ) { 145 52 count = -1; 146 maybe_accept( mapper( node ) ); 53 54 if ( ast::Type const * type = mapper( node ) ) { 55 ast::Type const * newType = type->accept( *visitor ); 56 assert( newType == nullptr || newType == type ); 57 } 58 147 59 if ( count != -1 && count < minimum ) minimum = count; 148 60 } … … 157 69 } 158 70 159 // The three mappers:160 static const ast::Type * decl_type( const ast::ptr< ast::DeclWithType > & decl ) {161 return decl->get_type();162 }163 static const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) {164 return expr->result;165 }166 static const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) {167 return type.get();168 }169 170 71 public: 171 int get_count() const { return 0 <= count ? count : 0; }72 int result() const { return 0 <= count ? count : 0; } 172 73 173 74 // Mark specialization of base type. … … 215 116 216 117 int specCost( const ast::Type * type ) { 217 if ( nullptr == type ) { 218 return 0; 219 } 220 ast::Pass<SpecCounter> counter; 221 type->accept( counter ); 222 return counter.core.get_count(); 118 return ( nullptr == type ) ? 0 : ast::Pass<SpecCounter>::read( type ); 223 119 } 224 120 -
src/ResolvExpr/Unify.cc
rdf8ba61a r8d182b1 33 33 #include "AST/TypeEnvironment.hpp" 34 34 #include "Common/Eval.h" // for eval 35 #include "Common/PassVisitor.h" // for PassVisitor36 35 #include "CommonType.hpp" // for commonType 37 36 #include "FindOpenVars.h" // for findOpenVars 38 37 #include "SpecCost.hpp" // for SpecCost 39 #include "SynTree/LinkageSpec.h" // for C40 #include "SynTree/Constant.h" // for Constant41 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Declarati...42 #include "SynTree/Expression.h" // for TypeExpr, Expression, ConstantExpr43 #include "SynTree/Mutator.h" // for Mutator44 #include "SynTree/Type.h" // for Type, TypeInstType, FunctionType45 #include "SynTree/Visitor.h" // for Visitor46 38 #include "Tuples/Tuples.h" // for isTtype 47 #include "TypeEnvironment.h" // for EqvClass, AssertionSet, OpenVarSet48 39 #include "typeops.h" // for flatten, occurs 49 40 … … 52 43 } 53 44 54 namespace SymTab {55 class Indexer;56 } // namespace SymTab57 58 45 // #define DEBUG 59 46 60 47 namespace ResolvExpr { 61 62 // Template Helpers:63 template< typename Iterator1, typename Iterator2 >64 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {65 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {66 Type *commonType = 0;67 if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {68 return false;69 } // if70 commonTypes.push_back( commonType );71 } // for72 return ( list1Begin == list1End && list2Begin == list2End );73 }74 75 template< typename Iterator1, typename Iterator2 >76 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {77 std::list< Type* > commonTypes;78 if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions, openVars, indexer, commonTypes ) ) {79 deleteAll( commonTypes );80 return true;81 } else {82 return false;83 } // if84 }85 86 struct Unify_old : public WithShortCircuiting {87 Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );88 89 bool get_result() const { return result; }90 91 void previsit( BaseSyntaxNode * ) { visit_children = false; }92 93 void postvisit( VoidType * voidType );94 void postvisit( BasicType * basicType );95 void postvisit( PointerType * pointerType );96 void postvisit( ArrayType * arrayType );97 void postvisit( ReferenceType * refType );98 void postvisit( FunctionType * functionType );99 void postvisit( StructInstType * aggregateUseType );100 void postvisit( UnionInstType * aggregateUseType );101 void postvisit( EnumInstType * aggregateUseType );102 void postvisit( TraitInstType * aggregateUseType );103 void postvisit( TypeInstType * aggregateUseType );104 void postvisit( TupleType * tupleType );105 void postvisit( VarArgsType * varArgsType );106 void postvisit( ZeroType * zeroType );107 void postvisit( OneType * oneType );108 109 private:110 template< typename RefType > void handleRefType( RefType *inst, Type *other );111 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );112 113 bool result;114 Type *type2; // inherited115 TypeEnvironment &env;116 AssertionSet &needAssertions;117 AssertionSet &haveAssertions;118 const OpenVarSet &openVars;119 WidenMode widen;120 const SymTab::Indexer &indexer;121 };122 123 /// Attempts an inexact unification of type1 and type2.124 /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)125 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );126 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );127 128 bool unifyExact(129 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,130 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,131 WidenMode widen );132 133 bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {134 TypeEnvironment newEnv;135 OpenVarSet openVars, closedVars; // added closedVars136 AssertionSet needAssertions, haveAssertions;137 Type * newFirst = first->clone(), * newSecond = second->clone();138 env.apply( newFirst );139 env.apply( newSecond );140 141 // do we need to do this? Seems like we do, types should be able to be compatible if they142 // have free variables that can unify143 findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );144 findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );145 146 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );147 delete newFirst;148 delete newSecond;149 return result;150 }151 48 152 49 bool typesCompatible( … … 165 62 166 63 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() ); 167 }168 169 bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {170 TypeEnvironment newEnv;171 OpenVarSet openVars;172 AssertionSet needAssertions, haveAssertions;173 Type *newFirst = first->clone(), *newSecond = second->clone();174 env.apply( newFirst );175 env.apply( newSecond );176 newFirst->get_qualifiers() = Type::Qualifiers();177 newSecond->get_qualifiers() = Type::Qualifiers();178 179 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );180 delete newFirst;181 delete newSecond;182 return result;183 64 } 184 65 … … 220 101 } 221 102 222 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {223 OpenVarSet closedVars;224 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );225 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );226 Type *commonType = 0;227 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {228 if ( commonType ) {229 delete commonType;230 } // if231 return true;232 } else {233 return false;234 } // if235 }236 237 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {238 OpenVarSet closedVars;239 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );240 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );241 return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );242 }243 244 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {245 #ifdef DEBUG246 TypeEnvironment debugEnv( env );247 #endif248 if ( type1->get_qualifiers() != type2->get_qualifiers() ) {249 return false;250 }251 252 bool result;253 TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );254 TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );255 OpenVarSet::const_iterator entry1, entry2;256 if ( var1 ) {257 entry1 = openVars.find( var1->get_name() );258 } // if259 if ( var2 ) {260 entry2 = openVars.find( var2->get_name() );261 } // if262 bool isopen1 = var1 && ( entry1 != openVars.end() );263 bool isopen2 = var2 && ( entry2 != openVars.end() );264 265 if ( isopen1 && isopen2 ) {266 if ( entry1->second.kind != entry2->second.kind ) {267 result = false;268 } else {269 result = env.bindVarToVar(270 var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,271 haveAssertions, openVars, widen, indexer );272 }273 } else if ( isopen1 ) {274 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );275 } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?276 result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );277 } else {278 PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );279 type1->accept( comparator );280 result = comparator.pass.get_result();281 } // if282 #ifdef DEBUG283 std::cerr << "============ unifyExact" << std::endl;284 std::cerr << "type1 is ";285 type1->print( std::cerr );286 std::cerr << std::endl << "type2 is ";287 type2->print( std::cerr );288 std::cerr << std::endl << "openVars are ";289 printOpenVarSet( openVars, std::cerr, 8 );290 std::cerr << std::endl << "input env is " << std::endl;291 debugEnv.print( std::cerr, 8 );292 std::cerr << std::endl << "result env is " << std::endl;293 env.print( std::cerr, 8 );294 std::cerr << "result is " << result << std::endl;295 #endif296 return result;297 }298 299 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {300 return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );301 }302 303 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {304 Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();305 type1->get_qualifiers() = Type::Qualifiers();306 type2->get_qualifiers() = Type::Qualifiers();307 bool result;308 #ifdef DEBUG309 std::cerr << "unifyInexact type 1 is ";310 type1->print( std::cerr );311 std::cerr << " type 2 is ";312 type2->print( std::cerr );313 std::cerr << std::endl;314 #endif315 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {316 #ifdef DEBUG317 std::cerr << "unifyInexact: no exact unification found" << std::endl;318 #endif319 if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {320 common->tq = tq1.unify( tq2 );321 #ifdef DEBUG322 std::cerr << "unifyInexact: common type is ";323 common->print( std::cerr );324 std::cerr << std::endl;325 #endif326 result = true;327 } else {328 #ifdef DEBUG329 std::cerr << "unifyInexact: no common type found" << std::endl;330 #endif331 result = false;332 } // if333 } else {334 if ( tq1 != tq2 ) {335 if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {336 common = type1->clone();337 common->tq = tq1.unify( tq2 );338 result = true;339 } else {340 result = false;341 } // if342 } else {343 common = type1->clone();344 common->tq = tq1.unify( tq2 );345 result = true;346 } // if347 } // if348 type1->get_qualifiers() = tq1;349 type2->get_qualifiers() = tq2;350 return result;351 }352 353 Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )354 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {355 }356 357 void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {358 result = dynamic_cast< VoidType* >( type2 );359 }360 361 void Unify_old::postvisit(BasicType *basicType) {362 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {363 result = basicType->get_kind() == otherBasic->get_kind();364 } // if365 }366 367 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {368 AssertionSet::iterator i = assertions.find( assert );369 if ( i != assertions.end() ) {370 i->second.isUsed = true;371 } // if372 }373 374 void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {375 for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {376 for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {377 markAssertionSet( assertion1, *assert );378 markAssertionSet( assertion2, *assert );379 } // for380 } // for381 }382 383 void Unify_old::postvisit(PointerType *pointerType) {384 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {385 result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );386 markAssertions( haveAssertions, needAssertions, pointerType );387 markAssertions( haveAssertions, needAssertions, otherPointer );388 } // if389 }390 391 void Unify_old::postvisit(ReferenceType *refType) {392 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {393 result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );394 markAssertions( haveAssertions, needAssertions, refType );395 markAssertions( haveAssertions, needAssertions, otherRef );396 } // if397 }398 399 void Unify_old::postvisit(ArrayType *arrayType) {400 ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );401 // to unify, array types must both be VLA or both not VLA402 // and must both have a dimension expression or not have a dimension403 if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {404 405 if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&406 arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {407 ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );408 ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );409 // see C11 Reference Manual 6.7.6.2.6410 // two array types with size specifiers that are integer constant expressions are411 // compatible if both size specifiers have the same constant value412 if ( ce1 && ce2 ) {413 Constant * c1 = ce1->get_constant();414 Constant * c2 = ce2->get_constant();415 416 if ( c1->get_value() != c2->get_value() ) {417 // does not unify if the dimension is different418 return;419 }420 }421 }422 423 result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );424 } // if425 }426 427 template< typename Iterator, typename Func >428 std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {429 std::list< Type * > types;430 for ( ; begin != end; ++begin ) {431 // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple432 flatten( toType( *begin ), back_inserter( types ) );433 }434 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );435 }436 437 template< typename Iterator1, typename Iterator2 >438 bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {439 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };440 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {441 Type * t1 = (*list1Begin)->get_type();442 Type * t2 = (*list2Begin)->get_type();443 bool isTtype1 = Tuples::isTtype( t1 );444 bool isTtype2 = Tuples::isTtype( t2 );445 // xxx - assumes ttype must be last parameter446 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.447 if ( isTtype1 && ! isTtype2 ) {448 // combine all of the things in list2, then unify449 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );450 } else if ( isTtype2 && ! isTtype1 ) {451 // combine all of the things in list1, then unify452 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );453 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {454 return false;455 } // if456 } // for457 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype458 if ( list1Begin != list1End ) {459 // try unifying empty tuple type with ttype460 Type * t1 = (*list1Begin)->get_type();461 if ( Tuples::isTtype( t1 ) ) {462 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );463 } else return false;464 } else if ( list2Begin != list2End ) {465 // try unifying empty tuple type with ttype466 Type * t2 = (*list2Begin)->get_type();467 if ( Tuples::isTtype( t2 ) ) {468 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );469 } else return false;470 } else {471 return true;472 } // if473 }474 475 /// Finds ttypes and replaces them with their expansion, if known.476 /// This needs to be done so that satisfying ttype assertions is easier.477 /// If this isn't done then argument lists can have wildly different478 /// size and structure, when they should be compatible.479 struct TtypeExpander_old : public WithShortCircuiting {480 TypeEnvironment & tenv;481 TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}482 void premutate( TypeInstType * ) { visit_children = false; }483 Type * postmutate( TypeInstType * typeInst ) {484 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {485 // expand ttype parameter into its actual type486 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {487 delete typeInst;488 return eqvClass->type->clone();489 }490 }491 return typeInst;492 }493 };494 495 /// flattens a list of declarations, so that each tuple type has a single declaration.496 /// makes use of TtypeExpander to ensure ttypes are flat as well.497 void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {498 dst.clear();499 for ( DeclarationWithType * dcl : src ) {500 PassVisitor<TtypeExpander_old> expander( env );501 dcl->acceptMutator( expander );502 std::list< Type * > types;503 flatten( dcl->get_type(), back_inserter( types ) );504 for ( Type * t : types ) {505 // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.506 // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.507 t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);508 509 dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );510 }511 delete dcl;512 }513 }514 515 void Unify_old::postvisit(FunctionType *functionType) {516 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );517 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {518 // flatten the parameter lists for both functions so that tuple structure519 // doesn't affect unification. Must be a clone so that the types don't change.520 std::unique_ptr<FunctionType> flatFunc( functionType->clone() );521 std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );522 flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );523 flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );524 525 // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors526 if (527 (flatFunc->parameters.size() == flatOther->parameters.size() &&528 flatFunc->returnVals.size() == flatOther->returnVals.size())529 || flatFunc->isTtype()530 || flatOther->isTtype()531 ) {532 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {533 if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {534 535 // the original types must be used in mark assertions, since pointer comparisons are used536 markAssertions( haveAssertions, needAssertions, functionType );537 markAssertions( haveAssertions, needAssertions, otherFunction );538 539 result = true;540 } // if541 } // if542 } // if543 } // if544 }545 546 template< typename RefType >547 void Unify_old::handleRefType( RefType *inst, Type *other ) {548 // check that other type is compatible and named the same549 RefType *otherStruct = dynamic_cast< RefType* >( other );550 result = otherStruct && inst->name == otherStruct->name;551 }552 553 template< typename RefType >554 void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {555 // Check that other type is compatible and named the same556 handleRefType( inst, other );557 if ( ! result ) return;558 // Check that parameters of types unify, if any559 std::list< Expression* > params = inst->parameters;560 std::list< Expression* > otherParams = ((RefType*)other)->parameters;561 562 std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();563 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {564 TypeExpr *param = dynamic_cast< TypeExpr* >(*it);565 assertf(param, "Aggregate parameters should be type expressions");566 TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);567 assertf(otherParam, "Aggregate parameters should be type expressions");568 569 Type* paramTy = param->get_type();570 Type* otherParamTy = otherParam->get_type();571 572 bool tupleParam = Tuples::isTtype( paramTy );573 bool otherTupleParam = Tuples::isTtype( otherParamTy );574 575 if ( tupleParam && otherTupleParam ) {576 ++it; ++jt; // skip ttype parameters for break577 } else if ( tupleParam ) {578 // bundle other parameters into tuple to match579 std::list< Type * > binderTypes;580 581 do {582 binderTypes.push_back( otherParam->get_type()->clone() );583 ++jt;584 585 if ( jt == otherParams.end() ) break;586 587 otherParam = dynamic_cast< TypeExpr* >(*jt);588 assertf(otherParam, "Aggregate parameters should be type expressions");589 } while (true);590 591 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };592 ++it; // skip ttype parameter for break593 } else if ( otherTupleParam ) {594 // bundle parameters into tuple to match other595 std::list< Type * > binderTypes;596 597 do {598 binderTypes.push_back( param->get_type()->clone() );599 ++it;600 601 if ( it == params.end() ) break;602 603 param = dynamic_cast< TypeExpr* >(*it);604 assertf(param, "Aggregate parameters should be type expressions");605 } while (true);606 607 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };608 ++jt; // skip ttype parameter for break609 }610 611 if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {612 result = false;613 return;614 }615 616 // ttype parameter should be last617 if ( tupleParam || otherTupleParam ) break;618 }619 result = ( it == params.end() && jt == otherParams.end() );620 }621 622 void Unify_old::postvisit(StructInstType *structInst) {623 handleGenericRefType( structInst, type2 );624 }625 626 void Unify_old::postvisit(UnionInstType *unionInst) {627 handleGenericRefType( unionInst, type2 );628 }629 630 void Unify_old::postvisit(EnumInstType *enumInst) {631 handleRefType( enumInst, type2 );632 }633 634 void Unify_old::postvisit(TraitInstType *contextInst) {635 handleRefType( contextInst, type2 );636 }637 638 void Unify_old::postvisit(TypeInstType *typeInst) {639 assert( openVars.find( typeInst->get_name() ) == openVars.end() );640 TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );641 if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {642 result = true;643 /// } else {644 /// NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );645 /// if ( nt ) {646 /// TypeDecl *type = dynamic_cast< TypeDecl* >( nt );647 /// assert( type );648 /// if ( type->get_base() ) {649 /// result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );650 /// }651 /// }652 } // if653 }654 655 template< typename Iterator1, typename Iterator2 >656 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {657 auto get_type = [](Type * t) { return t; };658 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {659 Type * t1 = *list1Begin;660 Type * t2 = *list2Begin;661 bool isTtype1 = Tuples::isTtype( t1 );662 bool isTtype2 = Tuples::isTtype( t2 );663 // xxx - assumes ttype must be last parameter664 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.665 if ( isTtype1 && ! isTtype2 ) {666 // combine all of the things in list2, then unify667 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );668 } else if ( isTtype2 && ! isTtype1 ) {669 // combine all of the things in list1, then unify670 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );671 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {672 return false;673 } // if674 675 } // for676 if ( list1Begin != list1End ) {677 // try unifying empty tuple type with ttype678 Type * t1 = *list1Begin;679 if ( Tuples::isTtype( t1 ) ) {680 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );681 } else return false;682 } else if ( list2Begin != list2End ) {683 // try unifying empty tuple type with ttype684 Type * t2 = *list2Begin;685 if ( Tuples::isTtype( t2 ) ) {686 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );687 } else return false;688 } else {689 return true;690 } // if691 }692 693 void Unify_old::postvisit(TupleType *tupleType) {694 if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {695 std::unique_ptr<TupleType> flat1( tupleType->clone() );696 std::unique_ptr<TupleType> flat2( otherTuple->clone() );697 std::list<Type *> types1, types2;698 699 PassVisitor<TtypeExpander_old> expander( env );700 flat1->acceptMutator( expander );701 flat2->acceptMutator( expander );702 703 flatten( flat1.get(), back_inserter( types1 ) );704 flatten( flat2.get(), back_inserter( types2 ) );705 706 result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );707 } // if708 }709 710 void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {711 result = dynamic_cast< VarArgsType* >( type2 );712 }713 714 void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {715 result = dynamic_cast< ZeroType* >( type2 );716 }717 718 void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {719 result = dynamic_cast< OneType* >( type2 );720 }721 722 Type * extractResultType( FunctionType * function ) {723 if ( function->get_returnVals().size() == 0 ) {724 return new VoidType( Type::Qualifiers() );725 } else if ( function->get_returnVals().size() == 1 ) {726 return function->get_returnVals().front()->get_type()->clone();727 } else {728 std::list< Type * > types;729 for ( DeclarationWithType * decl : function->get_returnVals() ) {730 types.push_back( decl->get_type()->clone() );731 } // for732 return new TupleType( Type::Qualifiers(), types );733 }734 }735 736 103 namespace { 737 104 /// Replaces ttype variables with their bound types. 738 105 /// If this isn't done when satifying ttype assertions, then argument lists can have 739 106 /// different size and structure when they should be compatible. 740 struct TtypeExpander _new: public ast::WithShortCircuiting, public ast::PureVisitor {107 struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor { 741 108 ast::TypeEnvironment & tenv; 742 109 743 TtypeExpander _new( ast::TypeEnvironment & env ) : tenv( env ) {}110 TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {} 744 111 745 112 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) { … … 761 128 dst.reserve( src.size() ); 762 129 for ( const auto & d : src ) { 763 ast::Pass<TtypeExpander _new> expander{ env };130 ast::Pass<TtypeExpander> expander{ env }; 764 131 // TtypeExpander pass is impure (may mutate nodes in place) 765 132 // need to make nodes shared to prevent accidental mutation … … 901 268 } 902 269 903 class Unify _newfinal : public ast::WithShortCircuiting {270 class Unify final : public ast::WithShortCircuiting { 904 271 const ast::Type * type2; 905 272 ast::TypeEnvironment & tenv; … … 912 279 bool result; 913 280 914 Unify _new(281 Unify( 915 282 const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need, 916 283 ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen ) … … 1239 606 if ( ! tuple2 ) return; 1240 607 1241 ast::Pass<TtypeExpander _new> expander{ tenv };608 ast::Pass<TtypeExpander> expander{ tenv }; 1242 609 1243 610 const ast::Type * flat = tuple->accept( expander ); … … 1267 634 }; 1268 635 1269 // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new"); 636 // size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify"); 637 1270 638 bool unify( 1271 639 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, … … 1311 679 return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen ); 1312 680 } else { 1313 return ast::Pass<Unify _new>::read(681 return ast::Pass<Unify>::read( 1314 682 type1, type2, env, need, have, open, widen ); 1315 683 } -
src/ResolvExpr/Unify.h
rdf8ba61a r8d182b1 20 20 #include "AST/Node.hpp" // for ptr 21 21 #include "AST/TypeEnvironment.hpp" // for TypeEnvironment, AssertionSet, OpenVarSet 22 #include "Common/utility.h" // for deleteAll23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data24 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet25 22 #include "WidenMode.h" // for WidenMode 26 27 class Type;28 class TypeInstType;29 namespace SymTab {30 class Indexer;31 }32 23 33 24 namespace ast { … … 37 28 38 29 namespace ResolvExpr { 39 40 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );41 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );42 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );43 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );44 45 bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );46 bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );47 48 inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {49 TypeEnvironment env;50 return typesCompatible( t1, t2, indexer, env );51 }52 53 inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {54 TypeEnvironment env;55 return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );56 }57 30 58 31 bool unify( … … 85 58 const ast::TypeEnvironment & env = {} ); 86 59 87 /// Creates the type represented by the list of returnVals in a FunctionType.88 /// The caller owns the return value.89 Type * extractResultType( FunctionType * functionType );90 60 /// Creates or extracts the type represented by returns in a `FunctionType`. 91 61 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ); -
src/ResolvExpr/module.mk
rdf8ba61a r8d182b1 18 18 ResolvExpr/AdjustExprType.cc \ 19 19 ResolvExpr/AdjustExprType.hpp \ 20 ResolvExpr/Alternative.cc \21 ResolvExpr/AlternativeFinder.cc \22 ResolvExpr/AlternativeFinder.h \23 ResolvExpr/Alternative.h \24 20 ResolvExpr/Candidate.cpp \ 25 21 ResolvExpr/CandidateFinder.cpp \ … … 35 31 ResolvExpr/CurrentObject.cc \ 36 32 ResolvExpr/CurrentObject.h \ 37 ResolvExpr/ExplodedActual.cc \38 ResolvExpr/ExplodedActual.h \39 33 ResolvExpr/ExplodedArg.cpp \ 40 34 ResolvExpr/ExplodedArg.hpp \ 41 35 ResolvExpr/FindOpenVars.cc \ 42 36 ResolvExpr/FindOpenVars.h \ 43 ResolvExpr/Occurs.cc \44 37 ResolvExpr/PolyCost.cc \ 45 38 ResolvExpr/PolyCost.hpp \ … … 50 43 ResolvExpr/RenameVars.cc \ 51 44 ResolvExpr/RenameVars.h \ 52 ResolvExpr/ResolveAssertions.cc \53 ResolvExpr/ResolveAssertions.h \54 45 ResolvExpr/Resolver.cc \ 55 46 ResolvExpr/Resolver.h \ … … 61 52 ResolvExpr/SpecCost.cc \ 62 53 ResolvExpr/SpecCost.hpp \ 63 ResolvExpr/TypeEnvironment.cc \64 ResolvExpr/TypeEnvironment.h \65 54 ResolvExpr/typeops.h \ 66 55 ResolvExpr/Unify.cc \ … … 69 58 70 59 SRC += $(SRC_RESOLVEXPR) \ 71 ResolvExpr/AlternativePrinter.cc \72 ResolvExpr/AlternativePrinter.h \73 60 ResolvExpr/CandidatePrinter.cpp \ 74 61 ResolvExpr/CandidatePrinter.hpp \ -
src/ResolvExpr/typeops.h
rdf8ba61a r8d182b1 19 19 20 20 #include "AST/Type.hpp" 21 #include "SynTree/Type.h"22 23 namespace SymTab {24 class Indexer;25 }26 21 27 22 namespace ResolvExpr { … … 52 47 std::copy( i.begin(), i.end(), inserter ); 53 48 *out++ = result; 54 }55 }56 57 // in Occurs.cc58 bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );59 // new AST version in TypeEnvironment.cpp (only place it was used in old AST)60 61 template<typename Iter>62 bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) {63 while ( begin != end ) {64 if ( occurs( ty, *begin, env ) ) return true;65 ++begin;66 }67 return false;68 }69 70 /// flatten tuple type into list of types71 template< typename OutputIterator >72 void flatten( Type * type, OutputIterator out ) {73 if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {74 for ( Type * t : tupleType->get_types() ) {75 flatten( t, out );76 }77 } else {78 *out++ = type->clone();79 49 } 80 50 } … … 120 90 return tupleFromTypes( tys.begin(), tys.end() ); 121 91 } 122 123 // in TypeEnvironment.cc124 bool isFtype( const Type * type );125 92 } // namespace ResolvExpr 126 93 -
src/SymTab/Demangle.cc
rdf8ba61a r8d182b1 17 17 #include <sstream> 18 18 19 #include "AST/Pass.hpp" 20 #include "AST/Type.hpp" 19 21 #include "CodeGen/GenType.h" 20 22 #include "CodeGen/OperatorTable.h" 21 #include "Common/PassVisitor.h"22 23 #include "Common/utility.h" // isPrefix 23 24 #include "Mangler.h" 24 #include "SynTree/Type.h"25 #include "SynTree/Declaration.h"26 25 27 26 #define DEBUG … … 32 31 #endif 33 32 33 namespace Mangle { 34 34 35 namespace { 35 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting { 36 std::string typeString; 37 GenType( const std::string &typeString ); 38 39 void previsit( BaseSyntaxNode * ); 40 void postvisit( BaseSyntaxNode * ); 41 42 void postvisit( FunctionType * funcType ); 43 void postvisit( VoidType * voidType ); 44 void postvisit( BasicType * basicType ); 45 void postvisit( PointerType * pointerType ); 46 void postvisit( ArrayType * arrayType ); 47 void postvisit( ReferenceType * refType ); 48 void postvisit( StructInstType * structInst ); 49 void postvisit( UnionInstType * unionInst ); 50 void postvisit( EnumInstType * enumInst ); 51 void postvisit( TypeInstType * typeInst ); 52 void postvisit( TupleType * tupleType ); 53 void postvisit( VarArgsType * varArgsType ); 54 void postvisit( ZeroType * zeroType ); 55 void postvisit( OneType * oneType ); 56 void postvisit( GlobalScopeType * globalType ); 57 void postvisit( QualifiedType * qualType ); 58 59 private: 60 void handleQualifiers( Type *type ); 61 std::string handleGeneric( ReferenceToType * refType ); 62 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ); 63 }; 64 65 std::string genDemangleType( Type * type, const std::string & baseString ) { 66 PassVisitor<GenType> gt( baseString ); 67 assert( type ); 68 type->accept( gt ); 69 return gt.pass.typeString; 70 } 71 72 GenType::GenType( const std::string &typeString ) : typeString( typeString ) {} 73 74 // *** BaseSyntaxNode 75 void GenType::previsit( BaseSyntaxNode * ) { 76 // turn off automatic recursion for all nodes, to allow each visitor to 77 // precisely control the order in which its children are visited. 78 visit_children = false; 79 } 80 81 void GenType::postvisit( BaseSyntaxNode * node ) { 82 std::stringstream ss; 83 node->print( ss ); 84 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() ); 85 } 86 87 void GenType::postvisit( VoidType * voidType ) { 88 typeString = "void " + typeString; 89 handleQualifiers( voidType ); 90 } 91 92 void GenType::postvisit( BasicType * basicType ) { 93 BasicType::Kind kind = basicType->kind; 94 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES ); 95 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString; 96 handleQualifiers( basicType ); 97 } 98 99 void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool ) { 100 std::ostringstream os; 101 if ( typeString != "" ) { 102 if ( typeString[ 0 ] == '*' ) { 103 os << "(" << typeString << ")"; 104 } else { 105 os << typeString; 106 } // if 107 } // if 108 os << "["; 109 110 if ( qualifiers.is_const ) { 111 os << "const "; 112 } // if 113 if ( qualifiers.is_volatile ) { 114 os << "volatile "; 115 } // if 116 if ( qualifiers.is_restrict ) { 117 os << "__restrict "; 118 } // if 119 if ( qualifiers.is_atomic ) { 120 os << "_Atomic "; 121 } // if 122 if ( dimension != 0 ) { 123 // TODO: ??? 124 // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 125 // dimension->accept( cg ); 126 } else if ( isVarLen ) { 127 // no dimension expression on a VLA means it came in with the * token 128 os << "*"; 129 } // if 130 os << "]"; 131 132 typeString = os.str(); 133 134 base->accept( *visitor ); 135 } 136 137 void GenType::postvisit( PointerType * pointerType ) { 138 assert( pointerType->base != 0); 139 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) { 140 assert(false); 141 genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() ); 142 } else { 143 handleQualifiers( pointerType ); 144 if ( typeString[ 0 ] == '?' ) { 145 typeString = "* " + typeString; 146 } else { 147 typeString = "*" + typeString; 148 } // if 149 pointerType->base->accept( *visitor ); 150 } // if 151 } 152 153 void GenType::postvisit( ArrayType * arrayType ) { 154 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() ); 155 } 156 157 void GenType::postvisit( ReferenceType * refType ) { 158 assert( false ); 159 assert( refType->base != 0); 160 handleQualifiers( refType ); 161 typeString = "&" + typeString; 162 refType->base->accept( *visitor ); 163 } 164 165 void GenType::postvisit( FunctionType * funcType ) { 166 std::ostringstream os; 167 168 if ( typeString != "" ) { 169 if ( typeString[0] == '*' ) { 170 os << "(" << typeString << ")"; 171 } else { 172 os << typeString; 173 } // if 174 } // if 175 176 /************* parameters ***************/ 177 const std::list<DeclarationWithType *> &pars = funcType->parameters; 178 179 if ( pars.empty() ) { 180 if ( funcType->get_isVarArgs() ) { 181 os << "()"; 182 } else { 183 os << "(void)"; 184 } // if 185 } else { 186 os << "(" ; 187 188 unsigned int i = 0; 189 for (DeclarationWithType * p : pars) { 190 os << genDemangleType( p->get_type(), "" ); 191 if (++i != pars.size()) os << ", "; 192 } 193 194 if ( funcType->get_isVarArgs() ) { 195 os << ", ..."; 196 } // if 197 os << ")"; 198 } // if 199 200 typeString = os.str(); 201 202 if ( funcType->returnVals.size() == 0 ) { 203 typeString += ": void"; 204 } else { 205 typeString += ": " + genDemangleType(funcType->returnVals.front()->get_type(), ""); 206 } // if 207 208 // add forall 209 if( ! funcType->forall.empty() ) { 210 std::ostringstream os; 211 os << "forall("; 212 unsigned int i = 0; 213 for ( auto td : funcType->forall ) { 214 os << td->typeString() << " " << td->name; 215 if (! td->assertions.empty()) { 216 os << " | { "; 217 unsigned int j = 0; 218 for (DeclarationWithType * assert : td->assertions) { 219 os << genDemangleType(assert->get_type(), assert->name); 220 if (++j != td->assertions.size()) os << ", "; 221 } 222 os << "}"; 223 } 224 if (++i != funcType->forall.size()) os << ", "; 225 } 226 os << ")"; 227 typeString = typeString + " -> " + os.str(); 36 37 struct Demangler { 38 private: 39 std::string str; 40 size_t index = 0; 41 using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>; 42 std::vector<std::pair<std::string, Parser>> parsers; 43 public: 44 Demangler( const std::string & str ); 45 46 bool done() const { return str.size() <= index; } 47 char cur() const { assert( !done() ); return str[index]; } 48 bool expect( char ch ) { return str[index++] == ch; } 49 50 bool isPrefix( const std::string & pref ); 51 bool extractNumber( size_t & out ); 52 bool extractName( std::string & out ); 53 bool stripMangleName( std::string & name ); 54 55 ast::Type * parseFunction( ast::CV::Qualifiers tq ); 56 ast::Type * parseTuple( ast::CV::Qualifiers tq ); 57 ast::Type * parsePointer( ast::CV::Qualifiers tq ); 58 ast::Type * parseArray( ast::CV::Qualifiers tq ); 59 ast::Type * parseStruct( ast::CV::Qualifiers tq ); 60 ast::Type * parseUnion( ast::CV::Qualifiers tq ); 61 ast::Type * parseEnum( ast::CV::Qualifiers tq ); 62 ast::Type * parseType( ast::CV::Qualifiers tq ); 63 ast::Type * parseZero( ast::CV::Qualifiers tq ); 64 ast::Type * parseOne( ast::CV::Qualifiers tq ); 65 66 ast::Type * parseType(); 67 bool parse( std::string & name, ast::Type *& type ); 68 }; 69 70 Demangler::Demangler(const std::string & str) : str(str) { 71 for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) { 72 parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) { 73 PRINT( std::cerr << "basic type: " << k << std::endl; ) 74 return new ast::BasicType( (ast::BasicType::Kind)k, tq ); 75 }); 76 } 77 78 for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) { 79 static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", }; 80 static_assert( 81 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS, 82 "Each type variable kind should have a demangle name prefix" 83 ); 84 parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * { 85 PRINT( std::cerr << "type variable type: " << k << std::endl; ) 86 size_t N; 87 if (!extractNumber(N)) return nullptr; 88 return new ast::TypeInstType( 89 toString(typeVariableNames[k], N), 90 (ast::TypeDecl::Kind)k, 91 tq ); 92 }); 93 } 94 95 parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); }); 96 parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); }); 97 parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); }); 98 parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); }); 99 parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); }); 100 parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); }); 101 parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); }); 102 parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); }); 103 parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); }); 104 parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); }); 105 parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); }); 106 } 107 108 bool Demangler::extractNumber( size_t & out ) { 109 std::stringstream numss; 110 if ( str.size() <= index ) return false; 111 while ( isdigit( str[index] ) ) { 112 numss << str[index]; 113 ++index; 114 if ( str.size() == index ) break; 115 } 116 if ( !(numss >> out) ) return false; 117 PRINT( std::cerr << "extractNumber success: " << out << std::endl; ) 118 return true; 119 } 120 121 bool Demangler::extractName( std::string & out ) { 122 size_t len; 123 if ( !extractNumber(len) ) return false; 124 if ( str.size() < index + len ) return false; 125 out = str.substr( index, len ); 126 index += len; 127 PRINT( std::cerr << "extractName success: " << out << std::endl; ) 128 return true; 129 } 130 131 bool Demangler::isPrefix( const std::string & pref ) { 132 // Wraps the utility isPrefix function. 133 if ( ::isPrefix( str, pref, index ) ) { 134 index += pref.size(); 135 return true; 136 } 137 return false; 138 } 139 140 // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise 141 bool Demangler::stripMangleName( std::string & name ) { 142 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; ) 143 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix 144 if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false; 145 146 if (!extractName(name)) return false; 147 148 // Find bounds for type. 149 PRINT( std::cerr << index << " " << str.size() << std::endl; ) 150 PRINT( std::cerr << "["); 151 while (isdigit(str.back())) { 152 PRINT(std::cerr << "."); 153 str.pop_back(); 154 if (str.size() <= index) return false; 155 } 156 PRINT( std::cerr << "]" << std::endl ); 157 if (str.back() != '_') return false; 158 str.pop_back(); 159 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; ) 160 return index < str.size(); 161 } 162 163 ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) { 164 PRINT( std::cerr << "function..." << std::endl; ) 165 if ( done() ) return nullptr; 166 ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq ); 167 std::unique_ptr<ast::Type> manager( ftype ); 168 ast::Type * retVal = parseType(); 169 if ( !retVal ) return nullptr; 170 PRINT( std::cerr << "with return type: " << retVal << std::endl; ) 171 ftype->returns.emplace_back( retVal ); 172 if ( done() || !expect('_') ) return nullptr; 173 while ( !done() ) { 174 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 175 if ( cur() == '_' ) return manager.release(); 176 ast::Type * param = parseType(); 177 if ( !param ) return nullptr; 178 PRINT( std::cerr << "with parameter : " << param << std::endl; ) 179 ftype->params.emplace_back( param ); 180 } 181 return nullptr; 182 } 183 184 ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) { 185 PRINT( std::cerr << "tuple..." << std::endl; ) 186 std::vector<ast::ptr<ast::Type>> types; 187 size_t ncomponents; 188 if ( !extractNumber(ncomponents) ) return nullptr; 189 for ( size_t i = 0; i < ncomponents; ++i ) { 190 if ( done() ) return nullptr; 191 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 192 ast::Type * t = parseType(); 193 if ( !t ) return nullptr; 194 PRINT( std::cerr << "with type : " << t << std::endl; ) 195 types.push_back( t ); 196 } 197 return new ast::TupleType( std::move( types ), tq ); 198 } 199 200 ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) { 201 PRINT( std::cerr << "pointer..." << std::endl; ) 202 ast::Type * t = parseType(); 203 if ( !t ) return nullptr; 204 return new ast::PointerType( t, tq ); 205 } 206 207 ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) { 208 PRINT( std::cerr << "array..." << std::endl; ) 209 size_t length; 210 if ( !extractNumber(length) ) return nullptr; 211 ast::Type * t = parseType(); 212 if ( !t ) return nullptr; 213 return new ast::ArrayType( 214 t, 215 ast::ConstantExpr::from_ulong( CodeLocation(), length ), 216 ast::FixedLen, 217 ast::DynamicDim, 218 tq ); 219 } 220 221 ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) { 222 PRINT( std::cerr << "struct..." << std::endl; ) 223 std::string name; 224 if ( !extractName(name) ) return nullptr; 225 return new ast::StructInstType( name, tq ); 226 } 227 228 ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) { 229 PRINT( std::cerr << "union..." << std::endl; ) 230 std::string name; 231 if ( !extractName(name) ) return nullptr; 232 return new ast::UnionInstType( name, tq ); 233 } 234 235 ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) { 236 PRINT( std::cerr << "enum..." << std::endl; ) 237 std::string name; 238 if ( !extractName(name) ) return nullptr; 239 return new ast::EnumInstType( name, tq ); 240 } 241 242 ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) { 243 PRINT( std::cerr << "type..." << std::endl; ) 244 std::string name; 245 if ( !extractName(name) ) return nullptr; 246 PRINT( std::cerr << "typename..." << name << std::endl; ) 247 return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq ); 248 } 249 250 ast::Type * Demangler::parseType() { 251 if (done()) return nullptr; 252 253 if (isPrefix(Encoding::forall)) { 254 PRINT( std::cerr << "polymorphic with..." << std::endl; ) 255 size_t dcount, fcount, vcount, acount; 256 if ( !extractNumber(dcount) ) return nullptr; 257 PRINT( std::cerr << dcount << " dtypes" << std::endl; ) 258 if ( !expect('_') ) return nullptr; 259 if ( !extractNumber(fcount) ) return nullptr; 260 PRINT( std::cerr << fcount << " ftypes" << std::endl; ) 261 if ( !expect('_')) return nullptr; 262 if ( !extractNumber(vcount)) return nullptr; 263 PRINT( std::cerr << vcount << " ttypes" << std::endl; ) 264 if ( !expect('_') ) return nullptr; 265 if ( !extractNumber(acount) ) return nullptr; 266 PRINT( std::cerr << acount << " assertions" << std::endl; ) 267 if ( !expect('_') ) return nullptr; 268 for ( size_t i = 0 ; i < acount ; ++i ) { 269 // TODO: need to recursively parse assertions, but for now just return nullptr so that 270 // demangler does not crash if there are assertions 271 return nullptr; 228 272 } 229 } 230 231 std::string GenType::handleGeneric( ReferenceToType * refType ) { 232 if ( ! refType->parameters.empty() ) { 233 std::ostringstream os; 234 // TODO: ??? 235 // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 236 os << "("; 237 // cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() ); 238 os << ") "; 239 return os.str(); 240 } 241 return ""; 242 } 243 244 void GenType::postvisit( StructInstType * structInst ) { 245 typeString = "struct " + structInst->name + handleGeneric( structInst ) + " " + typeString; 246 handleQualifiers( structInst ); 247 } 248 249 void GenType::postvisit( UnionInstType * unionInst ) { 250 typeString = "union " + unionInst->name + handleGeneric( unionInst ) + " " + typeString; 251 handleQualifiers( unionInst ); 252 } 253 254 void GenType::postvisit( EnumInstType * enumInst ) { 255 typeString = "enum " + enumInst->name + " " + typeString; 256 handleQualifiers( enumInst ); 257 } 258 259 void GenType::postvisit( TypeInstType * typeInst ) { 260 typeString = typeInst->name + " " + typeString; 261 handleQualifiers( typeInst ); 262 } 263 264 void GenType::postvisit( TupleType * tupleType ) { 265 unsigned int i = 0; 266 std::ostringstream os; 267 os << "["; 268 for ( Type * t : *tupleType ) { 269 i++; 270 os << genDemangleType( t, "" ) << (i == tupleType->size() ? "" : ", "); 271 } 272 os << "] "; 273 typeString = os.str() + typeString; 274 } 275 276 void GenType::postvisit( VarArgsType * varArgsType ) { 277 typeString = "__builtin_va_list " + typeString; 278 handleQualifiers( varArgsType ); 279 } 280 281 void GenType::postvisit( ZeroType * zeroType ) { 282 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 283 typeString = "zero_t " + typeString; 284 handleQualifiers( zeroType ); 285 } 286 287 void GenType::postvisit( OneType * oneType ) { 288 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 289 typeString = "one_t " + typeString; 290 handleQualifiers( oneType ); 291 } 292 293 void GenType::postvisit( GlobalScopeType * globalType ) { 294 handleQualifiers( globalType ); 295 } 296 297 void GenType::postvisit( QualifiedType * qualType ) { 298 std::ostringstream os; 299 os << genDemangleType( qualType->parent, "" ) << "." << genDemangleType( qualType->child, "" ) << typeString; 300 typeString = os.str(); 301 handleQualifiers( qualType ); 302 } 303 304 void GenType::handleQualifiers( Type * type ) { 305 if ( type->get_const() ) { 306 typeString = "const " + typeString; 307 } // if 308 if ( type->get_volatile() ) { 309 typeString = "volatile " + typeString; 310 } // if 311 if ( type->get_restrict() ) { 312 typeString = "__restrict " + typeString; 313 } // if 314 if ( type->get_atomic() ) { 315 typeString = "_Atomic " + typeString; 316 } // if 317 } 318 } 319 320 321 namespace SymTab { 322 namespace Mangler { 323 namespace { 324 struct StringView { 325 private: 326 std::string str; 327 size_t idx = 0; 328 // typedef Type * (StringView::*parser)(Type::Qualifiers); 329 typedef std::function<Type * (Type::Qualifiers)> parser; 330 std::vector<std::pair<std::string, parser>> parsers; 331 public: 332 StringView(const std::string & str); 333 334 bool done() const { return idx >= str.size(); } 335 char cur() const { assert(! done()); return str[idx]; } 336 337 bool expect(char ch) { return str[idx++] == ch; } 338 void next(size_t inc = 1) { idx += inc; } 339 340 /// determines if `pref` is a prefix of `str` 341 bool isPrefix(const std::string & pref); 342 bool extractNumber(size_t & out); 343 bool extractName(std::string & out); 344 bool stripMangleName(std::string & name); 345 346 Type * parseFunction(Type::Qualifiers tq); 347 Type * parseTuple(Type::Qualifiers tq); 348 Type * parseVoid(Type::Qualifiers tq); 349 Type * parsePointer(Type::Qualifiers tq); 350 Type * parseArray(Type::Qualifiers tq); 351 Type * parseStruct(Type::Qualifiers tq); 352 Type * parseUnion(Type::Qualifiers tq); 353 Type * parseEnum(Type::Qualifiers tq); 354 Type * parseType(Type::Qualifiers tq); 355 356 Type * parseType(); 357 bool parse(std::string & name, Type *& type); 358 }; 359 360 StringView::StringView(const std::string & str) : str(str) { 361 // basic types 362 for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) { 363 parsers.emplace_back(Encoding::basicTypes[k], [k](Type::Qualifiers tq) { 364 PRINT( std::cerr << "basic type: " << k << std::endl; ) 365 return new BasicType(tq, (BasicType::Kind)k); 366 }); 367 } 368 // type variable types 369 for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) { 370 static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", }; 371 static_assert( 372 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS, 373 "Each type variable kind should have a demangle name prefix" 374 ); 375 parsers.emplace_back(Encoding::typeVariables[k], [k, this](Type::Qualifiers tq) -> TypeInstType * { 376 PRINT( std::cerr << "type variable type: " << k << std::endl; ) 377 size_t N; 378 if (! extractNumber(N)) return nullptr; 379 return new TypeInstType(tq, toString(typeVariableNames[k], N), (TypeDecl::Kind)k != TypeDecl::Ftype); 380 }); 381 } 382 // everything else 383 parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); }); 384 parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); }); 385 parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); }); 386 parsers.emplace_back(Encoding::array, [this](Type::Qualifiers tq) { return parseArray(tq); }); 387 parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); }); 388 parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); }); 389 parsers.emplace_back(Encoding::union_t, [this](Type::Qualifiers tq) { return parseUnion(tq); }); 390 parsers.emplace_back(Encoding::enum_t, [this](Type::Qualifiers tq) { return parseEnum(tq); }); 391 parsers.emplace_back(Encoding::type, [this](Type::Qualifiers tq) { return parseType(tq); }); 392 parsers.emplace_back(Encoding::zero, [](Type::Qualifiers tq) { return new ZeroType(tq); }); 393 parsers.emplace_back(Encoding::one, [](Type::Qualifiers tq) { return new OneType(tq); }); 394 } 395 396 bool StringView::extractNumber(size_t & out) { 397 std::stringstream numss; 398 if (idx >= str.size()) return false; 399 while (isdigit(str[idx])) { 400 numss << str[idx]; 401 ++idx; 402 if (idx == str.size()) break; 403 } 404 if (! (numss >> out)) return false; 405 PRINT( std::cerr << "extractNumber success: " << out << std::endl; ) 406 return true; 407 } 408 409 bool StringView::extractName(std::string & out) { 410 size_t len; 411 if (! extractNumber(len)) return false; 412 if (idx+len > str.size()) return false; 413 out = str.substr(idx, len); 414 idx += len; 415 PRINT( std::cerr << "extractName success: " << out << std::endl; ) 416 return true; 417 } 418 419 bool StringView::isPrefix(const std::string & pref) { 420 // if ( pref.size() > str.size()-idx ) return false; 421 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) ); 422 // if (its.first == pref.end()) { 423 // idx += pref.size(); 424 // return true; 425 // } 426 427 // This update is untested because there are no tests for this code. 428 if ( ::isPrefix( str, pref, idx ) ) { 429 idx += pref.size(); 430 return true; 431 } 432 return false; 433 } 434 435 // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise 436 bool StringView::stripMangleName(std::string & name) { 437 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; ) 438 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix 439 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false; 440 441 // get name 442 if (! extractName(name)) return false; 443 444 // find bounds for type 445 PRINT( std::cerr << idx << " " << str.size() << std::endl; ) 446 PRINT( std::cerr << "["); 447 while (isdigit(str.back())) { 448 PRINT(std::cerr << "."); 449 str.pop_back(); 450 if (str.size() <= idx) return false; 451 } 452 PRINT( std::cerr << "]" << std::endl ); 453 if (str.back() != '_') return false; 454 str.pop_back(); 455 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; ) 456 return str.size() > idx; 457 } 458 459 Type * StringView::parseFunction(Type::Qualifiers tq) { 460 PRINT( std::cerr << "function..." << std::endl; ) 461 if (done()) return nullptr; 462 FunctionType * ftype = new FunctionType( tq, false ); 463 std::unique_ptr<Type> manager(ftype); 464 Type * retVal = parseType(); 465 if (! retVal) return nullptr; 466 PRINT( std::cerr << "with return type: " << retVal << std::endl; ) 467 ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr)); 468 if (done() || ! expect('_')) return nullptr; 469 while (! done()) { 470 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 471 if (cur() == '_') return manager.release(); 472 Type * param = parseType(); 473 if (! param) return nullptr; 474 PRINT( std::cerr << "with parameter : " << param << std::endl; ) 475 ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr)); 476 } 477 return nullptr; 478 } 479 480 Type * StringView::parseTuple(Type::Qualifiers tq) { 481 PRINT( std::cerr << "tuple..." << std::endl; ) 482 std::list< Type * > types; 483 size_t ncomponents; 484 if (! extractNumber(ncomponents)) return nullptr; 485 for (size_t i = 0; i < ncomponents; ++i) { 486 // TODO: delete all on return 487 if (done()) return nullptr; 488 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 489 Type * t = parseType(); 490 if (! t) return nullptr; 491 PRINT( std::cerr << "with type : " << t << std::endl; ) 492 types.push_back(t); 493 } 494 return new TupleType( tq, types ); 495 } 496 497 Type * StringView::parseVoid(Type::Qualifiers tq) { 498 return new VoidType( tq ); 499 } 500 501 Type * StringView::parsePointer(Type::Qualifiers tq) { 502 PRINT( std::cerr << "pointer..." << std::endl; ) 503 Type * t = parseType(); 504 if (! t) return nullptr; 505 return new PointerType( tq, t ); 506 } 507 508 Type * StringView::parseArray(Type::Qualifiers tq) { 509 PRINT( std::cerr << "array..." << std::endl; ) 510 size_t length; 511 if (! extractNumber(length)) return nullptr; 512 Type * t = parseType(); 513 if (! t) return nullptr; 514 return new ArrayType( tq, t, new ConstantExpr( Constant::from_ulong(length) ), false, false ); 515 } 516 517 Type * StringView::parseStruct(Type::Qualifiers tq) { 518 PRINT( std::cerr << "struct..." << std::endl; ) 519 std::string name; 520 if (! extractName(name)) return nullptr; 521 return new StructInstType(tq, name); 522 } 523 524 Type * StringView::parseUnion(Type::Qualifiers tq) { 525 PRINT( std::cerr << "union..." << std::endl; ) 526 std::string name; 527 if (! extractName(name)) return nullptr; 528 return new UnionInstType(tq, name); 529 } 530 531 Type * StringView::parseEnum(Type::Qualifiers tq) { 532 PRINT( std::cerr << "enum..." << std::endl; ) 533 std::string name; 534 if (! extractName(name)) return nullptr; 535 return new EnumInstType(tq, name); 536 } 537 538 Type * StringView::parseType(Type::Qualifiers tq) { 539 PRINT( std::cerr << "type..." << std::endl; ) 540 std::string name; 541 if (! extractName(name)) return nullptr; 542 PRINT( std::cerr << "typename..." << name << std::endl; ) 543 return new TypeInstType(tq, name, false); 544 } 545 546 Type * StringView::parseType() { 547 if (done()) return nullptr; 548 549 std::list<TypeDecl *> forall; 550 if (isPrefix(Encoding::forall)) { 551 PRINT( std::cerr << "polymorphic with..." << std::endl; ) 552 size_t dcount, fcount, vcount, acount; 553 if (! extractNumber(dcount)) return nullptr; 554 PRINT( std::cerr << dcount << " dtypes" << std::endl; ) 555 if (! expect('_')) return nullptr; 556 if (! extractNumber(fcount)) return nullptr; 557 PRINT( std::cerr << fcount << " ftypes" << std::endl; ) 558 if (! expect('_')) return nullptr; 559 if (! extractNumber(vcount)) return nullptr; 560 PRINT( std::cerr << vcount << " ttypes" << std::endl; ) 561 if (! expect('_')) return nullptr; 562 if (! extractNumber(acount)) return nullptr; 563 PRINT( std::cerr << acount << " assertions" << std::endl; ) 564 if (! expect('_')) return nullptr; 565 for (size_t i = 0; i < acount; ++i) { 566 // TODO: need to recursively parse assertions, but for now just return nullptr so that 567 // demangler does not crash if there are assertions 568 return nullptr; 569 } 570 if (! expect('_')) return nullptr; 571 } 572 573 // qualifiers 574 Type::Qualifiers tq; 575 while (true) { 576 auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) { 577 return isPrefix(val.second); 578 }); 579 if (qual == Encoding::qualifiers.end()) break; 580 tq |= qual->first; 581 } 582 583 // find the correct type parser and use it 584 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) { 585 return isPrefix(p.first); 586 }); 587 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx); 588 Type * ret = iter->second(tq); 589 if (! ret) return nullptr; 590 ret->forall = std::move(forall); 591 return ret; 592 } 593 594 bool StringView::parse(std::string & name, Type *& type) { 595 if (! stripMangleName(name)) return false; 596 PRINT( std::cerr << "stripped name: " << name << std::endl; ) 597 Type * t = parseType(); 598 if (! t) return false; 599 type = t; 600 return true; 601 } 602 603 std::string demangle(const std::string & mangleName) { 604 SymTab::Mangler::StringView view(mangleName); 605 std::string name; 606 Type * type = nullptr; 607 if (! view.parse(name, type)) return mangleName; 608 auto info = CodeGen::operatorLookupByOutput(name); 609 if (info) name = info->inputName; 610 std::unique_ptr<Type> manager(type); 611 return genDemangleType(type, name); 612 } 613 } // namespace 614 } // namespace Mangler 615 } // namespace SymTab 273 if ( !expect('_') ) return nullptr; 274 } 275 276 ast::CV::Qualifiers tq; 277 while (true) { 278 auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) { 279 return isPrefix(val.second); 280 }); 281 if (qual == Encoding::qualifiers.end()) break; 282 tq |= qual->first; 283 } 284 285 // Find the correct type parser and then apply it. 286 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) { 287 return isPrefix(p.first); 288 }); 289 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index); 290 ast::Type * ret = iter->second(tq); 291 if ( !ret ) return nullptr; 292 return ret; 293 } 294 295 bool Demangler::parse( std::string & name, ast::Type *& type) { 296 if ( !stripMangleName(name) ) return false; 297 PRINT( std::cerr << "stripped name: " << name << std::endl; ) 298 ast::Type * t = parseType(); 299 if ( !t ) return false; 300 type = t; 301 return true; 302 } 303 304 std::string demangle( const std::string & mangleName ) { 305 using namespace CodeGen; 306 Demangler demangler( mangleName ); 307 std::string name; 308 ast::Type * type = nullptr; 309 if ( !demangler.parse( name, type ) ) return mangleName; 310 ast::readonly<ast::Type> roType = type; 311 if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName; 312 return genType( type, name, Options( false, false, false, false ) ); 313 } 314 315 } // namespace 316 317 } // namespace Mangle 616 318 617 319 extern "C" { 618 320 char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) { 619 const std::string & demangleName = SymTab::Mangler::demangle(mangleName);321 const std::string & demangleName = Mangle::demangle(mangleName); 620 322 return strdup(demangleName.c_str()); 621 323 } -
src/SymTab/FixFunction.cc
rdf8ba61a r8d182b1 22 22 #include "AST/Type.hpp" 23 23 #include "Common/utility.h" // for copy 24 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarati...25 #include "SynTree/Expression.h" // for Expression26 #include "SynTree/Type.h" // for ArrayType, PointerType, Type, Basic...27 24 28 25 namespace SymTab { 29 class FixFunction_old : public WithShortCircuiting {30 typedef Mutator Parent;31 public:32 FixFunction_old() : isVoid( false ) {}33 34 void premutate(FunctionDecl *functionDecl);35 DeclarationWithType* postmutate(FunctionDecl *functionDecl);36 37 Type * postmutate(ArrayType * arrayType);38 39 void premutate(ArrayType * arrayType);40 void premutate(VoidType * voidType);41 void premutate(BasicType * basicType);42 void premutate(PointerType * pointerType);43 void premutate(StructInstType * aggregateUseType);44 void premutate(UnionInstType * aggregateUseType);45 void premutate(EnumInstType * aggregateUseType);46 void premutate(TraitInstType * aggregateUseType);47 void premutate(TypeInstType * aggregateUseType);48 void premutate(TupleType * tupleType);49 void premutate(VarArgsType * varArgsType);50 void premutate(ZeroType * zeroType);51 void premutate(OneType * oneType);52 53 bool isVoid;54 };55 56 DeclarationWithType * FixFunction_old::postmutate(FunctionDecl *functionDecl) {57 // can't delete function type because it may contain assertions, so transfer ownership to new object58 ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes );59 pointer->location = functionDecl->location;60 functionDecl->attributes.clear();61 functionDecl->type = nullptr;62 delete functionDecl;63 return pointer;64 }65 66 // xxx - this passes on void[], e.g.67 // void foo(void [10]);68 // does not cause an error69 70 Type * FixFunction_old::postmutate(ArrayType *arrayType) {71 // need to recursively mutate the base type in order for multi-dimensional arrays to work.72 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic );73 pointerType->location = arrayType->location;74 arrayType->base = nullptr;75 arrayType->dimension = nullptr;76 delete arrayType;77 return pointerType;78 }79 80 void FixFunction_old::premutate(VoidType *) {81 isVoid = true;82 }83 84 void FixFunction_old::premutate(FunctionDecl *) { visit_children = false; }85 void FixFunction_old::premutate(ArrayType *) { visit_children = false; }86 void FixFunction_old::premutate(BasicType *) { visit_children = false; }87 void FixFunction_old::premutate(PointerType *) { visit_children = false; }88 void FixFunction_old::premutate(StructInstType *) { visit_children = false; }89 void FixFunction_old::premutate(UnionInstType *) { visit_children = false; }90 void FixFunction_old::premutate(EnumInstType *) { visit_children = false; }91 void FixFunction_old::premutate(TraitInstType *) { visit_children = false; }92 void FixFunction_old::premutate(TypeInstType *) { visit_children = false; }93 void FixFunction_old::premutate(TupleType *) { visit_children = false; }94 void FixFunction_old::premutate(VarArgsType *) { visit_children = false; }95 void FixFunction_old::premutate(ZeroType *) { visit_children = false; }96 void FixFunction_old::premutate(OneType *) { visit_children = false; }97 98 bool fixFunction( DeclarationWithType *& dwt ) {99 PassVisitor<FixFunction_old> fixer;100 dwt = dwt->acceptMutator( fixer );101 return fixer.pass.isVoid;102 }103 26 104 27 namespace { 105 struct FixFunction _newfinal : public ast::WithShortCircuiting {28 struct FixFunction final : public ast::WithShortCircuiting { 106 29 bool isVoid = false; 107 30 … … 147 70 148 71 const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ) { 149 ast::Pass< FixFunction _new> fixer;72 ast::Pass< FixFunction > fixer; 150 73 dwt = dwt->accept( fixer ); 151 74 isVoid |= fixer.core.isVoid; … … 154 77 155 78 const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ) { 156 ast::Pass< FixFunction _new> fixer;79 ast::Pass< FixFunction > fixer; 157 80 type = type->accept( fixer ); 158 81 isVoid |= fixer.core.isVoid; -
src/SymTab/FixFunction.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include "Common/PassVisitor.h" // for PassVisitor19 #include "SynTree/SynTree.h" // for Types20 21 18 namespace ast { 22 19 class DeclWithType; … … 25 22 26 23 namespace SymTab { 27 /// Replaces function and array types by equivalent pointer types. Returns true if type is28 /// void29 bool fixFunction( DeclarationWithType *& );30 31 24 /// Returns declaration with function and array types replaced by equivalent pointer types. 32 25 /// Sets isVoid to true if type is void -
src/SymTab/GenImplicitCall.cpp
rdf8ba61a r8d182b1 32 32 template< typename OutIter > 33 33 ast::ptr< ast::Stmt > genCall( 34 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,34 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 35 35 const CodeLocation & loc, const std::string & fname, OutIter && out, 36 36 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward ); … … 42 42 template< typename OutIter > 43 43 ast::ptr< ast::Stmt > genScalarCall( 44 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,44 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 45 45 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 46 46 const ast::Type * addCast = nullptr … … 98 98 template< typename OutIter > 99 99 void genArrayCall( 100 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,100 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 101 101 const CodeLocation & loc, const std::string & fname, OutIter && out, 102 102 const ast::ArrayType * array, const ast::Type * addCast = nullptr, … … 167 167 template< typename OutIter > 168 168 ast::ptr< ast::Stmt > genCall( 169 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,169 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 170 170 const CodeLocation & loc, const std::string & fname, OutIter && out, 171 171 const ast::Type * type, const ast::Type * addCast, LoopDirection forward … … 185 185 186 186 ast::ptr< ast::Stmt > genImplicitCall( 187 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,187 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 188 188 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 189 189 LoopDirection forward -
src/SymTab/GenImplicitCall.hpp
rdf8ba61a r8d182b1 26 26 /// dstParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. 27 27 ast::ptr<ast::Stmt> genImplicitCall( 28 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,28 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 29 29 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 30 30 LoopDirection forward = LoopForward -
src/SymTab/Mangler.cc
rdf8ba61a r8d182b1 24 24 #include "AST/Pass.hpp" 25 25 #include "CodeGen/OperatorTable.h" // for OperatorInfo, operatorLookup 26 #include "Common/PassVisitor.h"27 26 #include "Common/ToString.hpp" // for toCString 28 27 #include "Common/SemanticError.h" // for SemanticError 29 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment30 #include "SynTree/LinkageSpec.h" // for Spec, isOverridable, AutoGen, Int...31 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType32 #include "SynTree/Expression.h" // for TypeExpr, Expression, operator<<33 #include "SynTree/Type.h" // for Type, ReferenceToType, Type::Fora...34 35 namespace SymTab {36 namespace Mangler {37 namespace {38 /// Mangles names to a unique C identifier39 struct Mangler_old : public WithShortCircuiting, public WithVisitorRef<Mangler_old>, public WithGuards {40 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams );41 Mangler_old( const Mangler_old & ) = delete;42 43 void previsit( const BaseSyntaxNode * ) { visit_children = false; }44 45 void postvisit( const ObjectDecl * declaration );46 void postvisit( const FunctionDecl * declaration );47 void postvisit( const TypeDecl * declaration );48 49 void postvisit( const VoidType * voidType );50 void postvisit( const BasicType * basicType );51 void postvisit( const PointerType * pointerType );52 void postvisit( const ArrayType * arrayType );53 void postvisit( const ReferenceType * refType );54 void postvisit( const FunctionType * functionType );55 void postvisit( const StructInstType * aggregateUseType );56 void postvisit( const UnionInstType * aggregateUseType );57 void postvisit( const EnumInstType * aggregateUseType );58 void postvisit( const TypeInstType * aggregateUseType );59 void postvisit( const TraitInstType * inst );60 void postvisit( const TupleType * tupleType );61 void postvisit( const VarArgsType * varArgsType );62 void postvisit( const ZeroType * zeroType );63 void postvisit( const OneType * oneType );64 void postvisit( const QualifiedType * qualType );65 66 std::string get_mangleName() { return mangleName; }67 private:68 std::string mangleName; ///< Mangled name being constructed69 typedef std::map< std::string, std::pair< int, int > > VarMapType;70 VarMapType varNums; ///< Map of type variables to indices71 int nextVarNum; ///< Next type variable index72 bool isTopLevel; ///< Is the Mangler at the top level73 bool mangleOverridable; ///< Specially mangle overridable built-in methods74 bool typeMode; ///< Produce a unique mangled name for a type75 bool mangleGenericParams; ///< Include generic parameters in name mangling if true76 bool inFunctionType = false; ///< Include type qualifiers if false.77 bool inQualifiedType = false; ///< Add start/end delimiters around qualified type78 79 public:80 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,81 int nextVarNum, const VarMapType& varNums );82 83 private:84 void mangleDecl( const DeclarationWithType * declaration );85 void mangleRef( const ReferenceToType * refType, std::string prefix );86 87 void printQualifiers( const Type *type );88 }; // Mangler_old89 } // namespace90 91 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {92 PassVisitor<Mangler_old> mangler( mangleOverridable, typeMode, mangleGenericParams );93 maybeAccept( decl, mangler );94 return mangler.pass.get_mangleName();95 }96 97 std::string mangleType( const Type * ty ) {98 PassVisitor<Mangler_old> mangler( false, true, true );99 maybeAccept( ty, mangler );100 return mangler.pass.get_mangleName();101 }102 103 std::string mangleConcrete( const Type * ty ) {104 PassVisitor<Mangler_old> mangler( false, false, false );105 maybeAccept( ty, mangler );106 return mangler.pass.get_mangleName();107 }108 109 namespace {110 Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams )111 : nextVarNum( 0 ), isTopLevel( true ),112 mangleOverridable( mangleOverridable ), typeMode( typeMode ),113 mangleGenericParams( mangleGenericParams ) {}114 115 Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,116 int nextVarNum, const VarMapType& varNums )117 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),118 mangleOverridable( mangleOverridable ), typeMode( typeMode ),119 mangleGenericParams( mangleGenericParams ) {}120 121 void Mangler_old::mangleDecl( const DeclarationWithType * declaration ) {122 bool wasTopLevel = isTopLevel;123 if ( isTopLevel ) {124 varNums.clear();125 nextVarNum = 0;126 isTopLevel = false;127 } // if128 mangleName += Encoding::manglePrefix;129 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );130 if ( opInfo ) {131 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;132 } else {133 mangleName += std::to_string( declaration->name.size() ) + declaration->name;134 } // if135 maybeAccept( declaration->get_type(), *visitor );136 if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {137 // want to be able to override autogenerated and intrinsic routines,138 // so they need a different name mangling139 if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {140 mangleName += Encoding::autogen;141 } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {142 mangleName += Encoding::intrinsic;143 } else {144 // if we add another kind of overridable function, this has to change145 assert( false && "unknown overrideable linkage" );146 } // if147 }148 isTopLevel = wasTopLevel;149 }150 151 void Mangler_old::postvisit( const ObjectDecl * declaration ) {152 mangleDecl( declaration );153 }154 155 void Mangler_old::postvisit( const FunctionDecl * declaration ) {156 mangleDecl( declaration );157 }158 159 void Mangler_old::postvisit( const VoidType * voidType ) {160 printQualifiers( voidType );161 mangleName += Encoding::void_t;162 }163 164 void Mangler_old::postvisit( const BasicType * basicType ) {165 printQualifiers( basicType );166 assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );167 mangleName += Encoding::basicTypes[ basicType->kind ];168 }169 170 void Mangler_old::postvisit( const PointerType * pointerType ) {171 printQualifiers( pointerType );172 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers173 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer;174 maybeAccept( pointerType->base, *visitor );175 }176 177 void Mangler_old::postvisit( const ArrayType * arrayType ) {178 // TODO: encode dimension179 printQualifiers( arrayType );180 mangleName += Encoding::array + "0";181 maybeAccept( arrayType->base, *visitor );182 }183 184 void Mangler_old::postvisit( const ReferenceType * refType ) {185 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.186 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),187 // by pretending every reference type is a function parameter.188 GuardValue( inFunctionType );189 inFunctionType = true;190 printQualifiers( refType );191 maybeAccept( refType->base, *visitor );192 }193 194 namespace {195 inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {196 std::list< Type* > ret;197 std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),198 std::mem_fun( &DeclarationWithType::get_type ) );199 return ret;200 }201 }202 203 void Mangler_old::postvisit( const FunctionType * functionType ) {204 printQualifiers( functionType );205 mangleName += Encoding::function;206 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,207 // since qualifiers on outermost parameter type do not differentiate function types, e.g.,208 // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different209 GuardValue( inFunctionType );210 inFunctionType = true;211 std::list< Type* > returnTypes = getTypes( functionType->returnVals );212 if (returnTypes.empty()) mangleName += Encoding::void_t;213 else acceptAll( returnTypes, *visitor );214 mangleName += "_";215 std::list< Type* > paramTypes = getTypes( functionType->parameters );216 acceptAll( paramTypes, *visitor );217 mangleName += "_";218 }219 220 void Mangler_old::mangleRef( const ReferenceToType * refType, std::string prefix ) {221 printQualifiers( refType );222 223 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;224 225 if ( mangleGenericParams ) {226 const std::list< Expression* > & params = refType->parameters;227 if ( ! params.empty() ) {228 mangleName += "_";229 for ( const Expression * param : params ) {230 const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param );231 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));232 maybeAccept( paramType->type, *visitor );233 }234 mangleName += "_";235 }236 }237 }238 239 void Mangler_old::postvisit( const StructInstType * aggregateUseType ) {240 mangleRef( aggregateUseType, Encoding::struct_t );241 }242 243 void Mangler_old::postvisit( const UnionInstType * aggregateUseType ) {244 mangleRef( aggregateUseType, Encoding::union_t );245 }246 247 void Mangler_old::postvisit( const EnumInstType * aggregateUseType ) {248 mangleRef( aggregateUseType, Encoding::enum_t );249 }250 251 void Mangler_old::postvisit( const TypeInstType * typeInst ) {252 VarMapType::iterator varNum = varNums.find( typeInst->get_name() );253 if ( varNum == varNums.end() ) {254 mangleRef( typeInst, Encoding::type );255 } else {256 printQualifiers( typeInst );257 // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.258 // forall(dtype T) void f(T);259 // forall(dtype S) void f(S);260 // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they261 // are first found and prefixing with the appropriate encoding for the type class.262 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );263 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );264 } // if265 }266 267 void Mangler_old::postvisit( const TraitInstType * inst ) {268 printQualifiers( inst );269 mangleName += std::to_string( inst->name.size() ) + inst->name;270 }271 272 void Mangler_old::postvisit( const TupleType * tupleType ) {273 printQualifiers( tupleType );274 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );275 acceptAll( tupleType->types, *visitor );276 }277 278 void Mangler_old::postvisit( const VarArgsType * varArgsType ) {279 printQualifiers( varArgsType );280 static const std::string vargs = "__builtin_va_list";281 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;282 }283 284 void Mangler_old::postvisit( const ZeroType * ) {285 mangleName += Encoding::zero;286 }287 288 void Mangler_old::postvisit( const OneType * ) {289 mangleName += Encoding::one;290 }291 292 void Mangler_old::postvisit( const QualifiedType * qualType ) {293 bool inqual = inQualifiedType;294 if (! inqual ) {295 // N marks the start of a qualified type296 inQualifiedType = true;297 mangleName += Encoding::qualifiedTypeStart;298 }299 maybeAccept( qualType->parent, *visitor );300 maybeAccept( qualType->child, *visitor );301 if ( ! inqual ) {302 // E marks the end of a qualified type303 inQualifiedType = false;304 mangleName += Encoding::qualifiedTypeEnd;305 }306 }307 308 void Mangler_old::postvisit( const TypeDecl * decl ) {309 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be310 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.311 // Note: The current scheme may already work correctly for this case, I have not thought about this deeply312 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed313 // aside from the assert false.314 assertf( false, "Mangler_old should not visit typedecl: %s", toCString(decl));315 assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );316 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;317 }318 319 __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {320 for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {321 os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;322 } // for323 }324 325 void Mangler_old::printQualifiers( const Type * type ) {326 // skip if not including qualifiers327 if ( typeMode ) return;328 if ( ! type->forall.empty() ) {329 std::list< std::string > assertionNames;330 int dcount = 0, fcount = 0, vcount = 0, acount = 0;331 mangleName += Encoding::forall;332 for ( const TypeDecl * i : type->forall ) {333 switch ( i->kind ) {334 case TypeDecl::Dtype:335 dcount++;336 break;337 case TypeDecl::Ftype:338 fcount++;339 break;340 case TypeDecl::Ttype:341 vcount++;342 break;343 default:344 assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[i->kind].c_str() );345 } // switch346 varNums[ i->name ] = std::make_pair( nextVarNum, (int)i->kind );347 for ( const DeclarationWithType * assert : i->assertions ) {348 PassVisitor<Mangler_old> sub_mangler(349 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );350 assert->accept( sub_mangler );351 assertionNames.push_back( sub_mangler.pass.get_mangleName() );352 acount++;353 } // for354 } // for355 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";356 for(const auto & a : assertionNames) mangleName += a;357 // std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );358 mangleName += "_";359 } // if360 if ( ! inFunctionType ) {361 // these qualifiers do not distinguish the outermost type of a function parameter362 if ( type->get_const() ) {363 mangleName += Encoding::qualifiers.at(Type::Const);364 } // if365 if ( type->get_volatile() ) {366 mangleName += Encoding::qualifiers.at(Type::Volatile);367 } // if368 // Removed due to restrict not affecting function compatibility in GCC369 // if ( type->get_isRestrict() ) {370 // mangleName += "E";371 // } // if372 if ( type->get_atomic() ) {373 mangleName += Encoding::qualifiers.at(Type::Atomic);374 } // if375 }376 if ( type->get_mutex() ) {377 mangleName += Encoding::qualifiers.at(Type::Mutex);378 } // if379 if ( inFunctionType ) {380 // turn off inFunctionType so that types can be differentiated for nested qualifiers381 GuardValue( inFunctionType );382 inFunctionType = false;383 }384 }385 } // namespace386 } // namespace Mangler387 } // namespace SymTab388 28 389 29 namespace Mangle { 390 30 namespace { 391 31 /// Mangles names to a unique C identifier 392 struct Mangler _new : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler_new>, public ast::WithGuards {393 Mangler _new( Mangle::Mode mode );394 Mangler _new( const Mangler_new& ) = delete;32 struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards { 33 Mangler( Mangle::Mode mode ); 34 Mangler( const Mangler & ) = delete; 395 35 396 36 void previsit( const ast::Node * ) { visit_children = false; } … … 432 72 433 73 private: 434 Mangler _new( bool mangleOverridable, bool typeMode, bool mangleGenericParams,74 Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 435 75 int nextVarNum, const VarMapType& varNums ); 436 friend class ast::Pass<Mangler _new>;76 friend class ast::Pass<Mangler>; 437 77 438 78 private: … … 441 81 442 82 void printQualifiers( const ast::Type *type ); 443 }; // Mangler _new83 }; // Mangler 444 84 } // namespace 445 85 446 86 std::string mangle( const ast::Node * decl, Mangle::Mode mode ) { 447 return ast::Pass<Mangler _new>::read( decl, mode );87 return ast::Pass<Mangler>::read( decl, mode ); 448 88 } 449 89 450 90 namespace { 451 Mangler _new::Mangler_new( Mangle::Mode mode )91 Mangler::Mangler( Mangle::Mode mode ) 452 92 : nextVarNum( 0 ), isTopLevel( true ), 453 93 mangleOverridable ( ! mode.no_overrideable ), … … 455 95 mangleGenericParams( ! mode.no_generic_params ) {} 456 96 457 Mangler _new::Mangler_new( bool mangleOverridable, bool typeMode, bool mangleGenericParams,97 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 458 98 int nextVarNum, const VarMapType& varNums ) 459 99 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ), … … 461 101 mangleGenericParams( mangleGenericParams ) {} 462 102 463 void Mangler _new::mangleDecl( const ast::DeclWithType * decl ) {103 void Mangler::mangleDecl( const ast::DeclWithType * decl ) { 464 104 bool wasTopLevel = isTopLevel; 465 105 if ( isTopLevel ) { … … 491 131 } 492 132 493 void Mangler _new::postvisit( const ast::ObjectDecl * decl ) {133 void Mangler::postvisit( const ast::ObjectDecl * decl ) { 494 134 mangleDecl( decl ); 495 135 } 496 136 497 void Mangler _new::postvisit( const ast::FunctionDecl * decl ) {137 void Mangler::postvisit( const ast::FunctionDecl * decl ) { 498 138 mangleDecl( decl ); 499 139 } 500 140 501 void Mangler _new::postvisit( const ast::VoidType * voidType ) {141 void Mangler::postvisit( const ast::VoidType * voidType ) { 502 142 printQualifiers( voidType ); 503 143 mangleName += Encoding::void_t; 504 144 } 505 145 506 void Mangler _new::postvisit( const ast::BasicType * basicType ) {146 void Mangler::postvisit( const ast::BasicType * basicType ) { 507 147 printQualifiers( basicType ); 508 148 assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind ); … … 510 150 } 511 151 512 void Mangler _new::postvisit( const ast::PointerType * pointerType ) {152 void Mangler::postvisit( const ast::PointerType * pointerType ) { 513 153 printQualifiers( pointerType ); 514 154 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers … … 517 157 } 518 158 519 void Mangler _new::postvisit( const ast::ArrayType * arrayType ) {159 void Mangler::postvisit( const ast::ArrayType * arrayType ) { 520 160 // TODO: encode dimension 521 161 printQualifiers( arrayType ); … … 524 164 } 525 165 526 void Mangler _new::postvisit( const ast::ReferenceType * refType ) {166 void Mangler::postvisit( const ast::ReferenceType * refType ) { 527 167 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload. 528 168 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.), … … 534 174 } 535 175 536 void Mangler _new::postvisit( const ast::FunctionType * functionType ) {176 void Mangler::postvisit( const ast::FunctionType * functionType ) { 537 177 printQualifiers( functionType ); 538 178 mangleName += Encoding::function; … … 549 189 } 550 190 551 void Mangler _new::mangleRef(191 void Mangler::mangleRef( 552 192 const ast::BaseInstType * refType, const std::string & prefix ) { 553 193 printQualifiers( refType ); … … 566 206 } 567 207 568 void Mangler _new::postvisit( const ast::StructInstType * aggregateUseType ) {208 void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) { 569 209 mangleRef( aggregateUseType, Encoding::struct_t ); 570 210 } 571 211 572 void Mangler _new::postvisit( const ast::UnionInstType * aggregateUseType ) {212 void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) { 573 213 mangleRef( aggregateUseType, Encoding::union_t ); 574 214 } 575 215 576 void Mangler _new::postvisit( const ast::EnumInstType * aggregateUseType ) {216 void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) { 577 217 mangleRef( aggregateUseType, Encoding::enum_t ); 578 218 } 579 219 580 void Mangler _new::postvisit( const ast::TypeInstType * typeInst ) {220 void Mangler::postvisit( const ast::TypeInstType * typeInst ) { 581 221 VarMapType::iterator varNum = varNums.find( typeInst->name ); 582 222 if ( varNum == varNums.end() ) { … … 594 234 } 595 235 596 void Mangler _new::postvisit( const ast::TraitInstType * inst ) {236 void Mangler::postvisit( const ast::TraitInstType * inst ) { 597 237 printQualifiers( inst ); 598 238 mangleName += std::to_string( inst->name.size() ) + inst->name; 599 239 } 600 240 601 void Mangler _new::postvisit( const ast::TupleType * tupleType ) {241 void Mangler::postvisit( const ast::TupleType * tupleType ) { 602 242 printQualifiers( tupleType ); 603 243 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() ); … … 605 245 } 606 246 607 void Mangler _new::postvisit( const ast::VarArgsType * varArgsType ) {247 void Mangler::postvisit( const ast::VarArgsType * varArgsType ) { 608 248 printQualifiers( varArgsType ); 609 249 static const std::string vargs = "__builtin_va_list"; … … 611 251 } 612 252 613 void Mangler _new::postvisit( const ast::ZeroType * ) {253 void Mangler::postvisit( const ast::ZeroType * ) { 614 254 mangleName += Encoding::zero; 615 255 } 616 256 617 void Mangler _new::postvisit( const ast::OneType * ) {257 void Mangler::postvisit( const ast::OneType * ) { 618 258 mangleName += Encoding::one; 619 259 } 620 260 621 void Mangler _new::postvisit( const ast::QualifiedType * qualType ) {261 void Mangler::postvisit( const ast::QualifiedType * qualType ) { 622 262 bool inqual = inQualifiedType; 623 263 if ( !inqual ) { … … 635 275 } 636 276 637 void Mangler _new::postvisit( const ast::TypeDecl * decl ) {277 void Mangler::postvisit( const ast::TypeDecl * decl ) { 638 278 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be 639 279 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa. … … 641 281 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed 642 282 // aside from the assert false. 643 assertf(false, "Mangler _newshould not visit typedecl: %s", toCString(decl));283 assertf(false, "Mangler should not visit typedecl: %s", toCString(decl)); 644 284 assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind ); 645 285 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name; … … 653 293 } 654 294 655 void Mangler _new::printQualifiers( const ast::Type * type ) {295 void Mangler::printQualifiers( const ast::Type * type ) { 656 296 // skip if not including qualifiers 657 297 if ( typeMode ) return; … … 678 318 } // for 679 319 for ( auto & assert : funcType->assertions ) { 680 assertionNames.push_back( ast::Pass<Mangler _new>::read(320 assertionNames.push_back( ast::Pass<Mangler>::read( 681 321 assert->var.get(), 682 322 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) ); -
src/SymTab/Mangler.h
rdf8ba61a r8d182b1 22 22 23 23 #include "AST/Bitfield.hpp" 24 #include "SynTree/SynTree.h" // for Types25 #include "SynTree/Visitor.h" // for Visitor, maybeAccept26 24 27 25 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling … … 35 33 class Node; 36 34 } 37 namespace ResolvExpr {38 class TypeEnvironment;39 }40 35 41 36 namespace SymTab { 42 37 namespace Mangler { 43 /// Mangle syntax tree object; primary interface to clients44 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );45 46 /// Mangle a type name; secondary interface47 std::string mangleType( const Type * ty );48 /// Mangle ignoring generic type parameters49 std::string mangleConcrete( const Type * ty );50 51 38 namespace Encoding { 52 39 extern const std::string manglePrefix; -
src/SymTab/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC_SYMTAB = \ 18 SymTab/Autogen.cc \19 SymTab/Autogen.h \20 18 SymTab/FixFunction.cc \ 21 19 SymTab/FixFunction.h \ 22 20 SymTab/GenImplicitCall.cpp \ 23 21 SymTab/GenImplicitCall.hpp \ 24 SymTab/Indexer.cc \25 SymTab/Indexer.h \26 22 SymTab/Mangler.cc \ 27 23 SymTab/ManglerCommon.cc \ 28 SymTab/Mangler.h \ 29 SymTab/ValidateType.cc \ 30 SymTab/ValidateType.h 24 SymTab/Mangler.h 31 25 32 SRC += $(SRC_SYMTAB) \ 33 SymTab/Validate.cc \ 34 SymTab/Validate.h 26 SRC += $(SRC_SYMTAB) 35 27 36 28 SRCDEMANGLE += $(SRC_SYMTAB) \ -
src/Tuples/Explode.cc
rdf8ba61a r8d182b1 15 15 16 16 #include "Explode.h" 17 #include <list> // for list18 17 19 18 #include "AST/Pass.hpp" // for Pass 20 #include "SynTree/Mutator.h" // for Mutator21 #include "Common/PassVisitor.h" // for PassVisitor22 19 23 20 namespace Tuples { 24 namespace {25 // remove one level of reference from a reference type -- may be useful elsewhere.26 Type * getReferenceBase( Type * t ) {27 if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) {28 return refType->get_base();29 } else {30 // for the moment, I want to know immediately if a non-reference type is ever passed in here.31 assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() );32 return nullptr;33 }34 }35 36 struct CastExploder {37 bool castAdded = false;38 bool foundUniqueExpr = false;39 Expression * applyCast( Expression * expr, bool first = true ) {40 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){41 foundUniqueExpr = true;42 std::list< Expression * > exprs;43 for ( Expression *& expr : tupleExpr->get_exprs() ) {44 // move cast into tuple exprs45 exprs.push_back( applyCast( expr, false ) );46 }47 // want the top-level expression to be cast to reference type, but not nested48 // tuple expressions49 if ( first ) {50 castAdded = true;51 Expression * tupleExpr = new TupleExpr( exprs );52 return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );53 } else {54 return new TupleExpr( exprs );55 }56 }57 if ( dynamic_cast<ReferenceType*>( expr->result ) ) {58 // don't need to cast reference type to another reference type59 return expr->clone();60 } else {61 // anything else should be cast to reference as normal62 castAdded = true;63 return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );64 }65 }66 67 Expression * postmutate( UniqueExpr * uniqueExpr ) {68 // move cast into unique expr so that the unique expr has type T& rather than69 // type T. In particular, this transformation helps with generating the70 // correct code for reference-cast member tuple expressions, since the result71 // should now be a tuple of references rather than a reference to a tuple.72 // Still, this code is a bit awkward, and could use some improvement.73 UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() );74 delete uniqueExpr;75 if ( castAdded ) {76 // if a cast was added by applyCast, then unique expr now has one more layer of reference77 // than it had coming into this function. To ensure types still match correctly, need to cast78 // to reference base so that outer expressions are still correct.79 castAdded = false;80 Type * toType = getReferenceBase( newUniqueExpr->result );81 return new CastExpr( newUniqueExpr, toType->clone() );82 }83 return newUniqueExpr;84 }85 86 87 Expression * postmutate( TupleIndexExpr * tupleExpr ) {88 // tuple index expr needs to be rebuilt to ensure that the type of the89 // field is consistent with the type of the tuple expr, since the field90 // may have changed from type T to T&.91 Expression * expr = tupleExpr->get_tuple();92 tupleExpr->set_tuple( nullptr );93 TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );94 delete tupleExpr;95 return ret;96 }97 };98 } // namespace99 100 Expression * distributeReference( Expression * expr ) {101 PassVisitor<CastExploder> exploder;102 expr = expr->acceptMutator( exploder );103 if ( ! exploder.pass.foundUniqueExpr ) {104 // if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate105 expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );106 }107 return expr;108 }109 21 110 22 namespace { -
src/Tuples/Explode.h
rdf8ba61a r8d182b1 20 20 21 21 #include "AST/Expr.hpp" 22 #include "ResolvExpr/Alternative.h" // for Alternative, AltList23 22 #include "ResolvExpr/Candidate.hpp" // for Candidate, CandidateList 24 #include "ResolvExpr/ExplodedActual.h" // for ExplodedActual25 23 #include "ResolvExpr/ExplodedArg.hpp" // for ExplodedArg 26 #include "SynTree/Expression.h" // for Expression, UniqueExpr, AddressExpr27 #include "SynTree/Type.h" // for TupleType, Type28 24 #include "Tuples.h" // for maybeImpure 29 25 … … 32 28 } 33 29 34 namespace SymTab {35 class Indexer;36 } // namespace SymTab37 38 30 namespace Tuples { 39 Expression * distributeReference( Expression * );40 41 static inline CastExpr * isReferenceCast( Expression * expr ) {42 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {43 if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) {44 return castExpr;45 }46 }47 return nullptr;48 }49 50 /// Append alternative to an OutputIterator of Alternatives51 template<typename OutputIterator>52 void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,53 const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,54 const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {55 *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };56 }57 58 /// Append alternative to an ExplodedActual59 static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,60 const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,61 const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {62 ea.exprs.emplace_back( expr );63 /// xxx -- merge environment, openVars, need, cost?64 }65 66 /// helper function used by explode67 template< typename Output >68 void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt,69 const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {70 if ( isTupleAssign ) {71 // tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components72 if ( CastExpr * castExpr = isReferenceCast( expr ) ) {73 ResolvExpr::AltList alts;74 explodeUnique(75 castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );76 for ( ResolvExpr::Alternative & alt : alts ) {77 // distribute reference cast over all components78 append( std::forward<Output>(out), distributeReference( alt.release_expr() ),79 alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );80 }81 // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)82 return;83 }84 }85 Type * res = expr->get_result()->stripReferences();86 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {87 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {88 // can open tuple expr and dump its exploded components89 for ( Expression * expr : tupleExpr->get_exprs() ) {90 explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );91 }92 } else {93 // tuple type, but not tuple expr - recursively index into its components.94 // if expr type is reference, convert to value type95 Expression * arg = expr->clone();96 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {97 // expressions which may contain side effects require a single unique instance of the expression.98 arg = new UniqueExpr( arg );99 }100 // cast reference to value type to facilitate further explosion101 if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {102 arg = new CastExpr( arg, tupleType->clone() );103 }104 for ( unsigned int i = 0; i < tupleType->size(); i++ ) {105 TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );106 explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );107 delete idx;108 }109 delete arg;110 }111 } else {112 // atomic (non-tuple) type - output a clone of the expression in a new alternative113 append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,114 alt.cost, alt.cvtCost );115 }116 }117 118 /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type119 template< typename Output >120 void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer,121 Output&& out, bool isTupleAssign = false ) {122 explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );123 }124 125 // explode list of alternatives126 template< typename AltIterator, typename Output >127 void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer,128 Output&& out, bool isTupleAssign = false ) {129 for ( ; altBegin != altEnd; ++altBegin ) {130 explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );131 }132 }133 134 template< typename Output >135 void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out,136 bool isTupleAssign = false ) {137 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );138 }139 31 140 32 const ast::Expr * distributeReference( const ast::Expr * ); -
src/Tuples/TupleAssignment.cc
rdf8ba61a r8d182b1 28 28 #include "AST/TypeEnvironment.hpp" 29 29 #include "CodeGen/OperatorTable.h" 30 #include "Common/PassVisitor.h"31 30 #include "Common/UniqueName.h" // for UniqueName 32 31 #include "Common/utility.h" // for splice, zipWith … … 34 33 #include "InitTweak/GenInit.h" // for genCtorInit 35 34 #include "InitTweak/InitTweak.h" // for getPointerBase, isAssignment 36 #include "ResolvExpr/Alternative.h" // for AltList, Alternative37 #include "ResolvExpr/AlternativeFinder.h" // for AlternativeFinder, simpleC...38 35 #include "ResolvExpr/Cost.h" // for Cost 39 36 #include "ResolvExpr/Resolver.h" // for resolveCtorInit 40 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment41 37 #include "ResolvExpr/typeops.h" // for combos 42 #include "SynTree/LinkageSpec.h" // for Cforall43 #include "SynTree/Declaration.h" // for ObjectDecl44 #include "SynTree/Expression.h" // for Expression, CastExpr, Name...45 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit46 #include "SynTree/Statement.h" // for ExprStmt47 #include "SynTree/Type.h" // for Type, Type::Qualifiers48 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution49 #include "SynTree/Visitor.h" // for Visitor50 38 51 39 #if 0 … … 56 44 57 45 namespace Tuples { 58 class TupleAssignSpotter_old {59 public:60 // dispatcher for Tuple (multiple and mass) assignment operations61 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );62 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );63 64 private:65 void match();66 67 struct Matcher {68 public:69 Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,70 const ResolvExpr::AltList& rhs );71 virtual ~Matcher() {}72 73 virtual void match( std::list< Expression * > &out ) = 0;74 ObjectDecl * newObject( UniqueName & namer, Expression * expr );75 76 void combineState( const ResolvExpr::Alternative& alt ) {77 compositeEnv.simpleCombine( alt.env );78 ResolvExpr::mergeOpenVars( openVars, alt.openVars );79 cloneAll( alt.need, need );80 }81 82 void combineState( const ResolvExpr::AltList& alts ) {83 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }84 }85 86 ResolvExpr::AltList lhs, rhs;87 TupleAssignSpotter_old &spotter;88 ResolvExpr::Cost baseCost;89 std::list< ObjectDecl * > tmpDecls;90 ResolvExpr::TypeEnvironment compositeEnv;91 ResolvExpr::OpenVarSet openVars;92 ResolvExpr::AssertionSet need;93 };94 95 struct MassAssignMatcher : public Matcher {96 public:97 MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,98 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}99 virtual void match( std::list< Expression * > &out );100 };101 102 struct MultipleAssignMatcher : public Matcher {103 public:104 MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,105 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}106 virtual void match( std::list< Expression * > &out );107 };108 109 ResolvExpr::AlternativeFinder ¤tFinder;110 std::string fname;111 std::unique_ptr< Matcher > matcher;112 };113 114 /// true if expr is an expression of tuple type115 bool isTuple( Expression *expr ) {116 if ( ! expr ) return false;117 assert( expr->result );118 return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );119 }120 121 template< typename AltIter >122 bool isMultAssign( AltIter begin, AltIter end ) {123 // multiple assignment if more than one alternative in the range or if124 // the alternative is a tuple125 if ( begin == end ) return false;126 if ( isTuple( begin->expr ) ) return true;127 return ++begin != end;128 }129 130 bool refToTuple( Expression *expr ) {131 assert( expr->get_result() );132 // also check for function returning tuple of reference types133 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {134 return refToTuple( castExpr->get_arg() );135 } else {136 return isTuple( expr );137 }138 return false;139 }140 141 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,142 std::vector<ResolvExpr::AlternativeFinder> &args ) {143 TupleAssignSpotter_old spotter( currentFinder );144 spotter.spot( expr, args );145 }146 147 TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )148 : currentFinder(f) {}149 150 void TupleAssignSpotter_old::spot( UntypedExpr * expr,151 std::vector<ResolvExpr::AlternativeFinder> &args ) {152 if ( NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {153 if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {154 fname = op->get_name();155 156 // AlternativeFinder will naturally handle this case case, if it's legal157 if ( args.size() == 0 ) return;158 159 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote160 // the function, in which case AlternativeFinder will handle it normally161 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;162 163 // look over all possible left-hand-sides164 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {165 // skip non-tuple LHS166 if ( ! refToTuple(lhsAlt.expr) ) continue;167 168 // explode is aware of casts - ensure every LHS expression is sent into explode169 // with a reference cast170 // xxx - this seems to change the alternatives before the normal171 // AlternativeFinder flow; maybe this is desired?172 if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {173 lhsAlt.expr = new CastExpr( lhsAlt.expr,174 new ReferenceType( Type::Qualifiers(),175 lhsAlt.expr->result->clone() ) );176 }177 178 // explode the LHS so that each field of a tuple-valued-expr is assigned179 ResolvExpr::AltList lhs;180 explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );181 for ( ResolvExpr::Alternative& alt : lhs ) {182 // each LHS value must be a reference - some come in with a cast expression,183 // if not just cast to reference here184 if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {185 alt.expr = new CastExpr( alt.expr,186 new ReferenceType( Type::Qualifiers(),187 alt.expr->get_result()->clone() ) );188 }189 }190 191 if ( args.size() == 1 ) {192 // mass default-initialization/destruction193 ResolvExpr::AltList rhs{};194 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );195 match();196 } else if ( args.size() > 2 ) {197 // expand all possible RHS possibilities198 // TODO build iterative version of this instead of using combos199 std::vector< ResolvExpr::AltList > rhsAlts;200 combos( std::next(args.begin(), 1), args.end(),201 std::back_inserter( rhsAlts ) );202 for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {203 // multiple assignment204 ResolvExpr::AltList rhs;205 explode( rhsAlt, currentFinder.get_indexer(),206 std::back_inserter(rhs), true );207 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );208 match();209 }210 } else {211 for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {212 ResolvExpr::AltList rhs;213 if ( isTuple(rhsAlt.expr) ) {214 // multiple assignment215 explode( rhsAlt, currentFinder.get_indexer(),216 std::back_inserter(rhs), true );217 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );218 } else {219 // mass assignment220 rhs.push_back( rhsAlt );221 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );222 }223 match();224 }225 }226 }227 }228 }229 }230 231 void TupleAssignSpotter_old::match() {232 assert ( matcher != 0 );233 234 std::list< Expression * > new_assigns;235 matcher->match( new_assigns );236 237 if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {238 // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.239 // if not the empty tuple case, return early so that no new alternatives are generated.240 if ( new_assigns.empty() ) return;241 }242 ResolvExpr::AltList current;243 // now resolve new assignments244 for ( std::list< Expression * >::iterator i = new_assigns.begin();245 i != new_assigns.end(); ++i ) {246 PRINT(247 std::cerr << "== resolving tuple assign ==" << std::endl;248 std::cerr << *i << std::endl;249 )250 251 ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),252 matcher->compositeEnv };253 254 try {255 finder.findWithAdjustment(*i);256 } catch (...) {257 return; // no match should not mean failure, it just means this particular tuple assignment isn't valid258 }259 // prune expressions that don't coincide with260 ResolvExpr::AltList alts = finder.get_alternatives();261 assert( alts.size() == 1 );262 assert( alts.front().expr != 0 );263 current.push_back( alts.front() );264 }265 266 // extract expressions from the assignment alternatives to produce a list of assignments267 // that together form a single alternative268 std::list< Expression *> solved_assigns;269 for ( ResolvExpr::Alternative & alt : current ) {270 solved_assigns.push_back( alt.expr->clone() );271 matcher->combineState( alt );272 }273 274 // xxx -- was push_front275 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{276 new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,277 matcher->openVars,278 ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),279 ResolvExpr::sumCost( current ) + matcher->baseCost } );280 }281 282 TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,283 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )284 : lhs(lhs), rhs(rhs), spotter(spotter),285 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {286 combineState( lhs );287 combineState( rhs );288 }289 290 UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {291 assert( left );292 std::list< Expression * > args;293 args.push_back( new VariableExpr( left ) );294 // args.push_back( new AddressExpr( new VariableExpr( left ) ) );295 if ( right ) args.push_back( new VariableExpr( right ) );296 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {297 args.front() = new AddressExpr( args.front() );298 if ( right ) args.back() = new AddressExpr( args.back() );299 return new UntypedExpr( new NameExpr( "?=?" ), args );300 } else {301 return new UntypedExpr( new NameExpr( fname ), args );302 }303 }304 305 // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv306 // xxx - maybe this should happen in alternative finder for every StmtExpr?307 struct EnvRemover {308 void previsit( ExprStmt * stmt ) {309 assert( compositeEnv );310 if ( stmt->expr->env ) {311 compositeEnv->add( *stmt->expr->env );312 delete stmt->expr->env;313 stmt->expr->env = nullptr;314 }315 }316 317 ResolvExpr::TypeEnvironment * compositeEnv = nullptr;318 };319 320 ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {321 assert( expr->result && ! expr->get_result()->isVoid() );322 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );323 // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.324 if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {325 ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );326 ret->init = ctorInit;327 ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object328 PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs329 rm.pass.compositeEnv = &compositeEnv;330 ctorInit->accept( rm );331 }332 PRINT( std::cerr << "new object: " << ret << std::endl; )333 return ret;334 }335 336 void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {337 static UniqueName lhsNamer( "__massassign_L" );338 static UniqueName rhsNamer( "__massassign_R" );339 // empty tuple case falls into this matcher, hence the second part of the assert340 assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );341 342 // xxx - may need to split this up into multiple declarations, because potential conversion to references343 // probably should not reference local variable - see MultipleAssignMatcher::match344 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;345 for ( ResolvExpr::Alternative & lhsAlt : lhs ) {346 // create a temporary object for each value in the lhs and create a call involving the rhs347 ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );348 out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );349 tmpDecls.push_back( ltmp );350 }351 if ( rtmp ) tmpDecls.push_back( rtmp );352 }353 354 void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {355 static UniqueName lhsNamer( "__multassign_L" );356 static UniqueName rhsNamer( "__multassign_R" );357 358 if ( lhs.size() == rhs.size() ) {359 // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls360 std::list< ObjectDecl * > ltmp;361 std::list< ObjectDecl * > rtmp;362 for ( auto p : group_iterate( lhs, rhs ) ) {363 ResolvExpr::Alternative & lhsAlt = std::get<0>(p);364 ResolvExpr::Alternative & rhsAlt = std::get<1>(p);365 // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.366 ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );367 rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );368 ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );369 ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );370 out.push_back( createFunc(spotter.fname, lobj, robj) );371 ltmp.push_back( lobj );372 rtmp.push_back( robj );373 374 // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment375 ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };376 finder.findWithAdjustment( rhsAlt.expr );377 assert( finder.get_alternatives().size() == 1 );378 compositeEnv = std::move( finder.get_alternatives().front().env );379 }380 tmpDecls.splice( tmpDecls.end(), ltmp );381 tmpDecls.splice( tmpDecls.end(), rtmp );382 }383 }384 46 385 47 namespace { … … 403 65 404 66 /// Dispatcher for tuple (multiple and mass) assignment operations 405 class TupleAssignSpotter _newfinal {67 class TupleAssignSpotter final { 406 68 /// Actually finds tuple assignment operations, by subclass 407 69 struct Matcher { 408 70 ResolvExpr::CandidateList lhs, rhs; 409 TupleAssignSpotter _new& spotter;71 TupleAssignSpotter & spotter; 410 72 CodeLocation location; 411 73 ResolvExpr::Cost baseCost; … … 422 84 423 85 Matcher( 424 TupleAssignSpotter _new& s, const CodeLocation & loc,86 TupleAssignSpotter & s, const CodeLocation & loc, 425 87 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 426 88 : lhs( l ), rhs( r ), spotter( s ), location( loc ), … … 499 161 struct MassAssignMatcher final : public Matcher { 500 162 MassAssignMatcher( 501 TupleAssignSpotter _new& s, const CodeLocation & loc,163 TupleAssignSpotter & s, const CodeLocation & loc, 502 164 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 503 165 : Matcher( s, loc, l, r ) {} … … 529 191 struct MultipleAssignMatcher final : public Matcher { 530 192 MultipleAssignMatcher( 531 TupleAssignSpotter _new& s, const CodeLocation & loc,193 TupleAssignSpotter & s, const CodeLocation & loc, 532 194 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 533 195 : Matcher( s, loc, l, r ) {} … … 578 240 579 241 public: 580 TupleAssignSpotter _new( ResolvExpr::CandidateFinder & f )242 TupleAssignSpotter( ResolvExpr::CandidateFinder & f ) 581 243 : crntFinder( f ), fname(), matcher() {} 582 244 … … 715 377 std::vector< ResolvExpr::CandidateFinder > & args 716 378 ) { 717 TupleAssignSpotter _newspotter{ finder };379 TupleAssignSpotter spotter{ finder }; 718 380 spotter.spot( assign, args ); 719 381 } -
src/Tuples/TupleExpansion.cc
rdf8ba61a r8d182b1 23 23 #include "AST/Node.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu...26 25 #include "Common/ScopedMap.h" // for ScopedMap 27 26 #include "Common/utility.h" // for CodeLocation 28 27 #include "InitTweak/InitTweak.h" // for getFunction 29 #include "SynTree/LinkageSpec.h" // for Spec, C, Intrinsic30 #include "SynTree/Constant.h" // for Constant31 #include "SynTree/Declaration.h" // for StructDecl, DeclarationWithType32 #include "SynTree/Expression.h" // for UntypedMemberExpr, Expression, Uniq...33 #include "SynTree/Label.h" // for operator==, Label34 #include "SynTree/Mutator.h" // for Mutator35 #include "SynTree/Type.h" // for Type, Type::Qualifiers, TupleType36 #include "SynTree/Visitor.h" // for Visitor37 28 #include "Tuples.h" 38 29 39 class CompoundStmt; 40 class TypeSubstitution; 30 namespace Tuples { 41 31 42 namespace Tuples {43 namespace {44 struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> {45 void premutate( UntypedMemberExpr * ) { visit_children = false; }46 Expression * postmutate( UntypedMemberExpr * memberExpr );47 };48 49 struct UniqueExprExpander final : public WithDeclsToAdd {50 Expression * postmutate( UniqueExpr * unqExpr );51 52 std::map< int, Expression * > decls; // not vector, because order added may not be increasing order53 54 ~UniqueExprExpander() {55 for ( std::pair<const int, Expression *> & p : decls ) {56 delete p.second;57 }58 }59 };60 61 struct TupleAssignExpander {62 Expression * postmutate( TupleAssignExpr * tupleExpr );63 };64 65 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {66 Type * postmutate( TupleType * tupleType );67 68 void premutate( CompoundStmt * ) {69 GuardScope( typeMap );70 }71 private:72 ScopedMap< int, StructDecl * > typeMap;73 };74 75 struct TupleIndexExpander {76 Expression * postmutate( TupleIndexExpr * tupleExpr );77 };78 79 struct TupleExprExpander final {80 Expression * postmutate( TupleExpr * tupleExpr );81 };82 }83 84 void expandMemberTuples( std::list< Declaration * > & translationUnit ) {85 PassVisitor<MemberTupleExpander> expander;86 mutateAll( translationUnit, expander );87 }88 89 void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {90 PassVisitor<UniqueExprExpander> unqExpander;91 mutateAll( translationUnit, unqExpander );92 }93 94 void expandTuples( std::list< Declaration * > & translationUnit ) {95 PassVisitor<TupleAssignExpander> assnExpander;96 mutateAll( translationUnit, assnExpander );97 98 PassVisitor<TupleTypeReplacer> replacer;99 mutateAll( translationUnit, replacer );100 101 PassVisitor<TupleIndexExpander> idxExpander;102 mutateAll( translationUnit, idxExpander );103 104 PassVisitor<TupleExprExpander> exprExpander;105 mutateAll( translationUnit, exprExpander );106 }107 108 namespace {109 /// given a expression representing the member and an expression representing the aggregate,110 /// reconstructs a flattened UntypedMemberExpr with the right precedence111 Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {112 if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {113 // construct a new UntypedMemberExpr with the correct structure , and recursively114 // expand that member expression.115 PassVisitor<MemberTupleExpander> expander;116 UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() );117 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner );118 inner->location = newMemberExpr->location = loc;119 memberExpr->member = nullptr;120 memberExpr->aggregate = nullptr;121 delete memberExpr;122 return newMemberExpr->acceptMutator( expander );123 } else {124 // not a member expression, so there is nothing to do but attach and return125 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );126 newMemberExpr->location = loc;127 return newMemberExpr;128 }129 }130 }131 132 Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) {133 if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) {134 Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );135 // aggregate expressions which might be impure must be wrapped in unique expressions136 if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );137 for ( Expression *& expr : tupleExpr->exprs ) {138 expr = reconstructMemberExpr( expr, aggr, memberExpr->location );139 expr->location = memberExpr->location;140 }141 delete aggr;142 tupleExpr->location = memberExpr->location;143 return tupleExpr;144 } else {145 // there may be a tuple expr buried in the aggregate146 // xxx - this is a memory leak147 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) );148 newMemberExpr->location = memberExpr->location;149 return newMemberExpr;150 }151 }152 153 Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {154 const int id = unqExpr->get_id();155 156 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,157 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.158 if ( ! decls.count( id ) ) {159 Expression * assignUnq;160 Expression * var = unqExpr->get_var();161 if ( unqExpr->get_object() ) {162 // an object was generated to represent this unique expression -- it should be added to the list of declarations now163 declsToAddBefore.push_back( unqExpr->get_object() );164 unqExpr->set_object( nullptr );165 // steal the expr from the unqExpr166 assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );167 unqExpr->set_expr( nullptr );168 } else {169 // steal the already generated assignment to var from the unqExpr - this has been generated by FixInit170 Expression * expr = unqExpr->get_expr();171 CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr );172 assignUnq = commaExpr->get_arg1();173 commaExpr->set_arg1( nullptr );174 }175 ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),176 new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );177 declsToAddBefore.push_back( finished );178 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))179 // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.180 Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) );181 ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),182 new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );183 condExpr->set_result( var->get_result()->clone() );184 condExpr->set_env( maybeClone( unqExpr->get_env() ) );185 decls[id] = condExpr;186 }187 delete unqExpr;188 return decls[id]->clone();189 }190 191 Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {192 StmtExpr * ret = assnExpr->get_stmtExpr();193 assnExpr->set_stmtExpr( nullptr );194 // move env to StmtExpr195 ret->set_env( assnExpr->get_env() );196 assnExpr->set_env( nullptr );197 delete assnExpr;198 return ret;199 }200 201 Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) {202 unsigned tupleSize = tupleType->size();203 if ( ! typeMap.count( tupleSize ) ) {204 // generate struct type to replace tuple type based on the number of components in the tuple205 StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );206 decl->location = tupleType->location;207 decl->set_body( true );208 for ( size_t i = 0; i < tupleSize; ++i ) {209 TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );210 decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );211 decl->get_parameters().push_back( tyParam );212 }213 if ( tupleSize == 0 ) {214 // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.215 decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );216 }217 typeMap[tupleSize] = decl;218 declsToAddBefore.push_back( decl );219 }220 Type::Qualifiers qualifiers = tupleType->get_qualifiers();221 222 StructDecl * decl = typeMap[tupleSize];223 StructInstType * newType = new StructInstType( qualifiers, decl );224 for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) {225 Type * t = std::get<0>(p);226 newType->get_parameters().push_back( new TypeExpr( t->clone() ) );227 }228 delete tupleType;229 return newType;230 }231 232 Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {233 Expression * tuple = tupleExpr->tuple;234 assert( tuple );235 tupleExpr->tuple = nullptr;236 unsigned int idx = tupleExpr->index;237 TypeSubstitution * env = tupleExpr->env;238 tupleExpr->env = nullptr;239 delete tupleExpr;240 241 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {242 if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {243 // optimization: definitely pure tuple expr => can reduce to the only relevant component.244 assert( tupleExpr->exprs.size() > idx );245 Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);246 Expression * ret = expr;247 ret->env = env;248 expr = nullptr; // remove from list so it can safely be deleted249 delete tupleExpr;250 return ret;251 }252 }253 254 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );255 StructDecl * structDecl = type->baseStruct;256 assert( structDecl->members.size() > idx );257 Declaration * member = *std::next(structDecl->members.begin(), idx);258 MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );259 memExpr->env = env;260 return memExpr;261 }262 263 Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {264 if ( result->isVoid() ) {265 // void result - don't need to produce a value for cascading - just output a chain of comma exprs266 assert( ! exprs.empty() );267 std::list< Expression * >::const_iterator iter = exprs.begin();268 Expression * expr = new CastExpr( *iter++ );269 for ( ; iter != exprs.end(); ++iter ) {270 expr = new CommaExpr( expr, new CastExpr( *iter ) );271 }272 expr->set_env( env );273 return expr;274 } else {275 // typed tuple expression - produce a compound literal which performs each of the expressions276 // as a distinct part of its initializer - the produced compound literal may be used as part of277 // another expression278 std::list< Initializer * > inits;279 for ( Expression * expr : exprs ) {280 inits.push_back( new SingleInit( expr ) );281 }282 Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );283 expr->set_env( env );284 return expr;285 }286 }287 288 Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {289 Type * result = tupleExpr->get_result();290 std::list< Expression * > exprs = tupleExpr->get_exprs();291 assert( result );292 TypeSubstitution * env = tupleExpr->get_env();293 294 // remove data from shell and delete it295 tupleExpr->set_result( nullptr );296 tupleExpr->get_exprs().clear();297 tupleExpr->set_env( nullptr );298 delete tupleExpr;299 300 return replaceTupleExpr( result, exprs, env );301 }302 303 Type * makeTupleType( const std::list< Expression * > & exprs ) {304 // produce the TupleType which aggregates the types of the exprs305 std::list< Type * > types;306 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );307 for ( Expression * expr : exprs ) {308 assert( expr->get_result() );309 if ( expr->get_result()->isVoid() ) {310 // if the type of any expr is void, the type of the entire tuple is void311 return new VoidType( Type::Qualifiers() );312 }313 Type * type = expr->get_result()->clone();314 types.push_back( type );315 // the qualifiers on the tuple type are the qualifiers that exist on all component types316 qualifiers &= type->get_qualifiers();317 } // for318 if ( exprs.empty() ) qualifiers = Type::Qualifiers();319 return new TupleType( qualifiers, types );320 }321 32 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) { 322 33 // produce the TupleType which aggregates the types of the exprs … … 341 52 } 342 53 343 TypeInstType * isTtype( Type * type ) {344 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {345 if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {346 return inst;347 }348 }349 return nullptr;350 }351 352 const TypeInstType * isTtype( const Type * type ) {353 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {354 if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {355 return inst;356 }357 }358 return nullptr;359 }360 361 54 const ast::TypeInstType * isTtype( const ast::Type * type ) { 362 55 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { -
src/Tuples/Tuples.cc
rdf8ba61a r8d182b1 19 19 #include "AST/Inspect.hpp" 20 20 #include "AST/LinkageSpec.hpp" 21 #include "Common/PassVisitor.h"22 21 #include "InitTweak/InitTweak.h" 23 22 … … 25 24 26 25 namespace { 27 /// Checks if impurity (read: side-effects) may exist in a piece of code.28 /// Currently gives a very crude approximation, wherein any function29 /// call expression means the code may be impure.30 struct ImpurityDetector_old : public WithShortCircuiting {31 bool const ignoreUnique;32 bool maybeImpure;33 34 ImpurityDetector_old( bool ignoreUnique ) :35 ignoreUnique( ignoreUnique ), maybeImpure( false )36 {}37 38 void previsit( const ApplicationExpr * appExpr ) {39 visit_children = false;40 if ( const DeclarationWithType * function =41 InitTweak::getFunction( appExpr ) ) {42 if ( function->linkage == LinkageSpec::Intrinsic ) {43 if ( function->name == "*?" || function->name == "?[?]" ) {44 // intrinsic dereference, subscript are pure,45 // but need to recursively look for impurity46 visit_children = true;47 return;48 }49 }50 }51 maybeImpure = true;52 }53 54 void previsit( const UntypedExpr * ) {55 maybeImpure = true;56 visit_children = false;57 }58 59 void previsit( const UniqueExpr * ) {60 if ( ignoreUnique ) {61 // bottom out at unique expression.62 // The existence of a unique expression doesn't change the purity of an expression.63 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.64 visit_children = false;65 return;66 }67 }68 };69 70 bool detectImpurity( const Expression * expr, bool ignoreUnique ) {71 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );72 expr->accept( detector );73 return detector.pass.maybeImpure;74 }75 26 76 27 /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives … … 110 61 } 111 62 112 bool maybeImpure( const Expression * expr ) {113 return detectImpurity( expr, false );114 }115 116 bool maybeImpureIgnoreUnique( const Expression * expr ) {117 return detectImpurity( expr, true );118 }119 120 63 } // namespace Tuples 121 64 -
src/Tuples/Tuples.h
rdf8ba61a r8d182b1 21 21 #include "AST/Fwd.hpp" 22 22 #include "AST/Node.hpp" 23 #include "SynTree/Expression.h"24 #include "SynTree/Declaration.h"25 #include "SynTree/Type.h"26 27 #include "ResolvExpr/AlternativeFinder.h"28 23 #include "ResolvExpr/CandidateFinder.hpp" 29 24 30 25 namespace Tuples { 31 26 // TupleAssignment.cc 32 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,33 std::vector< ResolvExpr::AlternativeFinder >& args );34 27 void handleTupleAssignment( 35 28 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, … … 38 31 // TupleExpansion.cc 39 32 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate 40 void expandMemberTuples( std::list< Declaration * > & translationUnit );41 33 void expandMemberTuples( ast::TranslationUnit & translationUnit ); 42 34 43 35 /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc. 44 void expandTuples( std::list< Declaration * > & translationUnit );45 36 void expandTuples( ast::TranslationUnit & translaionUnit ); 46 37 47 38 /// replaces UniqueExprs with a temporary variable and one call 48 void expandUniqueExpr( std::list< Declaration * > & translationUnit );49 39 void expandUniqueExpr( ast::TranslationUnit & translationUnit ); 50 40 51 41 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 52 Type * makeTupleType( const std::list< Expression * > & exprs );53 42 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 54 43 55 44 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 56 TypeInstType * isTtype( Type * type );57 const TypeInstType * isTtype( const Type * type );58 45 const ast::TypeInstType * isTtype( const ast::Type * type ); 59 46 60 47 /// returns true if the expression may contain side-effects. 61 bool maybeImpure( const Expression * expr );62 48 bool maybeImpure( const ast::Expr * expr ); 63 49 64 50 /// Returns true if the expression may contain side-effect, 65 51 /// ignoring the presence of unique expressions. 66 bool maybeImpureIgnoreUnique( const Expression * expr );67 52 bool maybeImpureIgnoreUnique( const ast::Expr * expr ); 68 53 } // namespace Tuples -
src/Validate/Autogen.cpp
rdf8ba61a r8d182b1 49 49 50 50 // -------------------------------------------------------------------------- 51 struct AutogenerateRoutines _newfinal :51 struct AutogenerateRoutines final : 52 52 public ast::WithDeclsToAdd<>, 53 53 public ast::WithShortCircuiting { … … 232 232 233 233 // -------------------------------------------------------------------------- 234 void AutogenerateRoutines _new::previsit( const ast::EnumDecl * enumDecl ) {234 void AutogenerateRoutines::previsit( const ast::EnumDecl * enumDecl ) { 235 235 // Must visit children (enum constants) to add them to the symbol table. 236 236 if ( !enumDecl->body ) return; … … 249 249 } 250 250 251 void AutogenerateRoutines _new::previsit( const ast::StructDecl * structDecl ) {251 void AutogenerateRoutines::previsit( const ast::StructDecl * structDecl ) { 252 252 visit_children = false; 253 253 if ( !structDecl->body ) return; … … 265 265 } 266 266 267 void AutogenerateRoutines _new::previsit( const ast::UnionDecl * unionDecl ) {267 void AutogenerateRoutines::previsit( const ast::UnionDecl * unionDecl ) { 268 268 visit_children = false; 269 269 if ( !unionDecl->body ) return; … … 282 282 283 283 /// Generate ctor/dtors/assign for typedecls, e.g., otype T = int *; 284 void AutogenerateRoutines _new::previsit( const ast::TypeDecl * typeDecl ) {284 void AutogenerateRoutines::previsit( const ast::TypeDecl * typeDecl ) { 285 285 if ( !typeDecl->base ) return; 286 286 … … 290 290 } 291 291 292 void AutogenerateRoutines _new::previsit( const ast::TraitDecl * ) {292 void AutogenerateRoutines::previsit( const ast::TraitDecl * ) { 293 293 // Ensure that we don't add assignment ops for types defined as part of the trait 294 294 visit_children = false; 295 295 } 296 296 297 void AutogenerateRoutines _new::previsit( const ast::FunctionDecl * ) {297 void AutogenerateRoutines::previsit( const ast::FunctionDecl * ) { 298 298 // Track whether we're currently in a function. 299 299 // Can ignore function type idiosyncrasies, because function type can never … … 302 302 } 303 303 304 void AutogenerateRoutines _new::postvisit( const ast::FunctionDecl * ) {304 void AutogenerateRoutines::postvisit( const ast::FunctionDecl * ) { 305 305 functionNesting -= 1; 306 306 } … … 521 521 const ast::Expr * src, const ast::ObjectDecl * field, 522 522 ast::FunctionDecl * func, SymTab::LoopDirection direction ) { 523 InitTweak::InitExpander _newsrcParam( src );523 InitTweak::InitExpander srcParam( src ); 524 524 // Assign to destination. 525 525 ast::MemberExpr * dstSelect = new ast::MemberExpr( … … 795 795 796 796 void autogenerateRoutines( ast::TranslationUnit & translationUnit ) { 797 ast::Pass<AutogenerateRoutines _new>::run( translationUnit );797 ast::Pass<AutogenerateRoutines>::run( translationUnit ); 798 798 } 799 799 -
src/Validate/FindSpecialDecls.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 class Declaration;21 class FunctionDecl;22 class StructDecl;23 class Type;24 25 18 namespace ast { 26 19 class TranslationUnit; … … 28 21 29 22 namespace Validate { 30 /// size_t type - set when size_t typedef is seen. Useful in a few places,31 /// such as in determining array dimension type32 extern Type * SizeType;33 34 /// intrinsic dereference operator for unqualified types - set when *? function is seen in FindSpecialDeclarations.35 /// Useful for creating dereference ApplicationExprs without a full resolver pass.36 extern FunctionDecl * dereferenceOperator;37 38 /// special built-in functions and data structures necessary for destructor generation39 extern StructDecl * dtorStruct;40 extern FunctionDecl * dtorStructDestroy;41 42 /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times.43 void findSpecialDecls( std::list< Declaration * > & translationUnit );44 23 45 24 /// Find and remember some of the special declarations that are useful for -
src/Validate/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC_VALIDATE = \ 18 Validate/FindSpecialDecls.cc \19 18 Validate/FindSpecialDecls.h 20 19 … … 37 36 Validate/GenericParameter.cpp \ 38 37 Validate/GenericParameter.hpp \ 39 Validate/HandleAttributes.cc \40 Validate/HandleAttributes.h \41 38 Validate/HoistStruct.cpp \ 42 39 Validate/HoistStruct.hpp \ -
src/Virtual/ExpandCasts.cc
rdf8ba61a r8d182b1 24 24 #include "AST/Expr.hpp" 25 25 #include "AST/Pass.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/ScopedMap.h" // for ScopedMap 28 27 #include "Common/SemanticError.h" // for SemanticError 29 28 #include "SymTab/Mangler.h" // for mangleType 30 #include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl31 #include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address...32 #include "SynTree/Mutator.h" // for mutateAll33 #include "SynTree/Type.h" // for Type, PointerType, StructInstType34 #include "SynTree/Visitor.h" // for acceptAll35 29 36 30 namespace Virtual { … … 43 37 } 44 38 45 bool is_type_id_object( const ObjectDecl * objectDecl ) {46 const std::string & objectName = objectDecl->name;47 return is_prefix( "__cfatid_", objectName );48 }49 50 39 bool is_type_id_object( const ast::ObjectDecl * decl ) { 51 40 return is_prefix( "__cfatid_", decl->name ); … … 55 44 56 45 /// Maps virtual table types the instance for that type. 57 class VirtualTableMap final {58 ScopedMap<std::string, ObjectDecl *> vtable_instances;59 public:60 void enterScope() {61 vtable_instances.beginScope();62 }63 void leaveScope() {64 vtable_instances.endScope();65 }66 67 ObjectDecl * insert( ObjectDecl * vtableDecl ) {68 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );69 ObjectDecl *& value = vtable_instances[ mangledName ];70 if ( value ) {71 if ( vtableDecl->storageClasses.is_extern ) {72 return nullptr;73 } else if ( ! value->storageClasses.is_extern ) {74 return value;75 }76 }77 value = vtableDecl;78 return nullptr;79 }80 81 ObjectDecl * lookup( const Type * vtableType ) {82 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );83 const auto it = vtable_instances.find( mangledName );84 return ( vtable_instances.end() == it ) ? nullptr : it->second;85 }86 };87 88 class VirtualCastCore {89 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {90 Type * type = new StructInstType(91 Type::Qualifiers( Type::Const ), pvt_decl );92 for (int i = 0 ; i < level_of_indirection ; ++i) {93 type = new PointerType( noQualifiers, type );94 }95 return new CastExpr( expr, type );96 }97 98 public:99 VirtualCastCore() :100 indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )101 {}102 103 void premutate( FunctionDecl * functionDecl );104 void premutate( StructDecl * structDecl );105 void premutate( ObjectDecl * objectDecl );106 107 Expression * postmutate( VirtualCastExpr * castExpr );108 109 VirtualTableMap indexer;110 private:111 FunctionDecl *vcast_decl;112 StructDecl *pvt_decl;113 };114 115 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {116 if ( (! vcast_decl) &&117 functionDecl->get_name() == "__cfavir_virtual_cast" ) {118 vcast_decl = functionDecl;119 }120 }121 122 void VirtualCastCore::premutate( StructDecl * structDecl ) {123 if ( pvt_decl || ! structDecl->has_body() ) {124 return;125 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {126 pvt_decl = structDecl;127 }128 }129 130 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {131 if ( is_type_id_object( objectDecl ) ) {132 // Multiple definitions should be fine because of linkonce.133 indexer.insert( objectDecl );134 }135 }136 137 /// Better error locations for generated casts.138 CodeLocation castLocation( const VirtualCastExpr * castExpr ) {139 if ( castExpr->location.isSet() ) {140 return castExpr->location;141 } else if ( castExpr->arg->location.isSet() ) {142 return castExpr->arg->location;143 } else if ( castExpr->result->location.isSet() ) {144 return castExpr->result->location;145 } else {146 return CodeLocation();147 }148 }149 150 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {151 SemanticError( castLocation( castExpr ), message );152 }153 154 /// Get the base type from a pointer or reference.155 const Type * getBaseType( const Type * type ) {156 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {157 return target->base;158 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {159 return target->base;160 } else {161 return nullptr;162 }163 }164 165 /* Attempt to follow the "head" field of the structure to get the...166 * Returns nullptr on error, otherwise owner must free returned node.167 */168 StructInstType * followHeadPointerType(169 const StructInstType * oldType,170 const std::string& fieldName,171 const CodeLocation& errorLocation ) {172 173 // First section of the function is all about trying to fill this variable in.174 StructInstType * newType = nullptr;175 {176 const StructDecl * oldDecl = oldType->baseStruct;177 assert( oldDecl );178 179 // Helper function for throwing semantic errors.180 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {181 const std::string& context = "While following head pointer of " +182 oldDecl->name + " named '" + fieldName + "': ";183 SemanticError( errorLocation, context + message );184 };185 186 if ( oldDecl->members.empty() ) {187 throwError( "Type has no fields." );188 }189 const Declaration * memberDecl = oldDecl->members.front();190 assert( memberDecl );191 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );192 assert( fieldDecl );193 if ( fieldName != fieldDecl->name ) {194 throwError( "Head field did not have expected name." );195 }196 197 const Type * fieldType = fieldDecl->type;198 if ( nullptr == fieldType ) {199 throwError( "Could not get head field." );200 }201 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );202 if ( nullptr == ptrType ) {203 throwError( "First field is not a pointer type." );204 }205 assert( ptrType->base );206 newType = dynamic_cast<StructInstType *>( ptrType->base );207 if ( nullptr == newType ) {208 throwError( "First field does not point to a structure type." );209 }210 }211 212 // Now we can look into copying it.213 newType = newType->clone();214 if ( ! oldType->parameters.empty() ) {215 deleteAll( newType->parameters );216 newType->parameters.clear();217 cloneAll( oldType->parameters, newType->parameters );218 }219 return newType;220 }221 222 /// Get the type-id type from a virtual type.223 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {224 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );225 if ( nullptr == typeInst ) {226 return nullptr;227 }228 StructInstType * tableInst =229 followHeadPointerType( typeInst, "virtual_table", errorLocation );230 if ( nullptr == tableInst ) {231 return nullptr;232 }233 StructInstType * typeIdInst =234 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );235 delete tableInst;236 return typeIdInst;237 }238 239 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {240 assertf( castExpr->result, "Virtual Cast target not found before expansion." );241 242 assert( vcast_decl );243 assert( pvt_decl );244 245 const Type * base_type = getBaseType( castExpr->result );246 if ( nullptr == base_type ) {247 castError( castExpr, "Virtual cast target must be a pointer or reference type." );248 }249 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );250 if ( nullptr == type_id_type ) {251 castError( castExpr, "Ill formed virtual cast target type." );252 }253 ObjectDecl * type_id = indexer.lookup( type_id_type );254 delete type_id_type;255 if ( nullptr == type_id ) {256 castError( castExpr, "Virtual cast does not target a virtual type." );257 }258 259 Expression * result = new CastExpr(260 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {261 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),262 cast_to_type_id( castExpr->get_arg(), 2 ),263 } ),264 castExpr->get_result()->clone()265 );266 267 castExpr->set_arg( nullptr );268 castExpr->set_result( nullptr );269 delete castExpr;270 return result;271 }272 46 273 47 /// Better error locations for generated casts. … … 494 268 } // namespace 495 269 496 void expandCasts( std::list< Declaration * > & translationUnit ) {497 PassVisitor<VirtualCastCore> translator;498 mutateAll( translationUnit, translator );499 }500 501 270 void expandCasts( ast::TranslationUnit & translationUnit ) { 502 271 ast::Pass<ExpandCastsCore>::run( translationUnit ); -
src/Virtual/Tables.cc
rdf8ba61a r8d182b1 21 21 #include "AST/Stmt.hpp" 22 22 #include "AST/Type.hpp" 23 #include <SynTree/Attribute.h>24 #include <SynTree/Declaration.h>25 #include <SynTree/Expression.h>26 #include <SynTree/Statement.h>27 #include <SynTree/Type.h>28 23 29 24 namespace Virtual { … … 65 60 return 17 < name.size() && '_' == name[0] && 66 61 std::string("_vtable_instance") == name.substr(1, name.size() - 17); 67 }68 69 static ObjectDecl * makeVtableDeclaration(70 std::string const & name,71 StructInstType * type, Initializer * init ) {72 Type::StorageClasses storage = noStorageClasses;73 if ( nullptr == init ) {74 storage.is_extern = true;75 }76 return new ObjectDecl(77 name,78 storage,79 LinkageSpec::Cforall,80 nullptr,81 type,82 init83 );84 62 } 85 63 … … 101 79 } 102 80 103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {104 assert( type );105 return makeVtableDeclaration( name, type, nullptr );106 }107 108 81 ast::ObjectDecl * makeVtableForward( 109 82 CodeLocation const & location, std::string const & name, … … 111 84 assert( vtableType ); 112 85 return makeVtableDeclaration( location, name, vtableType, nullptr ); 113 }114 115 ObjectDecl * makeVtableInstance(116 std::string const & name, StructInstType * vtableType,117 Type * objectType, Initializer * init ) {118 assert( vtableType );119 assert( objectType );120 StructDecl * vtableStruct = vtableType->baseStruct;121 // Build the initialization122 if ( nullptr == init ) {123 std::list< Initializer * > inits;124 125 // This is going to have to be run before the resolver to connect expressions.126 for ( auto field : vtableStruct->members ) {127 if ( std::string( "parent" ) == field->name ) {128 // This will not work with polymorphic state.129 auto oField = strict_dynamic_cast< ObjectDecl * >( field );130 auto fieldType = strict_dynamic_cast< PointerType * >( oField->type );131 auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base );132 std::string const & parentInstance = instanceName( parentType->name );133 inits.push_back(134 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );135 } else if ( std::string( "__cfavir_typeid" ) == field->name ) {136 std::string const & baseType = baseTypeName( vtableType->name );137 std::string const & typeId = typeIdName( baseType );138 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );139 } else if ( std::string( "size" ) == field->name ) {140 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );141 } else if ( std::string( "align" ) == field->name ) {142 inits.push_back( new SingleInit( new AlignofExpr( objectType->clone() ) ) );143 } else {144 inits.push_back( new SingleInit( new NameExpr( field->name ) ) );145 }146 }147 init = new ListInit( inits );148 // This should initialize everything except the parent pointer, the149 // size-of and align-of fields. These should be inserted.150 } else {151 assert(false);152 }153 return makeVtableDeclaration( name, vtableType, init );154 86 } 155 87 … … 224 156 } 225 157 226 FunctionDecl * makeGetExceptionForward(227 Type * vtableType, Type * exceptType ) {228 assert( vtableType );229 assert( exceptType );230 FunctionType * type = new FunctionType( noQualifiers, false );231 vtableType->tq.is_const = true;232 type->returnVals.push_back( new ObjectDecl(233 "_retvalue",234 noStorageClasses,235 LinkageSpec::Cforall,236 nullptr,237 new ReferenceType( noQualifiers, vtableType ),238 nullptr,239 { new Attribute("unused") }240 ) );241 type->parameters.push_back( new ObjectDecl(242 "__unused",243 noStorageClasses,244 LinkageSpec::Cforall,245 nullptr,246 new PointerType( noQualifiers, exceptType ),247 nullptr,248 { new Attribute("unused") }249 ) );250 return new FunctionDecl(251 functionName,252 noStorageClasses,253 LinkageSpec::Cforall,254 type,255 nullptr256 );257 }258 259 158 ast::FunctionDecl * makeGetExceptionForward( 260 159 CodeLocation const & location, … … 284 183 } 285 184 286 FunctionDecl * makeGetExceptionFunction(287 ObjectDecl * vtableInstance, Type * exceptType ) {288 assert( vtableInstance );289 assert( exceptType );290 FunctionDecl * func = makeGetExceptionForward(291 vtableInstance->type->clone(), exceptType );292 func->statements = new CompoundStmt( {293 new ReturnStmt( new VariableExpr( vtableInstance ) ),294 } );295 return func;296 }297 298 185 ast::FunctionDecl * makeGetExceptionFunction( 299 186 CodeLocation const & location, … … 307 194 } ); 308 195 return func; 309 }310 311 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {312 assert( typeIdType );313 StructInstType * type = typeIdType->clone();314 type->tq.is_const = true;315 std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );316 return new ObjectDecl(317 typeid_name,318 noStorageClasses,319 LinkageSpec::Cforall,320 /* bitfieldWidth */ nullptr,321 type,322 new ListInit( { new SingleInit(323 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )324 ) } ),325 { new Attribute( "cfa_linkonce", {} ) },326 noFuncSpecifiers327 );328 196 } 329 197 -
src/Virtual/Tables.h
rdf8ba61a r8d182b1 18 18 #include <string> 19 19 #include "AST/Fwd.hpp" 20 class Declaration;21 class Expression;22 class FunctionDecl;23 class Initializer;24 class ObjectDecl;25 class StructDecl;26 class StructInstType;27 class Type;28 20 29 21 namespace Virtual { … … 37 29 bool isVTableInstanceName( std::string const & name ); 38 30 39 ObjectDecl * makeVtableForward(40 std::string const & name, StructInstType * vtableType );41 31 /* Create a forward declaration of a vtable of the given type. 42 32 * vtableType node is consumed. … … 46 36 ast::StructInstType const * vtableType ); 47 37 48 ObjectDecl * makeVtableInstance(49 std::string const & name,50 StructInstType * vtableType, Type * objectType,51 Initializer * init = nullptr );52 38 /* Create an initialized definition of a vtable. 53 39 * vtableType and init (if provided) nodes are consumed. … … 61 47 62 48 // Some special code for how exceptions interact with virtual tables. 63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType ); 49 64 50 /* Create a forward declaration of the exception virtual function 65 51 * linking the vtableType to the exceptType. Both nodes are consumed. … … 70 56 ast::Type const * exceptType ); 71 57 72 FunctionDecl * makeGetExceptionFunction(73 ObjectDecl * vtableInstance, Type * exceptType );74 58 /* Create the definition of the exception virtual function. 75 59 * exceptType node is consumed. … … 79 63 ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType ); 80 64 81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );82 65 /* Build an instance of the type-id from the type of the type-id. 83 66 * TODO: Should take the parent type. Currently locked to the exception_t. -
src/main.cc
rdf8ba61a r8d182b1 29 29 #include <string> // for char_traits, operator<< 30 30 31 #include "AST/Convert.hpp"32 31 #include "AST/Pass.hpp" // for pass_visitor_stats 33 32 #include "AST/Print.hpp" // for printAll … … 40 39 #include "CodeGen/Generate.h" // for generate 41 40 #include "CodeGen/LinkOnce.h" // for translateLinkOnce 42 #include "CodeTools/TrackLoc.h" // for fillLocations43 41 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 44 42 #include "Common/DeclStats.hpp" // for printDeclStats … … 66 64 #include "ResolvExpr/EraseWith.hpp" // for eraseWith 67 65 #include "ResolvExpr/Resolver.h" // for resolve 68 #include "SynTree/LinkageSpec.h" // for Spec, Cforall, Intrinsic69 #include "SynTree/Declaration.h" // for Declaration70 66 #include "Tuples/Tuples.h" // for expandMemberTuples, expan... 71 67 #include "Validate/Autogen.hpp" // for autogenerateRoutines … … 101 97 ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 102 98 } 103 {104 static auto group = build<CounterGroup>( "Syntax Node" );105 auto pass = build<CounterGroup>( name, group );106 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass );107 }108 99 } 109 100 … … 259 250 260 251 parse_cmdline( argc, argv ); // process command-line arguments 261 CodeGen::FixMain::setReplaceMain( !nomainp );262 252 263 253 if ( waiting_for_gdb ) { … … 403 393 PASS( "Translate Tries", ControlStruct::translateTries, transUnit ); 404 394 PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit ); 395 PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp ); 405 396 406 397 // Needs to happen before tuple types are expanded. … … 430 421 431 422 PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false ); 432 433 CodeGen::FixMain::fix( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() ); 423 CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() ); 424 434 425 if ( output != &cout ) { 435 426 delete output;
Note:
See TracChangeset
for help on using the changeset viewer.