Changeset c6b4432
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (23 months ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- Location:
- src
- Files:
-
- 113 deleted
- 77 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/module.mk
r790d835 rc6b4432 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
r790d835 rc6b4432 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/FixMain.cc
r790d835 rc6b4432 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 … … 35 32 36 33 namespace { 37 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 34 51 35 struct FindMainCore_new { … … 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(){ … … 159 108 } // namespace 160 109 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 110 bool FixMain::isMain( const ast::FunctionDecl * decl ) { 169 111 if ( std::string("main") != decl->name ) { -
src/CodeGen/FixMain.h
r790d835 rc6b4432 21 21 22 22 #include "AST/LinkageSpec.hpp" 23 #include "SynTree/LinkageSpec.h"24 23 25 class Declaration;26 class FunctionDecl;27 24 namespace ast { 28 25 class FunctionDecl; … … 34 31 class FixMain { 35 32 public : 36 static inline LinkageSpec::Spec mainLinkage() {37 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;38 }39 33 static inline ast::Linkage::Spec getMainLinkage() { 40 34 return replace_main ? ast::Linkage::Cforall : ast::Linkage::C; … … 45 39 } 46 40 47 static bool isMain(FunctionDecl* decl);48 41 static bool isMain(const ast::FunctionDecl * decl); 49 42 50 static void fix( std::list< Declaration * > & decls,51 std::ostream &os, const char* bootloader_filename );52 43 static void fix( ast::TranslationUnit & translationUnit, 53 44 std::ostream &os, const char * bootloader_filename ); -
src/CodeGen/FixNames.cc
r790d835 rc6b4432 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 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 } // if64 } // if65 }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 }87 88 30 /// Does work with the main function and scopeLevels. 89 31 class FixNames_new final { -
src/CodeGen/GenType.cc
r790d835 rc6b4432 21 21 #include "AST/Print.hpp" // for print 22 22 #include "AST/Vector.hpp" // for vector 23 #include "CodeGenerator.h" // for CodeGenerator24 23 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new 25 24 #include "Common/UniqueName.h" // for UniqueName 26 #include "SynTree/Declaration.h" // for DeclarationWithType27 #include "SynTree/Expression.h" // for Expression28 #include "SynTree/Type.h" // for PointerType, Type, FunctionType29 #include "SynTree/Visitor.h" // for Visitor30 25 31 26 namespace CodeGen { 32 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {33 std::string typeString;34 GenType( const std::string &typeString, const Options &options );35 36 void previsit( BaseSyntaxNode * );37 void postvisit( BaseSyntaxNode * );38 39 void postvisit( FunctionType * funcType );40 void postvisit( VoidType * voidType );41 void postvisit( BasicType * basicType );42 void postvisit( PointerType * pointerType );43 void postvisit( ArrayType * arrayType );44 void postvisit( ReferenceType * refType );45 void postvisit( StructInstType * structInst );46 void postvisit( UnionInstType * unionInst );47 void postvisit( EnumInstType * enumInst );48 void postvisit( TypeInstType * typeInst );49 void postvisit( TupleType * tupleType );50 void postvisit( VarArgsType * varArgsType );51 void postvisit( ZeroType * zeroType );52 void postvisit( OneType * oneType );53 void postvisit( GlobalScopeType * globalType );54 void postvisit( TraitInstType * inst );55 void postvisit( TypeofType * typeof );56 void postvisit( VTableType * vtable );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 Options options;65 };66 67 std::string genType( Type *type, const std::string &baseString, const Options &options ) {68 PassVisitor<GenType> gt( baseString, options );69 std::ostringstream os;70 71 if ( ! type->get_attributes().empty() ) {72 PassVisitor<CodeGenerator> cg( os, options );73 cg.pass.genAttributes( type->get_attributes() );74 } // if75 76 type->accept( gt );77 return os.str() + gt.pass.typeString;78 }79 80 std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {81 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) );82 }83 84 std::string genPrettyType( Type * type, const std::string & baseString ) {85 return genType( type, baseString, true, false );86 }87 88 GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {}89 90 // *** BaseSyntaxNode91 void GenType::previsit( BaseSyntaxNode * ) {92 // turn off automatic recursion for all nodes, to allow each visitor to93 // precisely control the order in which its children are visited.94 visit_children = false;95 }96 97 void GenType::postvisit( BaseSyntaxNode * node ) {98 std::stringstream ss;99 node->print( ss );100 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );101 }102 103 void GenType::postvisit( VoidType * voidType ) {104 typeString = "void " + typeString;105 handleQualifiers( voidType );106 }107 108 void GenType::postvisit( BasicType * basicType ) {109 BasicType::Kind kind = basicType->kind;110 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );111 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;112 handleQualifiers( basicType );113 }114 115 void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {116 std::ostringstream os;117 if ( typeString != "" ) {118 if ( typeString[ 0 ] == '*' ) {119 os << "(" << typeString << ")";120 } else {121 os << typeString;122 } // if123 } // if124 os << "[";125 126 if ( isStatic ) {127 os << "static ";128 } // if129 if ( qualifiers.is_const ) {130 os << "const ";131 } // if132 if ( qualifiers.is_volatile ) {133 os << "volatile ";134 } // if135 if ( qualifiers.is_restrict ) {136 os << "__restrict ";137 } // if138 if ( qualifiers.is_atomic ) {139 os << "_Atomic ";140 } // if141 if ( dimension != 0 ) {142 PassVisitor<CodeGenerator> cg( os, options );143 dimension->accept( cg );144 } else if ( isVarLen ) {145 // no dimension expression on a VLA means it came in with the * token146 os << "*";147 } // if148 os << "]";149 150 typeString = os.str();151 152 base->accept( *visitor );153 }154 155 void GenType::postvisit( PointerType * pointerType ) {156 assert( pointerType->base != 0);157 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {158 genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );159 } else {160 handleQualifiers( pointerType );161 if ( typeString[ 0 ] == '?' ) {162 typeString = "* " + typeString;163 } else {164 typeString = "*" + typeString;165 } // if166 pointerType->base->accept( *visitor );167 } // if168 }169 170 void GenType::postvisit( ArrayType * arrayType ) {171 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );172 }173 174 void GenType::postvisit( ReferenceType * refType ) {175 assert( 0 != refType->base );176 assertf( ! options.genC, "Reference types should not reach code generation." );177 handleQualifiers( refType );178 typeString = "&" + typeString;179 refType->base->accept( *visitor );180 }181 182 void GenType::postvisit( FunctionType * funcType ) {183 std::ostringstream os;184 185 if ( typeString != "" ) {186 if ( typeString[ 0 ] == '*' ) {187 os << "(" << typeString << ")";188 } else {189 os << typeString;190 } // if191 } // if192 193 /************* parameters ***************/194 195 const std::list<DeclarationWithType *> &pars = funcType->parameters;196 197 if ( pars.empty() ) {198 if ( funcType->get_isVarArgs() ) {199 os << "()";200 } else {201 os << "(void)";202 } // if203 } else {204 PassVisitor<CodeGenerator> cg( os, options );205 os << "(" ;206 207 cg.pass.genCommaList( pars.begin(), pars.end() );208 209 if ( funcType->get_isVarArgs() ) {210 os << ", ...";211 } // if212 os << ")";213 } // if214 215 typeString = os.str();216 217 if ( funcType->returnVals.size() == 0 ) {218 typeString = "void " + typeString;219 } else {220 funcType->returnVals.front()->get_type()->accept( *visitor );221 } // if222 223 // add forall224 if( ! funcType->forall.empty() && ! options.genC ) {225 // assertf( ! genC, "Aggregate type parameters should not reach code generation." );226 std::ostringstream os;227 PassVisitor<CodeGenerator> cg( os, options );228 os << "forall(";229 cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );230 os << ")" << std::endl;231 typeString = os.str() + typeString;232 }233 }234 235 std::string GenType::handleGeneric( ReferenceToType * refType ) {236 if ( ! refType->parameters.empty() ) {237 std::ostringstream os;238 PassVisitor<CodeGenerator> cg( os, options );239 os << "(";240 cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );241 os << ") ";242 return os.str();243 }244 return "";245 }246 247 void GenType::postvisit( StructInstType * structInst ) {248 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;249 if ( options.genC ) typeString = "struct " + typeString;250 handleQualifiers( structInst );251 }252 253 void GenType::postvisit( UnionInstType * unionInst ) {254 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;255 if ( options.genC ) typeString = "union " + typeString;256 handleQualifiers( unionInst );257 }258 259 void GenType::postvisit( EnumInstType * enumInst ) {260 if ( enumInst->baseEnum && enumInst->baseEnum->base ) {261 typeString = genType(enumInst->baseEnum->base, typeString, options);262 } else {263 typeString = enumInst->name + " " + typeString;264 if ( options.genC ) {265 typeString = "enum " + typeString;266 }267 }268 handleQualifiers( enumInst );269 }270 271 void GenType::postvisit( TypeInstType * typeInst ) {272 assertf( ! options.genC, "Type instance types should not reach code generation." );273 typeString = typeInst->name + " " + typeString;274 handleQualifiers( typeInst );275 }276 277 void GenType::postvisit( TupleType * tupleType ) {278 assertf( ! options.genC, "Tuple types should not reach code generation." );279 unsigned int i = 0;280 std::ostringstream os;281 os << "[";282 for ( Type * t : *tupleType ) {283 i++;284 os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");285 }286 os << "] ";287 typeString = os.str() + typeString;288 }289 290 void GenType::postvisit( VarArgsType * varArgsType ) {291 typeString = "__builtin_va_list " + typeString;292 handleQualifiers( varArgsType );293 }294 295 void GenType::postvisit( ZeroType * zeroType ) {296 // ideally these wouldn't hit codegen at all, but should be safe to make them ints297 typeString = (options.pretty ? "zero_t " : "long int ") + typeString;298 handleQualifiers( zeroType );299 }300 301 void GenType::postvisit( OneType * oneType ) {302 // ideally these wouldn't hit codegen at all, but should be safe to make them ints303 typeString = (options.pretty ? "one_t " : "long int ") + typeString;304 handleQualifiers( oneType );305 }306 307 void GenType::postvisit( GlobalScopeType * globalType ) {308 assertf( ! options.genC, "Global scope type should not reach code generation." );309 handleQualifiers( globalType );310 }311 312 void GenType::postvisit( TraitInstType * inst ) {313 assertf( ! options.genC, "Trait types should not reach code generation." );314 typeString = inst->name + " " + typeString;315 handleQualifiers( inst );316 }317 318 void GenType::postvisit( TypeofType * typeof ) {319 std::ostringstream os;320 PassVisitor<CodeGenerator> cg( os, options );321 os << "typeof(";322 typeof->expr->accept( cg );323 os << ") " << typeString;324 typeString = os.str();325 handleQualifiers( typeof );326 }327 328 void GenType::postvisit( VTableType * vtable ) {329 assertf( ! options.genC, "Virtual table types should not reach code generation." );330 std::ostringstream os;331 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString;332 typeString = os.str();333 handleQualifiers( vtable );334 }335 336 void GenType::postvisit( QualifiedType * qualType ) {337 assertf( ! options.genC, "Qualified types should not reach code generation." );338 std::ostringstream os;339 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString;340 typeString = os.str();341 handleQualifiers( qualType );342 }343 344 void GenType::handleQualifiers( Type * type ) {345 if ( type->get_const() ) {346 typeString = "const " + typeString;347 } // if348 if ( type->get_volatile() ) {349 typeString = "volatile " + typeString;350 } // if351 if ( type->get_restrict() ) {352 typeString = "__restrict " + typeString;353 } // if354 if ( type->get_atomic() ) {355 typeString = "_Atomic " + typeString;356 } // if357 }358 27 359 28 namespace { -
src/CodeGen/Generate.cc
r790d835 rc6b4432 20 20 21 21 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new, doSemicolon, ... 22 #include "CodeGenerator.h" // for CodeGenerator, doSemicolon, oper...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 { -
src/CodeGen/Generate.h
r790d835 rc6b4432 27 27 28 28 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 29 35 30 /// Generates all code in transUnit and writing it to the os. -
src/CodeGen/LinkOnce.cc
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 16 16 17 17 SRC_CODEGEN = \ 18 CodeGen/CodeGenerator.cc \19 CodeGen/CodeGenerator.h \20 18 CodeGen/CodeGeneratorNew.cpp \ 21 19 CodeGen/CodeGeneratorNew.hpp \ -
src/Common/Eval.cc
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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/module.mk
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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 29 class GlobalFixer_new : public ast::WithShortCircuiting { 59 30 public: … … 69 40 std::list< ast::ptr<ast::Stmt> > destroyStmts; 70 41 }; 71 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 42 111 43 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { … … 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 expressions148 // xxx - this is an optimization. Need to first resolve constructors before we decide149 // 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-NULL154 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, but159 // non-intrinsic dtors must be called160 destroyStatements.push_front( dtor );161 ctorInit->dtor = nullptr;162 } // if163 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 okay173 objDecl->init = nullptr;174 } // if175 delete ctorInit;176 } // if177 }178 179 75 void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) { 180 76 auto mutDecl = mutate(objDecl); … … 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
r790d835 rc6b4432 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 -
src/InitTweak/GenInit.cc
r790d835 rc6b4432 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 { … … 526 273 } 527 274 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 constructed535 if ( dynamic_cast< ReferenceType * >( type ) ) return false;536 // need to clear and reset qualifiers when determining if a type is managed537 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 managed541 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 C553 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 managed574 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 that578 // polymorphic constructors make generic types managed types579 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 275 bool ManagedTypes_new::isManaged( const ast::Type * type ) const { 591 276 // references are never constructed … … 647 332 void ManagedTypes_new::endScope() { managedTypes.endScope(); } 648 333 649 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {650 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor651 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 }659 660 334 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 661 335 assertf(objDecl, "genCtorDtor passed null objDecl"); 662 336 InitExpander_new srcParam(arg); 663 337 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 338 } 739 339 -
src/InitTweak/GenInit.h
r790d835 rc6b4432 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 44 class ManagedTypes {45 public:46 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed47 bool isManaged( Type * type ) const; // determine if type is managed48 49 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor50 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed51 52 void beginScope();53 void endScope();54 private:55 GenPoly::ScopedSet< std::string > managedTypes;56 };57 38 58 39 class ManagedTypes_new { -
src/InitTweak/InitTweak.cc
r790d835 rc6b4432 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 designations59 if ( hasDesignations ) visit_children = false;60 }61 62 void previsit( Designation * des ) {63 // short circuit if we already know there are designations64 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 41 struct HasDesignations_new : public ast::WithShortCircuiting { 92 42 bool result = false; … … 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 80 struct InitFlattener_new : public ast::WithShortCircuiting { 139 81 std::vector< ast::ptr< ast::Expr > > argList; … … 146 88 147 89 } // anonymous namespace 148 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 90 167 91 bool isDesignated( const ast::Init * init ) { … … 182 106 return std::move( flattener.core.argList ); 183 107 } 184 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 now199 // 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 statement250 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, generates271 /// if (i < d) f(..., init)272 /// ++i;273 /// so that only elements within the range of the array are constructed274 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 detect298 // that the number of elements exceeds to dimension of the array299 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 to314 // terminate without creating output, so should catch this error315 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 designations323 // if ( init-> ) {324 condition = new ConstantExpr( Constant::from_ulong( cond ) );325 ++cond;326 // } else {327 // condition = // ... take designation328 // cond = // ... take designation+1329 // }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 element343 // may have more initializers than elements in the array - need to check at each index that344 // we haven't exceeded size.345 // may have fewer initializers than elements in the array - need to default construct346 // remaining elements.347 // To accomplish this, generate switch statement, consuming all of expander's elements348 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 init357 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 108 369 109 class InitExpander_new::ExpanderImpl { … … 537 277 } 538 278 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 546 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 547 280 assertf( ftype, "getTypeofThis: nullptr 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 310 struct CallFinder_new final { 622 311 std::vector< const ast::Expr * > matches; … … 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 328 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; … … 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 … … 907 380 return app; 908 381 } 909 910 struct ConstExprChecker : public WithShortCircuiting {911 // most expressions are not const expr912 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 constexpr918 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 children923 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 expr941 return;942 }943 }944 isConstExpr = false;945 }946 947 bool isConstExpr = true;948 };949 382 950 383 struct ConstExprChecker_new : public ast::WithShortCircuiting { … … 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 ) { … … 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 ) { -
src/InitTweak/InitTweak.h
r790d835 rc6b4432 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 128 class InitExpander_old {129 public:130 // expand by stepping through init to get each list of arguments131 InitExpander_old( Initializer * init );132 133 // always expand to expr134 InitExpander_old( Expression * expr );135 136 // iterator-like interface137 std::list< Expression * > operator*();138 InitExpander_old & operator++();139 140 // builds statement which has the same semantics as a C-style list initializer141 // (for array initializers) using callExpr as the base expression to perform initialization142 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 80 158 81 class InitExpander_new { -
src/InitTweak/module.mk
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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 30 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 } // if83 } // if84 } // if85 return typeInst;86 }87 } // anonymous namespace88 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 23 101 24 namespace { -
src/ResolvExpr/CastCost.cc
r790d835 rc6b4432 26 26 #include "ResolvExpr/ConversionCost.h" // for conversionCost 27 27 #include "ResolvExpr/PtrsCastable.hpp" // for ptrsCastable 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass29 28 #include "ResolvExpr/typeops.h" // for ptrsCastable 30 29 #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 30 35 31 #if 0 … … 40 36 41 37 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 47 using ConversionCost::previsit;48 using ConversionCost::postvisit;49 void postvisit( const BasicType * basicType );50 void postvisit( const PointerType * pointerType );51 };52 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 point64 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 } // if68 } // if69 } // if70 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 } // if102 } // if103 }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 } // if118 }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 } // if134 } // if135 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {136 if ( destAsBasic->isInteger() ) {137 // necessary for, e.g. void * => unsigned long138 cost = Cost::unsafe;139 } // if140 }141 }142 38 143 39 namespace { … … 200 96 } // anonymous namespace 201 97 202 203 204 98 Cost castCost( 205 99 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, -
src/ResolvExpr/CommonType.cc
r790d835 rc6b4432 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 … … 488 342 "Each basic type kind should have a corresponding row in the combined type matrix" 489 343 ); 490 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 } // if503 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {504 // use signed int in lieu of the enum/zero/one type505 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 } // if509 } 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 } // if518 }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 } // if558 strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;559 } else {560 /// std::cerr << "place for ptr-to-type" << std::endl;561 } // if562 pointerType->get_base()->tq = tq1;563 otherPointer->get_base()->tq = tq2;564 } // if565 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {566 result = pointerType->clone();567 result->tq |= type2->tq;568 } // if569 }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 } // if595 strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;596 } else {597 /// std::cerr << "place for ptr-to-type" << std::endl;598 } // if599 refType->get_base()->tq = tq1;600 otherRef->get_base()->tq = tq2;601 } // if602 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {603 result = refType->clone();604 result->tq |= type2->tq;605 } // if606 }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 enumInstType615 result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );616 } // if617 }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 } // if637 type2->tq = tq2;638 type->get_base()->tq = Type::Qualifiers();639 } // if640 } // if641 } // if642 }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 344 675 345 class CommonType_new final : public ast::WithShortCircuiting { -
src/ResolvExpr/CommonType.hpp
r790d835 rc6b4432 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
r790d835 rc6b4432 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 155 # warning For overload resolution between the two versions. -
src/ResolvExpr/ConversionCost.h
r790d835 rc6b4432 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 24 28 25 namespace SymTab { … … 32 29 namespace ResolvExpr { 33 30 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 31 80 32 // Some function pointer types, differ in return type. -
src/ResolvExpr/CurrentObject.cc
r790d835 rc6b4432 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
r790d835 rc6b4432 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 { -
src/ResolvExpr/FindOpenVars.h
r790d835 rc6b4432 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
r790d835 rc6b4432 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 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 type50 result += 1;51 } // if52 } else {53 // bound to concrete type54 result += 1;55 } // if56 } // if57 } // if58 }59 22 60 23 // TODO: When the old PolyCost is torn out get rid of the _new suffix. -
src/ResolvExpr/PtrsAssignable.cc
r790d835 rc6b4432 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 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 } // if61 } // if62 if ( dynamic_cast< const VoidType* >( dest ) ) {63 // void * = T * for any T is unsafe64 // xxx - this should be safe, but that currently breaks the build65 return -1;66 } else {67 PassVisitor<PtrsAssignable> ptrs( dest, env );68 src->accept( ptrs );69 return ptrs.pass.get_result();70 } // if71 }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 any77 // 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 each91 // enum has one basic type that it is compatible with, an that type can92 // differ from enum to enum. Without replicating GCC's internal logic,93 // there is no way to know which type this particular enum is compatible94 // 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 T104 result = ptrsAssignable( eqvClass->type, dest, env );105 }106 } // if107 }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 23 114 24 // TODO: Get rid of the `_new` suffix when the old version is removed. -
src/ResolvExpr/PtrsCastable.cc
r790d835 rc6b4432 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 { -
src/ResolvExpr/RenameVars.cc
r790d835 rc6b4432 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 103 struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 151 104 RenameMode mode; … … 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 134 ast::Pass<RenameVars_new> renamer; -
src/ResolvExpr/RenameVars.h
r790d835 rc6b4432 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
r790d835 rc6b4432 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 { -
src/ResolvExpr/Resolver.cc
r790d835 rc6b4432 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 ) { … … 610 59 return it != end; 611 60 } 612 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 61 971 62 namespace { -
src/ResolvExpr/SatisfyAssertions.cpp
r790d835 rc6b4432 46 46 #include "SymTab/Mangler.h" 47 47 48 49 50 48 namespace ResolvExpr { 51 49 -
src/ResolvExpr/SpecCost.cc
r790d835 rc6b4432 21 21 #include "AST/Pass.hpp" 22 22 #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 23 28 24 namespace ResolvExpr { 29 30 /// Counts specializations in a type31 class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> {32 int count = -1; ///< specialization count (-1 for none)33 34 public:35 int get_count() const { return count >= 0 ? count : 0; }36 37 // mark specialization of base type38 void postvisit(PointerType*) { if ( count >= 0 ) ++count; }39 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 25 119 26 namespace { -
src/ResolvExpr/Unify.cc
r790d835 rc6b4432 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 … … 218 99 subSecond, 219 100 newEnv, need, have, open, noWiden() ); 220 }221 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 101 } 735 102 -
src/ResolvExpr/Unify.h
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 19 19 20 20 #include "AST/Type.hpp" 21 #include "SynTree/Type.h"22 21 23 22 namespace SymTab { … … 52 51 std::copy( i.begin(), i.end(), inserter ); 53 52 *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 53 } 80 54 } … … 120 94 return tupleFromTypes( tys.begin(), tys.end() ); 121 95 } 122 123 // in TypeEnvironment.cc124 bool isFtype( const Type * type );125 96 } // namespace ResolvExpr 126 97 -
src/SymTab/Demangle.cc
r790d835 rc6b4432 21 21 #include "CodeGen/GenType.h" 22 22 #include "CodeGen/OperatorTable.h" 23 #include "Common/PassVisitor.h"24 23 #include "Common/utility.h" // isPrefix 25 24 #include "Mangler.h" 26 #include "SynTree/Type.h"27 #include "SynTree/Declaration.h"28 25 29 26 #define DEBUG … … 33 30 #define PRINT(x) {} 34 31 #endif 35 36 namespace SymTab {37 namespace Mangler {38 namespace {39 struct StringView {40 private:41 std::string str;42 size_t idx = 0;43 // typedef Type * (StringView::*parser)(Type::Qualifiers);44 typedef std::function<Type * (Type::Qualifiers)> parser;45 std::vector<std::pair<std::string, parser>> parsers;46 public:47 StringView(const std::string & str);48 49 bool done() const { return idx >= str.size(); }50 char cur() const { assert(! done()); return str[idx]; }51 52 bool expect(char ch) { return str[idx++] == ch; }53 void next(size_t inc = 1) { idx += inc; }54 55 /// determines if `pref` is a prefix of `str`56 bool isPrefix(const std::string & pref);57 bool extractNumber(size_t & out);58 bool extractName(std::string & out);59 bool stripMangleName(std::string & name);60 61 Type * parseFunction(Type::Qualifiers tq);62 Type * parseTuple(Type::Qualifiers tq);63 Type * parseVoid(Type::Qualifiers tq);64 Type * parsePointer(Type::Qualifiers tq);65 Type * parseArray(Type::Qualifiers tq);66 Type * parseStruct(Type::Qualifiers tq);67 Type * parseUnion(Type::Qualifiers tq);68 Type * parseEnum(Type::Qualifiers tq);69 Type * parseType(Type::Qualifiers tq);70 71 Type * parseType();72 bool parse(std::string & name, Type *& type);73 };74 75 StringView::StringView(const std::string & str) : str(str) {76 // basic types77 for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) {78 parsers.emplace_back(Encoding::basicTypes[k], [k](Type::Qualifiers tq) {79 PRINT( std::cerr << "basic type: " << k << std::endl; )80 return new BasicType(tq, (BasicType::Kind)k);81 });82 }83 // type variable types84 for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) {85 static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };86 static_assert(87 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS,88 "Each type variable kind should have a demangle name prefix"89 );90 parsers.emplace_back(Encoding::typeVariables[k], [k, this](Type::Qualifiers tq) -> TypeInstType * {91 PRINT( std::cerr << "type variable type: " << k << std::endl; )92 size_t N;93 if (! extractNumber(N)) return nullptr;94 return new TypeInstType(tq, toString(typeVariableNames[k], N), (TypeDecl::Kind)k != TypeDecl::Ftype);95 });96 }97 // everything else98 parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); });99 parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); });100 parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); });101 parsers.emplace_back(Encoding::array, [this](Type::Qualifiers tq) { return parseArray(tq); });102 parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); });103 parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); });104 parsers.emplace_back(Encoding::union_t, [this](Type::Qualifiers tq) { return parseUnion(tq); });105 parsers.emplace_back(Encoding::enum_t, [this](Type::Qualifiers tq) { return parseEnum(tq); });106 parsers.emplace_back(Encoding::type, [this](Type::Qualifiers tq) { return parseType(tq); });107 parsers.emplace_back(Encoding::zero, [](Type::Qualifiers tq) { return new ZeroType(tq); });108 parsers.emplace_back(Encoding::one, [](Type::Qualifiers tq) { return new OneType(tq); });109 }110 111 bool StringView::extractNumber(size_t & out) {112 std::stringstream numss;113 if (idx >= str.size()) return false;114 while (isdigit(str[idx])) {115 numss << str[idx];116 ++idx;117 if (idx == str.size()) break;118 }119 if (! (numss >> out)) return false;120 PRINT( std::cerr << "extractNumber success: " << out << std::endl; )121 return true;122 }123 124 bool StringView::extractName(std::string & out) {125 size_t len;126 if (! extractNumber(len)) return false;127 if (idx+len > str.size()) return false;128 out = str.substr(idx, len);129 idx += len;130 PRINT( std::cerr << "extractName success: " << out << std::endl; )131 return true;132 }133 134 bool StringView::isPrefix(const std::string & pref) {135 // if ( pref.size() > str.size()-idx ) return false;136 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );137 // if (its.first == pref.end()) {138 // idx += pref.size();139 // return true;140 // }141 142 // This update is untested because there are no tests for this code.143 if ( ::isPrefix( str, pref, idx ) ) {144 idx += pref.size();145 return true;146 }147 return false;148 }149 150 // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise151 bool StringView::stripMangleName(std::string & name) {152 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )153 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix154 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;155 156 // get name157 if (! extractName(name)) return false;158 159 // find bounds for type160 PRINT( std::cerr << idx << " " << str.size() << std::endl; )161 PRINT( std::cerr << "[");162 while (isdigit(str.back())) {163 PRINT(std::cerr << ".");164 str.pop_back();165 if (str.size() <= idx) return false;166 }167 PRINT( std::cerr << "]" << std::endl );168 if (str.back() != '_') return false;169 str.pop_back();170 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; )171 return str.size() > idx;172 }173 174 Type * StringView::parseFunction(Type::Qualifiers tq) {175 PRINT( std::cerr << "function..." << std::endl; )176 if (done()) return nullptr;177 FunctionType * ftype = new FunctionType( tq, false );178 std::unique_ptr<Type> manager(ftype);179 Type * retVal = parseType();180 if (! retVal) return nullptr;181 PRINT( std::cerr << "with return type: " << retVal << std::endl; )182 ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr));183 if (done() || ! expect('_')) return nullptr;184 while (! done()) {185 PRINT( std::cerr << "got ch: " << cur() << std::endl; )186 if (cur() == '_') return manager.release();187 Type * param = parseType();188 if (! param) return nullptr;189 PRINT( std::cerr << "with parameter : " << param << std::endl; )190 ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr));191 }192 return nullptr;193 }194 195 Type * StringView::parseTuple(Type::Qualifiers tq) {196 PRINT( std::cerr << "tuple..." << std::endl; )197 std::list< Type * > types;198 size_t ncomponents;199 if (! extractNumber(ncomponents)) return nullptr;200 for (size_t i = 0; i < ncomponents; ++i) {201 // TODO: delete all on return202 if (done()) return nullptr;203 PRINT( std::cerr << "got ch: " << cur() << std::endl; )204 Type * t = parseType();205 if (! t) return nullptr;206 PRINT( std::cerr << "with type : " << t << std::endl; )207 types.push_back(t);208 }209 return new TupleType( tq, types );210 }211 212 Type * StringView::parseVoid(Type::Qualifiers tq) {213 return new VoidType( tq );214 }215 216 Type * StringView::parsePointer(Type::Qualifiers tq) {217 PRINT( std::cerr << "pointer..." << std::endl; )218 Type * t = parseType();219 if (! t) return nullptr;220 return new PointerType( tq, t );221 }222 223 Type * StringView::parseArray(Type::Qualifiers tq) {224 PRINT( std::cerr << "array..." << std::endl; )225 size_t length;226 if (! extractNumber(length)) return nullptr;227 Type * t = parseType();228 if (! t) return nullptr;229 return new ArrayType( tq, t, new ConstantExpr( Constant::from_ulong(length) ), false, false );230 }231 232 Type * StringView::parseStruct(Type::Qualifiers tq) {233 PRINT( std::cerr << "struct..." << std::endl; )234 std::string name;235 if (! extractName(name)) return nullptr;236 return new StructInstType(tq, name);237 }238 239 Type * StringView::parseUnion(Type::Qualifiers tq) {240 PRINT( std::cerr << "union..." << std::endl; )241 std::string name;242 if (! extractName(name)) return nullptr;243 return new UnionInstType(tq, name);244 }245 246 Type * StringView::parseEnum(Type::Qualifiers tq) {247 PRINT( std::cerr << "enum..." << std::endl; )248 std::string name;249 if (! extractName(name)) return nullptr;250 return new EnumInstType(tq, name);251 }252 253 Type * StringView::parseType(Type::Qualifiers tq) {254 PRINT( std::cerr << "type..." << std::endl; )255 std::string name;256 if (! extractName(name)) return nullptr;257 PRINT( std::cerr << "typename..." << name << std::endl; )258 return new TypeInstType(tq, name, false);259 }260 261 Type * StringView::parseType() {262 if (done()) return nullptr;263 264 std::list<TypeDecl *> forall;265 if (isPrefix(Encoding::forall)) {266 PRINT( std::cerr << "polymorphic with..." << std::endl; )267 size_t dcount, fcount, vcount, acount;268 if (! extractNumber(dcount)) return nullptr;269 PRINT( std::cerr << dcount << " dtypes" << std::endl; )270 if (! expect('_')) return nullptr;271 if (! extractNumber(fcount)) return nullptr;272 PRINT( std::cerr << fcount << " ftypes" << std::endl; )273 if (! expect('_')) return nullptr;274 if (! extractNumber(vcount)) return nullptr;275 PRINT( std::cerr << vcount << " ttypes" << std::endl; )276 if (! expect('_')) return nullptr;277 if (! extractNumber(acount)) return nullptr;278 PRINT( std::cerr << acount << " assertions" << std::endl; )279 if (! expect('_')) return nullptr;280 for (size_t i = 0; i < acount; ++i) {281 // TODO: need to recursively parse assertions, but for now just return nullptr so that282 // demangler does not crash if there are assertions283 return nullptr;284 }285 if (! expect('_')) return nullptr;286 }287 288 // qualifiers289 Type::Qualifiers tq;290 while (true) {291 auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {292 return isPrefix(val.second);293 });294 if (qual == Encoding::qualifiers.end()) break;295 tq |= qual->first;296 }297 298 // find the correct type parser and use it299 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) {300 return isPrefix(p.first);301 });302 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx);303 Type * ret = iter->second(tq);304 if (! ret) return nullptr;305 ret->forall = std::move(forall);306 return ret;307 }308 309 bool StringView::parse(std::string & name, Type *& type) {310 if (! stripMangleName(name)) return false;311 PRINT( std::cerr << "stripped name: " << name << std::endl; )312 Type * t = parseType();313 if (! t) return false;314 type = t;315 return true;316 }317 318 std::string demangle(const std::string & mangleName) {319 SymTab::Mangler::StringView view(mangleName);320 std::string name;321 Type * type = nullptr;322 if (! view.parse(name, type)) return mangleName;323 auto info = CodeGen::operatorLookupByOutput(name);324 if (info) name = info->inputName;325 std::unique_ptr<Type> manager(type);326 return CodeGen::genType(type, name);327 }328 } // namespace329 } // namespace Mangler330 } // namespace SymTab331 32 332 33 namespace Mangle { … … 550 251 if (done()) return nullptr; 551 252 552 std::list<TypeDecl *> forall;553 253 if (isPrefix(Encoding::forall)) { 554 254 PRINT( std::cerr << "polymorphic with..." << std::endl; ) -
src/SymTab/FixFunction.cc
r790d835 rc6b4432 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 { -
src/SymTab/FixFunction.h
r790d835 rc6b4432 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/Mangler.cc
r790d835 rc6b4432 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 { -
src/SymTab/Mangler.h
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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 { -
src/Tuples/TupleExpansion.cc
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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/FindSpecialDecls.h
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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 … … 100 96 ast::pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass ); 101 97 ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 102 }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 98 } 108 99 }
Note:
See TracChangeset
for help on using the changeset viewer.